Windows 上配置 GCC 15 + CMake 4 实现 Rust 与 C/C++ 无缝混合开发

📅 2026/7/27 11:33:58
Windows 上配置 GCC 15 + CMake 4 实现 Rust 与 C/C++ 无缝混合开发
如果你在 Windows 上同时进行 C/C 和 Rust 开发大概率遇到过这样的困境想用最新的 C23 特性却发现 MSVC 支持不全想编译一些依赖 GCC 的 C 库给 Rust 的build.rs用却发现环境变量配得一团糟好不容易找到一个 GCC结果 CMake 又找不到它。这种工具链的割裂感是 Windows 平台 C/C/Rust 混合开发中最消耗心力的“暗伤”。本文要解决的正是这个具体而微的痛点如何在 Windows 上配置一套统一、现代、且能与 Rust 工具链Cargo无缝协作的 GCC 环境。我们的目标不是简单地安装一个 GCC而是构建一个以 GCC 为核心、CMake 为构建系统、并能被 Rust 原生识别和调用的完整工具链。这能让你在 Windows 上获得接近 Linux/macOS 的开发体验尤其是在处理跨语言项目或依赖原生 C/C 库的 Rust 项目时。经过多次尝试和对比目前最稳定、最前沿的解决方案是WinLibs 构建的 GCC 15 CMake 4的组合。这个组合的优势在于GCC 15 的前沿性提供了对 C23、C2x 标准最完整的实验性支持让你能提前体验下一代语言特性。WinLibs 的纯净与完整它提供了包含运行时库、头文件、GDB 等在内的完整 MinGW-w64 发行版开箱即用避免了手动拼凑工具链的麻烦。CMake 4 的现代构建管理新版 CMake 对 Ninja 生成器、预设Presets等现代工作流支持更好能更智能地定位各种工具链。与 Rust 的天然亲和Rust 的cc和cmakecrate 能自动发现并使用系统 PATH 中的 GCC 和 CMake实现 C/C 依赖的自动编译。接下来我将从为什么选这个组合、详细配置步骤、与 Rust 项目的集成实战到常见坑点排查为你完整呈现这套工作流的搭建过程。无论你是想统一团队构建环境还是单纯厌倦了 MSVC 与 MinGW 的切换之苦这篇文章都能提供一条清晰的路径。1. 为什么是 WinLibs 的 GCC 15 和 CMake 4在 Windows 上C/C 编译器主要有 MSVC 和 MinGW-w64GCC两大阵营。对于需要与 Rust 紧密协作的场景GCC 往往是更优选择。MSVC 的局限标准支持滞后虽然稳定但对最新 C 标准的跟进速度通常慢于 GCC/Clang。ABI 兼容性问题MSVC 编译的库与 GCC 编译的库包括 Rust 默认使用的rustc链接的 MinGW 目标ABI 不兼容直接混用会导致链接错误或运行时崩溃。环境依赖重需要安装完整的 Visual Studio 或庞大的 Build Tools不够轻量。MinGW-w64 GCC 的优势标准支持快GCC 是标准推进的积极实践者能让你更快用上新特性。与 Rust 工具链同源Rust 的x86_64-pc-windows-gnu工具链本身就是基于 MinGW-w64 的使用 GCC 可以确保 C 库的 ABI 完全一致。轻量且跨平台工具链本身相对独立配置好环境变量即可更符合 Unix-like 的开发习惯。为什么选择 WinLibs网络上 MinGW-w64 发行版众多如 MSYS2, MinGW-w64 installer。WinLibs 的独特优势在于独立便携提供一个压缩包解压即用无需通过包管理器安装不污染系统。版本丰富且新它及时提供基于最新 GCC 主线版本的构建比如 GCC 15。包含完整工具链除了 GCC还包含 GDB、make、binutils 等甚至可选 Clang/LLVM一站式配齐。为什么需要 CMake 4CMake 是现代 C/C 项目的构建系统事实标准。Rust 的cmakecrate 在编译 C/C 依赖时会调用系统的 CMake。更好的工具链探测CMake 4 对非 MSVC 工具链的探测逻辑更健壮。预设Presets功能可以声明式地定义构建配置简化命令行操作这对自动化脚本和 CI/CD 友好。对 Ninja 的优先支持Ninja 比 GNU Make 构建速度更快CMake 4 对其支持更完善。这个组合的核心价值是用一个最新、最全、最兼容的 GCC 工具链配合一个现代化的构建系统为 Rust 的 C/C 交互铺平道路最终在 Windows 上实现高效、无痛的混合语言开发。2. 环境准备与工具下载在开始之前请确保你的系统是 Windows 10 或 Windows 11并拥有基本的命令行操作权限。2.1 下载 WinLibs GCC 15访问 WinLibs 官方发布页面https://winlibs.com/。找到 “UCRT runtime” 版本的 GCC。UCRTUniversal C Runtime是现代 Windows 10 的系统运行时比旧的 MSVCRT 更推荐。选择包含GCC 15.x.x和Mingw-w64 11.0的版本。例如gcc-15.2.0-mingw-w64ucrt-12.0.0-r1.7z。下载.7z压缩包格式。2.2 下载 CMake 4访问 CMake 官网下载页面https://cmake.org/download/。选择最新稳定版如 4.x.x的 Windowsx86_64安装包.msi或压缩包.zip。为了环境纯净本文推荐使用.zip压缩包cmake-4.x.x-windows-x86_64.zip。2.3 确保 Rust 工具链已安装你需要一个能正常工作的 Rust 环境。如果你还没有安装请前往https://rustup.rs/安装rustup。安装时对于 Windows 平台务必选择x86_64-pc-windows-gnu作为默认工具链这将确保 Rust 编译器使用 MinGW-w64 作为后端与我们将配置的 GCC 完美兼容。# 安装时通过 rustup 选择 rustup default stable-x86_64-pc-windows-gnu # 或者安装后切换 rustup toolchain install stable-x86_64-pc-windows-gnu rustup default stable-x86_64-pc-windows-gnu3. 详细配置步骤解压与系统集成假设你将工具都放在D:\DevTools目录下。请根据你的实际情况调整路径。3.1 安装 WinLibs GCC在D:\DevTools下新建一个文件夹例如mingw64。使用 7-Zip 等工具将下载的 WinLibs.7z压缩包解压到这个mingw64文件夹中。解压后目录结构应类似于D:\DevTools\mingw64\ ├── bin\ # 包含 gcc.exe, g.exe, gdb.exe, mingw32-make.exe ├── include\ # 系统头文件 ├── lib\ # 系统库文件 └── x86_64-w64-mingw32\ # 目标特定文件将D:\DevTools\mingw64\bin添加到系统的PATH环境变量中。右键点击“此电脑” - “属性” - “高级系统设置” - “环境变量”。在“系统变量”或“用户变量”中找到Path点击“编辑”。点击“新建”添加D:\DevTools\mingw64\bin。重要确保这个路径在包含其他编译器如 MSVC的路径之前这样命令行会优先使用我们的 GCC。3.2 安装 CMake在D:\DevTools下新建一个文件夹例如cmake。将下载的 CMake.zip压缩包解压到cmake文件夹中。目录结构应类似于D:\DevTools\cmake\ ├── bin\ # 包含 cmake.exe, ctest.exe, cpack.exe └── ...同样将D:\DevTools\cmake\bin添加到系统的PATH环境变量中。3.3 验证安装打开一个新的命令提示符CMD或PowerShell窗口必须新开以使 PATH 生效执行以下命令# 验证 GCC 版本 gcc --version # 应输出类似gcc (GCC) 15.2.0 ... g --version # 验证 CMake 版本 cmake --version # 应输出类似cmake version 4.x.x # 验证 GNU MakeWinLibs 提供的是 mingw32-make mingw32-make --version # 应输出 GNU Make 版本信息 # 验证 Rust 工具链 rustc --version cargo --version # 并确认目标平台 rustup show # 默认工具链应为 stable-x86_64-pc-windows-gnu如果所有命令都能正确输出版本信息恭喜你基础工具链配置成功。4. 核心配置让 CMake 识别我们的 GCC仅仅把 GCC 加入 PATH 还不够。CMake 在生成构建文件时需要明确知道使用哪个编译器。我们需要告诉 CMake 我们的 GCC 位置特别是当系统存在多个编译器时。4.1 方法一通过环境变量指定推荐设置一个名为CMAKE_C_COMPILER和CMAKE_CXX_COMPILER的环境变量直接指向我们的 GCC。环境变量名CMAKE_C_COMPILER值D:\DevTools\mingw64\bin\gcc.exe环境变量名CMAKE_CXX_COMPILER值D:\DevTools\mingw64\bin\g.exe你可以在系统环境变量中设置它们这样所有 CMake 项目都会自动使用这个编译器。4.2 方法二在 CMake 命令行中指定在运行cmake命令时通过-D选项传递。# 在项目构建目录中 cmake -G MinGW Makefiles ^ -D CMAKE_C_COMPILERD:/DevTools/mingw64/bin/gcc.exe ^ -D CMAKE_CXX_COMPILERD:/DevTools/mingw64/bin/g.exe ^ -D CMAKE_MAKE_PROGRAMD:/DevTools/mingw64/bin/mingw32-make.exe ^ [path/to/your/source]-G MinGW Makefiles指定生成器为 MinGW Makefiles这是配合 MinGW-w64 GCC 使用的。4.3 方法三使用 CMake PresetsCMake 4 推荐这是最现代、最清晰的方式。在你的项目根目录创建一个CMakePresets.json文件。{ version: 8, configurePresets: [ { name: mingw64-default, displayName: MinGW-w64 GCC Default Config, description: 使用 WinLibs GCC 15 进行配置, generator: Ninja, // 或 MinGW Makefiles cacheVariables: { CMAKE_C_COMPILER: D:/DevTools/mingw64/bin/gcc.exe, CMAKE_CXX_COMPILER: D:/DevTools/mingw64/bin/g.exe, CMAKE_MAKE_PROGRAM: D:/DevTools/mingw64/bin/mingw32-make.exe // 如果 generator 是 MinGW Makefiles }, environment: { PATH: D:/DevTools/mingw64/bin;%PATH% }, binaryDir: ${sourceDir}/build/${presetName} } ] }配置完成后只需运行cmake --presetmingw64-defaultCMake 会自动应用所有配置。使用 Ninja 生成器需要额外下载ninja.exe并放入 PATH它比 make 更快。5. 实战在 Rust 项目中调用 C/C 库这是检验我们配置成功与否的关键。我们将创建一个 Rust 项目其中通过build.rs脚本使用我们配置的 GCC 和 CMake 来编译一个简单的 C 库。5.1 创建项目与 C 库创建一个新的 Rust 库项目cargo new rust_calls_cpp --lib cd rust_calls_cpp在项目根目录创建cpp_src文件夹并添加一个简单的 C 类文件cpp_src/mylib.cpp// 使用一些简单的 C 特性 #include string #include vector #include iostream extern C { // 使用 C 链接规范便于 Rust 调用 int add_numbers(int a, int b) { return a b; } const char* greet(const char* name) { // 注意这里返回的指针在 Rust 中需要妥善管理生命周期 // 实际项目中应使用更安全的方式如返回结构体、由 Rust 分配缓冲区等 static std::string greeting Hello, ; greeting Hello, ; greeting name; greeting !; return greeting.c_str(); } // 演示 C 标准库的使用GCC 15 能良好支持 void print_vector() { std::vectorint vec {1, 2, 3, 4, 5}; for (auto v : vec) { // C11 范围 for 循环 std::cout v ; } std::cout std::endl; } }文件cpp_src/mylib.h#ifndef MYLIB_H #define MYLIB_H #ifdef __cplusplus extern C { #endif int add_numbers(int a, int b); const char* greet(const char* name); void print_vector(); #ifdef __cplusplus } #endif #endif // MYLIB_H5.2 编写build.rs脚本build.rs是 Cargo 在编译 Rust 代码前执行的构建脚本。我们将在这里调用 CMake。文件build.rs(放在项目根目录与Cargo.toml同级)use std::env; use std::path::PathBuf; use cmake::Config; fn main() { // 告诉 Cargo 如果 cpp_src 下的文件变化了要重新运行 build.rs println!(cargo:rerun-if-changedcpp_src/); // 使用 cmake crate 来构建 C 库 let dst Config::new(cpp_src) .profile(Release) // 或 Debug .define(CMAKE_BUILD_TYPE, Release) // 非常重要显式指定我们的工具链。 // 这里假设你已经将 CMAKE_C_COMPILER 等设置为环境变量。 // 如果没有可以在这里通过 .cflag、.cxxflag 传递但更推荐环境变量或 Presets。 .build(); // 告诉 Cargo 链接生成的库。 // 库名是 mylib在 Windows 上会生成 libmylib.a (静态库) 或 mylib.dll (动态库)。 // 这里我们链接静态库。 println!(cargo:rustc-link-searchnative{}, dst.join(lib).display()); println!(cargo:rustc-link-libstaticmylib); // 如果链接动态库则需要将 dll 文件复制到输出目录。 // 这里以静态库为例。 // 对于动态库还需要处理运行时依赖。 }5.3 配置Cargo.toml添加cmake和cc作为构建依赖。cccrate 更轻量适合简单 C 代码cmakecrate 适合已有 CMakeLists.txt 的复杂 C/C 项目。文件Cargo.toml[package] name rust_calls_cpp version 0.1.0 edition 2021 # 构建依赖 [build-dependencies] cmake 0.1 # 用于在 build.rs 中驱动 CMake # cc 1.0 // 如果不用 CMake可以用 cc crate 直接编译单个 C 文件 [dependencies] libc 0.2 # 用于 C 类型转换5.4 创建CMakeLists.txt在cpp_src目录下创建CMakeLists.txt指导 CMake 如何构建我们的库。文件cpp_src/CMakeLists.txtcmake_minimum_required(VERSION 3.15) project(mylib LANGUAGES CXX) # 设置 C 标准 set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) # 不使用编译器特定扩展 # 创建库目标 add_library(mylib STATIC mylib.cpp) # 设置包含目录如果需要公开头文件 target_include_directories(mylib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) # 安装指令可选用于系统级安装 # install(TARGETS mylib ARCHIVE DESTINATION lib) # install(FILES mylib.h DESTINATION include)5.5 编写 Rust 代码调用 C 库文件src/lib.rsuse std::ffi::CStr; use std::os::raw::c_char; // 声明外部 C 函数对应 mylib.h 中的内容 extern C { fn add_numbers(a: i32, b: i32) - i32; fn greet(name: *const c_char) - *const c_char; fn print_vector(); } pub fn rust_add(a: i32, b: i32) - i32 { unsafe { add_numbers(a, b) } } pub fn rust_greet(name: str) - String { let c_name std::ffi::CString::new(name).expect(CString::new failed); let c_greeting: *const c_char unsafe { greet(c_name.as_ptr()) }; // 将 C 字符串转换为 Rust 字符串 let greeting_cstr unsafe { CStr::from_ptr(c_greeting) }; greeting_cstr.to_string_lossy().into_owned() } pub fn rust_print_vector() { unsafe { print_vector() }; } #[cfg(test)] mod tests { use super::*; #[test] fn test_addition() { assert_eq!(rust_add(2, 3), 5); assert_eq!(rust_add(-1, 1), 0); } #[test] fn test_greet() { let greeting rust_greet(CSDN); assert!(greeting.contains(CSDN)); println!(Greeting: {}, greeting); } #[test] fn test_vector() { // 这个函数打印到标准输出我们主要确认它能被调用而不崩溃 rust_print_vector(); } }5.6 构建并运行在项目根目录打开配置好 PATH 的命令行执行cargo buildCargo 会运行build.rs。build.rs中的cmakecrate 会调用系统的 CMake即我们配置的 CMake 4。CMake 会根据CMakeLists.txt和系统环境变量CMAKE_CXX_COMPILER找到我们的 GCC 15编译mylib.cpp生成静态库libmylib.a。Cargo 链接这个静态库并编译 Rust 代码。构建成功后运行测试cargo test你应该能看到测试通过并且test_vector测试会在控制台输出1 2 3 4 5。6. 运行结果与效果验证如果一切顺利你将看到类似以下输出Compiling rust_calls_cpp v0.1.0 (D:\projects\rust_calls_cpp) Finished dev profile [unoptimized debuginfo] target(s) in 5.20s Running target\debug\deps\rust_calls_cpp-xxxxxxx.exe running 3 tests test tests::test_addition ... ok test tests::test_vector ... ok test tests::test_greet ... ok test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out这证明了GCC 15 被成功调用它编译了使用了 C11/17 特性的 C 代码。CMake 4 工作正常它被cmakecrate 调用并正确生成了构建系统。Rust 与 C 链接成功Rust 代码能够无缝调用 GCC 编译生成的静态库函数。整个工具链协同工作从 Rust 的cargo命令开始到 GCC 编译 C再到最终链接成一个可执行测试文件整个流程是自动化的。你可以进一步验证 GCC 的版本和 C 标准支持# 进入 CMake 构建目录build.rs 生成的临时目录通常在 target/build/ 下 # 查看 CMake 缓存确认编译器路径 find . -name CMakeCache.txt -exec grep CMAKE_CXX_COMPILER {} \;7. 常见问题与排查思路在配置过程中你可能会遇到以下问题问题现象可能原因排查方式解决方案gcc --version不生效或报错1. PATH 环境变量未生效。2. 路径添加错误。3. 与其他软件如 Git Bash 自带的 MinGW冲突。1. 新开命令行窗口。2.echo %PATH%检查路径。3.where gcc查看哪个 gcc 被优先找到。1. 重启终端或电脑。2. 修正 PATH。3. 调整 PATH 顺序确保我们的mingw64\bin在最前面。CMake 找不到编译器或使用 MSVC1. 未设置CMAKE_CXX_COMPILER等变量。2. 未指定-G MinGW Makefiles。3. 缓存CMakeCache.txt中记录了旧的编译器路径。1. 检查环境变量或命令行参数。2. 运行cmake -G查看可用生成器。3. 删除build目录重新生成。1. 使用“方法一”设置永久环境变量。2. 显式指定生成器和编译器路径。3. 清理构建目录。Cargo build 失败提示链接错误 (LNKxxxx)1. Rust 工具链是msvc而非gnu。2. C 库与 Rust 链接器不兼容Debug/Release 混用。3. C 函数声明 (extern C) 缺失或错误。1.rustup show确认工具链。2. 检查build.rs中的 profile 和 CMake 的CMAKE_BUILD_TYPE。3. 检查 C 头文件中的extern C和 Rust 中的extern C声明。1. 切换 Rust 工具链rustup default stable-gnu。2. 统一构建配置都使用 Release 或 Debug。3. 确保 C 接口声明正确名称修饰被禁用。undefined reference to ‘xxx’1. 链接库顺序问题。2. 库文件未找到。3. C 函数未以extern C导出。1. 检查cargo:rustc-link-lib顺序依赖库在后。2. 确认cargo:rustc-link-search路径正确。3. 使用nm或objdump工具查看库中的符号。1. 调整链接顺序。2. 打印dst变量确认库文件生成位置。3. 确保 C 实现文件中的函数也包裹在extern C中。CMake 报错关于std::cout或 C 标准库GCC 安装不完整或运行时库缺失。检查mingw64\bin下是否有libstdc-6.dll等文件。确保下载的是完整的 WinLibs UCRT 版本并解压了全部文件。编译速度慢1. 使用了MinGW Makefiles生成器而非Ninja。2. 未启用并行编译。检查 CMake 生成器。1. 安装 Ninja 并将其加入 PATH在 CMake 中使用-G Ninja。2. 对于 Make使用mingw32-make -jN(N 为 CPU 核心数)。8. 最佳实践与工程建议将这套配置用于实际项目时遵循以下建议可以避免很多麻烦工具链版本固化对于团队项目将特定版本的 WinLibs GCC 压缩包和 CMake 压缩包放入版本控制如 Git LFS或内部文件服务器。在项目的README.md或scripts/目录下提供一键配置脚本确保所有开发者环境一致。使用 CMake Presets强烈推荐使用CMakePresets.json。它可以将编译器路径、生成器、构建类型、缓存变量等定义在一个文件中与项目代码一同管理。cmake --preset命令让构建指令变得极其简洁。在build.rs中处理路径不要将绝对路径硬编码在build.rs中。可以通过环境变量如MINGW64_PATH来传递或者在build.rs中实现逻辑来查找工具链。let mingw_path env::var(MINGW64_PATH).unwrap_or_else(|_| rD:\DevTools\mingw64.to_string()); let c_compiler format!({}\\bin\\gcc.exe, mingw_path); // ... 在 Config 中通过 .define 传递区分开发与生产环境在build.rs中可以根据profile决定构建类型Debug/Release。Debug 版本便于调试Release 版本性能更好。let profile env::var(PROFILE).unwrap(); let mut config Config::new(cpp_src); if profile release { config.define(CMAKE_BUILD_TYPE, Release); } else { config.define(CMAKE_BUILD_TYPE, Debug); }处理动态库DLL如果 C 库编译为动态库.dll除了链接还需要在运行时能找到它。可以在build.rs中将.dll文件复制到 Cargo 的输出目录OUT_DIR或target/debug。// 在 .build() 之后 let dll_file dst.join(bin).join(mylib.dll); // 假设 DLL 在 bin 目录 if dll_file.exists() { let out_dir PathBuf::from(env::var(OUT_DIR).unwrap()); // 复制到更合适的目录例如 target/debug let target_dir PathBuf::from(env::var(CARGO_MANIFEST_DIR).unwrap()) .join(target) .join(profile); std::fs::copy(dll_file, target_dir.join(mylib.dll)).unwrap(); }IDE 集成在 VSCode 中安装 “CMake Tools” 扩展。它可以自动读取CMakePresets.json让你在 IDE 内轻松切换和运行配置。对于 CLion 等 JetBrains IDE它们对 CMake 的支持原生且强大直接打开包含CMakeLists.txt的目录即可。通过以上步骤和最佳实践你就在 Windows 上成功搭建了一套以 GCC 15 和 CMake 4 为核心的现代化 C/C/Rust 混合开发环境。这套环境不仅解决了工具链的统一问题还通过 CMake Presets 和 Rust 的build.rs实现了构建流程的自动化与可重复性显著提升了跨语言项目的开发效率和体验。下次当你需要在 Rust 项目中集成一个复杂的 C 库时这套配置将成为你可靠的基石。