一、前言与选择
今天决定在Windows 11上搭建一个Qt+Rust的混合开发环境。经过研究,我选择了MSYS2的UCRT64环境,而不是传统的MINGW64。主要原因是UCRT(Universal C Runtime)是Windows 10/11的现代C运行时库,与系统兼容性更好,能避免一些潜在的兼容性问题。
二、环境准备与安装
1. 安装MSYS2并切换环境
我首先从MSYS2官网下载并安装了MSYS2。安装完成后,我注意到开始菜单中有多个终端快捷方式:
- MSYS2 UCRT64 - 这是我今天要用的环境
- MSYS2 MINGW64 - 传统的64位环境
- MSYS2 MSYS - 模拟Unix的环境
我点击打开了"MSYS2 UCRT64"终端。
2. 在UCRT64环境中安装必要组件
在UCRT64终端中,我执行了以下命令:
bash
# 首先更新包数据库和系统(MSYS2的常规操作)
pacman -Syu
# 安装Qt6开发包(我选择了Qt6,因为它更现代)
pacman -S mingw-w64-ucrt-x86_64-qt6-base mingw-w64-ucrt-x86_64-qt6-tools mingw-w64-ucrt-x86_64-qt6-declarative
# 安装Rust工具链
pacman -S mingw-w64-ucrt-x86_64-rust
# 安装构建工具
pacman -S mingw-w64-ucrt-x86_64-cmake mingw-w64-ucrt-x86_64-ninja mingw-w64-ucrt-x86_64-gcc
# 安装调试器
pacman -S mingw-w64-ucrt-x86_64-gdb
安装完成后,我验证了安装是否成功:
bash
# 检查各组件版本
rustc --version # 输出: rustc 1.91.1 (MSYS2 UCRT64环境)
g++ --version # 输出: g++.exe (Rev8, Built by MSYS2 project) 15.2.0
qmake --version # 输出: QMake version 3.1
cmake --version # 输出: cmake version 4.2.0
3. 安装VSCode及必要扩展
在Windows 11上,我打开VSCode并安装了以下扩展:
- C/C++ (Microsoft) - 用于C++代码智能感知
- rust-analyzer - 用于Rust代码分析
- CMake Tools - 用于CMake项目支持
- Qt Configure - 可选,Qt项目辅助工具
三、VSCode项目配置
我创建了一个新的项目文件夹 qt_rust_mixed,并在其中进行配置。
1. 配置C++智能感知
在项目根目录创建 .vscode 文件夹,然后创建 c_cpp_properties.json:
json
{
"configurations": [
{
"name": "MSYS2_UCRT64",
"includePath": [
"${workspaceFolder}/**",
"C:/msys64/ucrt64/include/**",
"C:/msys64/ucrt64/include/qt6/**",
"C:/msys64/ucrt64/include/c++/12.2.0/**"
],
"defines": [
"QT_CORE_LIB",
"QT_GUI_LIB",
"QT_WIDGETS_LIB",
"UNICODE",
"_UNICODE"
],
"compilerPath": "C:/msys64/ucrt64/bin/g++.exe",
"cStandard": "c17",
"cppStandard": "c++17",
"intelliSenseMode": "windows-gcc-x64",
"configurationProvider": "ms-vscode.cmake-tools"
}
],
"version": 4
}
2. 配置VSCode使用UCRT64终端
为了确保所有命令都在统一环境下运行,我修改了VSCode的用户设置(通过Ctrl+Shift+P,输入"Preferences: Open User Settings (JSON)"):
json
{
"git.ignoreMissingGitWarning": true,
"terminal.integrated.profiles.windows": {
"MSYS2 UCRT64": {
"path": "C:\\msys64\\usr\\bin\\bash.exe",
"args": ["--login", "-i"],
"env": {
"MSYSTEM": "UCRT64",
"CHERE_INVOKING": "1"
},
"icon": "terminal-bash"
}
},
"terminal.integrated.defaultProfile.windows": "MSYS2 UCRT64",
"terminal.integrated.cursorStyle": "line"
}
3. 配置CMake
在项目根目录创建 CMakeLists.txt,这是混合项目的构建核心:
cmake
cmake_minimum_required(VERSION 3.20)
project(QtRustMixed LANGUAGES CXX)
# 设置C++标准
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# 查找Qt6组件
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
# 设置Rust构建
# 这里假设Rust部分会通过Cargo构建为静态库
# 实际项目中可能需要更复杂的集成
# 添加可执行文件
add_executable(qt_rust_mixed main.cpp)
# 链接Qt库
target_link_libraries(qt_rust_mixed
Qt6::Core
Qt6::Gui
Qt6::Widgets
)
# 在Windows上链接必要的库
if(WIN32)
# Windows可能需要额外的库
# target_link_libraries(qt_rust_mined) # 这是错误行,已删除
endif()
4. 配置调试环境
在 .vscode/launch.json 中配置调试:
json
{
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Debug - UCRT64",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/qt_rust_mixed.exe",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [
{
"name": "PATH",
"value": "C:/msys64/ucrt64/bin;C:/msys64/ucrt64/lib;${env:PATH}"
}
],
"externalConsole": false,
"MIMode": "gdb",
"miDebuggerPath": "C:/msys64/ucrt64/bin/gdb.exe",
"setupCommands": [
{
"description": "为 gdb 启用整齐打印",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
"preLaunchTask": "CMake: build",
"logging": {
"engineLogging": false
}
}
]
}
在 .vscode/tasks.json 中配置构建任务:
json
{
"version": "2.0.0",
"tasks": [
{
"label": "CMake: build",
"type": "shell",
"command": "cmake",
"args": [
"--build",
"${workspaceFolder}/build",
"--config",
"Debug"
],
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [],
"detail": "使用CMake构建项目"
}
]
}
四、验证环境配置
1. 验证C++/Qt环境
我创建了一个简单的Qt测试程序 main.cpp:
cpp
#include <QApplication>
#include <QWidget>
#include <QPushButton>
#include <QVBoxLayout>
#include <QLabel>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QWidget window;
window.setWindowTitle("Qt + Rust 测试环境");
window.resize(400, 300);
QVBoxLayout *layout = new QVBoxLayout(&window);
QLabel *label = new QLabel("环境配置成功!");
label->setAlignment(Qt::AlignCenter);
layout->addWidget(label);
QPushButton *button = new QPushButton("点击我");
layout->addWidget(button);
QObject::connect(button, &QPushButton::clicked, [label]() {
label->setText("按钮被点击了!");
});
window.show();
return app.exec();
}
然后在UCRT64终端中测试编译(qt_rust_mixed目录下):
bash
# 创建构建目录
mkdir -p build
cd build
# 配置CMake
cmake -G "Ninja" -DCMAKE_BUILD_TYPE=Debug ..
# 构建
cmake --build .
构建成功后,我运行了程序:
bash
./qt_rust_mixed.exe
程序正常启动,显示了一个带有按钮的窗口,点击按钮功能正常。
2. 验证Rust环境
我创建了一个简单的Rust库来测试。首先在项目根目录创建 rust-lib 文件夹:
bash
cargo new rust_lib --lib
cd rust_lib
然后编辑 rust-lib/Cargo.toml:
toml
[package]
name = "rust_lib"
version = "0.1.0"
edition = "2024"
[lib]
name = "rust_lib"
crate-type = ["staticlib", "cdylib"] # 静态库和动态库
[dependencies]
编辑 rust-lib/src/lib.rs:
rust
#![allow(unused)]
#[unsafe(no_mangle)]
pub extern "C" fn add_numbers(a: i32, b: i32) -> i32 {
a + b
}
#[unsafe(no_mangle)]
pub extern "C" fn greet(name: *const std::os::raw::c_char) {
unsafe {
if !name.is_null() {
let c_str = std::ffi::CStr::from_ptr(name);
if let Ok(rust_str) = c_str.to_str() {
println!("你好, {}!", rust_str);
}
}
}
}
在UCRT64终端中构建Rust库:
bash
cd rust-lib
cargo build --release
构建成功,在 target/release 目录下生成了 librust_lib.a(静态库)和 rust_lib.dll(动态库)。
3. 验证混合调用
为了测试Qt和Rust的混合调用,我修改了 main.cpp:
cpp
#include <QApplication>
#include <QWidget>
#include <QPushButton>
#include <QVBoxLayout>
#include <QLabel>
#include <QMessageBox>
// 声明Rust函数
extern "C" {
int add_numbers(int a, int b);
void greet(const char* name);
}
int main(int argc, char *argv[]) {
// 测试Rust函数
int result = add_numbers(10, 20);
greet("Qt+Rust开发者");
QApplication app(argc, argv);
QWidget window;
window.setWindowTitle("Qt + Rust 混合环境测试");
window.resize(500, 400);
QVBoxLayout *layout = new QVBoxLayout(&window);
QLabel *label = new QLabel(QString("Rust计算 10 + 20 = %1").arg(result));
label->setAlignment(Qt::AlignCenter);
layout->addWidget(label);
QPushButton *rustBtn = new QPushButton("调用Rust函数");
layout->addWidget(rustBtn);
QPushButton *quitBtn = new QPushButton("退出");
layout->addWidget(quitBtn);
QObject::connect(rustBtn, &QPushButton::clicked, [label]() {
static int count = 0;
count++;
int new_result = add_numbers(count * 10, count * 5);
label->setText(QString("Rust计算 %1*10 + %1*5 = %2").arg(count).arg(new_result));
greet("VSCode用户");
});
QObject::connect(quitBtn, &QPushButton::clicked, &app, &QApplication::quit);
window.show();
return app.exec();
}
更新CMakeLists.txt以链接Rust库:
cmake
cmake_minimum_required(VERSION 3.20)
project(QtRustMixed)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
# 设置Rust库路径
set(RUST_LIB "${CMAKE_CURRENT_SOURCE_DIR}/rust_lib/target/release/librust_lib.a")
add_executable(qt_rust_mixed main.cpp)
target_link_libraries(qt_rust_mixed
Qt6::Widgets
Qt6::Gui
Qt6::Core
"${RUST_LIB}"
ws2_32
ntdll
advapi32
userenv
)
# ============================================
# Windows平台:自动部署依赖
# ============================================
if(WIN32)
# 获取MSYS2 UCRT64安装路径
if(DEFINED ENV{MSYSTEM_PREFIX})
set(MSYS2_PREFIX "$ENV{MSYSTEM_PREFIX}")
else()
# 默认路径(适用于标准安装)
set(MSYS2_PREFIX "C:/msys64/ucrt64")
endif()
message(STATUS "MSYS2 prefix: ${MSYS2_PREFIX}")
# 输出目录
set(OUTPUT_DIR "$<TARGET_FILE_DIR:qt_rust_mixed>")
# 函数:安全复制文件(检查文件是否存在)
function(safe_copy_dll target src dest_dir)
if(EXISTS "${src}")
add_custom_command(TARGET ${target} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${src}"
"${dest_dir}"
COMMENT "复制: $(notdir ${src})"
)
message(STATUS "已配置: $(notdir ${src})")
else()
message(WARNING "文件不存在: ${src}")
endif()
endfunction()
# 1. Qt6核心DLL
set(QT6_CORE_DLLS
"${MSYS2_PREFIX}/bin/Qt6Core.dll"
"${MSYS2_PREFIX}/bin/Qt6Gui.dll"
"${MSYS2_PREFIX}/bin/Qt6Widgets.dll"
)
# 2. Qt6图形和字体依赖(必须的)
set(QT6_GRAPHICS_DLLS
"${MSYS2_PREFIX}/bin/libfreetype-6.dll"
"${MSYS2_PREFIX}/bin/libharfbuzz-0.dll"
"${MSYS2_PREFIX}/bin/libb2-1.dll"
"${MSYS2_PREFIX}/bin/libdouble-conversion.dll"
"${MSYS2_PREFIX}/bin/libpcre2-16-0.dll"
"${MSYS2_PREFIX}/bin/libzstd.dll"
"${MSYS2_PREFIX}/bin/zlib1.dll" # 注意:不是libz.dll
)
# 3. ICU国际化支持(可选,但如果Qt编译时包含ICU则需要)
set(ICU_DLLS
"${MSYS2_PREFIX}/bin/libicuin78.dll"
"${MSYS2_PREFIX}/bin/libicuuc78.dll"
"${MSYS2_PREFIX}/bin/libicudt78.dll"
)
# 4. MSYS2运行时
set(MSYS2_RUNTIME_DLLS
"${MSYS2_PREFIX}/bin/libstdc++-6.dll"
"${MSYS2_PREFIX}/bin/libgcc_s_seh-1.dll"
"${MSYS2_PREFIX}/bin/libwinpthread-1.dll"
)
# 复制所有DLL
message(STATUS "配置Windows依赖部署...")
# 创建部署列表
set(ALL_DLLS
${QT6_CORE_DLLS}
${QT6_GRAPHICS_DLLS}
${MSYS2_RUNTIME_DLLS}
)
# 检查并添加ICU DLL(如果存在)
if(EXISTS "${MSYS2_PREFIX}/bin/libicuin78.dll")
list(APPEND ALL_DLLS ${ICU_DLLS})
message(STATUS "包含ICU国际化支持")
else()
message(STATUS "跳过ICU库(未找到)")
endif()
# 复制每个DLL
foreach(DLL ${ALL_DLLS})
safe_copy_dll(qt_rust_mixed "${DLL}" "${OUTPUT_DIR}")
endforeach()
# Rust DLL(如果存在)
set(RUST_DLL "${CMAKE_CURRENT_SOURCE_DIR}/rust_lib/target/release/rust_lib.dll")
if(EXISTS "${RUST_DLL}")
safe_copy_dll(qt_rust_mixed "${RUST_DLL}" "${OUTPUT_DIR}")
else()
message(WARNING "Rust DLL未找到: ${RUST_DLL}")
message(WARNING "请先运行: cd rust_lib && cargo build --release")
endif()
# 平台插件
set(PLATFORM_PLUGIN "${MSYS2_PREFIX}/share/qt6/plugins/platforms/qwindows.dll")
if(EXISTS "${PLATFORM_PLUGIN}")
# 创建platforms目录
add_custom_command(TARGET qt_rust_mixed POST_BUILD
COMMAND ${CMAKE_COMMAND} -E make_directory
"${OUTPUT_DIR}/platforms"
)
# 复制平台插件
safe_copy_dll(qt_rust_mixed
"${PLATFORM_PLUGIN}"
"${OUTPUT_DIR}/platforms/"
)
else()
message(WARNING "Qt平台插件未找到: ${PLATFORM_PLUGIN}")
endif()
# 可选:创建快捷运行脚本
file(GENERATE OUTPUT "${CMAKE_BINARY_DIR}/run_app.bat" CONTENT "@echo off
set PATH=${MSYS2_PREFIX}/bin;%PATH%
$<TARGET_FILE_NAME:qt_rust_mixed>
pause")
message(STATUS "Windows部署配置完成")
endif()
# ============================================
# 清理构建的辅助目标
# ============================================
add_custom_target(clean-all
COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}
COMMENT "完全清理构建目录"
)
重新构建并运行程序,成功实现了Qt界面调用Rust函数的功能。
五、配置代码分析功能
1. 验证代码跳转功能
现在测试VSCode的核心代码分析功能:
- C++代码跳转 :在
main.cpp中,将光标放在QApplication上,按F12,成功跳转到Qt的头文件定义。 - 查找所有引用 :在
main.cpp中,右键点击add_numbers函数,选择"查找所有引用",成功找到所有调用位置。 - 调用层次结构 :右键点击
greet函数,选择"显示调用层次结构",成功显示调用关系图。
2. Rust代码分析
在 rust-lib/src/lib.rs 中:
- 将光标放在
add_numbers函数上,按F12,跳转到定义。 - 使用Shift+F12查找所有对
add_numbers的引用。 rust-analyzer扩展提供了完整的代码补全、类型提示和内联错误检查。
3. 跨语言调用分析
我注意到一个有用的技巧:通过创建虚拟的C++头文件来描述Rust函数的接口,可以改善C++端的代码分析体验。
创建 rust_interface.h:
cpp
// rust_interface.h
#ifndef RUST_INTERFACE_H
#define RUST_INTERFACE_H
#ifdef __cplusplus
extern "C" {
#endif
int add_numbers(int a, int b);
void greet(const char* name);
#ifdef __cplusplus
}
#endif
#endif // RUST_INTERFACE_H
然后在 main.cpp 中包含这个头文件,而不是直接使用 extern "C" 声明。这样C/C++扩展就能更好地理解这些函数。
六、遇到的问题与解决方案
1. 问题:VSCode的C++扩展找不到Qt头文件
现象:在VSCode中打开Qt头文件时出现红色波浪线错误。
解决 :我检查了 c_cpp_properties.json,确保 includePath 正确指向了UCRT64的Qt路径。还需要注意Qt6和Qt5的路径不同。
2. 问题:调试时找不到DLL
现象:程序编译成功,但运行时崩溃,提示缺少DLL。
解决 :在 launch.json 的 environment 部分正确设置PATH,包含UCRT64的bin目录和Qt的bin目录。
3. 问题:rust-analyzer有时不工作
现象:Rust文件没有代码补全和错误提示。
解决:
- 检查VSCode右下角,确保rust-analyzer已激活。
- 在UCRT64终端中运行
cargo check,确保Rust项目本身能编译。 - 重启rust-analyzer:在VSCode中按Ctrl+Shift+P,输入"Rust Analyzer: Restart Server"。
七、环境优化
1. 创建环境检查脚本
我创建了一个 check_env.sh 脚本来自动化环境检查:
bash
#!/bin/bash
echo "=== MSYS2 UCRT64 Qt+Rust 环境检查 ==="
echo ""
echo "1. 检查基本工具:"
command -v g++ && g++ --version | head -1
command -v cmake && cmake --version | head -1
command -v rustc && rustc --version
command -v cargo && cargo --version
echo ""
echo "2. 检查Qt安装:"
find /ucrt64 -name "qmake.exe" 2>/dev/null | head -1
if [ -f "/ucrt64/bin/qmake.exe" ]; then
/ucrt64/bin/qmake.exe --version | head -1
fi
echo ""
echo "3. 检查关键路径是否存在:"
echo "Qt头文件路径:"
ls -d /ucrt64/include/qt* 2>/dev/null
echo ""
echo "Rust工具链:"
rustup toolchain list
echo ""
echo "=== 检查完成 ==="
2. 配置VSCode工作区设置
在 .vscode/settings.json 中,我添加了项目特定设置:
json
{
"cmake.configureSettings": {
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_C_COMPILER": "C:/msys64/ucrt64/bin/gcc.exe",
"CMAKE_CXX_COMPILER": "C:/msys64/ucrt64/bin/g++.exe"
},
"rust-analyzer.checkOnSave.command": "clippy",
"rust-analyzer.cargo.target": "x86_64-pc-windows-gnu",
"C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools",
"files.associations": {
"*.rs": "rust",
"*.cpp": "cpp",
"*.h": "cpp",
"*.hpp": "cpp"
}
}
八、总结
经过一天的配置和测试,我成功在Windows 11上搭建了基于MSYS2 UCRT64环境的Qt+Rust混合开发环境。主要收获:
- UCRT64环境选择正确:与Windows 11的兼容性确实更好,运行时问题更少。
- VSCode配置是关键 :正确配置
c_cpp_properties.json、终端设置和调试环境是成功的前提。 - 混合编程可行:通过C接口,Qt和Rust可以很好地协作,各自发挥优势。
- 代码分析功能完整:两个语言的代码跳转、查找引用、查看调用层次结构功能都工作正常。
这个环境现在完全满足我的开发需求,可以同时享受Qt强大的GUI能力和Rust的内存安全与高性能。
最后更新时间 :2025年12月
环境状态 :稳定可用
下次优化方向:探索更深入的Qt+Rust集成模式,如使用CXX-Qt等高级绑定库。