【问题标题】:CUDA *.obj files are not processed by Visual Studio linkerVisual Studio 链接器不处理 CUDA *.obj 文件
【发布时间】:2019-05-04 01:47:14
【问题描述】:

我使用 CMake 3.13 来创建具有单个项目“cudatest”的 Visual Studio (VS 2017) 解决方案。该项目包含两个文件:

main.cpp
kernel.cu

为了整合对 CUDA 的支持,我使用了 Nvidia 提供的脚本,即 FindCUDA.cmake,而不是对基于 CUDA 的应用程序使用最新的 CMake 支持(我没有使用这个最新的支持,因为它不允许我做某些事情,所以我需要求助于 FindCUDA)。

CMake 成功生成包含上述两个文件的项目。无需赘述,文件main.cpp 包含一个函数声明:

cudaError_t addWithCuda(int *c, const int *a, const int *b, unsigned int size);

您可能会将其识别为在 Visual Studio 中使用 CUDA 运行时类型的项目(用于 Visual Studio 的 NVIDIA CUDA 集成)创建新项目时默认创建的函数。

而文件kernel.cu 包含上述函数的定义:

__global__ void addKernel(int *c, const int *a, const int *b)
{
    int i = threadIdx.x;
    c[i] = a[i] + b[i];
}

cudaError_t addWithCuda(int *c, const int *a, const int *b, unsigned int size)
{
    int *dev_a = 0;
    int *dev_b = 0;
    int *dev_c = 0;
...
    addKernel<<<1, size>>>(dev_c, dev_a, dev_b);
...
}

两个文件都编译成功,错误被链接器触发:

Error   LNK2019 unresolved external symbol "enum cudaError __cdecl addWithCuda(int *,int const *,int const *,unsigned int)" ...

需要注意的是,kernel.cu 的 *.obj 文件是由 NVCC 成功生成的。

但是 *.obj 文件被放置在不同的目录中,这让我认为这可能是问题所在,并且恰好揭示了我对 Visual Studio 链接器在何处查找 *.obj 文件以解决问题缺乏了解符号。

main.obj 文件以build\cudatest.dir\Debug 结尾,其中build 是包含生成的解决方案的文件夹。

cudatest_generated_kernel.cu.obj 文件以 build\CMakeFiles\cudatest.dir\Debug 结尾

输出文件路径的配置由FindCUDA.cmake脚本设置。

我尝试将cudatest_generated_kernel.cu.objmain.obj 放在同一个文件夹中,但没有任何作用。

将链接器的“显示进度”属性设置为 /VERBOSE 表明链接器甚至不会寻找 cudatest_generated_kernel.cu.obj 来尝试查找相应的符号。

======================

问题是:

鉴于我使用 NVCC 将 CUDA 内核编译成 *.obj 文件,并使用 CL.exe 将 *.cpp 文件编译成它自己的 *.obj 文件,我如何告诉链接器检查 cuda 内核 * .obj 文件?

如果我应该扩展问题以使其更清楚,请告诉我,即指定我使用的 NVCC 编译器选项,提供完整的代码列表等。任何正确方向的提示和指针将不胜感激!

编辑: 根据用户@talonmies 的建议(__cdecl addWithCuda 可能建议链接器正在寻找 C 链接),我在 main.cppkernel.cu 中都用 extern "C" 明确标记了 addWithCuda 函数:

extern "C" cudaError_t addWithCuda(int *c, const int *a, const int *b, unsigned int size)

现在报错如下:

Error   LNK2019 unresolved external symbol addWithCuda referenced in function main  cudatest    D:\projects\vs2017\TestCUDA_CMake\build\main.obj        

【问题讨论】:

  • 这看起来像是一个符号修饰问题。 __cdecl addWithCuda( 表明链接器正在寻找 C 链接,而不是 C++ 链接
  • @talonmies 已编辑:用 extern "C" 显式标记所述函数同样会导致 LNK2019;谢谢你的建议!

标签: c++ visual-studio cuda


【解决方案1】:

所以事实证明,除非 Visual Studio 项目具有 CUDA 集成(右键单击项目 -> 属性 -> 存在 CUDA C++/CUDA 链接器属性),否则主机链接器不会自动考虑编译成 *.obj 文件的 CUDA 内核。

首先,我在 Linker->Additional Library Directories 中添加了编译后的 CUDA *.obj 文件的路径。

其次,我在Linker->Input->Additional Dependencies中指定了目标文件的名称。

这解决了问题。需要注意的是,最初我使用了原生 cmake 命令和FindCUDA.cmake 宏的组合:

add_executable(cudatest main.cpp kernel.cu)
CUDA_WRAP_SRCS(cudatest OBJ generated_files kernel.cu ${cmake_options} OPTIONS ${options} )

CUDA_WRAP_SRCS 宏添加了自定义构建步骤,使 Visual Studio 调用 nvcc 而不是 CL 来编译 CUDA 内核。这个宏也从CUDA_ADD_EXECUTABLECUDA_ADD_LIBRARY 宏,它还指定了生成的 *.obj 文件的所有路径,这些文件已经包含在生成的 Visual Studio 项目中,从而节省了我上面描述的额外工作。

此外,CUDA_ADD_EXECUTABLECUDA_ADD_LIBRARY 还有助于为启用了可重定位设备代码的内核生成项目,这意味着必须有一个预链接步骤将设备链接所有 CUDA *.obj 文件与可重定位设备代码将它们中的设备代码转换为可由主机链接器使用的中间 CUDA *.obj 文件(否则主机链接器将无法处理包含可重定位设备代码的 *.obj 文件)。上述宏也将包含对这个中间生成的 CUDA *.obj 文件的依赖。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-11-05
    • 1970-01-01
    • 2011-03-29
    • 1970-01-01
    • 2015-08-05
    • 1970-01-01
    • 2013-05-23
    • 2011-07-02
    相关资源
    最近更新 更多