You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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配置存在冗余问题:

  1. include目录的CMakeLists.txt完全多余,无需单独声明project
  2. example中对纯C库设置CUDA_SEPARABLE_COMPILATION属性无效
  3. 主目录与子目录重复声明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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 03:01:25