基于VScode的C/C++环境搭建
learn from https://subingwen.cn/vscode/cpp-windows/编译工具对于上大一初学编程的同学来说如果受不了比自己年纪还大的DEV C可以使用最新版本的Visual Studio即装即用无需额外配置也可以利用扩展进行vibe coding和复杂工程构建但是整个软件过于臃肿交叉编译和跨平台开发的能力暂时还不够灵活全面因此今天为大家介绍VScode上搭建C/C环境的方法。首先是编译器的安装这边使用MinGW通用性更强最后确保gcc可用即可。关于gcc的介绍我这边就不再赘述了之前的文章已经写了太多遍大家也可以自行去网上搜索。这边只提两个注意点①如果你已经安装了Qt那么直接配置环境变量即可②这里的gcc是编译x86平台运行程序的和我们编译单片机固件的使用的arm-none-eabi-gcc是两回事至于开发嵌入式Linux系统需要的交叉编译工具则是arm-poky-linux-gnueabi这类的。下一个需要的工具是CMakeCMake是一个跨平台的编译工具,可以用简单的语句来描述所有平台的编译过程。他能够输出各种各样的makefile或者project文件。Cmake并不直接建构出最终的软件,而是产生标准的项目构建文件(如Linux的Makefile或Windows Visual C的projects/workspaces),然后再调用编译器按照构建文件规则编译整个项目。现在越来越多的开源项目都支持使用CMake进行项目构建,如果想要在VSCode搭建的C开发环境中实现类似IDE的一键编译或者一键调试的效果,就可以依赖CMake来解决这个问题。注意CMake的环境变量也需要配置。语法检查在 vscode 中编写 C/C 程序并搭建一个类似 IDE 的编译调试环境一共需要安装两个插件C/C、CMake Tools。注意现在不需要再单独下载CMake插件了。首先需要基于 vscode 的扩展面板搜索插件名找到插件之后直接安装就可以。单文件编译与调试gcc编译所有源文件为可执行文件命令gcc *.c -0 Test如下图所示下面开始调试我们调试C\C需要使用GDB注意Qt里面也有可以复用没有的话就自己从下面网址下一个。Download GDB检查方法VScode运行调试代码需要launch.json指示它。如果我们下载了微软官方的C/C插件我们就可以自动生成这两个文件。自动生成task.json的标准操作自动生成launch.json的标准操作这两个地方记得按照你的实际情况更改哦。下面划重点gcc生成可调试程序需要显式声明编译选项-ggcc -g your_code.c -o your_program现在可以打断点调试了多文件编译多个源文件编译成可执行文件主要有两种方式第一种依然是使用gcc命令gcc -g *.c -o test针对源文件、头文件分开的标准架构gcc也设计了标准方法比如下面这种命令如下$ gcc ./Src/*.c -o test -I ./Inc/另外一种是使用CMake工具。gcc命令一般适合在架构简单的工程下使用如果我们想要编译的东西是Linux内核呢gcc命令可能就显得有些捉襟见肘。使用CMake工具咱们分为下面几步走。步骤1目录下新建CMakeLists.txt文件touch CMakeLists.txt步骤2了解CMake常用函数#创建了一个名叫MultiSource的cmake项目 project(MultiSource) #获取src目录下的所有源文件并将其存储在变量SRC_SUB中 aux_source_directory(Src SRC_SUB) aux_source_directory(. SRC_CUR) #将SRC_SUB和SRC_CUR变量中的源文件列表合并生成可执行文件signtest add_executable(signtest ${SRC_SUB} ${SRC_CUR}) # 设置包含的头文件目录 include_directories(Inc)不过貌似我多余写注释鼠标悬停CMakeTools会有提示———————————————————————————————————————————此外想要多了解一些CMakeLists的可以参考拙作使用CMake管理Arm芯片工程简介-CSDN博客那一期视频里面Keysking大哥带着大家研读了ST原厂工程师写的CMakeLists。这其实是我非常推崇的一种学习方式现在这个年代大部分年轻人都有点浮躁看不上这个看不上那个觉得官方写的库都是屎山所谓文人相轻但事实上真正的工程管理维护完全是另外一回事。今年有幸进入一家芯片公司维护自研芯片配套SDK才有了如此感慨对ST官方现在是越了解越拥护doge。———————————————————————————————————————————步骤3按下CTRLSHIFTP,进行CMake Configure。这里忘记声明CMake最低版本要求了cmake_minimum_required(VERSION 3.10) #创建了一个名叫MultiSource的cmake项目 project(MultiSource) #获取src目录下的所有源文件并将其存储在变量SRC_SUB中 aux_source_directory(Src SRC_SUB) aux_source_directory(. SRC_CUR) #将SRC_SUB和SRC_CUR变量中的源文件列表合并生成可执行文件signtest add_executable(signtest ${SRC_SUB} ${SRC_CUR}) # 设置包含的头文件目录 include_directories(Inc)如果成功配置了就可以看到build文件夹了。下面用终端进入build目录使用下面的命令生成构建文件cmake ..具体作用可以看到CMake基于我们编写的CMakeLists.txt生成了大量附属文件最重要的莫过于这个Makefile它会指导gcc进行源文件编译。再下面使用mingw32命令编译源文件mingw32-make.exe效果如下现在有简单方法多文件调试规范操作请先来到main方法所在的源文件再进行下面的操作。下面需要修改launch.json:这里的修改也有两个注意点使用CMake管理的可执行程序一般在build文件夹下因此有program: ${workspaceFolder}/build/*.exe,找GDB的位置可以在git bash里面用which命令但是记得改斜杠pipeProgram: D://QtCreator//application//Tools//mingw730_32//bin//gdb,launch.json示例{ // 使用 IntelliSense 了解相关属性。 // 悬停以查看现有属性的描述。 // 欲了解更多信息请访问: https://go.microsoft.com/fwlink/?linkid830387 version: 0.2.0, configurations: [ { name: (gdb) 启动, type: cppdbg, request: launch, program: ${workspaceFolder}/build/signtest.exe, args: [], stopAtEntry: false, cwd: ${fileDirname}, environment: [], externalConsole: false, MIMode: gdb, miDebuggerPath: C:/QtCreator/application/Tools/mingw730_64/bin/gdb.exe, setupCommands: [ { description: 为 gdb 启用整齐打印, text: -enable-pretty-printing, ignoreFailures: true }, { description: 将反汇编风格设置为 Intel, text: -gdb-set disassembly-flavor intel, ignoreFailures: true } ] } ] }改完就可以打断点调试了如果出现不能调试的情况那是因为gcc默认优化编译可以通过cmake命令更改编译选项请参考下文CMake预设文件法的设置更改。现在多文件调试光有一个launch.json就OK了用task.json生成可执行程序会有点冲突我不建议这么弄。都是同样的源文件编译出来的可执行程序建议一个工程里面有一个就行。番外篇——基于Ninja构建C语言工程Ninja是一个专注于速度的小型构建系统由Evan Martin于2010年在Chrome团队工作时开发。Evan Martin从2007年到2012年在Chrome团队工作。在加入初期Chrome只能够在Windows上运行他的主要任务是把代码移植到其它平台而面临的第一个任务就是确定构建系统。Chrome团队的成员提出了GYP增量解决方案它的作用是从高级的描述规则生成平台相关的构建文件。在Linux上他最开始尝试把Scons作为GYP的目标构建系统但当文件发生变化启动构建就需要花费30秒时间。因为他的工作是移植代码涉及到频繁的更改文件和重新编译所以这被认为是不可接受的。后来他又尝试make作为GYP的目标构建系统。在刚开始的时候速度相当快但当文件越来越多时它变慢了。后来他注意到make中的一些问题觉得可以优化因此有了开发Ninja的想法。在使用Ninja后修改文件后Chrome增量构建的时间降到了6秒钟。使用“Ninja”命名是因为作者觉得它速度很快。获取网址Pre built Ninja packages · ninja-build/ninja Wiki · GitHub在你的系统终端中敲对应的命令完成下载。winget install Ninja-build.ninja下面介绍两种使用Ninja作为CMake Generator的方法。CMake命令法第一种cmake命令法注意我们在CMakeLists.txt中按下ctrls系统会自动运行cmake生成build文件夹此文件夹默认使用Makefile作为构造工具。因此我们需要新建空白build文件夹并且进入该目录mkdir build cd build下面这个状态下输入终端命令cmake -G Ninja ..构建文件生成完毕下面终端输入Ninja就可以进行编译了注意cmake侧边栏图标编译默认的指导文件是Makefile此时不可用这种方法下直接生成的可执行程序也默认无法调试。但无论你使用Makefile还是Ninja指导gcc编译只要是cmake框架下构建的文件无法被调试都可以通过下面的命令解决$ cmake -DCMAKE_BUILD_TYPEDebug .. ##下面是终端日志 -- Configuring done (0.1s) -- Generating done (0.1s) -- Build files have been written to: C:/VC_Projects/C_Projects/6_MultiSorce/build正确输入命令后CMAKE_BUILD_TYPE:STRING被赋值为了DEBUGCMake预设文件法先在CMakeLists.txt文件中修改最低CMake版本为3.20该版本开始支持CMakePresets.json预设文件可在项目中固定生成器同时还能配置其他构建参数cmake_minimum_required(VERSION 3.20)注意CMakePresets.json与CMakeLists.txt需要在同一个路径下共存CMakePresets.json参考{ version: 3, configurePresets: [ { name: default, displayName: Default (Ninja), generator: Ninja, binaryDir: ${sourceDir}/build, cacheVariables: { CMAKE_BUILD_TYPE: Release } } ] }注意这里如果修改CMAKE_BUILD_TYPE:Debug,那么就可以自由调试了。之后终端输入cmake --preset default正确执行后会生成build文件夹因此ninja构建C语言程序的推荐目录架构如下所示现在侧边栏的CMake编译下载就会默认使用Ninja指导gcc编译源文件了不过此时的可执行文件依旧是优化编译状态因为我上面选了release编译我们可以来到CMakeCahe.txt文件夹所在的目录cd build/然后使用cmake -DCMAKE_BUILD_TYPEDebug ..命令cmake -DCMAKE_BUILD_TYPEDebug ..调试效果如下总结小型工程使用Makefile是最简单的只需要在工程根目录下编写CMakeLists.txt然后按下ctrls就能使用侧边栏控键了代码量小的时候其实和Ninja相比起来也不慢。使用Ninja就请参考我的CMake预设文件法注意gcc默认优化编译如需调试还请用命令修改CMakeCache.txt文件。番外篇——基于Clangd实现语法检查老实讲我不是很推荐使用微软给我们提供的语法检查插件我个人的使用体检是开发复杂项目的时候语法检查和定义跳转不太精准当然也有可能是我使用的问题。我这边更推荐大家使用基于llvm的clangd大家可以自行去官网下载一整个develop kit然后像gcc那样添加到环境变量之中。注意这里的clang有目标Target。推荐版本Release LLVM 21.1.0 · llvm/llvm-project此外为了让VScode启动这些工具链需要一些安装一些插件我这边是为VScode新建一个配置使用这个方案并且参考我的这篇文章设置clangd path使用VScode开发ARM核芯片通用配置_如何使用vs code开发arm芯片-CSDN博客注意到clangd官方要求cmake生成一个compile_commands.json这意味着我们需要修改CMakeLists.txt文件增加下面这一句set(CMAKE_EXPORT_COMPILE_COMMANDS 1)这样cmake会帮我们自动生成compile_commands.json。现在可以正常跳转了。整体展示一下CMakeLists.txt:cmake_minimum_required(VERSION 3.20) set(CMAKE_EXPORT_COMPILE_COMMANDS 1) project(LibManageSys) set(CMAKE_C_STANDARD 99) set(CMAKE_C_STANDARD_REQUIRED ON) #设置包含的头文件目录 include_directories(Inc) #获取src目录下的所有源文件并将其存储在变量SRC_SUB中 aux_source_directory(Src SRC_SUB) aux_source_directory(. SRC_CUR) #将SRC_SUB和SRC_CUR变量中的源文件列表合并生成可执行文件 add_executable(LibManageSys ${SRC_SUB} ${SRC_CUR})以及CMakePresets.json:{ version: 3, configurePresets: [ { name: default, displayName: Default (Ninja), generator: Ninja, binaryDir: ${sourceDir}/build, cacheVariables: { CMAKE_BUILD_TYPE: Debug } } ] }虽然这个时候我们还是可以用GDB调试但是既然已经下了青眼白龙的拓展那么就来测评一下吧。此外按照下图的插件说明青眼白龙是可以调试嵌入式平台的后面有空我会帮我大家测试一下可行性理论上来讲gcc编译的exe可以被lldb调试的话那么arm-none-eabi-gcc编译的elf也可以被lldb远程调试。青眼白龙官方教程codelldb/MANUAL.md at v1.12.1 · vadimcn/codelldb想要进行lldb调试还是按照和GDB同样的办法新建launch.json。首次调试vscode会主动质询你想用的调试器是什么我们选择lldb即可。launch.json参考代码如下{ // 使用 IntelliSense 了解相关属性。 // 悬停以查看现有属性的描述。 // 欲了解更多信息请访问: https://go.microsoft.com/fwlink/?linkid830387 version: 0.2.0, configurations: [ { name: Debug, type: lldb, request: launch, program: ${workspaceRoot}/build/LibManageSys.exe, args: [], cwd: ${workspaceFolder}, internalConsoleOptions:neverOpen, console: integratedTerminal } ] }注意①program这个键值对里面需要声明你的可执行文件的具体路径。②internalConsoleOptions代表是否开启内部控制台咱们直接用终端观察现象用不上。③console直接选择vscode的内部终端。效果如下最后提醒请尽量在在powershell终端里面执行\调试exegit bash可能不太兼容。番外篇——复杂项目CMakeLists构造之前我主要介绍了这种类型的项目结构相对比较简单清晰把头文件塞进Inc把源文件塞进Src里面就行。但实际开发过程中我们往往需要链接其他库函数。可能是公司内部的架构可能是官方开源的代码比如下面这种。最麻烦的情形还是Src和common之间还有耦合调用这种情况下我们可以在所有有源文件的目录下都新建CMakeLists.txt进行编译管理。另外最好从下级往上一层层传递引用关系。所以我们优先为common库编写CMake。# 指定最低CMake版本按需调整建议与上层保持一致 cmake_minimum_required(VERSION 3.20) set(CMAKE_EXPORT_COMPILE_COMMANDS 1) # 定义库名称自定义 set(LIB_NAME Common) # 设置C语言标准与上层保持一致 set(CMAKE_C_STANDARD 99) set(CMAKE_C_STANDARD_REQUIRED ON) # 收集Src目录下所有C源文件自动遍历无需手动列文件 aux_source_directory(. SRC_FILES) # 构建静态库STATIC也可根据需求改为动态库SHARED add_library(${LIB_NAME} STATIC ${SRC_FILES}) # 指定库的头文件目录让上层引用时能找到Inc下的头文件 target_include_directories(${LIB_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../Include # 暴露Inc目录给上层PUBLIC表示依赖该库的目标也能访问 )然后是Src层# 1_KeySigGen/Src/CMakeLists.txt # 指定最低CMake版本按需调整建议与上层保持一致 cmake_minimum_required(VERSION 3.20) set(CMAKE_EXPORT_COMPILE_COMMANDS 1) # 定义库名称自定义比如 KeySigGenCore set(LIB_NAME Core) # 设置C语言标准与上层保持一致 set(CMAKE_C_STANDARD 99) set(CMAKE_C_STANDARD_REQUIRED ON) # 收集Src目录下所有C源文件自动遍历无需手动列文件 aux_source_directory(. SRC_FILES) # 构建静态库STATIC也可根据需求改为动态库SHARED add_library(${LIB_NAME} STATIC ${SRC_FILES}) # 指定库的头文件目录让上层引用时能找到Inc下的头文件 target_include_directories(${LIB_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../Inc # 暴露Inc目录给上层PUBLIC表示依赖该库的目标也能访问 ${CMAKE_CURRENT_SOURCE_DIR}/../common/Include # 暴露common目录给上层 )最后是顶层# 1_KeySigGen/CMakeLists.txt cmake_minimum_required(VERSION 3.20) set(CMAKE_EXPORT_COMPILE_COMMANDS 1) project(KeySigGen) set(CMAKE_C_STANDARD 99) set(CMAKE_C_STANDARD_REQUIRED ON) # 引入Src目录的CMake配置编译出静态库 add_subdirectory(Src) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/common/Source) # 如果上层有自己的源文件比如主函数入口按需添加 # 示例假设上层有main.c可通过aux_source_directory收集 aux_source_directory(. MAIN_SRC) # 生成可执行文件核心是链接Src下的库 Core add_executable(KeySigGen ${MAIN_SRC} # 上层自有源文件如有则放开 ) # 链接Src目录构建的静态库 target_link_libraries(KeySigGen PRIVATE Core) target_link_libraries(KeySigGen PRIVATE Common)整体目录cmake界面