visual stuidio 创建的C/C++项目是不会识别出CUDA库中的某些标识符那些的,比如:编译器根本没有把标识符__global__当作 CUDA 代码来编译。nvcc 看到 global 是合法的存储类说明符,而 MSVC 的 cl.exe 或 g++ 看到它就是一个未定义的标识符。因此我们需要将cuda代码文件使用".cu"格式,而不是".cpp"。这样,在编译到".cu"格式文件时cuda编译器才能识别出里面的代码为cuda代码。我们可以通过在".cu"格式文件内编写代码实现,通过".h"或者".hpp"格式头文件来声明".cu"格式文件里实现的函数,这样在别处include该头文件时既可以使用".cu"格式文件内的函数实现。
下面是将visual studio C/C++空项目修改为CUDA c++的方法,主要有2种方式
一种方式是使用vs的界面来图形化操作;另一种是参考已有的cuda库提供的测试例程,按照文件".vcxproj"里面的来修改为支持cuda代码的编译。
不管使用哪种方式,都应该先准备好cuda库(最好配置在系统上,并在环境变量上也配置好,不然需要将生成的exe拷贝到与cuda库一起才能调用)以及配置上cuda相关的:包含目录、库目录、附加依赖项。
cuda配置见:参考这里
比如我的:
包含目录:
..\3rdparty\CUDA11.8+CUDNN8.9.6+tensorRT8.6.1.6\include
库目录:
..\3rdparty\CUDA11.8+CUDNN8.9.6+tensorRT8.6.1.6\lib
..\3rdparty\CUDA11.8+CUDNN8.9.6+tensorRT8.6.1.6\lib\x64
附加依赖项:
cudnn.lib
cublas.lib
cudart.lib
若编译出现报错/utf-8 编码错误还可以在:c/c++ ---》命令行 ---》 其它选项 中输入"/utf-8 "保存即可。
准备好cuda库后进行二选一配置:
一、方式一:使用vs的界面来图形化操作
1、按照上述提到的,配置好包含目录、库目录、附加依赖项;
2、右击项目--》属性--》生成依赖项 --》 生成自定义--》 勾选上你对应的cuda


3、将项目属性中的 平台工具集修改为与你使用的cuda库所需要的一致

否则编译时可能会报以下错误:
error MSB4019: 找不到导入的项目"C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Microsoft\VC\v150\BuildCustomizations\CUDA 11.8.targets"
4、在项目中,右击".cu"文件---》属性

修改为:

5、有时会看到cu文件中的代码有些仍然标有红色报错,但是不需要理会。
如:

实际上代码已经能够正确编译,只是索引有问题而已。
二、参考已有的cuda库提供的测试例程,按照文件".vcxproj"里面的来修改为支持cuda代码的编译
主要修改以下几点:
1、同样的:按照上述提到的,配置好包含目录、库目录、附加依赖项;
2、在项ItemGroup中添加(或将原来的ClInclude修改为CudaCompile )
<ItemGroup>
<ClInclude Include="test.cu" />
</ItemGroup>
修改为
<ItemGroup>
<CudaCompile Include="test.cu" />
</ItemGroup>
表明当前的"test.cu"文件是使用cuda编译,而不是c/c++的编译。其它的cpp、hpp保持为使用"ClInclude "。
这里其实就是对应方法一图形界面操作中的"右击项目--》属性--》生成依赖项 --》 生成自定义--》 勾选上你对应的cuda"。
3、在项ImportGroup 中添加
<ImportGroup Label="ExtensionTargets">
<Import Project="$(VCTargetsPath)\BuildCustomizations\CUDA 11.8.targets" />
</ImportGroup>
这里其实就是对应方法一图形界面操作中的"在项目中,右击".cu"文件---》属性"。
最后,提供一个可测试cuda的程序,保存时需要格式为".cu"而不是".cpp":
cpp
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <stdio.h>
cudaError_t addWithCuda(int *c, const int *a, const int *b, unsigned int size);
__global__ void addKernel(int *c, const int *a, const int *b)
{
int i = threadIdx.x;
c[i] = a[i] + b[i];
}
int main()
{
const int arraySize = 5;
const int a[arraySize] = { 1, 2, 3, 4, 5 };
const int b[arraySize] = { 10, 20, 30, 40, 50 };
int c[arraySize] = { 0 };
// Add vectors in parallel.
cudaError_t cudaStatus = addWithCuda(c, a, b, arraySize);
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "addWithCuda failed!");
return 1;
}
printf("{1,2,3,4,5} + {10,20,30,40,50} = {%d,%d,%d,%d,%d}\n",
c[0], c[1], c[2], c[3], c[4]);
// cudaDeviceReset must be called before exiting in order for profiling and
// tracing tools such as Nsight and Visual Profiler to show complete traces.
cudaStatus = cudaDeviceReset();
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaDeviceReset failed!");
return 1;
}
return 0;
}
// Helper function for using CUDA to add vectors in parallel.
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;
cudaError_t cudaStatus;
// Choose which GPU to run on, change this on a multi-GPU system.
cudaStatus = cudaSetDevice(0);
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaSetDevice failed! Do you have a CUDA-capable GPU installed?");
goto Error;
}
// Allocate GPU buffers for three vectors (two input, one output) .
cudaStatus = cudaMalloc((void**)&dev_c, size * sizeof(int));
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaMalloc failed!");
goto Error;
}
cudaStatus = cudaMalloc((void**)&dev_a, size * sizeof(int));
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaMalloc failed!");
goto Error;
}
cudaStatus = cudaMalloc((void**)&dev_b, size * sizeof(int));
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaMalloc failed!");
goto Error;
}
// Copy input vectors from host memory to GPU buffers.
cudaStatus = cudaMemcpy(dev_a, a, size * sizeof(int), cudaMemcpyHostToDevice);
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaMemcpy failed!");
goto Error;
}
cudaStatus = cudaMemcpy(dev_b, b, size * sizeof(int), cudaMemcpyHostToDevice);
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaMemcpy failed!");
goto Error;
}
// Launch a kernel on the GPU with one thread for each element.
addKernel<<<1, size>>>(dev_c, dev_a, dev_b);
// Check for any errors launching the kernel
cudaStatus = cudaGetLastError();
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "addKernel launch failed: %s\n", cudaGetErrorString(cudaStatus));
goto Error;
}
// cudaDeviceSynchronize waits for the kernel to finish, and returns
// any errors encountered during the launch.
cudaStatus = cudaDeviceSynchronize();
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaDeviceSynchronize returned error code %d after launching addKernel!\n", cudaStatus);
goto Error;
}
// Copy output vector from GPU buffer to host memory.
cudaStatus = cudaMemcpy(c, dev_c, size * sizeof(int), cudaMemcpyDeviceToHost);
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaMemcpy failed!");
goto Error;
}
Error:
cudaFree(dev_c);
cudaFree(dev_a);
cudaFree(dev_b);
return cudaStatus;
}