LOX: 利用VSCode进行C/C++开发

文章框架

脑图



前言

LOX(Lightweight Open-source Xplatform)是我正在编写的一个全新文集,意思就如其名:轻量级-开源-跨平台。就是这个系列中的文章和例程都符合轻量级(Lightweight)、开源(Open-Source)、跨平台(Cross-Platform)。嗯,我这人吧,就好起一些新的名词。
本篇作为LOX系列的第一篇,也向你展示了一个最简单的LOX项目。如果想看一个稍微复杂一点的LOX项目,可以clone我Github上的一个Repo:2048 CLI。欢迎来搞~


单源文件

先从简单的来,一个源文件。

工具

进行本次LOX开发所需要工具,点击下面的Title进入官网下载。

  • VSCode (Visual Studio Code)

    VSCode是微软出品的一款非常良心的轻量级编辑器,虽说是完全照着Sublime Text弄出来的,但它免费啊,还开源啊,所以我也就不深究模仿不模仿了。(嗨呀,原则呢?嗯?)

需要的插件

插件 标识符 说明
C/C++ ms-vscode.cpptools C/C++语言支持,简单的编辑、编译、调试等功能。

需要安装的包

说明
mingw32-gcc.bin GNU C编译器
mingw32-gcc-g++.bin GNU C++编译器
mingw32-gdb.bin GNU 调试器

环境变量
在系统变量的PATH中,添加MinGW安装的根目录中的bin文件夹(如C:\MinGW\bin),且尽量将这一项往上移(为了优先搜索该目录)。

设置过程
完成这一步后,如果打开了VSCode,记得要重启VSCode。


编码

建立工作空间

新建一个文件夹 - 右键 - Open with Code。使用这种方法的前提是你在安装VSCode时选中了“”
Open with Code
或者在VSCode中 - 文件 - 打开文件夹,选中一个空文件夹作工作空间。

新建源文件
鼠标移动到新建的文件夹的根目录处(我的是“HelloWorld”),点击下图蓝色框住的图标(新建文件)。
新建按钮
之后在其中输入文件名(包括后缀名),本例的后缀名写”.c”或”.cpp”。然后在其中写个最简单的HelloWorld。

代码

1
2
3
4
5
#include <stdio.h>
int main(){
printf("Hello World");
return 0;
}

编码时,如果想自动补全,需要在包含指定头文件后保存代码,然后才会启动自动补全。
也就是说,它只对保存后的代码进行探测。


生成

生成快捷键:Ctrl(Mac: Command)+Shift+B
第一次生成时,VSCode会提示找不到生成的配置文件task.json,点击“配置生成任务”。
配置生成任务
在给出的模板中选择Others。在打开的task.json中改为下述代码。

1
2
3
4
5
6
7
{
"version": "0.1.0",
"command": "gcc",
"isShellCommand": true, // 是否为Shell命令
"args": ["-g","${file}","-o","${fileDirname}/${fileBasenameNoExtension}.out"],
"showOutput": "always"
}

其实作用就是代码中所述的。
"command": "gcc""args": ["-g","${file}","-o","${fileDirname}/${fileBasenameNoExtension}.out"]就相当于在Shell)中直接键入gcc -c 源文件.c -o 源文件所在目录/源文件.out。将鼠标放在Key(冒号前面的)上会显示所对应的意思(下面的Launch.json同)。
简单的解释一下其中几个$标识

标识 作用
${file} 当前文件的完整文件名(包括路径、文件名、后缀名)
${fileDirname} 当前文件的路径
${fileBasenameNoExtension} 当前文件的文件名(包括路径、后缀名)

其中所说的“当前文件”指的是你在VSCode编辑器中打开的并正在编辑的文件。
当前正在编辑的文件

完成task.json的配置后,我们缩写的程序已经可以运行了。生成的程序就是源文件所在根目录中出现的与源文件同名但后缀名为.out的文件。


调试

我们当然不能仅仅满足于生成出程序就行的,大部分情况我们是要调试的。

调试快捷键:F5

第一次按F5时和生成时一样,找不到配置文件,在打开的模板中选C++ (GDB/LLDB)(可以跨平台)。
生成的配置文件为launch.json

launch.json改为下述代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch", // 本配置的名称,随便起
"type": "cppdbg",
"request": "launch", // 如果调试的类型为附加进程,需将这里改为attach
"program": "${fileDirname}/${fileBasenameNoExtension}.out", // 要调试的程序路径
"stopAtEntry": false, // 是否在起点处停顿
"cwd": "${workspaceRoot}",
"externalConsole": true, // 在外部控制台运行。若为false,则运行在VSCode自带的控制台中
"linux": { // Linux 系统下的配置
"MIMode": "gdb"
},
"osx": { // OS X系统下的配置
"MIMode": "lldb"
},
"windows": { // Windows 系统下的配置
"MIMode": "gdb",
"miDebuggerPath": "gdb.exe"
}
}
]
}

Windows默认是没有gdb或lldb的,所以我们需要安装MinGW中的gdb,并在这里设置gdb的路径。只写程序名是因为设置了环境变量。
完成launch.json的配置并切换到源代码编辑页之后

再一次:F5

打上断点

合影留念



多源文件

什么!你不满足于单源文件开发?!来来来,我给你看个宝贝。

的确,单源文件开发一般也就是个做做算法题,现在随便写个像样的工程都是多个源文件编译链接一条龙的。这样VSCode可以吗,也可以!但需要新的帮手:CMake

工具

新需要的插件
实际上通过CMake在VSCode上进行项目开发可以不需要任何插件,但是用上这些插件之后你会发现这个过程会变得特别方便!
除去单源文件中所提到的cpptools,还需要下面的插件。

插件 标识符 说明
CMake twxs.cmake 提供CMake语法支持,包括高亮和自动补全等
CMake Tools vector-of-bool.cmake-tools 这个屌!完全把CMake封装成一套VSCode底边栏的工具集

需要新安装的包

说明
mingw32-make.bin GNU Make,根据makefiles(在这里makefiles由CMake搞定)生成项目

为了方便调用,我一般会把mingw32-make.exe在其目录中复制一份出来,命名为make.exe
这一步某种程度意义上讲还蛮重要的,第一是方便自己调用(直接在shell里make),第二是方便vscode的插件调用(如果不弄一个cmake.exe出来的话,vector-of-bool.cmake-tools会报错,不过具体锅是vector-of-bool.cmake-tools还是twxs.cmake的也不太清楚,目前vector-of-bool已经把这个问题(#157)标记为bug,并打算在0.10.0版本解决。)。

  • CMake

    安装时记得将Add CMake to system PATH勾上。是for all users呢还是for current user你自己看咯。

编码

上个例子是C,那这个就上C++好了。

目录结构

我就不同目录下多文件了啊,那没啥意思。咱上多层级目录多源文件的。
目录结构

代码

  • Printer.h
1
2
3
4
5
6
7
#pragma once
class Printer{
public:
void print();
Printer();
~Printer();
};
  • Printer.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "Printer.h"
#include <iostream>
using namespace std;
void Printer::print(){
cout<<"Hello World"<<endl;
}

Printer::Printer() {
cout<<"Printer Object Constructed"<<endl;
}

Printer::~Printer(){
cout<<"Printer Object Destructed"<<endl;
}
  • ‘main.cpp’
1
2
3
4
5
6
7
#include "Lib/Printer.h"
int main(){
Printer* printer = new Printer();
printer->print();
delete printer;
return 0;
}

生成项目

编写CMakeLists

每一个包含源文件的目录中都要编写CMakeLists.txt

  • CMakeLists.txt
    根目录中的CMakeLists.txt,一般程序入口(main函数)在此。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 使用CMake Tools插件(可选,如果这个项目去到一个没有这个插件的机器也同样可以生成项目)
include(CMakeToolsHelpers OPTIONAL)

# CMake 最低版本号要求
cmake_minimum_required(VERSION 2.8)

# 项目名称
project(CMakeTest)

# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_ROOT_SRCS变量
aux_source_directory(. DIR_ROOT_SRCS)

# 添加 Lib子目录
add_subdirectory(Lib)

# 指定生成目标
add_executable(CMakeTest main.cpp ${DIR_ROOT_SRCS})

# 添加链接库
target_link_libraries(CMakeTest PrinterLib)
  • Lib/CMakeLists.txt
    子目录中的CMakeLists.txt,一般将子目录中的源文件编译为静态链接库。
1
2
3
4
5
6
7
8
include(CMakeToolsHelpers OPTIONAL)

cmake_minimum_required(VERSION 2.8)

aux_source_directory(. DIR_LIB_SRCS)

# 生成链接库
add_library(PrinterLib ${DIR_LIB_SRCS})

Build

完成上面步骤后,就可以Build了,如果你安装了vector-of-bool.cmake-tools插件,VSCode左下角的底边栏会有Build按钮。
Build Button
点击Build后,选择Debug(为了下一步演示调试,若不调试就Release
Build Setting
输出框会不停往出喷东西,只要最后输出了[vscode] cmake exited with return code 0,就说明Build成功。
Build Output

目录结构

目录结构
新增加的build文件夹是vector-of-bool.cmake-tools插件干的,它做的很好,如果我们手动cmake - make,那些生成文件会跑的到处都是。
其中build/CMakeTests.exe就是我们生成的可执行程序。


调试

调试设置

文件 - 首选项 - 设置
CMake Tools configuration中找到cmake.debugConfig,生成设置:

1
2
3
4
5
"cmake.debugConfig": {
"miDebuggerPath": "gdb.exe", // Windows 下指定gdb路径(已添加到PATH)
"externalConsole": true, // 使用外部控制台
"stopAtEntry": false // 在起点处停顿(噢!在这停顿!)
},

Start Debugging

藏起来的Debug按钮

刚Build完你可能看不到这两个按钮:
调试按钮
其实他们藏起来了… 这应该是个Bug,我已经反馈给作者了。

重启VSCode后他们就会出现,或者直接点那两个藏起来的按钮(还有这种操作?!):先点右边选择调试目标,再点左边开始调试。

合影留念

完结撒花



结语

Code Everywhere, Build Everywhere.
这样的搭配是不是很爽呢?除了MinGW是Windows特有的矫情外。其余的在任何平台都是一样的。虽说现在VSCode和上面的大部分插件都运行的不太稳定,但是我还是很喜欢这种组合进行跨平台的轻量级开发的。


FAQ

  • ####Q: VSCode或编译器找不到头文件?
    A: 如果VSCode用绿色波浪线给你划出那些找不到源的代码时,将鼠标停留在波浪线上,然后会出现一个小 灯泡。点“Add include path to settings.”。然后它会自动帮你建立一个名为“c_cpp_properties.json”的文件。
    1
    2
    3
    4
    5
    6
    "name": "Mac",
    "includePath": [
    "${workspaceRoot}",
    "/usr/include",
    "/usr/local/include"
    ],

你会在其中找到类似上述代码块的地方,根据“name”后面所描述的系统,在其下的“includePath”中手动添加头文件目录。JSON语法

  • ####Q: 为什么路径动不动就写成${fileDirname}/${fileBasenameNoExtension}.out?
    A: 这样做的好处就是可以在同一配置下进行多个单文件的编译开发,不用每次生成和调试的时候都去写配置文件。使用场景嘛,主要就是写写算法题之类的。
    我写算法题时的目录结构
    .out后缀名就是自己瞎起的。不同平台的可执行后缀名都不一样,这样写就跟谁都不沾边了…

  • ####Q: 如果我不用vector-of-bool.cmake-tools插件,要如何Build?
    A: 写完CMakeLists.txt后,打开VSCode中自带的终端(点击底边栏的输出按钮)

输出按钮

终端
键入:cmake .会生成系统对应的项目(如果你是Windows并安装了Visual Studio,他就会生成VS项目)。
若想生成MinGW Makefiles则键入cmake -G "MinGW Makefiles" .(注意区分大小写),之后会为你生成makefiles,然后再键入make(若没制作前面所提到的mingw32-make.exe的名为make.exe的副本,则键入mingw32-make),最终生成可执行文件。

参考