如何使用CMake分别编译*.cpp与*.cu文件解决CUDA项目编译报错
错误原因分析
- 第一版CMake错误:同时定义了两个包含相同C++源文件的可执行目标
cuda和Project_4,且混用了已废弃的旧版CUDA CMake接口cuda_add_executable和3.10+版本原生支持的CUDA语言编译逻辑,导致中间生成文件冲突,触发.cu.o相关的CMake报错。 - 第二版CMake错误:完全未将.cu文件加入可执行目标的源文件列表,且如果CUDA核函数调用的
<<<>>>语法直接写在.cpp文件中,会被C++编译器(GCC/Clang)识别为非法语法,因此抛出<符号前缺少表达式的语法错误。
修复方案
1. 修正CMakeLists.txt配置
3.16版本CMake原生支持CUDA语言编译,无需调用FindCUDA等旧版模块,也无需使用cuda_add_executable接口,正确配置如下:
cmake_minimum_required(VERSION 3.16) project(Project_4 LANGUAGES CXX CUDA) # 语言标准设置 set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CUDA_STANDARD 17) set(CMAKE_CUDA_STANDARD_REQUIRED ON) set(CMAKE_BUILD_TYPE Release) # 输出路径设置 set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/build) # 头文件路径 include_directories(include) # 自动适配当前设备的CUDA架构,无需手动指定sm版本 # 如需手动指定,可改为set(CMAKE_CUDA_ARCHITECTURES 75) 对应10系/20系显卡,86对应30系显卡 set(CMAKE_CUDA_ARCHITECTURES Auto) # 收集所有源文件,同时包含cpp和cu文件 file(GLOB_RECURSE DIR_SRCS ${PROJECT_SOURCE_DIR}/src/*.cpp ${PROJECT_SOURCE_DIR}/src/*.cu ) # 原生add_executable会自动识别后缀,用NVCC编译cu文件,用C++编译器编译cpp文件 add_executable(Project_4 ${DIR_SRCS}) # 链接CUDA依赖库 target_link_libraries(Project_4 PRIVATE ${CUDA_LIBRARIES}) # 开启CUDA分离编译 set_target_properties(Project_4 PROPERTIES CUDA_SEPARABLE_COMPILATION ON )
注意:原配置中的
arch=compute_30,code=sm_30对应开普勒架构显卡,CUDA 11及以上版本已完全弃用该架构支持,若使用新版本CUDA会触发编译报错,建议直接用CMAKE_CUDA_ARCHITECTURES Auto自动适配。
2. 代码层面适配
不要在.cpp文件中直接使用<<<>>>语法调用CUDA核函数,建议采用接口封装方案:
- 在头文件中定义C/C++兼容的接口函数,例如
matrix_mul_cuda.h:
#pragma once // 矩阵乘法CUDA实现对外接口,无CUDA专属语法 void matrix_mul_cuda(const float* a, const float* b, float* c, int m, int n, int k);
- 在对应的.cu文件中实现接口,内部调用核函数:
#include "matrix_mul_cuda.h" // 核函数仅在cu文件内部可见 __global__ void mat_mul_kernel(const float* a, const float* b, float* c, int m, int n, int k) { // 核函数逻辑实现 } void matrix_mul_cuda(const float* a, const float* b, float* c, int m, int n, int k) { dim3 block_size(32, 32); dim3 grid_size((n + 31) / 32, (m + 31) / 32); // <<<>>>语法仅出现在cu文件中,由NVCC编译 mat_mul_kernel<<<grid_size, block_size>>>(a, b, c, m, n, k); cudaDeviceSynchronize(); }
- C++代码中直接引入头文件调用封装后的接口即可,无需处理CUDA专属语法。
如果确实需要在原有.cpp文件中写核函数调用,直接将该文件后缀改为.cu即可,CMake会自动识别并使用NVCC编译。
内容的提问来源于stack exchange,提问作者zephyrus
相关产品推荐
相关产品推荐

