Liangbk's blog

Back

linux环境下cmake + clangd + lldb搭建cpp开发环境#

一. 基础环境#

  • wsl2
  • ubuntu22
  • ubuntu24

以上均可(其他没试过,不过理论上都可以)

二. 源配置#

如果要配置多编译器环境或者更想用gcc/g++,这里的源配置主要针对需要下载高等级的gcc版本

由于一些低版本的ubuntu(如22)默认下载gcc11版本,如果想要下载更高的版本,12以及往上,可以使用下面两条命令:

sudo add-apt-repository ppa:ubuntu-toolchain-r/test
sudo add-apt-repository ppa:ubuntu-toolchain-r/ppa
bash

然后可以安装高版本的gcc和g++

apt search gcc-12
# apt search gcc-13
sudo apt install gcc-12
sudo apt install g++-12
bash

不过由于是国外源,下载的会比较慢,需要额外配置镜像(这个镜像不是/etc/apt/sources.list文件)

执行上面两条add-apt-repository命令后,查看/etc/apt/sources.list.d目录:

ll /etc/apt/sources.list.d
bash

如下图所示(一个ppa,一个test):

ppa-jammy.list为例,里面的内容原本是:

deb https://ppa.launchpadcontent.net/ubuntu-toolchain-r/ppa/ubuntu/ jammy main 
# deb-src https://ppa.launchpadcontent.net/ubuntu-toolchain-r/ppa/ubuntu/ jammy main
bash

使用如下命令换为中科大的源(最后两个参数是ppatest两个文件名):

sudo sed -i 's|https://ppa.launchpadcontent.net|https://launchpad.proxy.ustclug.org|g' /etc/apt/sources.list.d/ubuntu-toolchain-r-ubuntu-ppa-jammy.list /etc/apt/sources.list.d/ubuntu-toolchain-r-ubuntu-test-jammy.list
bash

然后执行:

sudo apt update
sudo apt install gcc-12 g++-12
bash

就会快很多了

三. gcc/g++版本切换(可选)#

如果电脑下有多个gcc/g++,想要切换版本,首先查看各个gcc/g++的版本号:

ls -l /usr/bin | grep gcc
bash

如下图:

使用update-alternatives命令设置各个gcc/g++的优先级:

# 13的权值是100, 11是80...
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 100 --slave /usr/bin/g++ g++ /usr/bin/g++-13 --slave /usr/bin/gcov gcov /usr/bin/gcov-13
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-11 80 --slave /usr/bin/g++ g++ /usr/bin/g++-11 --slave /usr/bin/gcov gcov /usr/bin/gcov-11
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 60 --slave /usr/bin/g++ g++ /usr/bin/g++-10 --slave /usr/bin/gcov gcov /usr/bin/gcov-10
bash

设置完毕后再执行gcc -v就能看到当前是gcc-13

如果想要切换版本:

sudo update-alternatives --config gcc
bash

如下图,选择对应版本即可:

四. llvm配置#

国外的网址:apt llvm

找到下图中的脚本命令:

和版本:

(我安装的时候stable版本是20)

但不要执行,同样是由于国外源太慢的问题,这次换清华源:tsinghua apt llvm

LLVM版本选为20(一般选stable版本就对了)

将上面的命令逐行粘贴到终端执行:

sudo wget https://mirrors.tuna.tsinghua.edu.cn/llvm-apt/llvm.sh
sudo chmod +x llvm.sh
sudo ./llvm.sh all -m https://mirrors.tuna.tsinghua.edu.cn/llvm-apt
bash

之后再安装libstdc++,配置gcc/g++使用

sudo apt-get install libc++-20-dev libc++abi-20-dev
bash

这样就安装好了llvm全套(clang/clang++/clangd/lldb)和libc++

五. cmake配置#

不推荐直接从apt下载cmake,版本一般比较旧

一般从源码安装或者作者仓库中拉取,具体参考下面这篇文章:

ubuntu 22.04环境中cmake安装 - 知乎

六. vscode配置#

插件安装列表(自行安装),还有一个Test Explorer UI插件没有截进来:

6.1 clangd#

6.1.1 clangd path#

刚下载完clangd,会弹窗提示没有下载clangd-server,这时候不要点击,直接去clangd设置中:

不是用户的设置而是wsl2或者虚拟机的设置中,找到Clangd: Path选项,之前下载llvm组件时已经下载了clangd-<version><version>是stable的版本号),直接填入到选项中:

6.1.2 .clangd配置系统文件寻找路径#

  1. 使用clang/clang++头文件

    在项目目录下创建.clangd文件,然后填入下面的内容:

    CompileFlags:
      Add:
        - "-stdlib=libc++"  # 主要是这行
        - "-ferror-limit=0"
      Compiler: clang++-20
    yaml
  2. 使用gcc,可以这么写(不需要配置-stdlib,因为linux下默认用libstdc++):

    CompileFlags:
      Add:
        - "-I/usr/include/c++/13" # 
        - "-ferror-limit=0"
      Compiler: g++-13
    yaml

6.2 codelldb#

6.2.1 安装vsix#

下载插件后,可能会报错,弹窗open ... url,点击后在浏览器下载一个.vsix文件

然后在扩展中安装:

6.2.2 调试#

配置好cmake tools之前的cmake项

打断点,按F5调试,一开始会报错,让创建launch.json文件,跟着步骤创建:

{
    // 使用 IntelliSense 了解相关属性。 
    // 悬停以查看现有属性的描述。
    // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type": "lldb",
            "request": "launch",
            "name": "Debug",
            "program": "${workspaceFolder}/<executable file>",
            "args": [],
            "cwd": "${workspaceFolder}"
        }
    ]
}
json

"program"项换为可执行文件的位置,就可以正常调试了

6.3 cmake#

6.3.1 cmake path#

在CMake插件中的设置中,找到Cmake: Cmake Path选项,设置为cmake的可执行文件路径:

6.3.2 cmake快速创建项目#

  • 创建一个文件夹,然后使用vscode打开
  • Ctrl + Shift + P唤出命令面板
  • 输入cmake:quick,找到CMake: Quick Start
  • 按提示步骤完成剩余操作

6.3.3 CMAKE_EXPORT_COMPILE_COMMANDS#

使用git下载一个cmake项目,比如fmt: git clone https://github.com/fmtlib/fmt.git

如果要使用clang++,则找到项目根目录下的CMakeLists.txt,加入:

# 生成 compile_commands.json
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
cmake

上述命令会在build目录下生成compile_commands.json,clangd会根据这个文件生成索引,存放在项目的.cache目录下,如果没有,可能不会正常工作

至此,clangd应该能够正常工作了

6.3.4 cmake tools#

使用过clion和vs2022都清楚有比较方便的切换启动哪个可执行程序的功能,借助cmake tools插件,可以做到这一点,修改launch.json(主要是"program"项):

{
    // 使用 IntelliSense 了解相关属性。 
    // 悬停以查看现有属性的描述。
    // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type": "lldb",
            "request": "launch",
            "name": "Debug",
            "program": "${command:cmake.launchTargetPath}",
            "args": [],
            "cwd": "${workspaceFolder}"
        }
    ]
}
json

在vscode左侧cmake-tools的图标中,选择启动和调试的目标即可:

6.4 unit-test#

安装C++ TestMateTest Explorer UI后,在左侧测试按钮中可以进行对应的测试:

在编译后也可以在对应的测试文件中直接使用图形化运行按钮进行测试

但是测试文件(指可执行文件)的识别默认为build或者out目录下的带有test名的文件,所以在生成可执行文件时要注意正确的命名:

七. windows下环境配置#

请参考VSCode C/C++开发环境配置 Clang/LLVM+LLDB+CMake

windows上使用lldb和msvc stl只能看到stl组件的地址,看不到内容,建议直接使用cmake-tools自带的cppdbg,或者用lldb配合MinGW使用,个人认为window上还是直接用msvc工具链比较好

八. vcpkg配置#

8.1 下载与环境配置#

下载:

git clone https://github.com/microsoft/vcpkg.git # 克隆仓库
cd vcpkg
./bootstrap-vcpkg.sh # Linux bash
bash

环境配置:

~/.bashrc文件最后添加:

export VCPKG_ROOT=/path/to/vcpkg # vcpkg文件夹的实际路径
export PATH=$VCPKG_ROOT:$PATH
bash

8.2 案例#

  1. 创建vcpkg依赖

    mkdir vcpkg_test && cd vcpkg_test
    vcpkg new --application # 初始化vcpkg项目
    vcpkg add port fmt # 添加 fmt 依赖项
    bash
  2. 创建cmake项目

    Ctrl + Shift + P唤出vscode命令行,使用CMake: Quick Start创建cmake项目

  3. 设置CMakePresets.json

    项目目录创建CMakePresets.json

    {
        "version": 2,
        "configurePresets": [
            {
                "name": "vcpkg",
                "generator": "Ninja",
                "binaryDir": "${sourceDir}/build",
                "cacheVariables": {
                    "CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
                },
            }
        ]
    }
    json

    如有需要可以再创建CMakeUserPresets.json

    {
        "version": 2,
        "configurePresets": [
            {
                "name": "default",
                "inherits": "vcpkg",
                "environment": {
                    "VCPKG_ROOT": "" // 填vcpkg的实际路径
                }
            }
        ]
    }
    json
  4. 此时可以在CMake-Tools提供的配置中选择对应的配置:

  5. CMakeLists.txtmain.cpp

    cmake_minimum_required(VERSION 3.10)
    
    project(Helloworld)
    # 生成 compile_commands.json
    set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
    # 设置链接标志
    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++ -lc++abi")
    find_package(fmt CONFIG REQUIRED) # 指定vcpkg的查找的库
    
    add_executable(Helloworld helloworld.cpp)
    
    target_link_libraries(Helloworld PRIVATE fmt::fmt)
    cmake
    #include <fmt/core.h>
    int main()
    {
        fmt::print("Hello World!\n");
        return 0;
    }
    c
  6. 编译即可

如果要下载到全局可以直接:

vcpkg install fmt

路径在:

xxx/vcpkg/installed/x64-linux

如果要让clangd解析到对应的头文件,需要额外配置.clangd

CompileFlags:
  Add:
    - "-I/usr/include/c++/13" #
    - "-Isystem/xxx/vcpkg/installed/x64-linux/include"
    - "-ferror-limit=0"
  Compiler: g++-13
yaml

8.3 其他配置#

8.3.1 适配clang与libc++#

警告:

如果不是非使用libc++库不可,就不需要下面的内容,直接CMakePresets.json里面指定编译器就好了,反正clang++libstdc++也能一块用

vcpkg安装和主动拉取依赖默认用gcc工具链(如果有的话),编译链接也一样

如果要配clang和libc++,需要修改以下几个配置:

  1. CC,CXX:

    改一下两个环境变量所指的编译器(在~/.bashrc):

    export CC=clang-20
    export CXX=clang++-20
    bash
  2. CMakePresets.json,原先写在CMake中的内容,现在要放在该文件里:

    {
        "version": 2,
        "configurePresets": [
            {
                "name": "vcpkg",
                "generator": "Ninja",
                "binaryDir": "${sourceDir}/build",
                "cacheVariables": {
                    "VCPKG_TARGET_TRIPLET": "x64-linux-clang-libcxx",
                    "CMAKE_BUILD_TYPE": "Debug",
                    "CMAKE_C_COMPILER": "clang-20",
                    "CMAKE_CXX_COMPILER": "clang++-20",
                    "CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
                },
                "environment": {
                    "CC": "clang-20",
                    "CXX": "clang++-20"
                }
            }
        ]
    }
    json
  3. xxx/vcpkg/triplets/community中新建x64-linux-clang-libcxx.cmake

    set(VCPKG_TARGET_ARCHITECTURE x64)
    set(VCPKG_CRT_LINKAGE dynamic)
    set(VCPKG_LIBRARY_LINKAGE static)
    set(VCPKG_CMAKE_SYSTEM_NAME Linux)
    
    # 注意:VCPKG_CXX_FLAGS 是会被传入编译器的变量
    set(VCPKG_C_FLAGS "${VCPKG_C_FLAGS}")
    set(VCPKG_CXX_FLAGS "${VCPKG_CXX_FLAGS} -stdlib=libc++")
    set(VCPKG_LINKER_FLAGS "${VCPKG_LINKER_FLAGS} -stdlib=libc++")
    set(VCPKG_EXE_LINKER_FLAGS "${VCPKG_EXE_LINKER_FLAGS} -stdlib=libc++ -lc++abi")
    
    cmake

    直接用vcpkg install命令默认使用/vcpkg/triplets/x64-linux.cmake文件

  4. 使用vcpkg install fmt:x64-linux-clang-libcxx安装对应的包,同样的CMakeLists.txt指定链接标志,见9.1的解决方案

8.3.2 先找全局再拉依赖#

案例中vcpkg的使用方式属于manifest,属于自动下载依赖到项目中,不会去vcpkg的已经安装的包里找,工作模式类似一般CMake项目中的third_party文件夹,优点是版本能控制,缺点就是每次修改CMakeLists.txt重新载入的时间就比较长

查了一下好像没办法在这种模式下直接的先找全局包,没找到再拉依赖

问了下gemini给出的答案是:

配置二进制缓存

虽然这依然会在项目下生成 vcpkg_installed 目录,但它不会重新编译代码,而是直接从缓存(或全局缓存)中拷贝编译好的二进制文件。这是 vcpkg 官方推荐的复用机制。

  1. 设置环境变量: 在你的系统环境变量中添加(或确保默认已启用):

    Bash

    VCPKG_DEFAULT_BINARY_CACHE=<你的缓存路径>
    # Windows 默认通常在 %LOCALAPPDATA%\vcpkg\archives
    # Linux/Mac 默认通常在 $HOME/.cache/vcpkg/archives
    plaintext
  2. 效果: 当你在全局 vcpkg install xxx 时,编译产物会存入 Cache。 当你在项目中 build 时,vcpkg 发现 vcpkg.json 需要同样的库(且版本、编译器参数一致),它会直接从 Cache 极速解压到 vcpkg_installed,跳过编译过程。

8.4 常用指令#

  • list
  • install
  • remove
  • search
  • update

九. 常见问题#

9.1 llvm标准库头文件内报错#

问题描述#

此问题针对强迫症患者,如果你点进去头文件碰到了下面的情况:

那么在项目下配置.clangd已经没用了

解决方案#

~/目录下新增.config/clangd/config.yaml文件,把.clangd的内容复制过来

这个全局文件的优先级比项目下.clangd要高,所以配置之后项目路径下里面相同的配置会被全局的覆盖掉,所以可以在全局配置配clangd去解析哪个编译器的头文件,然后项目的.clangd配置第三方库的头文件。至于为什么内容头文件会爆这么多错,搜了一堆也没找到答案,所以该方法就凑活用吧

9.2 codelldb调试无法正常显示STL内容#

问题描述#

比如源码为:

struct node {
    unordered_map<int, int> map;
};
int main() {
    node node;
    node.map.insert({1, 1});
    return 0;
}
c

return 0处打断点,显示的是:

可以看到内嵌到struct或者class内的STL组件可能无法正常显示

解决方案#

https://github.com/vadimcn/codelldb/issues/707

原因还是llvm工具链的问题,clang++lldblibc++对应的是g++gdblibstdc++,虽然llvm支持使用libstdc++做链接,但是多少有些小问题,比如性能上,再比如这个lldb不能正确显示unordered_map,最新的llvm-21中的lldb已经把这个问题修复了:

[lldb] Fix StdUnorderedMapSynthProvider for GCC #164251

有两种解决办法:

  1. 修改CMakeLists.txt,使用llvm组件(这些组件在llvm配置时应该就配置完成了):

    # 设置编译器
    set(CMAKE_CXX_COMPILER clang++-20)
    # 添加编译标志 库名 libc++.so
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
    # 设置链接标志 库名 libc++abi.so
    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++ -lc++abi")
    cmake

    重新编译,再调试:

    这么做会强制程序链接libc++库,但是linux上一般会默认链接libstdc++,因此每个cmake项目都要搞一遍,尤其是再去配vcpkg环境或者是xmake的项目(默认都是链接libstdc++的),都得额外搞一套配置,不然到时候libstdc++libc++链接冲突了很难搞,考虑到库切换起来很麻烦,切换编译器很简单(而且兼容),推荐还是用第二种方法

  2. 修改本地的lldb formatter,然后改codelldb的后端

    用下面的命令找gnu_libstdcpp.py这个文件:

    find /usr -name "gnu_libstdcpp.py" 2>/dev/null
    bash

    复制一份备用,然后拉取llvm项目上最新的文件:

    # 复制一份备用
    sudo cp /usr/lib/llvm-20/lib/python3.10/site-packages/lldb/formatters/cpp/gnu_libstdcpp.py \
            /usr/lib/llvm-20/lib/python3.10/site-packages/lldb/formatters/cpp/gnu_libstdcpp.py.bak
    # 下载github最新文件
    sudo wget https://raw.githubusercontent.com/llvm/llvm-project/main/lldb/examples/synthetic/gnu_libstdcpp.py \
              -O /usr/lib/llvm-20/lib/python3.10/site-packages/lldb/formatters/cpp/gnu_libstdcpp.py
    bash

    vscode修改codelldb,使用本地的lldb:

    • Ctrl + Shift + P
    • >LLDB: Use Alternate Backend
    • 输入lldb-<version>(下哪个版本就用哪个版本)

    codelldb自己会解析后端,完事,之后codelldb会调用本地修改后的lldb来调试,一劳永逸

ps:在linux上使用llvm工具链还是不太方便,修改了好多配置,不想折腾还是默认使用g++和gdb比较好

9.3 clangd设置代码补全#

问题描述#

clangd默认配置在代码补全的时候会把模板或函数的所有参数都补全出来,例如,当你输入了

std::set
c

并试图使用clangd提供的代码补全时,它会补全为:

std::set<class, class, class>
c

可以使用Tab一个一个填充或删除参数,但这样比较麻烦

解决方案#

.vscode文件夹下新增settings.json,内容为:

{
    "clangd.arguments": [
        "--function-arg-placeholders=false",
        "--completion-style=bundled"
    ]
}
json

这样会影响在当前项目目录下clangd的补全功能,当输入std::set时,会补全为std::set<>

也可以直接在clangd插件的设置中找到arguments项,设置上面两个参数,这样会影响所有目录下的补全行为

参考#

linux环境下cmake + clangd + lldb搭建cpp开发环境
https://liang-bk.github.io/blog/linux-cpp-environment
Author Liangbk
Published at November 3, 2025