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.