提问人:einpoklum 提问时间:12/16/2019 最后编辑:einpoklum 更新时间:11/30/2020 访问量:1254
分离库的主机端和 CUDA 设备端版本
Separate the host-side and CUDA-device-side versions of library
问:
我有一个带有一些功能的库。我还有一个小工具,可以确保常规的 C++ 编译器看不到,因此可以编译这些函数。__host__ __device__
#ifdef __CUDACC__
__host__ __device__
现在,我想在一个普通的 C++ 静态库文件(在 Linux 上)中使用我的库函数的编译主机端版本 - 我什至希望该库在 CUDA 不可用时可编译;我希望将编译的设备端版本放在单独的静态库中。.a
我快到了(我想),但被链接错误卡住了。以下是这样一个库、测试程序(它调用函数的设备端和主机端版本)和我使用的构建命令的玩具源代码。
我做错了什么?
my_lib.hpp
(库标题):
#ifdef __CUDACC__
__host__ __device__
#endif
void foo(int*x, int* y);
int bar();
my_lib.cu
(库源):
#include "my_lib.hpp"
#ifdef __CUDACC__
__host__ __device__
#endif
void foo(int*x, int* y) { *x = *y; }
int bar() { return 5; }
main.cu
(测试程序):
#include "my_lib.hpp"
__global__ void my_kernel() {
int z { 78 };
int w { 90 };
foo(&z,&w);
}
int main() {
int z { 123 };
int w { 456 };
foo(&z,&w);
my_kernel<<<1,1>>>();
cudaDeviceSynchronize();
cudaDeviceReset();
}
我的构建命令:
c++ -c -x c++ -o my_lib-noncuda.o my_lib.cu
ar qc my_lib-noncuda.a my_lib-noncuda.o
ranlib my_lib-noncuda.a
nvcc -dc -o my_lib-cuda.o my_lib.cu
ar qc my_lib-cuda.a my_lib-cuda.o
ranlib my_lib-cuda.a
nvcc -dc -o main.rdc.o main.cu
nvcc -dlink -o main.o main.rdc.o my_lib-cuda.a
c++ -o main main.o my_lib-noncuda.a -lcudart
我得到的错误 - 在最后一个链接命令上:
/usr/bin/ld: main.o: in function `__cudaRegisterLinkedBinary_39_tmpxft_00003f88_00000000_6_main_cpp1_ii_e7ab3416':
link.stub:(.text+0x5a): undefined reference to `__fatbinwrap_39_tmpxft_00003f88_00000000_6_main_cpp1_ii_e7ab3416'
/usr/bin/ld: main.o: in function `__cudaRegisterLinkedBinary_41_tmpxft_00003f69_00000000_6_my_lib_cpp1_ii_ab44b3f6':
link.stub:(.text+0xaa): undefined reference to `__fatbinwrap_41_tmpxft_00003f69_00000000_6_my_lib_cpp1_ii_ab44b3f6'
collect2: error: ld returned 1 exit status
笔记:
- 我在 Devuan GNU/Linux 上使用 CUDA 10.1 和 g++ 9.2.1。
- 这是对已删除问题的“跟进”;@talonmies评论说,我最好准确地展示我做了什么;这在一定程度上改变了问题。
- 有点相关的问题:这个。
答:
让我们将您的示例修改为我认为您的实际用例。修改放入一个文件中,由 进行编译,将 CUDA 代码放入一个单独的文件中,由 进行编译。这对于使双库设置正常工作非常重要;并且是有道理的,因为“main 包含需要单独编译和链接的 CUDA 内核”是编译模型的一个特殊极端情况。main()
.cpp
g++
.cu
nvcc
nvcc
重构后的代码:
main.cu
:
include "my_lib.hpp"
__global__ void my_kernel() {
int z { 78 };
int w { 90 };
foo(&z,&w);
}
int cudamain()
{
my_kernel<<<1,1>>>();
return 0;
}
main.cpp
:
#include <cuda_runtime_api.h>
#include "my_lib.hpp"
extern int cudamain();
int main() {
int z { 123 };
int w { 456 };
foo(&z,&w);
cudamain();
cudaDeviceSynchronize();
cudaDeviceReset();
}
所有其他文件仍与问题相同。
现在,构建程序所需的命令是:
c++ -c -x c++ -o my_lib-noncuda.o my_lib.cu
ar qc my_lib-noncuda.a my_lib-noncuda.o
ranlib my_lib-noncuda.a
nvcc -std=c++11 -dc -o my_lib-cuda.rdc.o my_lib.cu
ar qc my_lib-cuda.a my_lib-cuda.rdc.o
ranlib my_lib-cuda.a
# Until this line - identical to what you have tried in your question
nvcc -std=c++11 -c -rdc=true main.cu -o main.cu.o
nvcc -dlink -o main.o main.cu.o my_lib-cuda.a
c++ -std=c++11 -o main main.cpp main.o main.cu.o -I/path/to/cuda/include \
-L/path/to/cuda/lib64 my_lib-cuda.a my_lib-noncuda.a -lcudart -lcudadevrt
需要记住的重要一点是,在构建中需要继续执行主机端组件。因此,您必须将 CUDA 主机代码的输出传递给主链接,并且还必须将 CUDA 端库添加到主链接。否则,将缺少对代码的主机端运行时 API 支持。另请注意,必须链接设备运行时库才能实现此目的。nvcc
评论
my_lib-noncuda.a
my_lib-noncuda.a
my_lib-cuda.a
foo()
bar()
-cuda.a
-noncuda.a
以下是创建两个库的方法,一个仅包含 CUDA 设备函数,另一个仅包含主机函数。
您可以省略“复杂”和警卫。但是,您的库中也会有“非 CUDA 代码”。#if
#ifndef
my_lib-cuda.a
对于其他问题@talonmies请参阅社区 wiki 答案或参考我已经在评论中发布的链接:https://devblogs.nvidia.com/separate-compilation-linking-cuda-device-code/ - “高级用法:使用不同的链接器”部分。
my_lib.cu
#include "my_lib.hpp"
#ifdef __CUDA_ARCH__
__device__
#endif
#if (defined __CUDA_ARCH__) || (not defined __CUDACC__)
void foo(int*x, int* y) { *x = *y; }
#endif
#ifndef __CUDACC__
int bar() { return 5; }
#endif
库的构建过程保持不变:(仅更改为替换现有文件,因此在不事先删除库的情况下重新构建时不会出现错误)ar qc
ar rc
c++ -c -x c++ -o my_lib-noncuda.o my_lib.cu
ar rc my_lib-noncuda.a my_lib-noncuda.o
ranlib my_lib-noncuda.a
nvcc -dc -o my_lib-cuda.o my_lib.cu
ar rc my_lib-cuda.a my_lib-cuda.o
ranlib my_lib-cuda.a
构建 CUDA 程序:(通过仅使用而不是使用简化,或者查看@talonmies社区 wiki 答案)nvcc
c++
nvcc -dc main.cu -o main.o
nvcc main.o my_lib-cuda.a my_lib-noncuda.a -o main
如果如上所述省略了 and in,则可以省略 的链接。my_lib-noncuda.a
#if
#ifndef
my_lib.cu
构建 C++ 程序:(假设 CUDA 代码周围有守卫#ifdef __CUDACC__
main.cu
)
c++ -x c++ -c main.cu -o main.o
c++ main.o my_lib-noncuda.a -o main
评论
nvlink error : Multiple definition of '_Z3fooPiS_' in 'my_lib-cuda.a:my_lib-cuda.rdc.o', first defined in 'my_lib-cuda.a:my_lib-cuda.o' nvlink fatal : merge_elf failed
my_lib-cuda.a
评论
main()
-dc
-dc
nvcc -o main.o main.cu
Unresolved extern function '_Z3fooPiS_'
.a
.a