【问题标题】:Link error LNK2005 when trying to compile several CUDA files together尝试一起编译多个 CUDA 文件时出现链接错误 LNK2005
【发布时间】:2010-12-30 21:36:42
【问题描述】:

我有一个运行良好的 CUDA 程序,但目前都写在一个文件中。我想把这个大文件分成几个小文件,以便于维护和导航。

新结构是:

foo.cuh
foo.cu
bar.cuh
bar.cu
main.cu

.cuh 头文件包含结构和函数原型,.cu 文件包含函数定义(和往常一样)。主文件包括bar.cuhbar.cu包括foo.cuh。所有 .cu 文件都包含 cutil_inline.h,以便能够使用 CUDA 功能。

因此:

// main.cu
#include "bar.cuh"
#include <cutil_inline.h>

int main() [...]

// bar.cu
#include "bar.cuh"
#include "foo.cuh"
#include <cutil_inline.h>

[...]

// foo.cu
#include "foo.cuh"
#include <cutil_inline.h>

[...]

问题是,当我用这个新结构编译我的 Visual Studio 2008 项目时,我得到了大量的链接错误:

error LNK2005: "void __cdecl __cutilBankChecker(unsigned int,unsigned int,unsigned int,unsigned int,unsigned int,unsigned int,char *,int,char *,int)" (?__cutilBankChecker@@YAXIIIIIIPADH0H@Z) already defined in cuda_generated_foo.cu.obj cuda_generated_bar.cu.obj
error LNK2005: "void __cdecl __cutilCondition(int,char *,int)" (?__cutilCondition@@YAXHPADH@Z) already defined in cuda_generated_foo.cu.obj cuda_generated_bar.cu.obj
error LNK2005: "void __cdecl __cutilExit(int,char * *)" (?__cutilExit@@YAXHPAPAD@Z) already defined in cuda_generated_foo.cu.obj    cuda_generated_bar.cu.obj
error LNK2005: "int __cdecl cutGetMaxGflopsDeviceId(void)" (?cutGetMaxGflopsDeviceId@@YAHXZ) already defined in cuda_generated_foo.cu.obj   cuda_generated_bar.cu.obj
error LNK2005: "void __cdecl __cudaSafeCallNoSync(enum cudaError,char const *,int)" (?__cudaSafeCallNoSync@@YAXW4cudaError@@PBDH@Z) already defined in cuda_generated_foo.cu.obj    cuda_generated_bar.cu.obj
error LNK2005: "void __cdecl __cudaSafeCall(enum cudaError,char const *,int)" (?__cudaSafeCall@@YAXW4cudaError@@PBDH@Z) already defined in cuda_generated_foo.cu.obj    cuda_generated_bar.cu.obj
error LNK2005: "void __cdecl __cudaSafeThreadSync(char const *,int)" (?__cudaSafeThreadSync@@YAXPBDH@Z) already defined in cuda_generated_foo.cu.obj    cuda_generated_bar.cu.obj
error LNK2005: "void __cdecl __cufftSafeCall(enum cufftResult_t,char const *,int)" (?__cufftSafeCall@@YAXW4cufftResult_t@@PBDH@Z) already defined in cuda_generated_foo.cu.obj  cuda_generated_bar.cu.obj

我明白它们的意思(所有已经定义的符号都是 cutil_inline.h 的一部分)但是我必须在所有文件中包含这个头文件,否则它不会编译。我做错了什么?

更新:澄清情况: * 将所有代码放在一个大文件中,它可以编译、链接并运行良好 * 使用新结构(几个较小的文件)并在所有 .cu 文件中包含 cutil_inline.h,它可以正确编译但在链接期间失败 * 使用新结构并且仅在主文件中包含 cutil_inline.h,它在编译过程中失败,说 cutil 函数在不包含 cutil_inline.h 的文件中未知(如预期的那样,但我不得不尝试一切) - 列表项

【问题讨论】:

  • 您能否澄清一下,它是否与所有 .cu 文件中包含的 cutil_inline.h 进行编译和链接?你说你得到了描述结构的错误,但是你必须在所有文件中包含 cutil_inline.h 才能让它“编译”,所以不确定哪些有效,哪些无效。
  • 我更新了我的答案。我的意思是所有 .cu 文件中都包含 cutil_inline.h,它可以编译但无法链接,即错误来自链接器而不是编译器。

标签: c visual-studio-2008 refactoring cuda linker-errors


【解决方案1】:

考虑使用“静态”而不是“内联”以避免在编译期间出现警告。那是根据this answer. 这个错误的原因是discussed here:

但是,这很可能是由于将 .cuh 文件(包含您的内核)包含到通常的 .h 文件中造成的。要么:

  • 制作一个单独的 dll,其中包含您的 .cuh.cu 文件,并链接到它;

  • 或将您的 .h 文件重命名为 .cuh 并将 .cpp 重命名为 cu。对于此选项,请确保也这样做:https://stackoverflow.com/a/20057857/9007125

在 .cu 文件(您刚刚重命名)的上下文菜单中,选择“属性”。然后转到 General 并确保 Item Type 设置为 CUDA C/C++。

请注意,第二个选项会使您的项目编译速度慢很多(编译速度慢 4 倍)

【讨论】:

    【解决方案2】:

    这个错误也发生在我的程序中。我通过在__global____device__ 之前添加关键字inline 解决了这个问题。然后,错误消失了。

    【讨论】:

    • 它是什么? __global__device__?
    • 我将答案解析为if current token in ["__global__", "__device__"] then insert "inline"
    • 你能解释一下为什么 inline 能解决这个问题吗?
    • global 定义的内核不能被内联。这就是您将得到的:“警告:“global”函数的内联限定符被忽略”
    • 考虑使用 'static' 而不是 'inline' 以避免在编译期间出现警告。那是根据这个答案:stackoverflow.com/a/33050457/9007125这里讨论了这个错误的原因:codeyarns.com/2011/03/15/cuda-device-function-in-header-file
    【解决方案3】:

    不知何故,cutil_inline.h 中的函数在编译时并未标记为“内联”。

    如果你在一个普通的非 Cuda C++ 项目中遇到这个错误,答案就是你在头文件中有函数定义(不仅仅是声明)并且缺少“inline”关键字。

    您可能必须生成相应的 .i 文件(预处理器)输出才能真正了解所有宏扩展后发生的情况。

    编辑 2009 年 1 月 2 日

    如果由于某些宏扩展混淆,您无法仅通过读取 .h 文件找出问题所在,以下是生成 .i 文件的方法:

    1. 在 Visual Studio 中的“解决方案 资源管理器”窗口,右键单击 源文件并选择“属性”。

    2. 在属性树中,选择 “C/C++”、“预处理器”。

    3. 更改“生成预处理 文件”从“否”到另一个 选项。

    4. 然后编译文件。编译器 将写入预处理器输出 到一个文件,然后停止 实际编译。你可以在里面看到 .i 文件产生了最终的结果 所有宏扩展的结果是。

    5. 您必须返回并重置 该属性按顺序返回“否” 让项目编译到 再次正常工作。

    【讨论】:

    • 在 nvcc 命令行中添加 --keep 以保留整个中间文件的负载。
    【解决方案4】:

    是否需要链接 cutil 库(即用于 32 位调试的 cutil32D.lib 等)?

    由于某种原因,您有多个定义。您是否使用 NVIDIA Cuda.rules 文件使 Visual Studio 能够将您的 .cu 文件编译为 .obj 文件?看起来您已经修改了与 cutil 链接的规则,而您应该使用 NVIDIA Cuda.rules 告诉 VS 如何将 .cu 编译为 .obj,然后修改 standard 链接器属性以拉入cutil 库。

    【讨论】:

    • 是的,我链接到 cutil32.lib。为什么?
    • 因为您看到错误的符号是由 cutil32.lib 提供的,所以我误读并认为它们是丢失而不是重复。我已经更新了我的答案。
    • 我实际上是在使用 Cmake 2.8 为我的项目生成 VS2008 解决方案。通过查看它,我会说构建规则与 SDK 分发的 nVidia CUDA 规则非常相似。
    • 你能发布用于编译每个 .cu 文件的命令行吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-04
    • 1970-01-01
    • 2016-02-11
    相关资源
    最近更新 更多