1 目标
写作本文的目标如下:
- 记录VSCode的一些使用方法
- 提醒自己或帮助大家了解为什么这样做
- 由浅到深地进行学习和迁移,验证学习效果
- 了解不同软/硬件平台上交叉编译工具链的构建方式
- 本文目标受众是初识VSCode和编程入门的小白,更准确一点说,相比直接搜索到的答案,本文帮助大家配置环境的同时也介绍部分原理。受限于笔者的知识水平,想必会有不少错误,欢迎指正。
2 Revision and TODO
2.1 Revision
- v1.0 第一版
2.2 TODO
- Linux下VSCode的C/C++开发工具链的配置
- 逐步引入makefile与CMake
- Linux下VSCode配置STM32开发环境
3 预备知识
3.0 不会重点介绍的必备知识
- 基本的数模电知识,如高低电平表示数字10等
- CPU、内存、硬盘等计算机组成原理
- 各类文件在计算机内的存储方式
- 基本的计算机使用能力
3.1 了解VSCode
参考资料:韩骏 Visual Studio Code 权威指南
作者就职于微软,开发并维护了VSCode的二十几个插件,比较著名的有Code Runner等。他也是VSCode中文社区创始人。想要快速了解VSCode的构建方式与原理,务必结合书籍/官方文档而非过度信任网络博客。
3.1.1 什么是VSCode
VSCode是微软开发的一款跨平台的轻量级编辑器,在Windows/Linux发行版/Mac中的界面和功能乃至插件都几乎一致,方便在不同平台进行开发。通过微软开发人员的优化,VSCode的安装包仅仅只有几十MB,足够轻量。
编辑器简单来说就是用于打开、修改和保存文件。VSCode编辑器相当于一个文件处理的核心,能够具备不同的功能,但这些功能并非开箱即用,而是需要下载和配置不同的插件。想必有人已经接触过Visual Studio、Dev Cpp等集成开发环境(Integrated Development Environment),这些IDE通常具备完整的代码编写、编译、调试功能,但常常体积庞大。通过VSCode插件市场提供的不同插件,我们可以根据自己的需求实现特定语言的IDE功能,这些功能将完全符合我们的喜好。
3.1.2 为什么使用VSCode
- VSCode足够轻量,进行各种文件操作的速度极快,便于高效开发
- VSCode可以通过配置不同插件满足各类开发需求,插件市场社区活跃
- VSCode是跨平台的,在不同操作系统都可以保持类似的开发习惯
- VSCode支持必要的代码托管平台Git,能够满足企业开发需求
3.2 了解程序如何运行
3.2.1 从文本到可以运行的指令
计算机发展到现在,让程序在计算机上运行是非常复杂的过程。在IDE中可以快速地编写和运行简单程序,这是因为现代IDE和操作系统大大简化了复杂的构建步骤。笔者并不是计算机专业,因此没有深入学习过相关课程,只能大概地解释一些步骤。
我们以目标为导向,由必要的知识可知,CPU只能读取和执行机器指令,从而实现简单的加减乘除、比较跳转等,而机器指令是以0或1的形式存储在计算机的某些存储器中的。一般来说,CPU有自加的一个程序计数器,存储了下一条程序指令的地址,当时钟信号到来时,CPU对程序代码进行取址、译码和执行。我们最后需要输出的程序是一串01表示的文本,称为可执行文件。这种用0和1表示的,可以直接被CPU读取并执行的语言称为机器语言。
早期程序员直接写0和1来编写程序。开始是在纸带上打孔,后来使用紫外光照射的方式在只读存储器ROM上控制不同二极管的通断,以它们的状态表示01,从而记录程序代码,称为“烧录”。
但是机器语言并不方便人类阅读,程序员编写代码时也难免因看花眼而写错,因此人们创造了汇编语言,用英文文字和符号帮助记忆机器语言。汇编指令常常与一条或多条机器指令直接对应。这便需要一种程序将汇编语言翻译成机器语言,即汇编器(Assembler)。
在以前,一个机器通常只能以循环方式运行一个可执行文件,因此一个文件会写得非常复杂。我们需要将这些文件的前体汇编文件进行拆分,汇编出多个可执行文件。但如何处理相应的包含与跳转呢?我们通过链接器(linker)来实现将多个可执行文件合并成一个文件,同时处理好相应的包含与跳转关系。
人们发现汇编语言与硬件相关性还是很强,无法在不同硬件平台上重用代码,这就影响了开发效率。为此,人们需要更高级的语言,它实现相同功能的代码文本相同,但能够被翻译成不同的汇编语言。高级语言C语言便应运而生。CPU与硬件都是不同的,因此所需的可执行文件取决于硬件平台。而C语言则提供了高层次抽象的模型来构造可执行文件。也就是说,编译出的可执行文件具体内容是不同的,但要注意C语言的设计思想是类似的,甚至每一段代码应该存储在哪也是规定好的,即C语言的内存模型是类似的。
C语言编译为不同硬件平台机器码
将C语言转换成汇编语言的过程称为编译,而这项工作由编译器(Compiler)完成。编译过程包括语法分析、词法分析、语义分析和编译优化等,多个C语言文件最后生成了多个汇编文件。
在编译之前,需要进行展开宏定义、删除注释、去除多余空格、接收编译参数等的工作,这个过程称为预处理。
随着通用计算机的发展,现在,我们可以在自己的计算机平台上编写一些程序的==文本文件==,再通过预处理->编译->汇编->链接的流程,生成==可执行文件==并在当前平台运行。产生不同平台的可执行文件的过程称为交叉编译。一般的应用程序可执行文件存储在硬盘中,运行时由操作系统帮助加载到内存中运行。操作系统本质上也是一组程序,只不过它们的构建方式更加复杂,直接驱动硬件工作,并且为用户封装和提供了硬件调用接口,同时负责管理计算机的任务和资源。它们一般被放在硬盘中,在计算机启动时由一组引导程序加载到内存中,在启动后就可以使用相应的系统了。
操作系统层级简图
3.2.2 工具链
我们以上从文本文件到生成最终可执行文件的过程中,对文件的一系列操作都需要相应的工具来完成。这些工具集合起来就是工具链。对于常用的芯片和计算机硬件平台,专攻此业的程序员已经为我们开发了这些工具,能够完成一系列工作并最终生成可执行文件,并且还能进行代码的调试。GNU计划中包含的GCC工具链是其中的典型代表。另外还有LLVM工具链等。
这些工具链通常是配套的,即包含编译器、链接器、调试器一整套工具。工具链具体的实现则取决于硬件平台,即生成的可执行文件运行的硬件平台。如ARM GNU工具链包含的编译器arm-gcc-none-eabi-gcc.exe、链接器arm-gcc-none-eabi-ld.exe、调试器arm-gcc-none-eabi-gdb.exe,此工具链用于编译和调试ARM架构的裸机系统。交叉编译工具链的命名规范简介
而较新的LLVM工具链则趋向于模块化,其编译器有众多类型,比较知名的有Clang,用于Mac及iOS的开发。
如果要在某个崭新出厂的新架构芯片上运行代码,那么就不能使用现成的工具链,而是需要开发新的对应的工具链了,当然有些工具链的架构是方便迁移的。
通常,Windows环境下不会预装这些工具链,需要自行到官网进行下载。常见的Linux发行版则会预装GCC工具链,可以通过编译源码的方式更新。
我们使用GCC工具链,Linux原生支持这个工具链;而Windows有这个工具链的修改版MinGW-w64可以编译32位和64位应用程序,可以进行Windows的系统调用,因此可以开发Windows应用程序。这些工具的命名及关系较为复杂,可以说很难搞清这一坨Twist。但简单来说,GCC应用广泛。
3.3 VSCode界面
VSCode界面大概可以分为几个部分:上方菜单,左侧工具栏,右侧编辑器视图区,以及下方集成终端。
4 准备工作
4.1 下载安装VSCode
请根据自己计算机平台的架构和操作系统,在官网选择合适的VSCode版本进行下载,安装过程与普通应用程序并无二致,网络上可以轻易搜索到相关教程。
4.2 下载安装工具链
Windows下:
官网下载MSYS2
MSYS2具有多种完整的Windows应用程序编译工具链,我们需要其中的mingw64来生成一些windows64程序。
Linux(Ubuntu 22.04.1)下:
我们使用自带的GCC编译生成linux下的应用程序。常见的Linux发行版自带GCC工具链,可以通过编译源码的方式更新。
5 配置步骤
5.0 熟悉VSCode界面
根据需求在VSCode的扩展市场搜索Chinese(Simplified)扩展并安装,重启后可以发现界面变中文。
按快捷键ctrl+shift+`
打开一个终端,终端默认与windows的shell相连接,终端区右上角显示powershell。shell是操作系统提供的与内核进行交互的应用程序。此时终端框中PS的目录显示为当前工作区目录。可以输入命令gcc -v
检查编译器是否安装完成。
*成功界面*
要检查C++编译器,请输入g++ -v
(查看详细信息)或g++ --version
(仅查看版本号)
5.1 创建并打开文件夹、新建文件
文件夹=目录。在不包含中文路径的目录中创建一个文件夹,然后将其在VSCode中打开。可使用资源管理器或文件->打开文件夹。该文件夹作为工作区目录,我选择的目录的绝对路径是C:\Users\Even\Desktop\note\CTest
打开后VSCode会在其中生成隐藏文件夹.vscode
用于保存相关配置信息,当前为空。
在文件夹内新建一个.c
文件,如ctt.c
,写一点代码内容:
1 |
|
此时可能会产生报错提示,因为VSCode编辑器并不知道包含printf
函数的<stdio.h>
的库的路径在哪。此时我们也没有代码补全等功能。
5.2 安装C/C++扩展
5.2.1 扩展简介与安装
C/C++扩展是微软开发和维护的C/C++插件,提供了代码补全、代码格式化、代码导航(跳转)、代码片段、符号搜索等多种功能,能大大提高代码编写效率。
在VSCode左侧工具栏扩展市场搜索C/C++扩展并安装即可。
5.2.2 扩展特性介绍
VSCode多数插件会将设置项存储在settings.json文件中,但C/C++扩展通过c_cpp_properties.json文件来配置编译器、头文件路径、C++标准等设置项。
5.3 配置扩展与任务
VSCode中常使用JSON文件管理各种配置信息、设置任务等。
5.3.1 创建编译任务
任务是VSCode的一类机制,可以将需要多次在命令行(shell/bash)中敲打的命令、命令选项及参数放在任务文件中,然后一键完成操作。
我们需要先创建一个编译任务。
在工作区中,按ctrl+shift+P
打开命令面板,输入任务,选择任务:配置任务–>C/C++:gcc.exe生成活动文件,
.vscode
文件夹内生成tasks.json
文件,选择添加设置项,可得
1 | { |
鼠标悬浮在属性选项上可查看属性详细信息。type
默认为cppbuild
,label
为该任务在命令面板上的标签,command
是编译器路径,请选择msys2软件安装目录下mingw64-->bin-->gcc.exe
。gcc.exe
会自动搜索系统环境变量、安装目录等地的C标准库函数以供编译使用。该编译器可编译出64位windows应用程序。
其他均为默认,若想修改.exe
文件输出目录,请修改args
的-o
参数后面的路径。也就是说,在命令行内也可执行类似gcc -g ctt.c -o ctt.exe
的命令来编译生成可执行文件,只不过我们利用任务脚本自动化了这一过程。此处的args
即为传给编译器程序gcc.exe
的命令参数列表。
请注意VSCode的目录格式中,\
方向和数量与Windows文件资源管理器不同。
配置保存完成,编辑器打开ctt.c
,按右上小三角运行C/C++文件,可以发现在工作区生成了ctt.exe
文件。请注意终端输出的信息。
5.3.2 创建调试任务
调试采用gdb.exe
调试器。按ctrl+shift+P
打开命令面板,输入C/C++:添加调试配置。发现.vscode
内生成了launch.json
文件。选择添加配置–>(gdb)启动,得到如下内容:
1 | { |
program
指定需要调试的可执行文件完整路径,cwd
为目标的工作目录,通常包含了源文件.c
文件和.h
文件。miDebuggerPath
指定了调试器路径,对于windows64位程序,可以采用msys2安装目录中mingw64
->bin
->gdb.exe
进行调试。
gdb通过创建tcp Socket连接到应用程序,可以通过这种方式交互调试信息。可以在终端内使用gdb ctt.exe
直接调试.exe
文件,但不够方便。这也是为什么在VSCode中配置工具链的原因。
路径等属性配置完成后,可以进入左侧工具栏中的虫子三角形菜单进行debug,可在.c
文件行号左端单击添加断点(红色)。打断点后再调试,运行到断点暂停时可以查看变量及堆栈等。同时请注意终端输出的信息。
5.3.3 为C/C++扩展配置文件
在工作区中,按ctrl+shift+P
打开命令面板,输入C/C++编辑配置,找到选项并确定,会在.vscode
中生成一个c_cpp_properties.json
文件,内容与注释如下:
1 | { |
形如${workspaceFolder}
的参数是VSCode的变量,该变量为当前工作区。更多类似变量参考这里。
当.c
文件引用了不是C标准库内或不在工作区的函数时,需要将其头文件路径添加到includePath
属性内,以,
分隔,可选绝对路径或相对路径,一般是结合${}
等变量使用的相对路径,方便代码工程的移动。
以后复杂的工程常常需要拆分成多个.c
源文件和.h
头文件,因此需要用到includePath
来管理。
**
为通配符,请自行了解VSCode的通配符机制。类似于正则表达式,可以实现某一类文件的选取。
6 依据类似步骤配置一个C++工作区环境并完成运行和调试
上述工作基本与C++配置的内容相同,有所不同的是C++
的编译器是g++。exe
,调试器也是gdb.exe
注意事项
- ==务必保证所有的路径、文件名中不要出现中文等非ASCII字符==