Visual Studio 2022使用CMake+MinGW+Clang+LLDB作为开发环境

本文介绍了如何在VisualStudio2022中使用MinGW安装Clang和LLDB,并配置CMake进行编译调试。对比了GCC和Clang的优缺点,以及GDB和LLDB在调试行为上的差异。详细讲解了GCC和Clang的配置,包括调试格式的设定,以及GDB和LLDB的调试配置。最后提到了LLDB在VS2022中的源码反汇编问题。

笔者前面写了两篇关于Visual Studio 2022使用MinGW的博文:《Visual Studio 2022使用MinGW来编译调试C/C++程序》、《Visual Studio 2022 CMake+MinGW+GDB 调试目标程序》,这两篇博文都是介绍的是GCC+GDB的编译与调试,本文笔者介绍的则是Clang+LLDB的编译与调试。读完本文,读者可以在GCC、Clang与GDB、LLDB之间进行随意组合。

GCC与GDB的编译调试组合在Linux下是默认组合,像Linux内核以及Linux的绝大多数软件都是使用GCC来编译,使用GDB来调试的。Clang+LLDB是作为新秀存在的,在近年来的MacOS中却是作为默认的编译调试组合。Clang作为编译器的新秀,是有许多优点的,比如Clang的编译速度比GCC快许多,编译出的错误提示非常友好,模块化比GCC做得好等等;LLDB调试器也有许多优点,比如下面一段代码,引用笔者前面的博文《对C++变长参数中的字符串进行转义

template<typename ... Args>
string FormatSQL(const char* fmt, Args&& ... args)
{
	vector<char*> vct;
	size_t len = strlen(fmt);
	string str;
	Concat(str, len, fmt, EscapeArg(len, vct, args)...);
	for (auto iter : vct)
		delete[] iter;
	return str;
}

在调试到Concat(str, len, fmt, EscapeArg(len, vct, args)...);时,默认情况下,使用GDB进入EscapeArg函数执行到最后一句时,在VS中按F10执行逐过程,就会跳过Concat函数,即不会进入Concat函数,需要按F11执行逐语句,才会进入Concat函数,这个行为与VC的调试器不一致,而LLDB就与VC的调试器的行为一致,按F10执行逐过程可以进入Concat函数。GDB的这种行为不知道是否可以配置,有知道的读者可以在评论区留言或者讨论。

一、在MinGW中安装Clang和LLDB

MinGW的安装这里就不再赘述了,直接去MSYS2官网就可以下载最新的MinGW安装包安装就可以了。

安装好MinGW后,在MinGW终端使用下面的命令安装Clang和LLDB:

pacman -S mingw-w64-x86_64-clang
pacman -S mingw-w64-x86_64-clang-tools-extra
pacman -S mingw-w64-x86_64-clang-analyzer
pacman -S mingw-w64-x86_64-lldb
pacman -S mingw-w64-x86_64-lldb-mi

二、Visual Studio 2022配置

Visual Studio 2022有一系列的CMake模板配置,有本机VC的,有WSL的、有MinGW的,有ARM的,也有Linux远程的:

在这里插入图片描述

这些模板配置位于Visual Studio 2022的安装目录C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\CommonExtensions\Microsoft\CMake\CMakeSettingsTemplates,该目录下有许多json文件:

在这里插入图片描述

MinGW的相关配置就在MinGW.json中,内容如下:

{
  "configurations": [
    {
      // Test Comment
      "environments": [
        {
          "MINGW64_ROOT": "C:/msys64/mingw64",
          "BIN_ROOT": "${env.MINGW64_ROOT}/bin",
          "FLAVOR": "x86_64-w64-mingw32",
          "TOOLSET_VERSION": "9.1.0",
          "PATH": "${env.MINGW64_ROOT}/bin;${env.MINGW64_ROOT}/../usr/local/bin;${env.MINGW64_ROOT}/../usr/bin;${env.MINGW64_ROOT}/../bin;${env.PATH}",
          "INCLUDE": "${env.INCLUDE};${env.MINGW64_ROOT}/include/c++/${env.TOOLSET_VERSION};${env.MINGW64_ROOT}/include/c++/${env.TOOLSET_VERSION}/tr1;${env.MINGW64_ROOT}/include/c++/${env.TOOLSET_VERSION}/${env.FLAVOR}",
          "environment": "mingw_64"
        }
      ],
      "name": "Mingw64-Debug",
      "description": "TemplateDescription_Localize_Mingw64Debug",
      "generator": "Ninja",
      "configurationType": "Debug",
      "inheritEnvironments": [
        "mingw_64"
      ],
      "buildRoot": "${projectDir}\\out\\build\\${name}",
      "installRoot": "${projectDir}\\out\\install\\${name}",
      "cmakeCommandArgs": "",
      "buildCommandArgs": "-v",
      "ctestCommandArgs": "",
      "intelliSenseMode": "linux-gcc-x64",
      "variables": [
        {
          "name": "CMAKE_C_COMPILER",
          "value": "${env.BIN_ROOT}/gcc.exe"
        },
        {
          "name": "CMAKE_CXX_COMPILER",
          "value": "${env.BIN_ROOT}/g++.exe"
        }
      ]
    },
    {
      "environments": [
        {
          "MINGW64_ROOT": "C:/msys64/mingw64",
          "BIN_ROOT": "${env.MINGW64_ROOT}/bin",
          "FLAVOR": "x86_64-w64-mingw32",
          "TOOLSET_VERSION": "9.1.0",
          "PATH": "${env.MINGW64_ROOT}/bin;${env.MINGW64_ROOT}/../usr/local/bin;${env.MINGW64_ROOT}/../usr/bin;${env.MINGW64_ROOT}/../bin;${env.PATH}",
          "INCLUDE": "${env.INCLUDE};${env.MINGW64_ROOT}/include/c++/${env.TOOLSET_VERSION};${env.MINGW64_ROOT}/include/c++/${env.TOOLSET_VERSION}/tr1;${env.MINGW64_ROOT}/include/c++/${env.TOOLSET_VERSION}/${env.FLAVOR}",
          "environment": "mingw_64"
        }
      ],
      "name": "Mingw64-Release",
      "description": "TemplateDescription_Localize_Mingw64Release",
      "generator": "Ninja",
      "configurationType": "RelWithDebInfo",
      "inheritEnvironments": [
        "mingw_64"
      ],
      "buildRoot": "${projectDir}\\out\\build\\${name}",
      "installRoot": "${projectDir}\\out\\install\\${name}",
      "cmakeCommandArgs": "",
      "buildCommandArgs": "-v",
      "ctestCommandArgs": "",
      "intelliSenseMode": "linux-gcc-x64",
      "variables": [
        {
          "name": "CMAKE_C_COMPILER",
          "value": "${env.BIN_ROOT}/gcc.exe"
        },
        {
          "name": "CMAKE_CXX_COMPILER",
          "value": "${env.BIN_ROOT}/g++.exe"
        }
      ]
    }
  ]
}

(一)、GCC配置

1.配置MinGW根目录和TOOLSET_VERSION

可以看到MinGW中分别配置了Mingw64-DebugMingw64-Release,里面配置了MinGW的环境变量,使用的编译器,编译目录、安装目录等等。MinGW的安装目录默认为C:/msys64/mingw64,可以根据自己的实际情况更改安装目录以及TOOLSET_VERSION,比如笔者的GCC目前已经更新到13.1.0了,所以需要把TOOLSET_VERSION修改为13.1.0,否则可能会在VS中无法打开头文件。

2.配置调试格式

GCC与Clang在编译时添加调试信息的参数默认都是-g,但是各自生成的调试格式是不一定相同的。

GCC的官方文档解释-g

-g
Produce debugging information in the operating system’s native format (stabs, COFF, XCOFF, or DWARF). GDB can work with this debugging information.
On most systems that use stabs format, -g enables use of extra debugging information that only GDB can use; this extra information makes debugging work better in GDB but probably makes other debuggers crash or refuse to read the program. If you want to control for certain whether to generate the extra information, use -gvms (see below).

即使用的操作系统本地的调试格式,可能是stabs或者COFF或者XCOFF或者 DWARF,GDB是可以识别这些调试格式的。

Clang的官方文档:

-g
Generate complete debug info.

Controlling Debugger “Tuning”
While Clang generally emits standard DWARF debug info (http://dwarfstd.org), different debuggers may know how to take advantage of different specific DWARF features. You can “tune” the debug info for one of several different debuggers.
-ggdb, -glldb, -gsce, -gdbx
Tune the debug info for the gdb, lldb, Sony PlayStation® debugger, or dbx, respectively. Each of these options implies -g. (Therefore, if you want both -gline-tables-only and debugger tuning, the tuning option must come first.)

即默认是使用标准的DWARF格式,GDB是可以识别的,所以GCC与Clang使用参数-g生成的程序,都可以使用GDB来调试。

LLDB官方文档中提到的功能说明:

Debug symbol file parsers to incrementally extract debug information from object files. Support currently includes DWARF & Mach-O symbol tables.

即目前LLDB只支持DWARFMach-O符号表,那MinGW中就只能是DWARF了。DWARF格式目前已经发展到第5个版本了,LLDB目前只支持到第4个版本。

所以为了让GDB与LLDB都能进行调试,在使用GCC编译时需要指定调试格式为DWARF,即需要使用参数-gdwarf-4

前面的json文件中variables部分添加CMAKE_C_FLAGS_DEBUGCMAKE_CXX_FLAGS_DEBUG变量,如下配置:

"variables": [
        {
          "name": "CMAKE_C_COMPILER",
          "value": "${env.BIN_ROOT}/gcc.exe"
        },
        {
          "name": "CMAKE_CXX_COMPILER",
          "value": "${env.BIN_ROOT}/g++.exe"
        },
		{
          "name": "CMAKE_C_FLAGS_DEBUG",
          "value": "-gdwarf-4",
          "type": "STRING"
        },
		{
          "name": "CMAKE_CXX_FLAGS_DEBUG",
          "value": "-gdwarf-4",
          "type": "STRING"
        }
      ]

(二)、Clang配置

Clang编译器可以使用GCC的库libstdc++,也可以使用Clang自己的C++库libc++(参见笔者之前的博文《CentOS 6.X安装GCC 9.1和LLVM/Clang 8.0》中的CLANG_DEFAULT_CXX_STDLIB说明),Clang的libc++库头文件是在v1目录中,所以配置时需要让Clang可以查找到GCC的头文件以及Clang的头文件目录。TOOLSET_VERSION还是填写MinGW中当前安装的GCC的版本号,然后在environmentsINCLUDE中添加${env.MINGW64_ROOT}/include/c++/v1variables设置编译器为clang.exe以及clang++.exe

"variables": [
        {
          "name": "CMAKE_C_COMPILER",
          "value": "${env.BIN_ROOT}/clang.exe"
        },
        {
          "name": "CMAKE_CXX_COMPILER",
          "value": "${env.BIN_ROOT}/clang++.exe"
        }
      ]

由于Clang在MinGW默认就是使用的dwarf格式,所以可以不用指定,也可以指定。为了不与原来的文件混用,我们在原Mingw.json的基础上复制一个MingwClang.json文件来修改,并保存在相同的目录,下面列出完整配置:

{
  "configurations": [
    {
      // Test Comment
      "environments": [
        {
          "MINGW64_ROOT": "G:/msys64/mingw64",
          "BIN_ROOT": "${env.MINGW64_ROOT}/bin",
          "FLAVOR": "x86_64-w64-mingw32",
          "TOOLSET_VERSION": "13.1.0",
          "PATH": "${env.MINGW64_ROOT}/bin;${env.MINGW64_ROOT}/../usr/local/bin;${env.MINGW64_ROOT}/../usr/bin;${env.MINGW64_ROOT}/../bin;${env.PATH}",
          "INCLUDE": "${env.INCLUDE};${env.MINGW64_ROOT}/include/c++/v1;${env.MINGW64_ROOT}/include/c++/${env.TOOLSET_VERSION};${env.MINGW64_ROOT}/include/c++/${env.TOOLSET_VERSION}/tr1;${env.MINGW64_ROOT}/include/c++/${env.TOOLSET_VERSION}/${env.FLAVOR}",
          "environment": "mingw_64"
        }
      ],
      "name": "Mingw64-Clang-Debug",
      "description": "TemplateDescription_Localize_Mingw64Debug",
      "generator": "Ninja",
      "configurationType": "Debug",
      "inheritEnvironments": [
        "mingw_64"
      ],
      "buildRoot": "${projectDir}\\out\\build\\${name}",
      "installRoot": "${projectDir}\\out\\install\\${name}",
      "cmakeCommandArgs": "",
      "buildCommandArgs": "-v",
      "ctestCommandArgs": "",
      "intelliSenseMode": "windows-clang-x64",
      "variables": [
        {
          "name": "CMAKE_C_COMPILER",
          "value": "${env.BIN_ROOT}/clang.exe"
        },
        {
          "name": "CMAKE_CXX_COMPILER",
          "value": "${env.BIN_ROOT}/clang++.exe"
        },
        {
          "name": "CMAKE_C_FLAGS_DEBUG",
          "value": "-gdwarf-4",
          "type": "STRING"
        },
        {
          "name": "CMAKE_CXX_FLAGS_DEBUG",
          "value": "-gdwarf-4",
          "type": "STRING"
        }
      ]
    },
    {
      "environments": [
        {
          "MINGW64_ROOT": "G:/msys64/mingw64",
          "BIN_ROOT": "${env.MINGW64_ROOT}/bin",
          "FLAVOR": "x86_64-w64-mingw32",
          "TOOLSET_VERSION": "13.1.0",
          "PATH": "${env.MINGW64_ROOT}/bin;${env.MINGW64_ROOT}/../usr/local/bin;${env.MINGW64_ROOT}/../usr/bin;${env.MINGW64_ROOT}/../bin;${env.PATH}",
          "INCLUDE": "${env.INCLUDE};${env.MINGW64_ROOT}/include/c++/v1;${env.MINGW64_ROOT}/include/c++/${env.TOOLSET_VERSION};${env.MINGW64_ROOT}/include/c++/${env.TOOLSET_VERSION}/tr1;${env.MINGW64_ROOT}/include/c++/${env.TOOLSET_VERSION}/${env.FLAVOR}",
          "environment": "mingw_64"
        }
      ],
      "name": "Mingw64-Clang-Release",
      "description": "TemplateDescription_Localize_Mingw64Release",
      "generator": "Ninja",
      "configurationType": "RelWithDebInfo",
      "inheritEnvironments": [
        "mingw_64"
      ],
      "buildRoot": "${projectDir}\\out\\build\\${name}",
      "installRoot": "${projectDir}\\out\\install\\${name}",
      "cmakeCommandArgs": "",
      "buildCommandArgs": "-v",
      "ctestCommandArgs": "",
      "intelliSenseMode": "windows-clang-x64",
      "variables": [
        {
          "name": "CMAKE_C_COMPILER",
          "value": "${env.BIN_ROOT}/clang.exe"
        },
        {
          "name": "CMAKE_CXX_COMPILER",
          "value": "${env.BIN_ROOT}/clang++.exe"
        }
      ]
    }
  ]
}

配置好后可以在CMakeSettings对话框中看到:
在这里插入图片描述

如果要使用Clang的libc++库,CMakeLists.txt中添加下面两句:

add_compile_options("-stdlib=libc++")
link_libraries(c++)

(三)、GDB调试配置

下面直接列出一个简单的配置:

{
      "type": "cppdbg",
      "name": "CMakeLists.gdb",
      "project": "CMakeLists.txt",
      "projectTarget": "t.exe",
      "cwd": "${workspaceRoot}",
      "program": "${debugInfo.target}",
      "MIMode": "gdb",
      "miDebuggerPath": "${env.MINGW_PREFIX}\\bin\\gdb.exe",
      "externalConsole": true,
      "setupCommands": [
        {
          "description": "为 gdb 启用整齐打印",
          "text": "-enable-pretty-printing",
          "ignoreFailures": true
        },
        {
          "description": "将反汇编风格设置为 Intel",
          "text": "set disassembly-flavor intel",
          "ignoreFailures": true
        }
      ]
    }

可以参见:《Visual Studio 2022使用MinGW来编译调试C/C++程序》、《Visual Studio 2022 CMake+MinGW+GDB 调试目标程序

如果每次都添加setupCommands命令,也比较烦,我们可以在USERPROFILE环境变量所指目录中添加一个.gdbinit文件,将上面的命令放在里面,每次GDB启动时都会去执行里面的命令:

set disassembly-flavor intel

(四)、LLDB配置

LLDB配置与GDB配置类似:

{
      "type": "cppdbg",
      "name": "CMakeLists.lldb",
      "project": "CMakeLists.txt",
      "projectTarget": "t.exe",
      "cwd": "${workspaceRoot}",
      "program": "${debugInfo.target}",
      "MIMode": "lldb",
      "miDebuggerPath": "${env.MINGW_PREFIX}\\bin\\lldb-mi.exe",
      "externalConsole": true,
      "setupCommands": [
        {
          "description": "为 gdb 启用整齐打印",
          "text": "-enable-pretty-printing",
          "ignoreFailures": true
        },
        {
          "description": "将反汇编风格设置为 Intel",
          "text": "setting set target.x86-disassembly-flavor intel",
          "ignoreFailures": true
        }
      ]
    }

只需要把MIMode改为lldbmiDebuggerPath设置为lldb-mi.exe,如果反汇编格式使用Intel格式的命令为setting set target.x86-disassembly-flavor intel。同样地,为了方便省事,可以在USERPROFILE环境变量所指目录中添加一个.lldbinit文件,将命令放在里面,每次LLDB启动时都会去执行里面的命令:

setting set target.x86-disassembly-flavor intel

Btw:目前Visual Studio 2022使用LLDB调试器对源码反汇编还有Bug,期待新版本能快速修复。VSCode目前也可以使用LLDB进行调试,但是反汇编也是有Bug的。

若对你有所帮助,欢迎点赞收藏!

<think>我们正在处理用户的问题:如何在Visual Studio中添加环境变量? 根据引用[4]的内容,我们知道在Visual Studio 2022中,可以通过CMake设置来配置环境变量,特别是在使用MinGW时,配置了环境变量、编译器、编译目录等。 但是,用户的问题是关于添加环境变量,这可能有几种情况: 1. 在Visual Studio IDE中为调试运行的程序设置环境变量。 2. 在项目构建过程中设置环境变量(例如,在CMake项目中)。 3. 为Visual Studio本身设置环境变量(比如影响Visual Studio的行为)。 我们将主要关注第一种情况,因为这是最常见的需求:在调试时设置环境变量。 另外,引用[4]提到了MinGW的配置,其中包含环境变量的设置,我们可以参考这一点。 步骤: 1. 对于非CMake项目(如MSBuild项目): - 右键单击项目,选择“属性”。 - 在属性页中,选择“调试”选项卡。 - 在“环境”或“环境变量”部分,可以添加环境变量(格式为:NAME=VALUE,每行一个)。 2. 对于CMake项目: - 在CMakeLists.txt中,可以使用`set(ENV{<variable>} <value>)`来设置环境变量(但注意,这会影响CMake的配置过程)。 - 或者在Visual Studio中,通过CMake设置文件(如CMakeSettings.json)来设置环境变量。在CMakeSettings.json中,有一个"environments"数组,可以在其中设置环境变量。 3. 另外,用户可能希望设置系统环境变量,但这通常不是在Visual Studio中设置的,而是通过操作系统的设置。但是,Visual Studio在启动时会继承系统环境变量。 根据引用[4]中提到的配置,我们可以指导用户如何在CMake项目中设置环境变量(通过CMakeSettings.json)。 但是,考虑到用户可能使用的是非CMake项目(传统的.sln/.vcxproj),我们先从最常见的开始。 因此,回答将分为两部分:非CMake项目和CMake项目。 同时,用户可能想知道如何为调试会话设置环境变量,因为这是最常见的需求。 注意:用户的问题没有指定项目类型,所以我们提供两种主要情况的指导。 另外,引用[1]提到Visual Studio Code,但用户的问题是关于Visual Studio(可能是VS IDE),所以我们主要参考引用[4](关于Visual Studio 2022)的内容。 回答结构: 1. 介绍在Visual Studio中设置环境变量的常见场景。 2. 分步骤说明非CMake项目(MSBuild项目)的设置方法。 3. 分步骤说明CMake项目的设置方法(通过CMakeSettings.json)。 4. 附加说明:如何设置系统环境变量(如果用户需要的话,但通常不推荐在VS中直接设置,而是通过系统设置)。 注意:系统级环境变量设置不在Visual Studio内完成,而是在操作系统中设置(如Windows的环境变量设置)。 我们将按照这个结构回答。 同时,生成相关问题: 1. 如何为Visual Studio的构建过程设置环境变量? 2. 在CMake项目中,如何永久设置环境变量? 3. 环境变量在Visual Studio调试中的作用是什么?</think>### 在 Visual Studio 中配置环境变量的方法 在 Visual Studio 中添加环境变量主要有以下三种方式,根据项目类型和需求选择: #### 1. **调试时临时设置(适用于所有项目类型)** - 右键项目 → 选择 **属性** - 进入 **调试** 选项卡 - 在 **环境变量** 字段按格式添加变量(每行一个): ``` PATH=C:\your\path;%PATH% MY_VAR=value ``` - 这些变量仅在调试会话中生效,不影响系统环境[^4]。 #### 2. **CMake 项目配置(通过 CMakeSettings.json)** - 在解决方案资源管理器中打开 **CMakeSettings.json** - 在 `environments` 字段中添加变量: ```json "environments": [ { "MY_SDK_PATH": "C:/sdk/bin", "PATH": "C:/tools;${env.PATH}" } ] ``` - 支持继承系统变量(如 `${env.PATH}`)[^4]。 #### 3. **系统级永久设置(Windows 全局)** - 打开 Windows 设置 → **系统** → **关于** → **高级系统设置** - 点击 **环境变量** - 在 **用户变量** 或 **系统变量** 中添加/修改 - 需重启 Visual Studio 生效 > ⚠️ 重要提示: > - 调试时设置的变量优先级:项目属性 > CMake 配置 > 系统变量 > - 路径分隔符:Windows 用 `;`,Linux/macOS 用 `:` > - 变量引用:在 CMake使用 `$ENV{<VAR>}`,在代码中用 `getenv()` 获取 --- ### 相关问题 1. 如何在 Visual Studio 调试时查看当前生效的环境变量? 2. CMake 项目如何在不同构建配置(Debug/Release)中设置不同的环境变量? 3. 环境变量设置后未生效的可能原因及排查方法? 4. 如何在 Visual Studio Code 中配置环境变量(对比 VS 的区别)? [^1]: Installing Visual Studio Code is very accessible on any platform... [^4]: Visual Studio 2022使用CMake+MinGW+Clang+LLDB作为开发环境...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值