在CUDA头文件(.cuh)中使用常量内存时出现LNK2005错误

3

我有一个CUDA头文件(.cuh),其中包含两个常量浮点数组。有两个文件包括此头文件,一个是尝试复制到此常量内存的CPP文件,另一个是尝试使用此常量内存的CUDA文件。所有三个文件都在应该编译成DLL的项目中。

我尝试用以下代码简化事情:

obj1.cuh

#pragma once

__constant__ float d_array1[5];
__constant__ float d_array2[5];

obj1.cu

#include "obj1.cuh"

//do random stuff
__global__ void kernel(float * d_array1, float * d_array2) {
  int id = threadIdx.x;
  float sum = d_array1[i] + d_array2[i];
}

ext.cpp

#include "obj1.cuh"

void function(float * array1, float * array2) {
  cudaMemcpyToSymbol(d_array1, array1, sizeof(float)*5);
  cudaMemcpyToSymbol(d_array2, array2, sizeof(float)*5);

  kernel<<<1,5>>>(d_array1,d_array2);
}

构建失败并输出以下错误信息:
1>ext.obj : error LNK2005: "float * d_array1" (?d_array1@@3PAMA) already defined in obj1.cu.obj
1>ext.obj : error LNK2005: "float * d_array2" (?d_array2@@3PAMA) already defined in obj1.cu.obj

在您询问之前,是的,我已经尝试使用包含保护而不是#pragma once,但仍然输出相同的错误。

obj1.cuh的包含保护版本

#ifndef CONSTANTARRAYS
#define CONSTANTARRAYS
__constant__ float d_array1[5];
__constant__ float d_array2[5];
#endif
1个回答

3
问题就是链接器告诉你的那样:这些变量在多个翻译单元中被定义
当预处理器包含头文件时,它会将头文件中的文本文字实质上粘贴到#include指令所在的位置,这意味着生成的两个目标文件都将具有这些变量的定义。
您应该做的是只在头文件中声明变量,然后在一个单一的源文件中定义它们。将定义更改为声明的最简单方法是在前面加上extern关键字。
#pragma once

extern __constant__ float d_array1[5];
extern __constant__ float d_array2[5];

然后,在一个单一的源文件中,您有旧的定义:

__constant__ float d_array1[5];
__constant__ float d_array2[5];
#pragma once或头文件包含保护可以防止同一翻译单元中多次包含头文件。

谢谢Joachim。但我不理解的是,当我只在.cu文件中定义了这两个数组时,为什么.cpp文件能够使用这个数组,而在那个文件中没有定义呢?例如,我可以在cudaMemcpyToSymbol函数中使用这些数组而不会出现错误。 - Jonny Pringle
@JonnyPringle 这就是头文件中的声明所用之处。 - Some programmer dude

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