CUDA/C++ - 链接错误:未定义的引用

6
我是一个新手,正在寻求帮助,想要使用g++将一些编译好的CUDA目标代码与C++项目进行链接。之前已经有一些类似问题和解决方案发布过了(这里这里),但是都没有对我有效,并且我似乎也找不到原因。不幸的是,我必须在Windows上进行此操作。
我尝试让下面的简单示例正常工作:
// kernel.h
int cuda_vec_add(float *h_a, float *h_b, float *h_c, int n);

CUDA代码添加两个向量。

// kernel.cu
#include <kernel.h>

__global__ void vec_add_kernel(float *a, float *b, float *c, int n) {
    int i = threadIdx.x + blockDim.x * blockIdx.x;
    if (i < n) c[i] = a[i] + b[i];
}

int cuda_vec_add(float *h_a, float *h_b, float *h_c, int n) {
    float *d_a, *d_b, *d_c;

    cudaMalloc(&d_a, n*sizeof(float));
    cudaMalloc(&d_b, n*sizeof(float));
    cudaMalloc(&d_c, n*sizeof(float));

    cudaMemcpy(d_a, h_a, n*sizeof(float), cudaMemcpyHostToDevice);
    cudaMemcpy(d_b, h_b, n*sizeof(float), cudaMemcpyHostToDevice);

    vec_add_kernel<< <(n-1)/256+1,256>> >(d_a, d_b, d_c, n);

    cudaMemcpy(h_c, d_c, n*sizeof(float), cudaMemcpyDeviceToHost);

    cudaFree(d_a); cudaFree(d_b); cudaFree(d_c);

    return 0;
}

并且 c++ 代码调用 CUDA 函数。

// main.cpp
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <kernel.h>

using namespace std;


int main() {
    const int n = 5;
    float h_A[n] = { 0., 1., 2., 3., 4. };
    float h_B[n] = { 5., 4., 3., 2., 1. };
    float h_C[n];

    cuda_vec_add(h_A, h_B, h_C, n);

    printf("{ 0.0, 1.0, 2.0, 3.0, 4.0 } + { 5.0, 4.0, 3.0, 2.0, 1.0 } = { %0.01f, %0.01f, %0.01f, %0.01f, %0.01f }\n",
        h_C[0], h_C[1], h_C[2], h_C[3], h_C[4]);

    cin.get();

    return 0;
}

我首先使用nvcc将CUDA代码编译成"kernel.o":

nvcc -I. -arch=sm_30 -c kernel.cu -o kernel.o

这似乎很正常。但当我试图将其链接到我的C++项目时:
g++ -I. -L"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v7.5\lib\x64" main.cpp kernel.o -lcuda -lcudart

我得到以下错误:
Warning: corrupt .drectve at end of def file
C:\Users\Geoff\AppData\Local\Temp\cczu0qxj.o:main.cpp:(.text+0xbe):
undefined reference to `cuda_vec_add(float*, float*, float*, int)'
collect2.exe: error: ld returned 1 exit status

我正在使用CUDA工具包7.5,配合Visual Studio 2013和gcc版本5.2.0。
到目前为止,我尝试过:
- 使用nvcc编译所有内容。这很好用,但不符合我的项目要求。 - 使用此处中提供的解决方案,在nvcc中使用-dlink标志。不幸的是,这返回了相同的错误。 - 还有一些其他不太有成效的方法。
如果最终问题是一个愚蠢的错误,请见谅,我已经卡了一段时间了。感谢您的帮助。

为了了解这是否是名称混淆问题,您可以在 kernel.o 上运行 nm 命令,查看 cuda_vec_add 函数的样子。此外,有关数据损坏的警告似乎很奇怪。 - Rudolfs Bundulis
你不能在Windows平台上使用g ++或GNU工具来进行CUDA编程。这是不支持的配置。请参考Windows安装指南以获取支持的编译器和配置。基本上,您必须使用Visual Studio和MS C ++编译器cl.exe。 - Robert Crovella
1
看起来Robert是正确的,这是在Windows中使用g++和CUDA的问题。我刚刚在Linux上尝试了一下,没有出现错误。感谢您的帮助。 - Geoff M
1个回答

2
如果问题确实是g++和cl之间的名称混淆差异导致g++无法找到函数,尝试在extern "C" {}块中定义该函数以强制使用C链接。这可能有所帮助。
编辑
我尝试了同样的方法,并成功链接。让我贴出我所做的内容,希望能帮到你。
我的系统上安装了CUDA工具包7.5和mingw x64(gcc 4.5.4)。
我按照你描述的方式将你的代码放在三个文件中-kernel.cu、main.cpp和kernel.h,并将kernel.h更改为:
#pragma once

extern "C" 
{
int cuda_vec_add(float *h_a, float *h_b, float *h_c, int n);
}

接着我就做了

nvcc kernel.cu -c -o kernel.obj
g++.exe -c main.cpp -o main.obj
g++.exe  main.obj kernel.obj "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v7.5\lib\Win32\cuda.lib" "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v7.5\lib\Win32\cudart.lib" -o main.exe

我很高兴地得到了main.exe。有趣的是,nvcc自动调用了64位编译器——也许这是你使用32位g++而nvcc生成64位目标文件的问题,但这取决于你系统的配置。

我还使用objdump来转储kernel.obj文件,我的cuda_vec_add入口看起来像这样:

[302](sec  5)(fl 0x00)(ty  20)(scl   2) (nx 0) 0x0000000000000050 cuda_vec_add

与您的输入进行比较时,没有名称混淆。您是否正确地应用了extern "C"{}块?
同时,请仔细检查位数。我最初链接的是x86库,g++只抱怨无法解析cudaMemcpy,但没有提到库不兼容的事实。 objdump可以帮助您解决这个问题 - 它在第一行中打印体系结构。例如,当我运行objdump kernel.obj -t时,第一行是:
kernel.obj:     file format pe-x86-64

这样你就可以检查你的目标文件是否匹配。


似乎问题并不是由于名称混淆引起的。在 kernel.cu 中主机代码周围添加 extern "C" {} 块并没有改变错误。看起来 Robert 是正确的,这是我使用的工具在 Windows 上特有的问题。感谢您的帮助。 - Geoff M
@GeoffM 好的,Robert 正确指出了 Visual Studio 是官方支持的工具箱,然而,在混合使用 g++ 和 msvc 时可能会出现的主要问题是名称重整。你能否只是出于好奇心将内核对象文件中的符号转储出来,看看里面有什么? - Rudolfs Bundulis
好的,没问题。我对nmkernel.o上的输出不够了解,但我已经将完整的输出粘贴在这里 - http://pastebin.com/8Dj7j8iU。涉及到"cuda_vec_add"函数的那些行看起来像这样 - 000000000000000c p $pdata$?cuda_vec_add@@YAHPEAM00H@Z - Geoff M
1
尽管有人给我点了踩(是的,我知道我在宣传不受支持的机制,但是嘿——如果这个人需要使用g++而且他不能做其他事情——这就是我们在这里帮助他的原因),我还是尝试自己做了一下,并成功了,我会编辑我的帖子,希望这对你有所帮助。 - Rudolfs Bundulis
再次提醒 - 如果有人给负评,请留下至少一点反馈意见好吗? - Rudolfs Bundulis
显示剩余2条评论

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