Home > Back-end >  Creating CUDA C library using CMake
Creating CUDA C library using CMake

Time:10-17

I've the following code structure for my library

|-build
|-example
    |-CMakeLists.txt
    |-main_VecAdd.cu
|-include
    |-VonNeumann
        |-utils.h
        |-VecAdd.h
    |-CMakeLists.txt
|-src
    |-CMakeLists.txt
    |-utils.c
    |-VecAdd.c
|-CMakeLists.txt

CMakeLists.txt for folders example, include, src and main_folder are as follows (in order respectively):

project(VonNeumann LANGUAGES CUDA C)

add_executable(main_VecAdd main_VecAdd.cu)

set_target_properties(VonNeumann PROPERTIES CUDA_SEPARABLE_COMPILATION ON)

target_link_libraries(main_VecAdd 
    PRIVATE
    VonNeumann)
project(VonNeumann LANGUAGES CUDA C)
project(VonNeumann LANGUAGES CUDA C)

add_library(VonNeumann utils.c VecAdd.c)

target_include_directories(VonNeumann
    PUBLIC
    ${CMAKE_CURRENT_SOURCE_DIR}/../include)
cmake_minimum_required(VERSION 3.16.3)
project(VonNeumann LANGUAGES CUDA C)

# Adding subdirectories
add_subdirectory(include)
add_subdirectory(src)

# Giving an option to include code in examples or not
option(BUILD_EXAMPLES "Whether or not to build examples" ON)
if (BUILD_EXAMPLES)
    message(STATUS "Building examples...")
    add_subdirectory(example)
endif()

When I run cmake .. from build directory, everything works well however I get the following error when I run make command:

[ 16%] Linking C static library libVonNeumann.a
[ 50%] Built target VonNeumann
[ 66%] Linking CUDA device code CMakeFiles/main_VecAdd.dir/cmake_device_link.o
[ 83%] Linking CUDA executable main_VecAdd
/usr/bin/ld: CMakeFiles/main_VecAdd.dir/main_VecAdd.cu.o: in function `main':
tmpxft_000058c9_00000000-6_main_VecAdd.cudafe1.cpp:(.text 0x111): undefined reference to `RandVecFP32(float*, int)'
/usr/bin/ld: tmpxft_000058c9_00000000-6_main_VecAdd.cudafe1.cpp:(.text 0x122): undefined reference to `RandVecFP32(float*, int)'
/usr/bin/ld: tmpxft_000058c9_00000000-6_main_VecAdd.cudafe1.cpp:(.text 0x133): undefined reference to `ZeroVecFP32(float*, int)'
/usr/bin/ld: tmpxft_000058c9_00000000-6_main_VecAdd.cudafe1.cpp:(.text 0x144): undefined reference to `PrintVec(float*, int)'
/usr/bin/ld: tmpxft_000058c9_00000000-6_main_VecAdd.cudafe1.cpp:(.text 0x155): undefined reference to `PrintVec(float*, int)'
/usr/bin/ld: tmpxft_000058c9_00000000-6_main_VecAdd.cudafe1.cpp:(.text 0x166): undefined reference to `PrintVec(float*, int)'
/usr/bin/ld: tmpxft_000058c9_00000000-6_main_VecAdd.cudafe1.cpp:(.text 0x17d): undefined reference to `VecAddFP32(float*, float*, float*, int)'
/usr/bin/ld: tmpxft_000058c9_00000000-6_main_VecAdd.cudafe1.cpp:(.text 0x19a): undefined reference to `PrintVec(float*, int)'
collect2: error: ld returned 1 exit status
make[2]: *** [example/CMakeFiles/main_VecAdd.dir/build.make:105: example/main_VecAdd] Error 1
make[1]: *** [CMakeFiles/Makefile2:163: example/CMakeFiles/main_VecAdd.dir/all] Error 2
make: *** [Makefile:84: all] Error 2

I know that the error is because of failed linking but I can't figure out how to resolve this.

P.S. I've tested this same code without CUDA part and it works just fine.

CodePudding user response:

As @talonmies suggests, the problem is likely you trying to use functions implemented in your .cu file, in your .c file: CUDA uses "C linkage", that the function symbols appear in a certain way in the compiled object file, which differs from how function symbols appear when compiled using C.

To allow your C code to be used by C code, you must adapt the declarations to be read differently in C (or CUDA), in utils.h and VecAdd.h like so:

#ifdef __cplusplus
extern "C"
{
#endif

void PrintVec(float*, int);
// ... or whatever you're defining

#ifdef __cplusplus
}
#endif

See also:


By the way - you're using too many CMakeLists.txt files. You don't need one of these for every folder. In fact, for a project as small as yours, a top-level CMakeLists.txt and perhaps another one for the examples would have sufficed. Subdirectory-specific CMakeLists.txt files are appropriate where the contents of the subdirectory is worked on relatively independently, and the top-level CMakeLists.txt does not need to be aware of the dependencies and other configuration work towards producing the targets that do get used outside.

  • Related