如何在单个项目中用NVCC编译含模板函数的.cuh文件并搭配MSVC编译.cpp?
混合编译CUDA代码与C++代码的解决方案
完全可以在项目中混合使用NVCC和MSVC两种编译器,不需要全量用NVCC编译。核心思路是把CUDA相关代码和纯C++代码做隔离,避免MSVC解析CUDA专属语法(如<<<>>>),具体方案如下:
方案1:拆分CUDA实现与头文件声明
把模板函数的实现移到.cu文件中,头文件只保留对外调用的声明,同时用预编译宏隔离CUDA语法:
- 改造
A.cuh,仅保留声明并隔离CUDA代码:
// A.cuh #pragma once #ifdef __CUDACC__ // 仅NVCC会处理的CUDA核函数声明 template<typename T> __global__ void kernelFunc(T* data, int size); #endif // 供C++调用的包装函数声明 template<typename T> void cudaWrapperFunc(T* hostData, int size);
- 创建
A.cu文件,实现模板与核函数,用NVCC编译该文件:
// A.cu #include "A.cuh" template<typename T> __global__ void kernelFunc(T* data, int size) { int idx = threadIdx.x + blockIdx.x * blockDim.x; if (idx < size) { data[idx] *= 2; } } template<typename T> void cudaWrapperFunc(T* hostData, int size) { T* devData; cudaMalloc(&devData, size * sizeof(T)); cudaMemcpy(devData, hostData, size * sizeof(T), cudaMemcpyHostToDevice); kernelFunc<<<(size + 255)/256, 256>>>(devData, size); cudaMemcpy(hostData, devData, size * sizeof(T), cudaMemcpyDeviceToHost); cudaFree(devData); } // 显式实例化需要用到的模板类型,避免链接错误 template void cudaWrapperFunc<int>(int*, int); template void cudaWrapperFunc<float>(float*, int);
main.cpp正常调用接口,用MSVC编译:
// main.cpp #include "A.cuh" #include <iostream> int main() { int arr[] = {1,2,3,4}; int size = sizeof(arr)/sizeof(arr[0]); cudaWrapperFunc(arr, size); for(int i=0; i<size; i++){ std::cout << arr[i] << " "; } return 0; }
- 编译流程:用NVCC编译
A.cu生成目标文件,MSVC编译main.cpp生成目标文件,最后将两个文件链接成可执行程序。
方案2:用预编译宏隔离CUDA语法
如果不想拆分文件,在A.cuh中用__CUDACC__宏包裹所有CUDA相关代码,给MSVC仅提供声明:
// A.cuh #pragma once #ifdef __CUDACC__ // NVCC编译时的完整实现 template<typename T> __global__ void kernelFunc(T* data, int size) { int idx = threadIdx.x + blockIdx.x * blockDim.x; if (idx < size) { data[idx] *= 2; } } template<typename T> void cudaWrapperFunc(T* hostData, int size) { T* devData; cudaMalloc(&devData, size * sizeof(T)); cudaMemcpy(devData, hostData, size * sizeof(T), cudaMemcpyHostToDevice); kernelFunc<<<(size + 255)/256, 256>>>(devData, size); cudaMemcpy(hostData, devData, size * sizeof(T), cudaMemcpyDeviceToHost); cudaFree(devData); } #else // MSVC编译时仅声明,实际链接NVCC编译的目标文件 template<typename T> void cudaWrapperFunc(T* hostData, int size); #endif
同样需要在.cu文件中显式实例化模板,再分别编译链接。
关键注意事项
__CUDACC__是NVCC专属预编译宏,仅在NVCC编译时生效,用来隔离CUDA语法避免MSVC报错。- 模板显式实例化:因为模板实现仅在NVCC编译的文件中,MSVC编译的代码无法看到实现,必须显式实例化用到的模板类型,否则会出现链接错误。
- 链接阶段:要把NVCC生成的目标文件和MSVC生成的文件一起链接,同时确保链接器能找到CUDA运行时库(如
cudart.lib)。
内容的提问来源于stack exchange,提问作者Drem Lit
相关产品推荐
相关产品推荐

