在CMake中链接CUDA库

8
我正在使用CMake 3.10,在CMake中将已编译的库链接到测试可执行文件时遇到了问题。我进行了大量搜索,发现在早期版本中存在一个问题,即无法将中间库链接到结果可执行文件中。我无法确定这个问题是否已经解决或者仍然存在。
我的CMake文件如下:
Algo:
cmake_minimum_required (VERSION 3.9)
project(${MODULE_NAME}_core LANGUAGES CXX CUDA)


add_subdirectory("${core_impl_dir}" implementation)


set(cuda_src "parallel/ParallelComputation.cu")
set(cuda_hdr "parallel/ParallelComputation.h")

add_library(${PROJECT_NAME} STATIC "${cuda_src}" "${cuda_hdr}"
)


target_include_directories (${PROJECT_NAME} PUBLIC "include/" 
"parallel/"
)

source_group("parallel"  FILES "${cuda_src}" "${cuda_hdr}")


set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER ${MODULE_NAME})

测试:

project(${MODULE_NAME}_gtest LANGUAGES CXX CUDA)

add_subdirectory("${gtest_impl_dir}" implementation)

add_executable(${PROJECT_NAME} "${gtest_impl_src}")
target_link_libraries(${PROJECT_NAME} ${MODULE_NAME}_core)

enable_testing()
find_package(GTest REQUIRED)
include_directories("${GTEST_INCLUDE_DIRS}")


target_link_libraries(${PROJECT_NAME} ${GTEST_BOTH_LIBRARIES})

source_group("Implementation\\Source Files" FILES "${gtest_impl_src}" )

set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER ${MODULE_NAME})

add_test(${PROJECT_NAME} ${PROJECT_NAME})

只编译算法的话是可以的,但是同时编译测试时,我会遇到链接错误,例如:

../implementation/libmatrix1_testCuda_core.a(ParallelComputation.cu.o): 在函数'cudaError cudaMalloc(float**, unsigned long)'中: tmpxft_00005ad0_00000000-5_ParallelComputation.cudafe1.cpp:(.text+0x4f2): 未定义对'cudaMalloc'的引用

编辑
通过使用make VERBOSE=1我得到了以下链接命令:

/usr/bin/c++ -Wl,--no-as-needed -pthread -g -std=c++14 -Wall
CMakeFiles/matrix1_testCuda_gtest.dir//tests/eclipseProject/algos/testCuda/test/src/main.cpp.o CMakeFiles/matrix1_testCuda_gtest.dir/cmake_device_link.o -o matrix1_testCuda_gtest ../implementation/libmatrix1_testCuda_core.a /usr/lib/libgtest.a /usr/lib/libgtest_main.a


1
根本原因可能是未链接CUDA运行时库。如果nvcc正在进行链接,则不需要这样做,这表明您的主机编译器正在进行链接。如何在CMake中修复它,我不知道。 - talonmies
@talonmies 我通过使用find_package(CUDA 9.0 REQUIRED)或显式将链接器语言设置为CUDA来解决了CUDA运行时问题。现在链接器抱怨设备代码。我不明白的是,设备代码仅在库中调用,主测试代码仅导入公开普通C++方法的接口,这些方法又调用设备代码。为什么它需要在这里进行链接,难道在构建库的步骤中已经完成了设备代码的链接吗? - kutschkem
@talonmies 不要紧,那个错误实际上是我的错,头文件中的命名空间与实现不匹配,编译器没有捕捉到它。 - kutschkem
3个回答

14

这个答案适用于CMake版本<3.10。该方法自CMake 3.10开始已不推荐使用,但在原则上仍可用于更新的版本。这是我在使用CMake 3.10时使用的方法。

对于CMake版本>=3.10但<3.17,请首先检查Pat Lorton的答案是否有帮助。

对于CMake 3.17+,请查看VojtaK的答案


我通过调用以下命令使其工作

find_package(CUDA 9.0 REQUIRED)

在两个 CMake 文件中都需要进行更改。同时,在包含设备代码的 Algo 文件中,我不得不进行调整。

target_link_libraries(${PROJECT_NAME} ${CUDA_LIBRARIES})

我原本期望CUDA的语言支持能够使这些步骤变得不必要,但显然并非如此。


1
在更新的CMake版本中,这已经不再是惯用解决方案。 - einpoklum
4
@einpoklum:由于这似乎是被许多人查看的问题,如果较新的CMake版本有所不同,请添加一个答案,说明新的方法。 - kutschkem
@kutschkem 也许你想指出VojtaK的答案,该答案展示了FindCUDAToolkit的用法,它将不同的库作为目标导入。对我来说非常有效,并且似乎是一种更现代或惯用的解决方案。 - SimonH
@SimonH 我该如何最好地做到这一点? - kutschkem
@kutschkem 我不知道是否有最佳方法,但您可以编辑您的答案,说明对于 cmake 3.17+,如果程序不包含 CUDA 代码,但只需链接到 CUDA 库,则 FindCUDAToolkit 完全适用于该用例(参考 VojtaK 的答案)。您可以保留使用 FindCUDA 的解决方案,以供出于任何原因使用旧版 cmake 的人使用,但即使是 cmake 文档也指出 FindCUDA 自 cmake 3.10 起已弃用 - SimonH
1
@SimonH 编辑得不错,像这样? - kutschkem

8
我遇到了一个非常相似的问题,根本原因是我的大部分二进制代码是使用系统 cxx 编译器编译的,而 cuda 部分是用 cuda gcc 编译器 (系统为 9.1,cuda 为 8.3) 编译的。
令人惊讶的是,只需更改以下内容即可解决:project(MyProject LANGUAGES CXX CUDA) 更改为 project(MyProject LANGUAGES CUDA CXX)
更改后,CMake 捕获了 cuda 版本的 gcc 编译器作为主编译器,我的二进制文件再次开始构建。我不确定这是否会为其他包引入问题,但它解决了我遇到的链接问题。

我之前有一个可运行的项目,然后在使用CUDA编译时出现了问题。错误很相似,但解决方案是一样的。 - José D. Tascón-Vidarte
就我个人而言,如果不明确指定,它就无法链接CUDA库。 - Antoine Viallon

6
在CMake 3.17及更高版本中添加可能的方法
当您希望不包括任何CUDA代码,但是例如仅使用来自C++的cufft调用时,只需执行以下操作即可。
find_package(CUDAToolkit)
target_link_libraries(project CUDA::cudart)
target_link_libraries(project CUDA::cufft)

如果您要启用CUDA支持,除非您想遇到麻烦,否则请在启用CUDA后调用它。
include(CheckLanguage)
check_language(CUDA)
if(CMAKE_CUDA_COMPILER)
enable_language(CUDA)
find_package(CUDAToolkit)
target_link_libraries(project CUDA::cudart)
target_link_libraries(project CUDA::cuda_driver)
else()
message(STATUS "No CUDA compiler found")
endif()



因为CUDAToolkit尊重启用了CUDA运行时,但反过来则不起作用。

2
“FindCUDAToolkit”从cmake 3.17开始支持,而不是3.18,对吗?这是真正的答案,至少对于那些出于任何原因都不坚持使用中世纪版本的cmake的人来说。 - SimonH
我在3.18版本中尝试过,但在3.17版本中也可以制作。谢谢,我已经更改了它。 - VojtaK

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接