news 2026/10/26 10:34:44

Qt Creator 集成 CUDA:qmake 构建链配置与排错

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Qt Creator 集成 CUDA:qmake 构建链配置与排错

简介:面向Windows平台在Qt Creator中集成CUDA的示例工程包,适合具备Qt基础、希望借助NVIDIA GPU开展通用计算的开发者参考。包内共7个文件,以2个cpp源文件、1个ui界面文件、1个cu内核文件、1个h头文件及pro工程配置为主,另有user文件记录本地环境,压缩包约5KB,体量轻便,便于快速导入查看工程结构与编译配置关系。已有971人学习下载,反映该主题在Qt与GPU编程交叉场景中具有一定参考需求。工程覆盖主窗口界面、程序入口、CUDA源文件与Qt工程组织等关键组成,读者可据此了解.cu文件在项目中的识别方式、CUDA代码与界面代码的衔接关系,以及构建配置在工程文件中的体现。其体量小、结构集中的特点,也适合作为最小化模板,降低从零创建工程时文件类型与构建项配置的试错成本,为本地GPU计算实验提供可对照的工程骨架。

1. qtcreator中添加cuda:卡住的从来不是核函数,是构建链

在 Windows 上做 qtcreator中添加cuda,真正让人熬夜的环节几乎从来不是__global__里那几行计算,而是构建链本身。Qt Creator 只是个壳,它把.pro交给 qmake,qmake 生成 Makefile 再去调cl.exe;nvcc 是另一条完全独立的路,两套工具链最后要在同一个 obj 目录里重新关联,任何一个参数没对齐,报错都会指向一个看起来毫不相干的行号。我见过最典型的现场:代码一行没改,Release 构建得干干净净,切到 Debug 立刻抛出 LNK2038,新手很容易怀疑是自己核函数写错了。

这篇笔记按「套件对齐 →.pro挂 nvcc → 代码隔离 → 排错」的顺序走一遍,面向的是手里已经有一个能跑的 Qt Widgets 工程、想把某段计算搬到 GPU 上的人,也面向刚碰 CUDA 就被 MinGW 套件坑过一次的人。里面所有qmake片段和.cu骨架都是可以直接抄进工程的,参数为什么这么设、改哪一行会出什么事,我也会一并说清楚。

2. 套件与工具链对齐:MSVC、CUDA Toolkit、qmake 三者的版本咬合

在写第一行nvcc命令之前,必须先把「谁来编译 host 代码」这件事定下来。Windows 上的 CUDA 只认 MSVC 的cl.exe作为 host 编译器,这一条没有商量余地。很多人第一步就翻车,不是因为不会写.pro,而是新建工程时随手选了 MinGW 套件,后面无论怎么补规则都救不回来。

2.1 为什么必须走 MSVC 套件而不是 MinGW

Qt Creator 的「构建套件(Kit)」决定了 qmake 生成的 Makefile 最终调用哪个编译器。MinGW 套件背后是g++.exe,而 nvcc 在 Windows 上会去找cl.exe,找不到就直接nvcc fatal : Cannot find compiler 'cl.exe' in PATH。这不是路径没配好,是方向错了——nvcc 的 host 编译阶段根本不支持 MinGW。

确认套件的路径是:工具 > 选项 > Kits > 构建套件,看编译器一栏的 C++ 是不是指向cl.exe,名字里通常带MSVC2019或MSVC2022字样。如果是MinGW,直接在项目 > 管理构建套件里换一个 Desktop Qt 的 MSVC 版本。

版本咬合上有个粗线条的对应关系,装之前先看一眼,能省掉重装:

组件要求不满足时的表现
Qt 套件必须是 MSVC 构建版本,位数与 CUDA 一致(一般 64 位)nvcc 找不到 cl.exe,或编译出的 obj 位数不匹配
MSVC2019 或 2022,需带 Windows SDKCUDA 安装器检测不到宿主编译器,集成项灰掉
CUDA Toolkit与显卡驱动匹配,驱动版本不能低于 runtime 版本编译通过,运行时cudaErrorNoDevice或 unknown error
构建目录纯英文、无空格nvcc 报cannot open input file,路径被空格截断

安装顺序我一般这样走:先装 Visual Studio Build Tools(勾选 MSVC 生成工具 + Windows SDK),再装 Qt 的 MSVC 套件,最后装 CUDA Toolkit。反过来装也能成,但 CUDA 安装时如果没检测到 VS,就不会把编译集成的环境变量写进去,后面要手动补,麻烦。

2.2 用环境变量把 nvcc 路径固定下来

CUDA Toolkit 安装完会自动写一个CUDA_PATH环境变量,指向当前版本目录。工程里不要硬编码C:/Program Files/...,团队里两个人装的版本不一样,.pro一提交就打架。用$$(CUDA_PATH)在 qmake 执行时读取环境变量:

# 在 cmd 里先确认环境变量是否生效,注意是新开的窗口 echo %CUDA_PATH% # 预期输出类似 C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.x # 直接验证 nvcc 可用 nvcc --version

这里有个容易被忽略的地方:Qt Creator 继承的是它启动那一刻的系统环境。如果你在 Qt Creator 已经打开的情况下才装完 CUDA,或者刚改过环境变量,必须完全退出 Qt Creator 再重开,否则 qmake 读到的CUDA_PATH是空的。这个问题极难自查,因为.pro里isEmpty判断不会报错,只是所有 CUDA 规则静默失效。

.pro里加一层兜底,路径为空时直接让 qmake 报错中断,比让它生成一个残缺的 Makefile 好得多:

CUDA_DIR = $$(CUDA_PATH) isEmpty(CUDA_DIR) { error("CUDA_PATH 未设置:确认已安装 CUDA Toolkit,并重启 Qt Creator") }

2.3 工程目录分层:把 .cu 单独放进 kernels/

不要图省事把.cu和.cpp丢在同一个目录里。分层的目的是让「哪些文件归 cl.exe 管、哪些归 nvcc 管」在目录结构上就一目了然,.pro里也不会误把.cu写进SOURCES。

我一般这样组织:

路径归谁编译说明
kernels/vecadd.cunvcc核函数、cudaMalloc、kernel launch 全在这里
include/vecadd.h不单独编译纯 C 接口声明,不带任何 CUDA 关键字
mainwindow.cppcl.exe只调vecAdd(),对这个函数内部用的是 GPU 毫无感知
main.cppcl.exe程序入口

分层之后,.pro里CUDA_SOURCES只有一行,SOURCES里永远不出现.cu,后面排查问题时能快速排除一大类误配。顺带提一句 Qt Creator 的编辑器体验:.cu文件默认不被识别成 C++,代码补全和语法高亮都是灰的,可以在工具 > 选项 > C++ > 文件类型里把*.cu、*.cuh关联到 C++ 编辑器。关联之后 Clang 代码模型会对 CUDA 关键字画一堆红色波浪线,那是误报,不影响构建,别被它吓到去改代码。

3. 在 .pro 里挂 nvcc:QMAKE_EXTRA_COMPILERS 手写编译规则

工具链确认无误,接下来才是真正把 nvcc 接进 qmake。qmake 本身不认识.cu,必须通过QMAKE_EXTRA_COMPILERS注册一条自定义编译规则,告诉它「这类文件的输入是什么、输出是什么、用什么命令编译、依赖怎么算」。

3.1 nvcc 一条命令干了哪几件事

理解nvcc -c xxx.cu -o xxx.obj背后发生了什么,直接决定你能不能看懂报错。它并不是一个单一编译器,而是一个驱动:

  1. 预处理阶段,把.cu里的#include展开,这一步和 cl.exe 的预处理等价。
  2. device 代码被 cicc 编译成 PTX(虚拟指令集),再交给 ptxas 汇编成目标架构的 SASS 机器码。
  3. 生成的设备码被打包成 fatbin,作为一段特殊数据嵌进 obj 文件。
  4. host 代码(main那侧的cudaMalloc、<<<>>>展开后的cudaLaunchKernel)交给cl.exe编译。
  5. 两部分合成为一个标准 COFF 格式的.obj,后面 cl.exe 链接时把它当普通目标文件看待。

关键点在-arch。不指定时 nvcc 会用默认架构,可能在你的卡上跑不出最优性能,甚至在新卡上跑不了。工程里我一般显式写-gencode arch=compute_75,code=sm_75,75 对应的是图灵一代,实际按你手上的卡改,比如 86、89。-Xcompiler是把参数透传给 host 编译器cl.exe的通道,后面运行库对齐就靠它。

3.2 可抄的 .pro 片段与逐行解释

下面这段是整个工程的核心,直接贴进.pro末尾即可:

# ---------- CUDA 基础路径 ---------- CUDA_DIR = $$(CUDA_PATH) isEmpty(CUDA_DIR) { error("CUDA_PATH 未设置:确认已安装 CUDA Toolkit,并重启 Qt Creator") } NVCC = $$CUDA_DIR/bin/nvcc.exe CUDA_INC = $$CUDA_DIR/include CUDA_LIB = $$CUDA_DIR/lib/x64 INCLUDEPATH += $$CUDA_INC # ---------- 源文件与架构 ---------- CUDA_SOURCES += kernels/vecadd.cu # 按实际显卡改:75=图灵 86=安培 89=安培refresh CUDA_ARCH = -gencode arch=compute_75,code=sm_75 # ---------- 编译参数 ---------- CUDA_FLAGS = -c $$CUDA_ARCH \ -Xcompiler /EHsc \ -Xcompiler /utf-8 \ -Xcompiler /wd4819 # Debug 与 Release 的运行库必须和 Qt 套件保持同一套 CONFIG(debug, debug|release) { CUDA_FLAGS += -Xcompiler /MDd -Xcompiler /Zi -G } else { CUDA_FLAGS += -Xcompiler /MD -Xcompiler /O2 } # ---------- 注册自定义编译器 ---------- cuda.input = CUDA_SOURCES cuda.output = ${OBJECTS} cuda.commands = $$quote($$NVCC) $$CUDA_FLAGS $$quote(${QMAKE_FILE_IN}) -o $$quote(${QMAKE_FILE_OUT}) cuda.dependency_type = TYPE_C cuda.depend_command = $$quote($$NVCC) -M $$CUDA_ARCH $$quote(${QMAKE_FILE_IN}) QMAKE_EXTRA_COMPILERS += cuda # ---------- 链接 ---------- LIBS += -L$$quote($$CUDA_LIB) -lcudart

逐行说几个关键项:

cuda.input接收源文件列表,qmake 会为列表里每个文件各调一次cuda.commands。${QMAKE_FILE_IN}和${QMAKE_FILE_OUT}是 qmake 在展开时替换的单文件变量,注意它们用的是${}而不是$$,写错了不会报语法错,只会把字面量拼进命令里,然后 nvcc 抱怨找不到叫QMAKE_FILE_IN的文件。

cuda.output = ${OBJECTS}是个取巧写法:它让每个.cu对应一个 obj,由 qmake 自动分配名字并加入链接列表,不用手动维护。副作用是多个.cu时输出名是按顺序对应的,一旦你增删源文件,可能出现对象错位引起的诡异重链接问题。保守一点可以改成显式命名:

# 显式指定输出 obj 的名字与位置,多 .cu 工程更稳 cuda.output = $$OBJECTS_DIR/$$basename(QMAKE_FILE_IN)$$OBJECTS_EXT

cuda.depend_command用nvcc -M生成依赖清单,作用是当你改了被#include的头文件时,qmake 知道该重编哪个.cu。不加这一行也能编,但增量编译会失真,改了vecadd.h结果.cu不重编,链接出来的还是旧符号——这种问题非常像「玄学」,实际就是依赖没跟踪。

-Xcompiler /utf-8和/wd4819是给中文注释准备的。.cu里写了中文注释又没加编码参数,cl.exe 会刷一屏 C4819 警告,虽然不影响结果,但会把真正的错误淹没掉。

3.3 链接阶段:cudart 与 MSVC 运行库的配对

编译过了不代表能链接。CUDA runtime 有两种链接方式,选哪种决定了你发布的 exe 要不要带 dll:

方式写法特点
动态-lcudart编译快,运行时需要cudart64_*.dll在 PATH 或 exe 同目录
静态-lcudart_static部署省事,但要额外补系统库,链接器会提示缺哪个

新手建议先用动态版把流程跑通,等真到打包发布那一步再换静态。动态版最常见的问题是「开发机能跑,拷到别人机器上闪退」,原因就是缺 dll,用windeployqt是补 Qt 的库,不会顺手把 CUDA 的 dll 带上,得手动拷。

更隐蔽的是运行库配对。Qt 的 MSVC Release 套件用/MD,Debug 套件用/MDd,而 nvcc 默认按 Release 那一套走/MD。所以 Release 构建一切正常,一按 Debug 就炸:

mainwindow.obj : error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MDd_DynamicDebug”不匹配值“MD_DynamicRelease”

这就是上面.pro里CONFIG(debug, debug|release)那段存在的唯一理由。别嫌它啰嗦,删掉它你迟早会回来加。

4. 代码侧对接:Qt 界面调 kernel 的隔离写法

构建规则通了,接下来是代码怎么写才不给后面的自己挖坑。核心原则只有一条:CUDA 关键字不出现在任何会被 moc 处理的头文件里。

4.1 头文件隔离:别让 moc 看见global

moc 是 Qt 的元对象编译器,它要扫所有带Q_OBJECT的头文件并生成moc_xxx.cpp。moc 的解析器不是完整的 C++ 编译器,遇到__global__、__shared__这些宏它能忍,遇到<<<grid, block>>>这种非标准语法就直接报解析错误,而报错位置通常指向头文件里跟你完全无关的一行。

正确做法是切一条纯 C 边界。头文件里只暴露普通函数声明,extern "C"防止 C++ 名字修饰导致链接期找不到符号:

// include/vecadd.h #ifndef VECADD_H #define VECADD_H #ifdef __cplusplus extern "C" { #endif // 返回 0 表示成功,非 0 时是 cudaError_t 的整型值 int vecAdd(const float* a, const float* b, float* c, int n); #ifdef __cplusplus } #endif #endif // VECADD_H

这个头文件里没有任何 CUDA 头文件引用,mainwindow.cpp可以放心 include,moc 也完全不受影响。有人喜欢在头里写#include <cuda_runtime.h>图方便,那样 moc 会把整个 CUDA 头链拖进来解析,慢不说,还容易因为某些宏展开失败。cuda_runtime.h只应该出现在.cu里。

4.2 最小可跑的向量加法:.cu 与 .cpp 的分工

先看.cu这一侧,它承担了分配显存、拷贝、启动、回收的全部脏活:

// kernels/vecadd.cu #include <cuda_runtime.h> #include "vecadd.h" __global__ void vecAddKernel(const float* a, const float* b, float* c, int n) { int i = blockIdx.x * blockDim.x + threadIdx.x; if (i < n) { // 越界保护:最后一个 block 通常不满 c[i] = a[i] + b[i]; } } extern "C" int vecAdd(const float* a, const float* b, float* c, int n) { if (n <= 0) return 0; const size_t bytes = static_cast<size_t>(n) * sizeof(float); float *da = nullptr, *db = nullptr, *dc = nullptr; cudaError_t err = cudaMalloc(&da, bytes); if (err != cudaSuccess) return static_cast<int>(err); err = cudaMalloc(&db, bytes); if (err != cudaSuccess) { cudaFree(da); return static_cast<int>(err); } err = cudaMalloc(&dc, bytes); if (err != cudaSuccess) { cudaFree(da); cudaFree(db); return static_cast<int>(err); } cudaMemcpy(da, a, bytes, cudaMemcpyHostToDevice); cudaMemcpy(db, b, bytes, cudaMemcpyHostToDevice); const int threads = 256; const int blocks = (n + threads - 1) / threads; // 向上取整 vecAddKernel<<<blocks, threads>>>(da, db, dc, n); // 启动后立刻查一次,捕获配置错误、非法地址这类「启动即失败」 err = cudaGetLastError(); if (err == cudaSuccess) { err = cudaMemcpy(c, dc, bytes, cudaMemcpyDeviceToHost); } cudaFree(da); cudaFree(db); cudaFree(dc); return static_cast<int>(err); }

几个参数值得单独说。threads = 256是个稳妥起步值,必须是 32 的整数倍(一个 warp 是 32 线程),取 256 兼顾占用率和寄存器压力;超过 1024 直接编译报错。blocks必须向上取整,n不是 256 的倍数时最后一个 block 会有线程越界,所以核函数里那句if (i < n)不是保险,是必需品——删掉它,结果里会随机出现垃圾值,且长度不同表现不同,非常难查。

cudaGetLastError()的位置也有讲究,它必须紧跟在<<<>>>之后。核函数启动是异步的,如果先写了cudaMemcpy再查错误,拿到的是拷贝那一步的错误码,kernel 的配置错误(比如 block 数超限)就被覆盖掉了。

调用方这一侧就清爽了:

// mainwindow.cpp 片段 #include "mainwindow.h" #include "vecadd.h" void MainWindow::onRunClicked() { const int n = 1 << 20; // 约 100 万个元素 QVector<float> a(n, 1.0f), b(n, 2.0f), c(n, 0.0f); int ret = vecAdd(a.constData(), b.constData(), c.data(), n); if (ret != 0) { ui->statusLabel->setText(QString("CUDA 调用失败,错误码 %1").arg(ret)); return; } ui->statusLabel->setText(QString("完成,c[0]=%1").arg(c[0])); }

QVector::constData()保证连续内存,直接喂给cudaMemcpy是安全的。别传QList,它的元素不保证连续,拷贝出去就是一串错位数据。

4.3 错误检查放在哪一行

CUDA 的错误处理最忌讳「全都不查」。核函数出错时不抛异常、不中断,只是默默不干活,最后你拿到一数组 0,回头怀疑算法。我的习惯是每个可能失败的调用后面都判一次,并且集中转成一个函数,避免.cu里到处是if分支:

// 统一的错误检查宏,仅用于调试期 #define CUDA_CHECK(call) \ do { \ cudaError_t e = (call); \ if (e != cudaSuccess) { \ fprintf(stderr, "[CUDA] %s:%d %s -> %s\n", \ __FILE__, __LINE__, #call, cudaGetErrorString(e)); \ return static_cast<int>(e); \ } \ } while (0)

cudaDeviceSynchronize()要不要加?我的建议是只在调试期加。它的作用是让 CPU 阻塞等待 GPU 把活干完,这样核函数内部的非法访存才能被定位到具体那一次启动。代价是彻底破坏异步流水,一段本来 2ms 的计算可能变成 15ms,性能测试时千万别留着。上线前把同步去掉、只留cudaGetLastError(),这是我踩过坑之后固定下来的做法:同步留着测性能,测出来的数字全是假的。

5. 排查清单:五类翻车现场的现象、原因与解法

下面这五条,是我和周围人实际遇到过、并且每次都因为「报错信息和真实原因对不上」而浪费半天的场景。按构建阶段归类,遇到问题时对号入座比盲搜快得多。

5.1 编译期:找不到 cl.exe 与 .cu 被当成 C++

现象一:执行 qmake 后构建,第一条命令就失败,输出nvcc fatal : Cannot find compiler 'cl.exe' in PATH。

原因:工程用的是 MinGW 套件,或者你从普通 cmd 里手动跑 qmake,当前环境没有vcvarsall.bat注入的 MSVC 路径。nvcc 本身不负责找编译器,它只会在 PATH 里翻。

解决:Qt Creator 里换 MSVC 套件;要在命令行构建的话,先开「x64 Native Tools 命令提示符」再执行qmake和nmake,那个窗口的环境变量是预置好的。临时验证可以在构建前手动call "C:\...\vcvars64.bat"。

现象二:vecadd.cu报一堆__global__ 未定义或卡在<<<处报语法错误,错误信息由cl.exe而非 nvcc 抛出。

原因:.cu被同时写进了SOURCES。qmake 会为SOURCES里的每个文件生成一条cl.exe编译命令,cl 不认识 CUDA 语法,自然报错。

解决:从SOURCES里删掉所有.cu和.cuh,只保留在CUDA_SOURCES。改完必须执行一次「构建 > 执行 qmake」,光点构建不会重新生成 Makefile。

现象三:nvcc 报cannot open input file,文件名看起来被截断了。

原因:构建目录或工程路径里带空格、中文、括号。${QMAKE_FILE_IN}展开后路径没被引号包住,空格之后的内容被当成另一个参数。

解决:构建目录改成纯英文无空格路径;同时确认cuda.commands里用了$$quote(...)把每个路径参数包起来。两件事都做才彻底。

5.2 链接期:LNK2038 与找不到符号

现象四:Debug 构建报LNK2038: 检测到"RuntimeLibrary"的不匹配项,Release 一切正常。

原因:nvcc 默认用/MD编译 host 部分,而 Qt 的 Debug 套件用/MDd,同一个 exe 里混了两套 C 运行库,链接器直接拒绝。

解决:.pro里按CONFIG(debug, debug|release)给 nvcc 补-Xcompiler /MDd。改完清空构建目录重新编译,只做增量构建有时旧的 obj 还留着,症状会继续存在。

现象五:LNK2019: 无法解析的外部符号 vecAdd,明明.cu里有这个函数。

原因:三种可能,按概率排——头文件声明忘了extern "C",C++ 名字修饰对不上;.cu没真正参与编译(qmake 没重跑);.cu编译失败但被忽略,obj 根本没生成。

解决:先看构建输出里有没有vecadd.cu那一行编译命令,没有就执行 qmake;有的话检查extern "C";最后可以用dumpbin /symbols vecadd.obj看导出的符号名是不是未修饰的_vecAdd。

5.3 运行期:核函数静默失败与设备不可用

现象六:程序不崩、不报错,就是算出来的结果全 0 或者和 CPU 版本对不上。

原因:核函数启动失败但没人检查。最常见的是blocks或threads超限(比如误把threads填成元素总数),或者传了已经cudaFree的指针。CUDA 的异步模型让这些错误在启动那一刻不会反馈给调用方。

解决:在<<<>>>后面立刻加cudaGetLastError(),调试期再加cudaDeviceSynchronize()把异步错误逼出来。定位到具体是哪个指针后,用compute-sanitizer(CUDA Toolkit 自带)跑一遍,非法访存会精确报到 kernel 名和行号。

现象七:cudaMalloc返回cudaErrorNoDevice或unknown error,但开发机能正常跑。

原因:目标机器没装显卡驱动,或者驱动版本低于程序编译时用的 CUDA runtime 版本。runtime 版本高于驱动支持的版本时,cudaMalloc是第一个失败点。

解决:先在目标机跑nvidia-smi看驱动支持的 CUDA 版本,再决定是升级驱动还是把工程降到一个更低的 runtime 版本重编。这条在交付场景里比在开发机上重要得多。

6. 进阶:多架构编译、分离编译与迁移到 CMake

流程跑通之后,剩下三件事值得花时间:让程序在别人的卡上也能跑、让多个.cu之间能互相调用、以及跟上新版 Qt Creator 默认用 CMake 的趋势。

多架构编译是最容易漏的一步。只写一个-gencode arch=compute_75,code=sm_75,程序在 75 及以上的卡上能跑,但换到更新的架构就得走 PTX 即时编译,首次启动明显变慢。实际发布时我一般列两到三个目标:

# 同时产出 sm_75 的 SASS 和 compute_89 的 PTX 兜底 CUDA_ARCH = -gencode arch=compute_75,code=sm_75 \ -gencode arch=compute_89,code=sm_89 \ -gencode arch=compute_89,code=compute_89

最后一行code=compute_89是只生成 PTX 不生成 SASS,驱动会在运行期把它 JIT 成当前卡的机器码,兼容性最好、启动稍慢。三个目标一起上,编译时间大概翻倍,本地开发只留一个就够,发布构建再切全量。

分离编译是第二个坎。默认情况下每个.cu是独立编译单元,A 文件里的__device__函数没法被 B 文件调用,链接期报未解析符号。要让它们互相可见,得开-rdc=true并链接设备运行时:

# 需要跨 .cu 调用 __device__ 函数时启用 CUDA_FLAGS += -rdc=true LIBS += -L$$quote($$CUDA_LIB) -lcudart -lcudadevrt

代价是编译变慢、链接期多一步设备链接(dlink),小工程完全没必要开,看到「undefined reference todevicexxx」再回头加就行。

至于 CMake,新版 Qt Creator 建工程默认给的就是CMakeLists.txt,CUDA 的支持反而比 qmake 原生:

cmake_minimum_required(VERSION 3.20) project(GpuDemo LANGUAGES CXX CUDA) # CUDA 必须在这里声明 set(CMAKE_CUDA_STANDARD 17) set(CMAKE_CUDA_ARCHITECTURES 75) # 对应 sm_75,多架构写 75;89 # set(CMAKE_CUDA_SEPARABLE_COMPILATION ON) # 需要跨 .cu 调用时再打开 add_executable(GpuDemo main.cpp mainwindow.cpp kernels/vecadd.cu) target_include_directories(GpuDemo PRIVATE include)

要点只有两个:LANGUAGES里必须写CUDA,漏了的话.cu会被当成不可识别文件直接忽略,症状和 qmake 里忘了注册规则一模一样;CMAKE_CUDA_ARCHITECTURES不给值的话 CMake 会按检测到的本机显卡设一个,换机器构建时行为就变了,显式写死更稳。运行库对齐在 CMake 里不用操心,CMAKE_MSVC_RUNTIME_LIBRARY会统一带上 Debug/Release 的差异,这也是我更愿意把老工程迁过去的原因。

从那次 Debug 构建报了一屏 LNK2038、最后发现只是少了个/MDd之后,我每次新建带 CUDA 的 Qt 工程,都强制先把.pro里的 Debug/Release 分支和cudaGetLastError()的检查点写全,再去写第一行业务代码——这二十分钟,比事后顺着 obj 文件翻符号表划算太多。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/26 10:34:08

PyAutoGUI 0.9.26 桌面自动化:坐标、图像定位与稳定交付

简介&#xff1a;PyAutoGUI 0.9.26 的源码软件包&#xff0c;面向希望用 Python 完成鼠标键盘模拟、桌面自动化与界面测试的开发者&#xff0c;也适合初学者借助示例理解跨平台 GUI 控制流程&#xff0c;解决重复性桌面操作与脚本化交互问题。包内共 37 个文件&#xff0c;以 1…

作者头像 李华
网站建设 2026/10/26 10:34:08

PyAutoGUI 0.9.26 桌面自动化:安装避坑、坐标定位与时序控制

简介&#xff1a;PyAutoGUI-0.9.26.zip 面向 Python 开发者与自动化测试人员&#xff0c;是一份 GUI 自动控制库的完整源码包&#xff1a;用脚本模拟鼠标移动、点击、拖拽、滚动与键盘输入&#xff0c;把重复的桌面操作交给程序执行&#xff0c;支持 Windows、Mac OS X 与 Linu…

作者头像 李华
网站建设 2026/10/26 10:34:06

SQL Server+Swing宾馆管理系统:事务驱动的房态账目闭环

简介&#xff1a;面向数据库课程设计与Java桌面开发入门者的宾馆管理系统项目&#xff0c;将SQL Server数据库设计与Swing图形界面整合为可运行的酒店业务案例&#xff0c;适合需要完成课设、课程作业或自学JDBC与桌面开发的学生参考。压缩包共40个文件、约2.02MB&#xff0c;含…

作者头像 李华
网站建设 2026/10/26 10:33:55

Visual C++ 2008 x86运行库安装与0xc0150002排查指南

简介&#xff1a;Microsoft Visual C 2008 Redistributable&#xff08;x86&#xff09;是面向32位Windows用户与软件部署人员的VC 2008运行时库安装包&#xff0c;主要用于解决未安装完整开发环境时&#xff0c;依赖VC 2008编译的程序因缺少运行库而无法启动的问题&#xff0c…

作者头像 李华
网站建设 2026/10/26 10:33:53

VC++ 2008 x86运行库缺失与0xc000007b排查指南

简介&#xff1a;这款 Microsoft Visual C 2008 Redistributable&#xff08;x86&#xff09;运行时组件包面向32位 Windows 用户及使用 VC 2008 开发环境的人员&#xff0c;主要用于补齐应用程序依赖的运行库&#xff0c;缓解因缺少对应组件而出现的启动失败、动态链接库缺失等…

作者头像 李华