Cuda C - 链接错误 - 未定义的引用。

17
我很难编译一个仅由两个文件组成的简单cuda程序。
main.c看起来像这样:
#include "my_cuda.h"

int main(int argc, char** argv){
   dummy_gpu();
}

cuda.h的内容如下:

#ifndef MY_DUMMY
#define MY_DUMMY

void dummy_gpu();

#endif

而 my_cuda.cu 文件看起来像这样:

#include <cuda_runtime.h>
#include "my_cuda.h"

__global__ void dummy_gpu_kernel(){
   //do something
}

void dummy_gpu(){
   dummy_gpu_kernel<<<128,128>>>();
}

然而,如果我编译,我总是会收到以下错误:

gcc  -I/usr/local/cuda/5.0.35/include/ -c main.c
nvcc  -c my_cuda.cu
gcc  -L/usr/local_rwth/sw/cuda/5.0.35/lib64 -lcuda -lcudart -o md.exe main.o my_cuda.o 
main.o: In function `main':
main.c:(.text+0x15): undefined reference to `dummy_gpu'
collect2: ld returned 1 exit status

谢谢你的帮助。


我的CUDA有点生疏,但是你不应该能够调用使用nvcc编译器编译的符号。如果我没记错的话,你需要设置一个核函数并调用必要的启动函数。 - rutgersmike
真正的问题是:为什么不使用nvcc进行链接,让它来完成艰苦的工作呢?或者使用类似CMake的工具呢? - Charles Welton
1
CMake 也会失败。 - Constantin
2个回答

26

您遇到了符号名称混淆的问题。 nvcc 使用主机C++编译器编译主机代码,这意味着CUDA工具链发出的代码会应用名称混淆

有两种解决方案。 首先是使用C链接定义dummy_gpu,因此将您的my_cuda.cu 更改为以下内容:

extern "C" {
#include "my_cuda.h"
}

.....


extern "C"
void dummy_gpu(){
   dummy_gpu_kernel<<<128,128>>>();
}

请注意,你需要将你的链接命令更改为以下内容:

gcc -L/usr/local_rwth/sw/cuda/5.0.35/lib64 -o md.exe main.o my_cuda.o -lcuda -lcudart 
因为CUDA共享库需要在使用它们的目标文件后面指定。您的第二个选择是使用g++nvcc进行链接,这样整个问题应该就消失了。

1
只使用g++或nvcc进行链接会导致完全相同的错误。我在这里漏掉了什么?此外,第一种方法会导致不同的错误: gcc -I/usr/local_rwth/sw/cuda/5.0.35/include/ -c main.c nvcc -c my_cuda.cu my_cuda.cu(10): error: 链接规范与先前的"dummy_gpu"不兼容 my_cuda.h(4): 这里在"/tmp/tmpxft_000061a8_00000000-6_my_cuda.cpp1.ii"的编译中检测到1个错误。 - user1829358
@user1829358:您还需要修改如何将my_cuda.h包含到.cu文件中。有关更多详细信息,请参见我所做的编辑。 - talonmies
非常感谢您,talonmies。我很想知道您是如何发现nvcc使用g++的?我怀疑有些名称混淆正在进行中,但我不知道如何确认!再次感谢! - Constantin
@Constantin:你可以使用--dryrun或--verbose选项运行nvcc。这将打印出编译过程中每个阶段发出的确切命令。从那里,你可以看到编译主机代码的g++/cl调用。你还可以在Linux/OS X上使用elf/mach工具来转储对象文件的头表,并查看C++名称重整、RTTI空间、标准库钩子等的存在。 - talonmies
我当时走对了路!我正在使用 readelf -s 检查目标文件,但我不知道 C++ 名称修饰和 RTTI 空间的具体形式。今天我学到了。 - Constantin

8

你遇到了一个C/C++链接问题。nvcc以C++的方式修饰内容,但是你的gcc编译器使用C风格进行处理。一个简单的解决方法是将main.c重命名为main.cpp,然后使用g++而不是gcc重复你的命令。


很遗憾,我必须使用C编译器编译.c文件,而且我不能将其重命名(这个真实的项目需要一些C编译器的功能,这些功能目前还不被C++编译器支持)。 - user1829358
我建议使用@talonmies提出的方法,明确告诉C ++编译器不要混淆将链接到C端的函数名称。 这对我来说似乎有效。 - Robert Crovella

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