【C++】LLVM-mingw + VSCode:Windows 开发攻略
LLVM-mingw 是一个基于 LLVM 项目的开源工具链,用于在类 Unix 系统(如 Linux 或 macOS)上为 Windows 平台交叉编译应用程序,它结合了 LLVM 编译器基础设施(包括 Clang C/C++/Objective-C 编译器和 LLD 链接器,用以替代传统的 GNU 编译器 GCC)以及 MinGW-w64 运行时库(提供 Windows 平台的 API 头文件和导入库,支持 32 位和 64 位 Windows 应用程序开发)。
安装与配置 LLVM-mingw
1. 下载 LLVM-mingw
LLVM-mingw 提供了预编译工具链,可在以下地址获取:
推荐下载文件 llvm-mingw-20250826-ucrt-x86_64.zip,并将其解压至:
C:\Development\llvm-mingw 20250826:发布日期,格式为YYYYMMDD,表示版本时间(可选最新)ucrt:使用 Windows Universal C Runtime(UCRT)作为 C 运行时x86_64:架构类型,表示 64 位目标平台
解压后的文件夹结构应类似如下:
LICENSE.TXT arm64ec-w64-mingw32 bin include python x86_64-w64-mingw32 aarch64-w64-mingw32 armv7-w64-mingw32 i686-w64-mingw32 lib share 2. 配置环境变量
检查现有工具
确保系统中未添加旧版 MinGW 或其他 GCC 工具链路径。
在 PowerShell 中执行以下命令,查看是否已安装:
gcc --version clang++--version 如果命令未找到,说明未配置环境变量或尚未安装。
添加到 PATH
将 C:\Development\llvm-mingw\bin 添加到 系统级环境变量 PATH:
setx PATH "$($env:Path);C:\Development\llvm-mingw\bin"/M setx PATH:修改系统 PATH。"$($env:Path);...":保留原有 PATH 内容并追加新路径。/M:设置为系统变量,对所有用户生效。
配置完成后,需重新打开 PowerShell 或 VSCode 终端使其生效。
临时生效(当前会话)
如果仅希望当前 PowerShell 会话立即可用,可以使用:
$env:Path +=";C:\Development\llvm-mingw\bin"这种方式不会永久保存,窗口关闭后失效。
3. 测试编译和运行
创建测试文件
使用 PowerShell 一行命令创建 main.cpp:
echo'#include <iostream>' > main.cpp;echo'int main() { std::cout << "Hello, World!" << std::endl; return 0; }' >> main.cpp编译 C++ 程序
使用 clang++ 编译生成 main.exe:
clang++ main.cpp-o main.exe 运行测试程序
执行生成的程序:
./main.exe 输出结果应为:
Hello, World! 清理测试文件
如果不再需要测试文件,可以删除:
Remove-Item main.cpp, main.exe 可以按照之前的文风,将内容润色、分段和强化说明如下:
安装 VSCode 与插件
1. 下载与安装 VSCode
访问 Visual Studio Code 官网,下载安装最新版本的 VSCode。
安装过程中可保持默认设置即可,安装完成后即可打开编辑器。
2. 安装必要插件
在 VSCode 中按下 Ctrl + Shift + X 打开插件市场,然后搜索并安装以下插件:
- Chinese (Simplified):提供 VSCode 界面汉化,使编辑器更易上手
- CodeLLDB:利用 LLVM 工具链中的
lldb对 C++ 程序进行调试,包括断点、变量查看和堆栈分析 - Clangd:基于 LLVM 工具链中的
clangd提供 C++ 代码智能提示、格式化、高亮、跳转等功能
运行与调试单文件
1. 创建项目文件夹
- 新建一个代码文件夹,例如
demo。 - 使用 VSCode 打开该文件夹,作为工作区。
2. 配置编译任务(tasks.json)
在项目根目录下创建 .vscode\tasks.json 文件,用于定义 Clang++ 编译任务:
{"version":"2.0.0","tasks":[{"type":"shell","label":"Build with Clang++","command":"clang++.exe","args":[// === 调试与优化 ==="-g3",// 最高级调试信息,方便GDB/LLDB"-O0",// 关闭优化,便于调试// === 各类运行时检测 ==="-fsanitize=address",// ASan "-fsanitize=undefined",// UBSan"-fno-omit-frame-pointer",// 保留帧指针,ASan 需要"-fno-optimize-sibling-calls",// 调用栈更清晰// === 启用所有常见警告 ==="-Wall",// 基础警告"-Wextra",// 额外警告"-Wpedantic",// 严格遵循C++标准// === C++ 标准 (可改成 c++17 / c++23) ==="-std=c++17",// === 输出文件 ==="${file}","-o","${fileDirname}\\${fileBasenameNoExtension}.exe"],"group":{"kind":"build","isDefault":true}}]}-g3:生成调试信息-O0:关闭优化,便于调试${file}/${fileDirname}/${fileBasenameNoExtension}:VSCode 内置变量,可支持任意源文件名配置完成后,按Ctrl + Shift + B可以快速编译当前文件
3. 配置调试任务(launch.json)
在 .vscode\launch.json 中配置 CodeLLDB 调试器:
{"version":"0.2.0","configurations":[{"name":"Debug with CodeLLDB","type":"lldb","request":"launch","program":"${workspaceFolder}/${fileBasenameNoExtension}.exe","args":[],"cwd":"${workspaceFolder}","stopOnEntry":false,"preLaunchTask":"Build with Clang++","sourceLanguages":["cpp"],"terminal":"integrated"}]}preLaunchTask:在启动调试前自动执行编译任务${fileBasenameNoExtension}.exe:与源文件同名的可执行文件调试时可直接按 F5 启动
4. 创建测试源文件
在项目根目录下创建 main.cpp(支持任意文件名):
#include<iostream>intmain(){ std::cout <<"Hello, World!"<< std::endl;return0;}5. 编译与调试
- 在 VSCode 中打开
main.cpp。 - 按 F5 启动调试。
- 如果配置正确,调试器会编译源文件并运行程序,输出:
Hello, World! 至此,你已经完成了单文件的编译与调试环境配置。
可在此基础上,逐步扩展为多文件或 CMake 项目。
可以将你的章节内容润色、补充说明,并给出一个推荐的 .clang-format 配置示例:
代码格式化
1. 快捷格式化
安装 Clangd 后,你可以:
- 按
Ctrl + Alt + F或右键选择 “Format Document” 进行手动格式化 - 打开 设置(
Ctrl + ,),搜索 Format On Save 并勾选- 这样每次保存文件时,VSCode 会自动格式化代码
使用 Format On Save 可以保证代码风格统一,减少格式相关的提交差异。
2. 配置 .clang-format
Clangd 的格式化规则可通过项目根目录下的 .clang-format 文件进行定制。
下面给出一个适用于现代 C++ 项目的推荐配置:
# 语言: None, Cpp, Java, JavaScript, ObjC, Proto, TableGen, TextProtoLanguage: Cpp # BasedOnStyle: LLVM# 访问说明符(public、private等)的偏移AccessModifierOffset:-4# 开括号(开圆括号、开尖括号、开方括号)后的对齐: Align, DontAlign, AlwaysBreak(总是在开括号后换行)AlignAfterOpenBracket: Align # 连续赋值时,对齐所有等号AlignConsecutiveAssignments:false# 连续声明时,对齐所有声明的变量名AlignConsecutiveDeclarations:false# 右对齐逃脱换行(使用反斜杠换行)的反斜杠AlignEscapedNewlines: Right # 水平对齐二元和三元表达式的操作数AlignOperands:true# 对齐连续的尾随的注释AlignTrailingComments:true# 不允许函数声明的所有参数在放在下一行AllowAllParametersOfDeclarationOnNextLine:false# 不允许短的块放在同一行AllowShortBlocksOnASingleLine:true# 允许短的case标签放在同一行AllowShortCaseLabelsOnASingleLine:true# 允许短的函数放在同一行: None, InlineOnly(定义在类中), Empty(空函数), Inline(定义在类中,空函数), AllAllowShortFunctionsOnASingleLine: None # 允许短的if语句保持在同一行AllowShortIfStatementsOnASingleLine:true# 允许短的循环保持在同一行AllowShortLoopsOnASingleLine:true# 总是在返回类型后换行: None, All, TopLevel(顶级函数,不包括在类中的函数), # AllDefinitions(所有的定义,不包括声明), TopLevelDefinitions(所有的顶级函数的定义)AlwaysBreakAfterReturnType: None # 总是在多行string字面量前换行AlwaysBreakBeforeMultilineStrings:false# 总是在template声明后换行AlwaysBreakTemplateDeclarations:true# false表示函数实参要么都在同一行,要么都各自一行BinPackArguments:true# false表示所有形参要么都在同一行,要么都各自一行BinPackParameters:true# 大括号换行,只有当BreakBeforeBraces设置为Custom时才有效BraceWrapping:# class定义后面AfterClass:false# 控制语句后面AfterControlStatement:false# enum定义后面AfterEnum:false# 函数定义后面AfterFunction:false# 命名空间定义后面AfterNamespace:false# struct定义后面AfterStruct:false# union定义后面AfterUnion:false# extern之后AfterExternBlock:false# catch之前BeforeCatch:false# else之前BeforeElse:false# 缩进大括号IndentBraces:false# 分离空函数SplitEmptyFunction:false# 分离空语句SplitEmptyRecord:false# 分离空命名空间SplitEmptyNamespace:false# 在二元运算符前换行: None(在操作符后换行), NonAssignment(在非赋值的操作符前换行), All(在操作符前换行)BreakBeforeBinaryOperators: NonAssignment # 在大括号前换行: Attach(始终将大括号附加到周围的上下文), Linux(除函数、命名空间和类定义,与Attach类似), # Mozilla(除枚举、函数、记录定义,与Attach类似), Stroustrup(除函数定义、catch、else,与Attach类似), # Allman(总是在大括号前换行), GNU(总是在大括号前换行,并对于控制语句的大括号增加额外的缩进), WebKit(在函数前换行), Custom# 注:这里认为语句块也属于函数BreakBeforeBraces: Custom # 在三元运算符前换行BreakBeforeTernaryOperators:false# 在构造函数的初始化列表的冒号后换行BreakConstructorInitializers: AfterColon #BreakInheritanceList: AfterColonBreakStringLiterals:false# 每行字符的限制,0表示没有限制ColumnLimit:0CompactNamespaces:true# 构造函数的初始化列表要么都在同一行,要么都各自一行ConstructorInitializerAllOnOneLineOrOnePerLine:false# 构造函数的初始化列表的缩进宽度ConstructorInitializerIndentWidth:4# 延续的行的缩进宽度ContinuationIndentWidth:4# 去除C++11的列表初始化的大括号{后和}前的空格Cpp11BracedListStyle:true# 继承最常用的指针和引用的对齐方式DerivePointerAlignment:false# 固定命名空间注释FixNamespaceComments:true# 缩进case标签IndentCaseLabels:falseIndentPPDirectives: None # 缩进宽度IndentWidth:4# 函数返回类型换行时,缩进函数声明或函数定义的函数名IndentWrappedFunctionNames:false# 保留在块开始处的空行KeepEmptyLinesAtTheStartOfBlocks:false# 连续空行的最大数量MaxEmptyLinesToKeep:1# 命名空间的缩进: None, Inner(缩进嵌套的命名空间中的内容), AllNamespaceIndentation: None # 指针和引用的对齐: Left, Right, MiddlePointerAlignment: Right # 允许重新排版注释ReflowComments:true# 允许排序#includeSortIncludes:false# 允许排序 using 声明SortUsingDeclarations:false# 在C风格类型转换后添加空格SpaceAfterCStyleCast:false# 在Template 关键字后面添加空格SpaceAfterTemplateKeyword:true# 在赋值运算符之前添加空格SpaceBeforeAssignmentOperators:true# SpaceBeforeCpp11BracedList: true# SpaceBeforeCtorInitializerColon: true# SpaceBeforeInheritanceColon: true# 开圆括号之前添加一个空格: Never, ControlStatements, AlwaysSpaceBeforeParens: ControlStatements # SpaceBeforeRangeBasedForLoopColon: true# 在空的圆括号中添加空格SpaceInEmptyParentheses:false# 在尾随的评论前添加的空格数(只适用于//)SpacesBeforeTrailingComments:1# 在尖括号的<后和>前添加空格SpacesInAngles:false# 在C风格类型转换的括号中添加空格SpacesInCStyleCastParentheses:false# 在容器(ObjC和JavaScript的数组和字典等)字面量中添加空格SpacesInContainerLiterals:true# 在圆括号的(后和)前添加空格SpacesInParentheses:false# 在方括号的[后和]前添加空格,lamda表达式和未指明大小的数组的声明不受影响SpacesInSquareBrackets:false# 标准: Cpp03, Cpp11, AutoStandard: Auto # tab宽度TabWidth:4# 使用tab字符: Never, ForIndentation, ForContinuationAndIndentation, AlwaysUseTab: Never 新建万能头文件(可选)
虽然 LLVM-mingw 基于 MinGW,但它只包含标准 C++ 内容,而不包括 GCC 的扩展特性。bits/stdc++.h 是 GCC 中的一个特有头文件,它并不是 C++ 标准库的一部分,因此在 LLVM-mingw 中默认并不可用。如果你希望在 LLVM-mingw 中使用该头文件,可以手动创建一个 bits/stdc++.h 并将其放置到工具链的 include 目录中。以下是详细的操作方法:
1. 创建 stdc++.h
在任意临时目录下新建文件 stdc++.h,内容可以如下(覆盖常用 C++ 标准库):
#ifndef_GLIBCXX_NO_ASSERT#include<cassert>#endif#include<cctype>#include<cfloat>#include<climits>#include<csetjmp>#include<cstdarg>#include<cstddef>#include<cstdlib>#if__cplusplus >=201103L#include<cstdint>#if__cplusplus <201703L#include<ciso646>#endif#endif// C++// #include <bitset>// #include <complex>#include<algorithm>#include<bitset>#include<functional>#include<iterator>#include<limits>#include<memory>#include<new>#include<numeric>#include<typeinfo>#include<utility>#if__cplusplus >=201103L#include<array>#include<atomic>#include<initializer_list>#include<ratio>#include<scoped_allocator>#include<tuple>#include<typeindex>#include<type_traits>#endif#if__cplusplus >=201402L#endif#if__cplusplus >=201703L#include<any>// #include <execution>#include<optional>#include<variant>#include<string_view>#endif#if__cplusplus >=202002L#include<bit>#include<compare>#include<concepts>#include<numbers>#include<ranges>#include<span>#include<source_location>#include<version>#if__cpp_impl_coroutine#include<coroutine>#endif#endif#if__cplusplus >202002L#include<expected>#include<stdatomic.h>#endif#if_GLIBCXX_HOSTED// C#ifndef_GLIBCXX_NO_ASSERT#include<cassert>#endif#include<cctype>#include<cerrno>#include<cfloat>#include<climits>#include<clocale>#include<cmath>#include<csetjmp>#include<csignal>#include<cstdarg>#include<cstddef>#include<cstdio>#include<cstdlib>#include<cstring>#include<ctime>#include<cwchar>#include<cwctype>#if__cplusplus >=201103L#include<cfenv>#include<cinttypes>#include<cstdint>#include<cuchar>#if__cplusplus <201703L#include<ccomplex>#include<cstdalign>#include<cstdbool>#include<ctgmath>#endif#endif// C++#include<complex>#include<deque>#include<exception>#include<fstream>#include<functional>#include<iomanip>#include<ios>#include<iosfwd>#include<iostream>#include<istream>#include<iterator>#include<limits>#include<list>#include<locale>#include<map>#include<memory>#include<new>#include<numeric>#include<ostream>#include<queue>#include<set>#include<sstream>#include<stack>#include<stdexcept>#include<streambuf>#include<string>#include<typeinfo>#include<utility>#include<valarray>#include<vector>#if__cplusplus >=201103L#include<array>#include<atomic>#include<chrono>#include<codecvt>#include<condition_variable>#include<forward_list>#include<future>#include<initializer_list>#include<mutex>#include<random>#include<ratio>#include<regex>#include<scoped_allocator>#include<system_error>#include<thread>#include<tuple>#include<typeindex>#include<type_traits>#include<unordered_map>#include<unordered_set>#endif#if__cplusplus >=201402L#include<shared_mutex>#endif#if__cplusplus >=201703L#include<any>#include<charconv>// #include <execution>#include<filesystem>#include<optional>#include<memory_resource>#include<variant>#endif#if__cplusplus >=202002L#include<barrier>#include<bit>#include<compare>#include<concepts>#include<format>#include<latch>#include<numbers>#include<ranges>#include<span>#include<stop_token>#include<semaphore>#include<source_location>#include<syncstream>#include<version>#endif#if__cplusplus >202002L#include<expected>#include<flat_map>#include<flat_set>#include<generator>#include<print>#include<spanstream>#include<stacktrace>#include<stdatomic.h>#include<stdfloat>#endif#if__cplusplus >202302L#include<text_encoding>#include<stdbit.h>#include<stdckdint.h>#endif#endif// HOSTED注:可以根据需要裁剪头文件,只包含项目会用到的内容。
2. 放置到系统 include 路径
LLVM-mingw 的 include 路径通常在:
C:\Development\llvm-mingw\include\c++\v1\ 你可以创建 bits 文件夹:
C:\Development\llvm-mingw\include\c++\v1\bits\ 然后将 stdc++.h 放入该目录:
C:\Development\llvm-mingw\include\c++\v1\bits\stdc++.h 这样在你的代码中就可以:
#include<bits/stdc++.h>总结
通过本教程,我们成功搭建了一个基于 LLVM-mingw 和 VSCode 的 Windows C++ 开发环境。使用 LLVM-mingw 工具链,不仅能享受 LLVM 编译器提供的高效优化和现代 C++ 支持,还能通过 MinGW-w64 提供的 Windows API 和运行时库实现无缝的 Windows 平台开发。
与传统的 Windows 开发工具链相比,LLVM-mingw 在跨平台开发、性能和编译速度上具有优势,同时结合 VSCode 的智能编辑功能和强大的插件支持,开发者可以在 Windows 平台上以更简洁、便捷的方式进行 C++ 开发。
整个开发流程涵盖了从环境配置、编译、调试到代码格式化等各个方面,确保了高效的开发和调试体验。通过配置 tasks.json 和 launch.json,VSCode 能够自动化编译、调试任务,使得开发流程更加顺畅。此外,借助 Clangd 插件的代码智能提示、格式化功能,能够提高代码的可维护性和团队协作的效率。
总体来说,使用 LLVM-mingw 和 VSCode 可以帮助开发者在 Windows 平台上获得更加现代化、高效的 C++ 开发体验,尤其适合那些希望避免 Visual Studio 或 Cygwin 等重量级工具的开发者。