自从微软出了 VSCode 编辑器后,就没在使用其他 IDE 了,用来编写一些动态语言(Node.js、Python)程序,不需要编译,安装的相关插件能很好的帮助调试。但是对于 c++ 这种静态编译语言,调试就成了一个大麻烦,环境配置都很难顺利的走下去,正好准备用 VSCode 看 SRS 源码,将相关的 c++ 配置及调试过程记录一下。
环境基于 WSL-Ubuntu 20.04
准备工作
- 必要的 c++ 环境程序,安装过程不会的自行 Google 吧
- gcc/g++
- make/cmake
- gdb
- 需要安装 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
开始配置
选择 gcc 编译工具版本
根据提示创建
CMakeLists.txt
, 选择Create
, 创建新文件, 选择Locate
打开已有文件若 2 选择
Create
, 则按提示创建文件,输入项目名称,选择输出类型,就会生成CMakeLists.txt
文件, 根据需要配置相关项,参考CMakeLists.txt 实例
当状态栏出现如下图表时,则表明配置完成,可以选择 Build
尝试编译
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++
,如下图所示:
然后根据需要选择不同版本的编译器配置,会生成 launch.json
和 tasks.json
, 根据调试需求更改相应的参数
下面以提供调试启动配置实例, 详细配置请参考官方文档
- 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
- Windows:
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 扩展 IDms-vscode.cmake-tools
提供来自 CMake 工具扩展的配置信息。windowsSdkVersion
Windows SDK 的版本包括在 Windows 上使用的路径,例如10.0.17134.0
。macFrameworkPath
IntelliSense 引擎在从 Mac 框架搜索包含的标头时使用的路径列表。仅支持 macOS 的配置。forcedInclude
(可选)在处理源文件中的任何其他字符之前应包含的文件列表。文件包含在列出的顺序中。compileCommands
(可选)工作区的compile_commands.json
文件的完整路径。将使用在此文件中发现的includePath
和defines
,而不是为包含路径和定义设置设置的值。如果编译命令数据库不包含与您在编辑器中打开的文件相对应的翻译单元条目,则会出现一条警告消息,扩展将使用includePath
和defines
设置。有关文件格式的更多信息,请参阅 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` 之间的数据。