使用CMake创建CUDA C库时遇链接错误,求解决方案
问题描述
代码结构
|-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内容
example/CMakeLists.txt
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)
include/CMakeLists.txt
project(VonNeumann LANGUAGES CUDA C)
src/CMakeLists.txt
project(VonNeumann LANGUAGES CUDA C) add_library(VonNeumann utils.c VecAdd.c) target_include_directories(VonNeumann PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../include)
主目录CMakeLists.txt
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()
编译错误
从build目录执行cmake ..正常,但make时出现链接错误:
[ 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
补充说明:不含CUDA的相同代码结构运行完全正常。
问题分析与解决
核心原因
CUDA编译器(nvcc)基于C++实现,会对函数名做名字修饰(name mangling);而库代码是纯C文件(utils.c、VecAdd.c),C编译器不会进行名字修饰。当CUDA代码调用C函数时,链接器找不到对应的修饰后符号,导致未定义引用错误。
同时现有CMake配置存在冗余问题:
include目录的CMakeLists.txt完全多余,无需单独声明projectexample中对纯C库设置CUDA_SEPARABLE_COMPILATION属性无效- 主目录与子目录重复声明
project(VonNeumann),无必要
修复步骤
1. 为头文件添加C语言链接声明
在include/VonNeumann/utils.h和VecAdd.h中,添加如下代码,确保CUDA编译器识别C函数符号:
#ifdef __cplusplus extern "C" { #endif // 原有函数声明示例 void RandVecFP32(float*, int); void ZeroVecFP32(float*, int); void PrintVec(float*, int); void VecAddFP32(float*, float*, float*, int); #ifdef __cplusplus } #endif
2. 精简CMake配置
删除include/CMakeLists.txt
该文件无实际作用,直接删除即可。
修改src/CMakeLists.txt
移除重复的project声明,简化为:
add_library(VonNeumann utils.c VecAdd.c) target_include_directories(VonNeumann PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../include)
修改example/CMakeLists.txt
移除无效的CUDA属性设置,简化为:
add_executable(main_VecAdd main_VecAdd.cu) target_link_libraries(main_VecAdd PRIVATE VonNeumann)
修改主目录CMakeLists.txt
移除多余的include子目录添加,保持核心逻辑:
cmake_minimum_required(VERSION 3.16.3) project(VonNeumann LANGUAGES CUDA C) # Adding subdirectories 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()
3. 重新编译
进入build目录,清理旧构建文件后重新执行编译:
rm -rf * cmake .. make
通过extern "C"声明,CUDA编译器会以C语言规则处理这些函数,避免名字修饰,链接时就能匹配到纯C库中的符号,解决链接错误。
内容的提问来源于stack exchange,提问作者Tushar Gautam
相关产品推荐
相关产品推荐

