Linux在VSCode中使用Clang、CMake编译与调试的简单配置
一、环境准备
以下以ubuntu 24.04LTS为例,会遵从默认配置,尽可能简单。
其他需求例如:使用libc++而不是libstdc++;更改编译输出的目录;clangd配置等会放在最后。
1.1 CMake安装
sudo apt install cmake
1.2 clang安装
sudo apt install clang
1.3 可选部分
clangd为代码编辑提供智能补全、代码导航和错误检查等功能
clang-tidy可以在编写代码时实时提供静态分析检查和代码改进建议
clang-format代码格式化和风格调整
sudo apt install clangd
sudo apt install clang-tidy
sudo apt install clang-format
二、此阶段所需的VSCode扩展安装
| 名称 | 扩展ID | 备注 |
|---|---|---|
| C/C++ Extension Pack | ms-vscode.cpptools-extension-pack | 用于后续CMake调试代码 |
| CMake Tools | ms-vscode.cmake-tools | CMake插件 |
三、从单文件开始
3.1 目录结构
project/
├── src/
│ └── main.cpp
├── CMakeLists.txt # CMake 主配置文件
└── CMakePresets.json # CMake 预设文件
3.2 main.cpp
#include
int main() {
std::cout << "hello world
";
return 0;
}
3.3 CMakeLists.txt
# CMake的最低版本要求
cmake_minimum_required(VERSION 3.10)
# 项目名字,这里用的是CMakeDemo
project(CMakeDemo)
# 指定C和C++使用 Clang 编译器
set(CMAKE_C_COMPILER clang)
set(CMAKE_CXX_COMPILER clang++)
# 第一个参数是可执行文件的名称,后面的参数是源文件路径
add_executable(main src/main.cpp)
3.4 CMakePresets.json
CMake的预设文件,指定编译器路径、生成路径、测试路径等
下面给出三个预设:配置预设configurePresets、构建预设buildPresets和测试预设testPresets。其中指定后两个直接使用配置预设。
⚠️ 注意:检查下面的路径/usr/bin/clang、/usr/bin/clang++是否存在
{
"version": 8,
"configurePresets": [
{
"name": "clang",
"displayName": "Clang 18.1.3 x86_64-pc-linux-gnu",
"description": "正在使用编译器: C = /usr/bin/clang, CXX = /usr/bin/clang++",
"binaryDir": "${sourceDir}/out/build/${presetName}",
"cacheVariables": {
"CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}",
"CMAKE_C_COMPILER": "/usr/bin/clang",
"CMAKE_CXX_COMPILER": "/usr/bin/clang++",
"CMAKE_BUILD_TYPE": "Debug"
}
}
],
"buildPresets": [
{
"name": "clang",
"configurePreset": "clang"
}
],
"testPresets": [
{
"name": "clang",
"configurePreset": "clang"
}
]
}
⚠️ 注意:上面的完成之后要重启VSCode
3.5 启动CMake扩展,运行代码
打开左侧的cmake工具栏,选择配置即可使用CMakePresets.json中的预设

选择配置后,点击底部运行按钮即可运行

设置好断点后可以点击旁边的debug进行调试
四、多个文件编译成一个可执行文件
4.1 源代码
4.1.1 目录结构
project/
├── src/ # 源代码目录
│ ├── qsort.cpp # 快速排序的主程序
│ └── data.cpp # 数据实现
├── include/ # 公共头文件目录
│ └── data.h # 数据头文件(公开接口)
├── CMakeLists.txt
└── CMakePresets.json
提示:这里为了简单,使用了相对路径
../include/data.h引入头文件,绝对路径的写法放在文末
4.1.2 src/qsort.cpp 快速排序
// 快速排序
#include
#include "../include/data.h"
void qsort(int* begin, int* end);
int main() {
// 快速排序算法实现
const int len = sizeof(numbers) / sizeof(numbers[0]);
qsort(numbers, numbers + len - 1);
printNumbers();
return 0;
}
void qsort(int* begin, int* end) {
if (begin >= end) return;
int pivot = *begin; // 选择基准值
int* left = begin;
int* right = end;
while (left < right) {
while (left < right && *right >= pivot)
right--; // 从右向左找小于 pivot 的值
while (left < right && *left <= pivot)
left++; // 从左向右找大于 pivot 的值
if (left < right) {
std::swap(*left, *right);
}
}
std::swap(*begin, *left); // 将基准值放到正确位置
qsort(begin, left - 1); // 递归处理左区间
qsort(left + 1, end); // 递归处理右区间
}
4.1.3 src/data.cpp 数据实现以及打印
#include "../include/data.h"
#include
// 定义数组并存储随机数字
int numbers[100] = {59, 16, 15, 82, 63, 28, 4, 32, 83, 85, 24, 57, 76, 70, 17,
91, 6, 66, 33, 42, 75, 88, 58, 18, 34, 54, 74, 68, 48, 60,
44, 53, 79, 73, 90, 8, 41, 71, 11, 19, 55, 84, 87, 92, 67,
14, 31, 29, 89, 72, 56, 22, 81, 2, 62, 1, 64, 30, 13, 27,
37, 12, 43, 99, 38, 3, 5, 25, 9, 20, 50, 26, 23, 21, 35,
36, 98, 40, 93, 96, 47, 46, 10, 51, 80, 52, 39, 69, 97, 77,
7, 100, 94, 49, 78, 95, 86, 61, 65, 45};
void printNumbers(){
// 输出数组
std::cout << "数组中的数字:
";
for (int i = 0; i < 100; ++i) {
std::cout << numbers[i] << " ";
}
std::cout << std::endl;
}
4.1.4 include/data.h 数据头文件
#pragma once
extern int numbers[100];
void printNumbers();
4.1.5 CMakeLists.txt
具体不同为
add_executable(qsort src/qsort.cpp src/data.cpp)
# CMake的最低版本要求
cmake_minimum_required(VERSION 3.10)
# 项目名字,这里用的是CMakeDemo
project(CMakeDemo)
# 指定C和C++使用 Clang 编译器
set(CMAKE_C_COMPILER clang)
set(CMAKE_CXX_COMPILER clang++)
# 第一个参数是可执行文件的名称,后面的参数是源文件路径
add_executable(qsort src/qsort.cpp src/data.cpp)
4.1.6 其他文件
CMakePresets.json与3.3的相同
4.2 不同点
具体不同
add_executable(qsort src/qsort.cpp src/data.cpp),除了名称不同外,还要加上src/data.cpp
⚠️ 警告:add_executable(qsort src/qsort.cpp src/data.cpp)中的两个源代码文件有且只能有一个main函数
五、多个文件编译成多个可执行文件
5.1 源代码
5.1.1 目录结构
project/
├── src/ # 源代码目录
│ ├── qsort.cpp # 快速排序的主程序
│ ├── bubble_sort.cpp # 冒泡排序的主程序
│ └── data.cpp # 数据实现
├── include/ # 公共头文件目录
│ └── data.h # 数据头文件(公开接口)
├── CMakeLists.txt
└── CMakePresets.json
5.1.2 src/bubble_sort.cpp 冒泡排序
// 冒泡排序
#include "../include/data.h"
int main() {
const int len = sizeof(numbers) / sizeof(numbers[0]);
for (int i = len-1; i > 0; i--) {
bool isSwapped = false;
for (int j = 0 ; j < i; ++j) {
if (numbers[j+1] < numbers [j]) {
int temp = numbers[j];
numbers[j] = numbers[j+1];
numbers[j+1] = temp;
isSwapped = true;
}
}
if (!isSwapped) break;
}
printNumbers();
}
5.1.3 CMakeLists.txt
# CMake的最低版本要求
cmake_minimum_required(VERSION 3.10)
# 项目名字,这里用的是CMakeDemo
project(CMakeDemo)
# 指定C和C++使用 Clang 编译器
set(CMAKE_C_COMPILER clang)
set(CMAKE_CXX_COMPILER clang++)
# 第一个参数是可执行文件的名称,后面的参数是源文件路径
add_executable(qsort src/qsort.cpp src/data.cpp)
add_executable(bubble_sort src/bubble_sort.cpp src/data.cpp)
5.2 如何执行
如果依照4的步骤会依旧执行快速排序的代码,而不是冒泡排序。
想要更改可以在CMake插件面板的调试或者启动下修改需要执行的目标,接下来与3.5相同
六、自定义配置
6.1 使用Clangd插件
⚠️ 警告:确保已经安装了clangd,clangd扩展会提示关闭c/c++扩展的智能提示
下面的配置文件都放在根目录
6.1.1 clang-tidy 文件检查 (可选)
---
Checks: >
clang-analyzer-*,
bugprone-*,
readability-*,
-readability-identifier-length,
performance-*,
cppcoreguidelines-*
HeaderFilterRegex: '*'
FormatStyle: file
6.1.2 .clangd
这个用途放在具体情况进行说明,例如6.2.5
6.1.3 .clang-format
用于格式化,具体含义省略。写错了配置会导致配置文件不可用
BasedOnStyle: Google
IndentWidth: 4
AllowShortFunctionsOnASingleLine: All
BreakBeforeBraces: Attach
SpaceBeforeParens: ControlStatements
AlignArrayOfStructures: Left
6.2 使用libc++而不是libstdc++
6.2.1 安装库文件
如果你安装clang时没有指定clang的版本,安装的是发行版默认的版本,例如ubuntu 24.04默认clang版本是18
那么可以不指定版本
sudo apt install libc++-dev libc++abi-dev
如果指定了版本,首先要确认clang的版本
⚠️ 警告:指定版本的可能不是clang++而是clang++-20之类
clang++ --version
如果clang++的版本是20
sudo apt install libc++-20-dev libc++abi-20-dev
可能需要处理clang-20名称与默认clang不同的问题
6.2.2 修改CMakeLists.txt
添加set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
# CMake的最低版本要求
cmake_minimum_required(VERSION 3.10)
# 项目名字,这里用的是CMakeDemo
project(CMakeDemo)
# 指定C和C++使用 Clang 编译器
set(CMAKE_C_COMPILER clang)
set(CMAKE_CXX_COMPILER clang++)
# 使用 libc++
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
# 第一个参数是可执行文件的名称,后面的参数是源文件路径
add_executable(qsort src/qsort.cpp src/data.cpp)
add_executable(bubble_sort src/bubble_sort.cpp src/data.cpp)
6.2.3 检测的方法
简单的检测文件
如果放到了根目录,并且文件名是detect.cpp,那么需要在CMakeLists.txt加上add_executable(detect detect.cpp)
#include
#include
#include
// 检测C++标准库类型
const char* detect_cpp_stdlib() {
#if defined(_LIBCPP_VERSION)
static char version[100];
// libc++版本格式:主版本.次版本.补丁
snprintf(version, sizeof(version), "libc++ %d.%d.%d",
_LIBCPP_VERSION / 10000,
(_LIBCPP_VERSION / 100) % 100,
_LIBCPP_VERSION % 100);
return version;
#elif defined(__GLIBCXX__)
return "libstdc++ (GNU)";
#elif defined(_CPPLIB_VER)
static char version[50];
// MSVC STL版本
snprintf(version, sizeof(version), "MSVC STL (version: %d)", _CPPLIB_VER);
return version;
#elif defined(__MSL_CPP__)
return "Metrowerks Standard Library";
#elif defined(_YVALS)
return "Dinkumware Standard Library";
#else
return "Unknown C++ Standard Library";
#endif
}
// 检测编译器类型
const char* detect_compiler() {
#if defined(__clang__)
static char info[100];
snprintf(info, sizeof(info), "Clang %d.%d.%d",
__clang_major__, __clang_minor__, __clang_patchlevel__);
return info;
#elif defined(__INTEL_COMPILER)
static char info[50];
snprintf(info, sizeof(info), "Intel ICC %d", __INTEL_COMPILER);
return info;
#elif defined(__GNUC__)
static char info[100];
snprintf(info, sizeof(info), "GCC %d.%d.%d",
__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__);
return info;
#elif defined(_MSC_VER)
static char info[50];
// 将_MSC_VER转换为Visual Studio版本
int msc_ver = _MSC_VER;
const char* vs_version = "Unknown";
if (msc_ver >= 1930) vs_version = "VS 2022";
else if (msc_ver >= 1920) vs_version = "VS 2019";
else if (msc_ver >= 1910) vs_version = "VS 2017";
else if (msc_ver >= 1900) vs_version = "VS 2015";
snprintf(info, sizeof(info), "MSVC %d (%s)", msc_ver, vs_version);
return info;
#else
return "Unknown Compiler";
#endif
}
// 获取详细的版本信息
void print_detailed_info() {
printf("=== C++ Runtime and Compiler Detection ===
");
printf("1. Compiler Information:
");
printf(" - Compiler: %s
", detect_compiler());
#if defined(__cplusplus)
printf(" - C++ Standard: ");
if (__cplusplus == 202002L) printf("C++20");
else if (__cplusplus == 201703L) printf("C++17");
else if (__cplusplus == 201402L) printf("C++14");
else if (__cplusplus == 201103L) printf("C++11");
else if (__cplusplus == 199711L) printf("C++98");
else printf("Unknown (__cplusplus = %ld)", __cplusplus);
printf("
");
#endif
printf("
2. C++ Standard Library:
");
printf(" - Library: %s
", detect_cpp_stdlib());
#if defined(__GLIBCXX__)
printf(" - GLIBCXX date: %d
", __GLIBCXX__);
#endif
#if defined(_LIBCPP_VERSION)
printf(" - Full version code: %d
", _LIBCPP_VERSION);
#endif
printf("
3. Platform Information:
");
#if defined(__linux__)
printf(" - Platform: Linux
");
#elif defined(_WIN32)
printf(" - Platform: Windows
");
#elif defined(__APPLE__)
printf(" - Platform: macOS
");
#elif defined(__unix__)
printf(" - Platform: Unix
");
#endif
#if defined(__x86_64__) || defined(_M_X64)
printf(" - Architecture: x86_64
");
#elif defined(__i386__) || defined(_M_IX86)
printf(" - Architecture: x86
");
#elif defined(__aarch64__)
printf(" - Architecture: ARM64
");
#elif defined(__arm__)
printf(" - Architecture: ARM
");
#endif
printf("
4. Feature Detection:
");
// 检查C++11特性可用性
#ifdef __cpp_threadsafe_static_init
printf(" - Thread-safe static init: C++11
");
#endif
#ifdef __cpp_initializer_lists
printf(" - Initializer lists: C++11
");
#endif
#ifdef __cpp_range_based_for
printf(" - Range-based for: C++11
");
#endif
printf("
===========================================
");
}
// 快速检测函数
void quick_detect() {
printf("C++ Runtime: ");
if (strstr(detect_cpp_stdlib(), "libc++")) {
printf("✓ libc++ (LLVM/Clang)
");
} else if (strstr(detect_cpp_stdlib(), "libstdc++")) {
printf("✓ libstdc++ (GNU GCC)
");
} else if (strstr(detect_cpp_stdlib(), "MSVC")) {
printf("✓ MSVC STL
");
} else {
printf("? %s
", detect_cpp_stdlib());
}
printf("Compiler: %s
", detect_compiler());
}
int main() {
int choice;
printf("Choose detection mode:
");
printf("1. Quick detection
");
printf("2. Detailed information
");
printf("Your choice (1 or 2): ");
std::cin >> choice;
if (choice == 1) {
quick_detect();
} else {
print_detailed_info();
}
return 0;
}
6.2.4 检测结果示例
Choose detection mode:
1. Quick detection
2. Detailed information
Your choice (1 or 2): 2
=== C++ Runtime and Compiler Detection ===
3. Compiler Information:
- Compiler: Clang 20.1.2
- C++ Standard: C++17
2. C++ Standard Library:
- Library: libc++ 20.1.0
- Full version code: 200100
3. Platform Information:
- Platform: Linux
- Architecture: x86_64
4. Feature Detection:
- Thread-safe static init: C++11
- Initializer lists: C++11
- Range-based for: C++11
6.2.5 Clangd仍然使用的是libstdc++,编辑器导航的源代码也是libstdc++
需要修改.clangd
下面的
out/build/clang来自于CMakePresets.json中的"binaryDir": "${sourceDir}/out/build/${presetName}"
如果CMakePresets.json中configurePresets的presetName不是clang,那么out/build/clang也需要修改
---
# C++配置
If:
PathMatch: .*.(cpp|cxx|cc|hpp|hxx)$
CompileFlags:
CompilationDatabase: out/build/clang
Add:
- -stdlib=libc++
- -std=c++20
如果按照上面配置了
CompilationDatabase: out/build/clang,还需要CMake导出编译命令
在CMakeList.txt加上set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# CMake的最低版本要求
cmake_minimum_required(VERSION 3.10)
# 项目名字,这里用的是CMakeDemo
project(CMakeDemo)
# 指定C和C++使用 Clang 编译器
set(CMAKE_C_COMPILER clang)
set(CMAKE_CXX_COMPILER clang++)
# 使用 libc++
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
# 导出编译命令
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# 第一个参数是可执行文件的名称,后面的参数是源文件路径
add_executable(qsort src/qsort.cpp src/data.cpp)
add_executable(bubble_sort src/bubble_sort.cpp src/data.cpp)
add_executable(detect detect.cpp)











