C++ 链接顺序规定在另一个模板类中使用一个类的哪个版本,如何控制使用哪个版本?
我正在研究一些跨平台的代码,某些顶级抽象包含CPU和GPU的相同代码,而它们调用的较低级别代码可以通过选中C++ 链接顺序规定在另一个模板类中使用一个类的哪个版本,如何控制使用哪个版本?,c++,cuda,linker,C++,Cuda,Linker,我正在研究一些跨平台的代码,某些顶级抽象包含CPU和GPU的相同代码,而它们调用的较低级别代码可以通过选中\uuuuuu CUDACC\uuuuu标志为任一设备构建,该标志被认为是由NVCC编译器为其涉及的所有内容定义的顶级代码 不幸的是,看起来应该用NVCC编译的某些头文件中的代码,不管出于什么原因,都被编译为普通CPU代码,而我需要将其编译为CUDA代码 这个最小的例子更好地解释了我的意思。zip存档中的所有文件,包括CMake,都可以从下载 main.cpp #include "Class
\uuuuuu CUDACC\uuuuu
标志为任一设备构建,该标志被认为是由NVCC编译器为其涉及的所有内容定义的顶级代码
不幸的是,看起来应该用NVCC编译的某些头文件中的代码,不管出于什么原因,都被编译为普通CPU代码,而我需要将其编译为CUDA代码
这个最小的例子更好地解释了我的意思。zip存档中的所有文件,包括CMake,都可以从下载
main.cpp
#include "ClassA.hpp"
int main() {
ClassA<DEVICE_CPU> a_cpu_instance;
a_cpu_instance.PrintDevice();
a_cpu_instance.PrintClassBDevice();
ClassA<DEVICE_CUDA> a_cuda_instance;
a_cuda_instance.PrintDevice();
a_cuda_instance.PrintClassBDevice();
return 0;
}
#pragma once
#include "Device.hpp"
template <Device device>
class ClassA{
public:
void PrintDevice();
void PrintClassBDevice();
};
#pragma once
#include "ClassA.hpp"
#include "ClassB.hpp"
template<Device device>
void ClassA<device>::PrintDevice() {
{
#if defined(__CUDACC__)
printf("CUDA\n");
#else
printf("CPU\n");
#endif
}
}
template<Device device>
void ClassA<device>::PrintClassBDevice() {
ClassB b_instance;
b_instance.PrintDevice();
}
#pragma once
#include <cstdio>
class ClassB{
public:
void PrintDevice(){
#if defined(__CUDACC__)
printf("CUDA\n");
#else
printf("CPU\n");
#endif
}
};
A类水电站
#include "ClassA.hpp"
int main() {
ClassA<DEVICE_CPU> a_cpu_instance;
a_cpu_instance.PrintDevice();
a_cpu_instance.PrintClassBDevice();
ClassA<DEVICE_CUDA> a_cuda_instance;
a_cuda_instance.PrintDevice();
a_cuda_instance.PrintClassBDevice();
return 0;
}
#pragma once
#include "Device.hpp"
template <Device device>
class ClassA{
public:
void PrintDevice();
void PrintClassBDevice();
};
#pragma once
#include "ClassA.hpp"
#include "ClassB.hpp"
template<Device device>
void ClassA<device>::PrintDevice() {
{
#if defined(__CUDACC__)
printf("CUDA\n");
#else
printf("CPU\n");
#endif
}
}
template<Device device>
void ClassA<device>::PrintClassBDevice() {
ClassB b_instance;
b_instance.PrintDevice();
}
#pragma once
#include <cstdio>
class ClassB{
public:
void PrintDevice(){
#if defined(__CUDACC__)
printf("CUDA\n");
#else
printf("CPU\n");
#endif
}
};
除了最后一行,一切都好。我需要为CUDA编译单元中的ClassB头定义\uuuuu CUDACC\uuuu
(按照.cu文件的指导),但事实并非如此。(是的,但是使用了错误的版本,请参见编辑和回答)另外,假设\uuuuudacc\uuuuuuuu
指导ClassB
的实际定义,而不仅仅是PrintDevice()
的实现,我希望它在同一个单元中编译,因此,我无法在与ClassA
单元不同的单元中实例化两个不同版本的ClassB
我该怎么做
另外,请随意降低所提供文件中所需的CMake版本,我认为它应该适用于>=3.9的任何内容
[编辑]2条新信息
ClassA\u CUDA.cu ClassA\u CPU.cpp
与ClassA\u CPU.cpp ClassA\u CUDA.cu
决定了在main.cpp中使用哪个版本的ClassB。我认为这并没有什么神奇之处,而是链接器的参数顺序,对应于这两个单元中编译的对象文件。作为参考,我使用的是标准的GCC链接器(ld
)#warning COMPILING CUDA VERSION
这类警告时,我会得到两个输出(“CUDA”两次,出于某种原因)[P>] [旁注:这个问题似乎是“强”>关于C/C++代码与不同定义的链接。CUDA用户可能更频繁地遇到这个问题,但实际上,如果只编译一个带有“-D”标志的C++单元,而另一个没有,不使用CUDA,则会得到同样的效果。问题似乎在于链接器对于类
ClassB
中的事物基本上有两组等价的符号,因此默认情况下它将使用第一组符号,具体取决于链接器的顺序
解决方案很简单(虽然不是很明显,至少对我来说)就是在设备上设置ClassB
,即
#pragma once
#include <cstdio>
template <Device>
class ClassB{
public:
void PrintDevice(){
#if defined(__CUDACC__)
printf("CUDA\n");
#else
printf("CPU\n");
#endif
}
};
#pragma一次
#包括
模板
B类{
公众:
无效打印设备(){
#如果已定义(uuu CUDACC_uuuuu)
printf(“CUDA\n”);
#否则
printf(“CPU\n”);
#恩迪夫
}
};
显然,当在ClassA中使用时,这需要使用模板参数来修饰它,如下所示:
template<Device device>
void ClassA<device>::PrintClassBDevice() {
ClassB<device> b_instance;
b_instance.PrintDevice();
}
模板
void ClassA::PrintClassB设备(){
b类b_实例;
b_instance.PrintDevice();
}
<>这将导致编译器产生两个不同的符号集,在链接时可以正确地区分它们。可以尝试<代码> NVCC -X Cu</代码>强制将C++文件编译为CUDA文件。或者将类B的主体放在一个.cu文件中。@JHBonarius我马上就会看到,但神秘的是:当我将#warning compileding CUDA VERSION
放在下,如果在类B中定义了(u CUDACC)
,它实际上会在编译过程中打印出警告。。。两次。。。我很困惑。@JHBonarius the-xcu
在默认情况下已经打开了,显然,CMakeThis的优点在某些情况下仍然会产生意想不到的效果。如果在.cu文件中编译DEVICE\u CPU
实例,您将获得“CUDA”行为,这可能不是您想要的。一旦你真的有GPU代码要编译,事情可能也不会像你预期的那样工作。是的,诀窍是跟踪,而不是在.cu内编译设备CPU代码,你可以通过显式实例化完全控制这一点。GPU代码(也有很多)已经按预期工作了,所以我对这个解决方案很满意。