【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 提供了预编译工具链,可在以下地址获取:
- MinGW-w64 官网下载
- LLVM-mingw GitHub Releases
推荐下载文件 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","-O0","${file}","-o","${fileDirname}\\${fileBasenameNoExtension}.exe"],"options": {"cwd": "${fileDirname}"},"group": {"kind": "build","isDefault": true},"detail": "Compiler: Clang++ from LLVM-mingw"}]
}
-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>int main() {std::cout << "Hello, World!" << std::endl;return 0;
}
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, TextProto
Language: 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(定义在类中,空函数), All
AllowShortFunctionsOnASingleLine: 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(缩进嵌套的命名空间中的内容), All
NamespaceIndentation: None# 指针和引用的对齐: Left, Right, Middle
PointerAlignment: Right# 允许重新排版注释
ReflowComments: true# 允许排序#include
SortIncludes: false# 允许排序 using 声明
SortUsingDeclarations: false# 在C风格类型转换后添加空格
SpaceAfterCStyleCast: false# 在Template 关键字后面添加空格
SpaceAfterTemplateKeyword: true# 在赋值运算符之前添加空格
SpaceBeforeAssignmentOperators: true# SpaceBeforeCpp11BracedList: true# SpaceBeforeCtorInitializerColon: true# SpaceBeforeInheritanceColon: true# 开圆括号之前添加一个空格: Never, ControlStatements, Always
SpaceBeforeParens: ControlStatements# SpaceBeforeRangeBasedForLoopColon: true# 在空的圆括号中添加空格
SpaceInEmptyParentheses: false# 在尾随的评论前添加的空格数(只适用于//)
SpacesBeforeTrailingComments: 1# 在尖括号的<后和>前添加空格
SpacesInAngles: false# 在C风格类型转换的括号中添加空格
SpacesInCStyleCastParentheses: false# 在容器(ObjC和JavaScript的数组和字典等)字面量中添加空格
SpacesInContainerLiterals: true# 在圆括号的(后和)前添加空格
SpacesInParentheses: false# 在方括号的[后和]前添加空格,lamda表达式和未指明大小的数组的声明不受影响
SpacesInSquareBrackets: false# 标准: Cpp03, Cpp11, Auto
Standard: Auto# tab宽度
TabWidth: 4# 使用tab字符: Never, ForIndentation, ForContinuationAndIndentation, Always
UseTab: 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 等重量级工具的开发者。