关于 Visual Studio 2008:使用 CUDA __device__ 函数时的链接器错误 2005 和 1169(多重定义的符号)(默认情况下应该是内联的)

Linker errors 2005 and 1169 (multiply defined symbols) when using CUDA __device__ functions (should be inline by default)

这个问题非常相关:

A) 如何将 CUDA 代码分成多个文件

B) 尝试同时编译多个 CUDA 文件时出现链接错误 LNK2005

听从这里的建议:
https://meta.stackexchange.com/questions/42343/same-question-but-not-quite
和这里
https://meta.stackexchange.com/questions/8910/asking-a-similar-but-not-the-same-question

我在问一个非常相似的问题,但我想绝对清楚我的问题与上面链接的问题之间的区别在哪里。

在将包含 __device__ 函数定义的头文件包含到多个源文件中时,我从标题中得到了链接器错误。

这与链接 A 不同),其中 __kernel__ 函数会发生相同的错误,因为根据 CUDA 手册,__device__ 意味着 inline:

In device code compiled for devices of compute capability 1.x, a __device__ function is always inlined by default. The __noinline__ function qualifier however can be used as a hint for the compiler not to inline the function if possible (see Section E.1).

链接 B)更相关(一个答案正确地指出,无论手册怎么说,它似乎都没有被内联)但链接 B)指的是 NVIDIA 提供的标头而不是自己的标头,所以虽然问题最有可能位于我的头文件中,最不可能位于 NVIDIA 头文件中。换句话说,链接 B) 和我的问题可能有不同的答案。

与此同时,我发现将函数声明为 __device__ inline 可以解决问题,因此以上内容只是为世界其他地方记录解决方案。

悬而未决的问题是这种行为的原因。

我想出的可能解释:

  • 说明书错了
  • nvcc -arch=compute_11 不符合"为计算能力 1.x 的设备编译"或 nvcc 中存在错误的条件
  • 这是特定于 MS-VS 的,并且可以在 NVIDIA 测试的平台上运行
  • 我对 inline 的工作原理有一个严重的误解。可以在这里找到一个与 cuda 无关的示例:使用内联函数乘以定义的链接器错误我的理解是"caf"在那里表达的意思是"编译器不应该生成函数的外部定义,所以它不应该打扰链接器"那边的其他人似乎不同意。

如果有更多见解的人能澄清这里发生的事情,我将不胜感激。


在 MS VS 以及 gcc 和可能的其他编译器中(但不在"多重定义的链接器错误"链接所引用的编译器中),默认情况下内联意味着静态。您可以强制函数为外部内联函数,但除非您这样做,否则编译器要么不会将函数的外部定义放入目标文件中,要么会将其标记为安全地以某种方式复制。

但是,文档中没有任何地方说 CUDA __device__ 函数被有效地声明为内联(因此是静态的)。文档说该函数"默认情况下总是内联"。有细微的差别。