在处理 CUDA 项目时,我收到
nvlink
错误,指出 __cxa_pure_virtual
具有未定义的引用。我的存储库的结构类似于 ModernCMake - 扩展示例中的示例。
令人惊讶的是,我在使用
nvcc
编译时没有收到此错误,我想使用clang
编译我的代码,因为我想使用clang
的LSP。
这可能是由于我处理虚拟课程的方式所致。这是我的编译命令以及相关错误:
➜ CUDA-Path-Tracer git:(main) ✗ make build
cmake -S . -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_CUDA_COMPILER=clang++-20 -DCMAKE_CXX_COMPILER=clang++-20 -DCMAKE_CUDA_ARCHITECTURES=native
-- The CXX compiler identification is Clang 20.0.0
-- The CUDA compiler identification is Clang 20.0.0
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/clang++-20 - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Detecting CUDA compiler ABI info
-- Detecting CUDA compiler ABI info - done
-- Check for working CUDA compiler: /usr/bin/clang++-20 - skipped
-- Detecting CUDA compile features
-- Detecting CUDA compile features - done
-- Performing Test HAVE_FLAG__ffile_prefix_map__home_eduard_Git_CUDA_Path_Tracer_build__deps_catch2_src__
-- Performing Test HAVE_FLAG__ffile_prefix_map__home_eduard_Git_CUDA_Path_Tracer_build__deps_catch2_src__ - Success
-- Configuring done (14.8s)
-- Generating done (0.1s)
-- Build files have been written to: /home/eduard/Git/CUDA-Path-Tracer/build
cmake --build build
gmake[1]: Entering directory '/home/eduard/Git/CUDA-Path-Tracer/build'
gmake[2]: Entering directory '/home/eduard/Git/CUDA-Path-Tracer/build'
gmake[3]: Entering directory '/home/eduard/Git/CUDA-Path-Tracer/build'
gmake[3]: Leaving directory '/home/eduard/Git/CUDA-Path-Tracer/build'
gmake[3]: Entering directory '/home/eduard/Git/CUDA-Path-Tracer/build'
[ 0%] Building CUDA object src/CMakeFiles/cuda_path_tracer_lib.dir/error.cu.o
clang++-20: warning: CUDA version 12.6 is only partially supported [-Wunknown-cuda-version]
[ 0%] Building CUDA object src/CMakeFiles/cuda_path_tracer_lib.dir/vec3.cu.o
clang++-20: warning: CUDA version 12.6 is only partially supported [-Wunknown-cuda-version]
[ 1%] Building CUDA object src/CMakeFiles/cuda_path_tracer_lib.dir/sphere.cu.o
clang++-20: warning: CUDA version 12.6 is only partially supported [-Wunknown-cuda-version]
[ 2%] Building CUDA object src/CMakeFiles/cuda_path_tracer_lib.dir/render.cu.o
clang++-20: warning: CUDA version 12.6 is only partially supported [-Wunknown-cuda-version]
[ 3%] Building CUDA object src/CMakeFiles/cuda_path_tracer_lib.dir/world.cu.o
clang++-20: warning: CUDA version 12.6 is only partially supported [-Wunknown-cuda-version]
[ 4%] Building CUDA object src/CMakeFiles/cuda_path_tracer_lib.dir/ray.cu.o
clang++-20: warning: CUDA version 12.6 is only partially supported [-Wunknown-cuda-version]
[ 5%] Building CXX object src/CMakeFiles/cuda_path_tracer_lib.dir/image.cpp.o
nvlink error : Undefined reference to '__cxa_pure_virtual' in 'src/CMakeFiles/cuda_path_tracer_lib.dir/sphere.cu.o'
gmake[3]: *** [src/CMakeFiles/cuda_path_tracer_lib.dir/build.make:177: src/CMakeFiles/cuda_path_tracer_lib.dir/sm_90.cubin] Error 255
gmake[3]: Leaving directory '/home/eduard/Git/CUDA-Path-Tracer/build'
gmake[2]: *** [CMakeFiles/Makefile2:924: src/CMakeFiles/cuda_path_tracer_lib.dir/all] Error 2
gmake[2]: Leaving directory '/home/eduard/Git/CUDA-Path-Tracer/build'
gmake[1]: *** [Makefile:101: all] Error 2
gmake[1]: Leaving directory '/home/eduard/Git/CUDA-Path-Tracer/build'
make: *** [Makefile:12: build] Error 2
我的存储库 atm 的结构如下:
├── apps
│ ├── CMakeLists.txt
│ └── main.cpp
├── CMakeLists.txt
├── include
│ └── cuda_path_tracer
│ ├── error.cuh
│ ├── image.hpp
│ ├── ray.cuh
│ ├── render.cuh
│ ├── shape.cuh
│ ├── sphere.cuh
│ ├── vec3.cuh
│ └── world.cuh
├── LICENSE
├── llvm.sh
├── Makefile
├── README.md
├── report
│ └── report.typ
├── src
│ ├── CMakeLists.txt
│ ├── error.cu
│ ├── image.cpp
│ ├── ray.cu
│ ├── render.cu
│ ├── sphere.cu
│ ├── vec3.cu
│ └── world.cu
└── tests
├── CMakeLists.txt
├── test_error.cpp
├── test_image.cpp
├── test_ray.cpp
└── test_vec3.cpp
我唯一的虚拟类是
Shape
,其定义为
/**
* @file shape.cuh
*/
#pragma once
#include "cuda_path_tracer/ray.cuh"
class Shape {
public:
__host__ __device__ virtual ~Shape() = default;
__host__ __device__ virtual auto hit(const Ray &r) const -> bool = 0;
};
对应的
Sphere
类是
/**
* @file sphere.cuh
*/
#pragma once
#include "shape.cuh"
class Sphere : public Shape {
public:
__host__ __device__ Sphere(const Vec3 ¢er, float radius);
__host__ __device__ auto hit(const Ray &r) const -> bool override;
private:
Vec3 center;
float radius;
};
和
/**
* @file sphere.cu
*/
#include "cuda_path_tracer/sphere.cuh"
__host__ __device__ Sphere::Sphere(const Vec3 ¢er, float radius)
: center(center), radius(radius) {}
__host__ __device__ auto Sphere::hit(const Ray &r) const -> bool {
Vec3 oc = r.getOrigin() - center;
float a = r.getDirection().dot(r.getDirection());
float b = 2.0f * oc.dot(r.getDirection());
float c = oc.dot(oc) - radius * radius;
float discriminant = b * b - 4 * a * c;
return discriminant > 0;
}
我尝试过不同版本的
llvm
套件,特别是v18、19和现在的20。我尝试按照clang-tidy
的建议定义隐式复制/移动成员,我尝试在shape.cuh
中定义默认构造函数,但是没有效果。
我可以确认问题源于这些类,因为当它们的代码被注释掉时,代码就会编译。
我还尝试按照某些问题(
__cxa_pure_virtual
)中的建议将 while(1) {}
函数定义为循环,但这也不起作用,或者也许我在错误的标头中定义了它。
事实证明,解决方案确实是将
__cxa_pure_virtual
定义为虚拟函数,因为 https://bugs.llvm.org/show_bug.cgi?id=49839 ,问题是我没有添加 __device__
属性位于前面。该函数应该类似于:
extern "C" __device__ void __cxa_pure_virtual() {
while (1) {
}
}