Visual Studio/CMake 中未解析的外部符号 cuda_library::foo(int)

unresolved external symbol cuda_library::foo(int) in Visual Studio/CMake

原题(标题:.cu 文件在 Visual Studio/CMake 中被处理为 .cpp 文件)

我正在尝试将带有 CUDA 代码的静态库添加到我的 C++ 项目中。我有一个顶级 CMakeLists.txt 文件,一个从那里添加的静态库,以及从该库添加的我的 CUDA-using 库(两个库都有自己的 CMakeLists.txt 文件。在根文件中我在一级图书馆的CMakeLists.txt中使用了enable_language(CUDA),我这样做了:

  add_subdirectory(cuda_library)
  set_target_properties(level_1_lib PROPERTIES POSITION_INDEPENDENT_CODE ON)
  set_target_properties(level_1_lib PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
  target_link_libraries(level_1_lib cuda_library)

并且在 CUDA 库的 CMakeLists.txt:

add_library(cuda_library 
  cuda_library.cu cuda_library.h)

target_include_directories(cuda_library
  INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
  )

1 级库中的一个 .cpp 文件调用了我在 cuda_library.h 中声明的“接口函数”,它在 cuda_library.cu 中实现并在内部启动了一个 CUDA __global__内核这样:

namespace cuda_library {
    __global__
    void real_foo(int number, int *out) { 
        *out = number * 2; 
    }

    inline int foo(int number) { 
        int* x;
        
        cudaMallocManaged(&x, sizeof(int));
        real_foo<<<1,1>>>(number, x); 
        cudaDeviceSynchronize();
        int y = *x;
        cudaFree(x);
        return y;
    } 
}

当我从 Visual Studio 构建时(启用了 CMake 扩展,它使用 ninja 作为生成器),但是,构建不喜欢 __global__ 关键字,使得我认为 .cu 文件被视为普通的 .cpp 文件,而不是编译为 CUDA 代码。

我做错了什么?

编辑以更好地澄清我得到的错误

如果我在 Visual Studio 命令提示符下点击 Visual Studio 的“全部构建”(或 运行 带有忍者的 CMake,通常可以使用 [=32 编译简单的 CUDA 示例=],错误是相同的)而且我不在 cuda_library.cu 文件中,我只得到归结为 unresolved external symbol cuda_library::foo(int) 的错误,根据一些研究,这意味着函数可能被声明但没有定义。如果包含 header 但未正确编译 .cu 文件,这是有意义的。

但是,只有当我使 .cu 文件处于活动状态时,VS 才会向我显示与 CUDA 代码相关的错误,它们被视为 C++ 代码,并且它们没有正常的错误徽标(如第一个此图像中的错误),但您可以在第二个和第三个中看到:

那么它们可能只是在构建时不会出现的智能感知错误吗?

在这种情况下,可能还有另一个原因导致静态库的实现未正确链接。为了更彻底,这是 header (cuda_library.h):

#ifndef _CUDA_LIBRARY_H_
#define _CUDA_LIBRARY_H_

namespace cuda_library {
    inline int foo(int number);
}

#endif

我尝试在发生 unresolved external symbol cuda_library::foo(int) 错误的 .cpp 文件中以这种方式导入和使用它:

#include "cuda_library/cuda_library.h"

printf("Result from the GPU: %d\n", cuda_library::foo(5));

有趣的是我也试过了

#include <cuda_library.h>

结果是一样的,可能是因为 CMake 将其包含在包含搜索路径中?

项目结构如下:

root_dir\
  CMakeLists.txt
  libs\
    CMakeLists.txt
    level_1_lib\
      CMakeLists.txt
      file_using_cuda_lib.cpp
      cuda_library\
        CMakeLists.txt
        cuda_library.cu
        cuda_library.h

我真的不明白到底出了什么问题,所以欢迎任何帮助。

你必须在每个源cpp文件中添加一个属性来表示它真的是一个cuda源。

    set_source_files_properties(file.cpp PROPERTIES LANGUAGE CUDA)

启用 CUDA 作为语言后 (enable_language(CUDA))。

我们使用它,但我不知道这是否是一个好的做法(欢迎提供反馈)。

我意识到有两个主要因素阻止了它的工作:

  • 函数签名中的 inline 似乎自行破坏了它(此时我不太关心我的代码中的它而不是删除它,如果有人想对其进行更多调查的话他们可以自由地做。
  • enable_language(CUDA) 必须在顶级 CMakeLists.txt 文件中。

修复它构建的这两个东西没有任何问题。