VSCode 调试 c++ 配置


自从微软出了 VSCode 编辑器后,就没在使用其他 IDE 了,用来编写一些动态语言(Node.js、Python)程序,不需要编译,安装的相关插件能很好的帮助调试。但是对于 c++ 这种静态编译语言,调试就成了一个大麻烦,环境配置都很难顺利的走下去,正好准备用 VSCode 看 SRS 源码,将相关的 c++ 配置及调试过程记录一下。

环境基于 WSL-Ubuntu 20.04

准备工作

  1. 必要的 c++ 环境程序,安装过程不会的自行 Google 吧
    • gcc/g++
    • make/cmake
    • gdb
  2. 需要安装 VSCode 插件
    • C/C++ (c/c++ 语法)
    • C++ Intellisense (代码格式化)
    • CMake (cmake 语法高亮)
    • CMake Tools

编译调试

CMake 编译需要写 CMakeLists.txt 文件, make 需要 Makefile 文件, 根据需要自行选择,这里以 CMake 为例

添加配置

CMake

按快捷键 Ctrl+Shift+P 调出控制台, 输入 cmake ,选择CMake:Configure 或者 CMake:Quick Start 开始配置

  1. 选择 gcc 编译工具版本

    select gcc

  2. 根据提示创建 CMakeLists.txt, 选择 Create, 创建新文件, 选择Locate 打开已有文件

    create CMakeLists.txt

  3. 若 2 选择Create, 则按提示创建文件,输入项目名称,选择输出类型,就会生成 CMakeLists.txt 文件, 根据需要配置相关项,参考CMakeLists.txt 实例

    input project name
    select output

当状态栏出现如下图表时,则表明配置完成,可以选择 Build 尝试编译

build status

CMakeLists.txt 实例

该配置是使用pkgconfig编译成动态库, 如需其他格式,自行修改

cmake_minimum_required(VERSION 3.5)

# 使用 pkgconfig 导入第三方库
project(decoder LANGUAGES C)
set(ENV{PKG_CONFIG_PATH} /usr/local/ffmpeg/lib/pkgconfig)
find_package(PkgConfig)
pkg_check_modules(FFMPEG REQUIRED libavcodec libavformat libavutil)
message('sss',${FFMPEG_INCLUDE_DIRS})
include_directories(${FFMPEG_INCLUDE_DIRS})
link_directories(${FFMPEG_LIBRARY_DIRS})

# 显式指定编译器
set(CMAKE_C_COMPILER "gcc")
 
# 开启调试信息
set(CMAKE_BUILD_TYPE "Debug")
set(CMAKE_C_FLAGS_DEBUG "$ENV{CFLAGS} -O0 -Wall -g2 -ggdb")
set(CMAKE_C_FLAGS_RELEASE "$ENV{CFLAGS} -O3 -Wall")
 
 
# 开启所有警告
set(CMAKE_C_FLAGS "-Wall")

add_executable(mediainfo mediainfo.c)
target_link_libraries(mediainfo ${FFMPEG_LIBRARIES})

add_executable(extra_audio extra_audio.c)
target_link_libraries(extra_audio ${FFMPEG_LIBRARIES})

Debug

设置好 CMake 后,打开 .cpp 文件, 按快捷键 Ctrl+Shift+D 打开调试面板,点击 运行和调试, 根据系统情况选取不同的 C++ ,如下图所示:

select environment

然后根据需要选择不同版本的编译器配置,会生成 launch.jsontasks.json, 根据调试需求更改相应的参数

select complier config

下面以提供调试启动配置实例, 详细配置请参考官方文档

  • task.json
{
    "tasks": [
        {  // 默认生成的配置,用于编译单个C++可行,但是大项目就需要其他配置了,可以不用管,
            "type": "cppbuild",
            "label": "C/C++: gcc-9 build active file",
            "command": "/usr/bin/gcc-9",
            "args": [
                "-g",
                "${workspaceFolder}/main.c",
                "-o",
                "${fileDirname}/${fileBasenameNoExtension}"
            ],
            "options": {
                "cwd": "${workspaceFolder}"
            },
            "problemMatcher": [
                "$gcc"
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            },
            "detail": "Task generated by Debugger."
        },
        // 这个任务配置对于小项目来说修改完直接编译调试还不错,
        // 但是大项目最好手动编译好后,直接使用 launch 调试,不建议用 task 配置 
        {
            // label 是 task 唯一标识, 对应下面 launch 的 preLaunchTask 配置
            "label": "cmake",
            "type": "shell",
            "command": "cmake",
            "args": [
                "../"
            ],
            "options": {
                // 工作目录
                "cwd": "${workspaceFolder}/build"
            }
        },
        {
            "label": "make",
            "type": "shell",
            "command": "make",
            "options": {
                "cwd": "${workspaceFolder}/build"
            }
        },
        {
            "label": "build",
            // dependsOn 按顺序执行多个 task
            "dependsOn": [
                "cmake",
                "make"
            ]
        }
    ],
    "version": "2.0.0"
}
  • launch.json
{
    // 使用 IntelliSense 了解相关属性。 
    // 悬停以查看现有属性的描述。
    // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "gdb launch",
            "type": "cppdbg",
            "request": "launch",
            // program 是调试启动可执行文件路径 
            "program": "${workspaceFolder}/build/decoder",
            // args 将照命令行参数以空格分割,顺序依次写入数组列表,
            "args": [
                "/mnt/e/film/Fate_Zero_all_OP_and_ED.mp4",
                "output"
            ],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": false,
            // preLaunchTask 调试启动前置任务,需要配置 task.json, 进行一些编译任务
            "preLaunchTask": "build",
            "miDebuggerPath": "/usr/bin/gdb",
            "MIMode": "gdb",
            "setupCommands": [
                {
                    "description": "为 gdb 启用整齐打印",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                }
            ]
        }
    ]
}

设置好后就可以愉快的 F5

C++ 插件配置

该配置可以解决阅读源码时导入第三方文件报红线错误,以及一些自定义 C++ 的配置

按快捷键 Ctrl+Shift+P 调出控制台, 输入 c++,选择 C/C++编辑配置 UI界面或者 JSON 格式进行配置 c_cpp_properties.json

{
    "configurations": [
         {
            "name": "Linux",
            // add header file path
            "includePath": [
                "${workspaceFolder}/**",
                "/usr/local/ffmpeg/include"
            ],
            "defines": [],
            // set search path
            "browse": {
                "path": [
                    "/usr/local/ffmpeg/include",
                    "${workspaceFolder}"
                ],
                "databaseFilename": "",
                "limitSymbolsToIncludedHeaders": false
            },
            "compilerPath": "/usr/bin/clang",
            "cStandard": "c11",
            "cppStandard": "c++14",
            "intelliSenseMode": "clang-x64",
            "compileCommands": "${workspaceFolder}/build/compile_commands.json",
            "configurationProvider": "ms-vscode.cmake-tools"
        }
    ],
    "version": 4
}
  • 配置属性

    • name 标识配置的友好名称。 Linux、Mac 和 Win32 是将在这些平台上自动选择的配置的特殊标识符。 VS Code 中的状态栏将显示哪个配置处于活动状态。您还可以单击状态栏中的标签来更改活动配置。

    • compilerPath (可选)用于构建项目的编译器的完整路径,例如 /usr/bin/gcc,以启用更准确的 IntelliSense。该扩展将查询编译器以确定用于 IntelliSense 的系统包含路径和默认定义。

    • compilerArgs (可选)用于修改所使用的包含或定义的编译器参数,例如 -nostdinc++、-m32 等。

    • intelliSenseMode 使用的 IntelliSense 模式映射到 MSVC、gcc 或 Clang 的特定于体系结构的变体。如果未设置或设置为 ${default},扩展将选择该平台的默认值。

      平台默认值:

      • Windows: msvc-x64
      • Linux: gcc-x64
      • macOS: clang-x64
    • includePath 包含路径是一个文件夹,其中包含源文件中包含的头文件(例如 #include "myHeaderFile.h")。指定 IntelliSense 引擎在搜索包含的头文件时使用的路径列表。在这些路径上搜索不是递归的。指定 ** 表示递归搜索。例如, ${workspaceFolder}/** 将搜索所有子目录,而 ${workspaceFolder} 则不会。如果在安装了 Visual Studio 的 Windows 上,或者如果在 compilerPath 设置中指定了编译器,则无需在此列表中列出系统包含路径。

    • defines 解析文件时要使用的 IntelliSense 引擎的预处理器定义列表。或者,使用 = 设置一个值,例如 VERSION=1。

    • cStandard 用于 IntelliSense 的 C 语言标准的版本。

    • cppStandard 用于 IntelliSense 的 C++ 语言标准的版本。

    • configurationProvider 可以为源文件提供 IntelliSense 配置信息的 VS Code 扩展的 ID。例如,使用 VS Code 扩展 ID ms-vscode.cmake-tools 提供来自 CMake 工具扩展的配置信息。

    • windowsSdkVersion Windows SDK 的版本包括在 Windows 上使用的路径,例如 10.0.17134.0

    • macFrameworkPath IntelliSense 引擎在从 Mac 框架搜索包含的标头时使用的路径列表。仅支持 macOS 的配置。

    • forcedInclude (可选)在处理源文件中的任何其他字符之前应包含的文件列表。文件包含在列出的顺序中。

    • compileCommands (可选)工作区的 compile_commands.json 文件的完整路径。将使用在此文件中发现的 includePathdefines,而不是为包含路径和定义设置设置的值。如果编译命令数据库不包含与您在编辑器中打开的文件相对应的翻译单元条目,则会出现一条警告消息,扩展将使用 includePathdefines 设置。

      有关文件格式的更多信息,请参阅 Clang 文档。某些构建系统(例如 CMake)简化了生成此文件的过程

    • browse"C_Cpp.intelliSenseEngine" 设置为 "Tag Parser"(也称为“模糊”IntelliSense,或“browse”引擎)时使用的属性集。这些属性也由转到定义/声明功能使用,或者当“Default”智能感知引擎无法解析源文件中的 #includes

      • path Tag Parser 用于搜索源文件中包含的标头的路径列表。如果省略,includePath 将用作 path默认情况下,在这些路径上搜索是递归的。指定 * 表示非递归搜索。例如: ${workspaceFolder} 将搜索所有子目录,而 ${workspaceFolder}/* 不会。
      • limitSymbolsToIncludedHeaders 当为 true 时,标签解析器将只解析 ${workspaceFolder} 中的源文件直接或间接包含的代码文件。当为 false 时,标签解析器将解析在 browse.path 列表中指定的路径中找到的所有代码文件。
      • databaseFilename 生成的符号数据库的路径。此属性指示扩展将标记解析器的符号数据库保存在工作区默认存储位置以外的其他位置。如果指定了相对路径,它将相对于工作区的默认存储位置,而不是工作区文件夹本身。 ${workspaceFolder} 变量可用于指定相对于工作区文件夹的路径(例如 ${workspaceFolder}/.vscode/browse.vc.db

多线程调试

当调试 SRS 多线程程序时, 因为有守护进程,VSCode 调试没有自动跟踪子线程,在父线程就退出了,可以在 launch.json 中添加强制跟踪子线程的配置,

  • launch.json
{
    "version": "0.2.0",
    "configurations": [
        {
            ...
            "setupCommands": [
                {
                    // 设置跟踪子进程
                    "text": "-gdb-set follow-fork-mode child"
                }
            ]
        }
    ]
}

调试技巧

调试控制台打印数组信息

调试遇见数组中存放指针时,vscode 调试器往往解析不出来数组信息,只能显示 0 索引的数据:

调试信息

该段代码出自 ffmpeg 的示例程序 muxing.c,有兴趣可以自行尝试。

因为 VSCode 也是基于 GDB 调试的,所以可以使用 GDB 的@操作符进行打印: *array@len,其中 len 是指定打印的长度,详细信息可以查看gdb 在线文档

调试输出

若要从中间打印数组,只需要将 *array 索引改至指定的起始位置 array[start]@len,就会打印从 start~`len` 之间的数据。


文章作者: MaZhuang
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 MaZhuang !
  目录