目录
[一、gcc 编译器](#一、gcc 编译器)
[1.1 gcc的编译过程](#1.1 gcc的编译过程)
[1.1.1 预处理](#1.1.1 预处理)
[1.1.2 编译](#1.1.2 编译)
[1.1.3 连接(链接)](#1.1.3 连接(链接))
[1.1.4 汇编](#1.1.4 汇编)
[1.2 gcc的使用](#1.2 gcc的使用)
[(1) 安装命令(有些系统会默认安装):](#(1) 安装命令(有些系统会默认安装):)
[(2) 单个文件生成可执行文件命令:](#(2) 单个文件生成可执行文件命令:)
[(3) 多文件生成可执行文件](#(3) 多文件生成可执行文件)
[3.1 gdb的使用](#3.1 gdb的使用)
[(1) 使用gcc编译包含标准调试信息的可执行文件](#(1) 使用gcc编译包含标准调试信息的可执行文件)
[(2) 启动gdb进入调试](#(2) 启动gdb进入调试)
[(3) 查看载入的文件](#(3) 查看载入的文件)
[(4) 设置断点](#(4) 设置断点)
[(5) 查看断点](#(5) 查看断点)
[(6) 运行代码](#(6) 运行代码)
[(7) 查看变量值](#(7) 查看变量值)
[(8) 单步运行](#(8) 单步运行)
[(9) 恢复运行](#(9) 恢复运行)
[(10) gdb命令](#(10) gdb命令)
[4.1 makefile](#4.1 makefile)
[4.2 makefile的规则](#4.2 makefile的规则)
[4.3 自动变量](#4.3 自动变量)
[5.1 为什么要cmake](#5.1 为什么要cmake)
[5.2 安装](#5.2 安装)
[5.3 使用](#5.3 使用)
[5.4 编写CMakeList.txt](#5.4 编写CMakeList.txt)
[5.4.1 代码源文件不多,并且处于同一目录下](#5.4.1 代码源文件不多,并且处于同一目录下)
[5.4.2 代码源文件很多,并且处于同一目录下时](#5.4.2 代码源文件很多,并且处于同一目录下时)
[5.4.3 源文件多并且处于不同的目录下](#5.4.3 源文件多并且处于不同的目录下)
[5.5 执行cmake](#5.5 执行cmake)
一、gcc 编译器
GCC 编译器是 Linux 系统下最常用的 C/C++ 编译器,GCC 编译器通常以gcc命令的形式在终端(Shell)中使用,它有很多选项,这是我们要重点学习的。
gcc能够在当前CPU平台上为多种不同体系结构的硬件平台开发软件,因此适合在嵌入式领域开发编译。
1.1 gcc的编译过程
1.1.1 预处理
gcc首先对源代码文件中的**文件包含(include)、预编译语句(如宏定义define等)**进行分析处理。
1.1.2 编译
用GCC编译C/C++代码时,它会试着用最少的时间完成编译并且编译后的代码易于调试。易于调试意味着编译后的代码与源代码有同样的执行顺序,编译后的代码没有经过优化。
1.1.3 连接(链接)
当所有的目标文件都生成之后,gcc就调用ld(链接器)来完成最后的关键性工作,这个阶段就是连接。在连接阶段,所有的目标文件被安排在可执行程序中的恰当的位置,同时,该程序所调用到的库函数也从各自所在的档案库中连到合适的地方。
1.1.4 汇编
汇编过程是针对汇编语言的步骤,调用as进行工作,一般来讲,.S为后缀的汇编语言源代码文件和汇编、.s为后缀的汇编语言文件经过预编译和汇编之后都生成以.o为后缀的目标文件。
1.2 gcc的使用
(1) 安装命令(有些系统会默认安装):
bash
sudo apt install gcc
(2) 单个文件生成可执行文件命令:
bash
gcc test.c -o test.out
- o选项可以指定生成文件的名称和类型,如果不指定,则直接生成 a.out
(3) 多文件生成可执行文件
bash
gcc -c add.c -o add.o
gcc -c suntraction.c -o subtraction.o
gcc -c main.c -o main.o
gcc main.o add.o subtraction.o -o test.out
|--------|-----------------------------|
| 选项 | 含义 |
| -c | 把预处理、编译、汇编都做了,但是不链接(.o) |
| -S | 只编译不汇编,生成汇编代码 |
| -E | 只进行预编译,不做其他处理 |
| -g | 在可执行程序中包含标准调试信息 |
| -o | 将 file 文件指定为输出文件 |
| -v | 打印出编译器内部编译各过程的命令行信息和编译器的版本 |
| -I | 指定头文件目录 |
| -L | 指定链接时库文件目录 |
二、使用虚拟机的共享文件夹
我们在Windows下写代码,然后到Linux下编译,是一种常见的编程方式。流程如下:
- 在Windows上创建文件夹
- 设置虚拟机共享
- linux上创建文件夹
- sudo mkdir -p /mnt/hgfs/myshare
- 关联两个系统下的文件夹(挂载)
- sudo mount -t vboxsf share /mnt/hgfs/myshare
- 查看是否关联成功
- ls
三、gdb调试器
在写代码的过程中,经常需要对代码进行调试,虽然调试器并不是代码执行过程中必备的,但确是一个必不可少的组成部分。
gdb就是多数Linux开发人员使用的调试器,可以方便的设置断点进行代码调试。
我们在Windows下面,会用到类似于DevC++这样集成编译器、编辑器、调试器一体的开发工具,而我们在Linux下面更多的则是使用Vim、gcc等。
3.1 gdb的使用
(1) 使用gcc编译包含标准调试信息的可执行文件
bash
gcc -g test.c -o test.out
(2) 启动gdb进入调试
bash
gdb test.out
进入调试后,在gdb的启动过程会输出gdb当前的一些信息,随后会显示到(gdb)开头的命令

(3) 查看载入的文件
(gdb) l
输入"l"(list)指令,不仅可以查看文件代码,还可以查看左边的行号,方便我们对代码进行定位。

(4)设置断点
(gdb) b 5
输入"b 行号"指令(b的英文指的是BreakPoint),可以在指定的行号设置一个断点。
(5) 查看断点
(gdb) info b
可以使用"info b",查看当前设置的断点情况。
(6) 运行代码
(gdb) r //从首行开始运行代码
(gdb) r 5//如果想从指定行开始运行,可以在r后面加行号
**输入"r"(run)**即可运行代码,并且程序会在断点行执行前停止。
(7) 查看变量值
(gdb) p a //查看当前变量a的值
**输入"p 变量名"**即可查看当前变量的值;可以在调试时直接使用$X来访问变量。
(8) 单步运行
(gdb) n //n指的是next的缩写,使用n命令会让代码往下执行,并且不进入具体的函数。
(gdb) s //s指的是step的缩写,也会让代码往下执行,但如果遇到函数,会跳转到函数。
(9) 恢复运行
(gdb) c //c指的是continue,会把没有执行完的代码执行完毕
代码执行完毕后,程序处于停止状态。
(10) gdb命令
gdb有很多命令,我们可以使用help来查看。
(gdb) help //直接查看所有命令
(gdb) help n //查看n命令说明
四、make工程管理器
一个工程中的源文件不计其数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作。
4.1 makefile
- makefile是make工程管理的配置文件,我们只需要关注makefile文件的编写规则,即可使用make。
- make以及makefile本身并不具备编译功能,但是它们可以很好地协调、沟通gcc这样的编译器。
4.2 makefile的规则
在makefile文件中,通常包含如下内容:
- 最终需要生成的文件或者可执行文件
- 创建最终文件所需要依赖的文件
- 创建可执行文件、依赖文件所时所需要运行的命令
格式如下:
最终生成的文件:依赖文件
所需要的命令 //这里需要遵循makefile的规则,使用Tab键添加一个缩进,表示声明的是命令
举个例子:以加减法多文件项目为例,咱们有main.c、add.c、subtraction.c 文件,最终需要生成一个可执行文件,需要分别编译生成main.o、add.o、subtraction.o,然后再将他们编译后的文件链接起来,生成可执行文件,过程很繁琐。但我们可以使用makefile来完成这件事情。
html
main.out:main.o add.o subtraction.o
gcc main.o add.o subtraction.o -o main.out
main.o:main.c
gcc -c main.c -o main.o
add.o:add.c
gcc -c add.c -o add.o
subtraction.o:subtraction.c
gcc -c subtraction.c -o subtraction.o
html
make //使用make指令,make会自行查找当前目录下的makefile,执行其中的规则,从而执行编译命令
html
clean:
rm -f *.o main.out //删除当前目录下的所有.o文件以及main.out文件
4.3 自动变量
我们可以使用自动变量来编写makefile,这样可以简化工作量。
和上面同样的makefile我们可以这样写:
html
main.out:main.o add.o subtraction.o
gcc *.o -o $@
%.o:%.c
gcc -c $< -o $@
- * 指的是当前目录下所有的同类型文件。
- % 指的是当前makefile文件中的所有文件。
|------|-------------------------------------|
| 自动变量 | 含义 |
| \* | 不包含扩展名的目标文件名称 |
| + | 所有的依赖文件,以空格分开,并以出现的先后为序,可能包含重复的依赖文件 |
| \< | 第一个依赖文件的名称 |
| ? | 所有时间戳比目标文件晚的依赖文件,并以空格分开 |
| @ | 目标文件的完整名称 |
| ^ | 所有不重复的依赖文件,以空格分开 |
| $% | 如果目标是归档成员,则该变量表示目标的归档成员名称 |
五、cmake
cmake是一款跨平台项目构建工具,可以用简单的语句来描述所有平台的编译过程,能够输出各种各样的makefile或者project文件。
cmake 可以编译源代码、制作程序库、产生适配器(wrapper)、还可以用任意的顺序建构执行档。
5.1 为什么要cmake
决定代码的组织方式及其编译方式,也是程序设计的一部分。因此,我们需要cmake和autotools这样的工具来帮助我们构建并维护项目代码。
不同Make工具遵循着不同的规范和标准,所执行的 Makefile 格式也千差万别。如果软件想跨平台,必须要保证能够在不同平台编译。而如果使用上面的 Make 工具,就得为每种标准写一次Makefile。
cmake和autotools正是makefile的上层工具,它们的目的正是为了产生可移植的makefile,并简化自己动手写makefile时的巨大工作量。我们可以编写一个与平台无关的文本文件来制定整个编译流程,来解决跨平台需要多个makefile的问题。
5.2 安装
html
sudo apt install cmake //安装cmake
cmake -version //查看版本
sudo apt install g++ //安装cmake所依赖的g++(gcc)
5.3 使用
- 编写 CMake 配置文件 CMakeLists.txt 。
- 执行命令 cmake PATH 生成 Makefile。其中, PATH 是 CMakeLists.txt 所在的目录。
- 使用 make 命令进行编译。
5.4 编写CMakeList.txt
5.4.1 代码源文件不多,并且处于同一目录下
html
./more3
|
+---main.c
|
+---add.c
|
+---add.h
|
+---subtraction.c
|
+---subtractuon.h
html
#指定cmake运行本配置文件最低版本号要求
cmake_minimum_required(VERSION 3.10.2)
#项目名称信息
project(Demo)
#将这些c文件编译成Demo.out
add_executable(Demo.out main.c add.c subtraction.c)
5.4.2 代码源文件很多,并且处于同一目录下时
html
./more3
|
+---main.c
|
+---add.c
|
+---add.h
|
+---subtraction.c
|
+---subtractuon.h
|
#假如还有很多源文件....
html
#指定cmake运行本配置文件最低版本号要求
cmake_minimum_required(VERSION 3.10.2)
#项目名称信息
project(Demo)
#查找当前目录下所有源文件,并将名称保存到DIR_SRCS变量
aux_source_directory(. DIR_SRCS)
#生成指定目标文件Demo.out
add_executable(Demo.out ${DIR_SRCS})
源文件多并且处于不同的目录下
5.4.3 源文件多并且处于不同的目录下
html
./more3
|
+---main.c
|
+---math/
|
+---add.c
|
+---add.h
|
+---subtraction.c
|
+---subtractuon.h
对于这种情况,我们会在根目录以及不同的子目录下各编写一个CMakeLists.txt文件,然后将子目录里的文件编译成静态库,供main调用。
html
#根目录下的CMakeLists.txt
#指定cmake运行本配置文件最低版本号要求
cmake_minimum_required(VERSION 3.10.2)
#项目名称信息
project(Demo)
#查找当前目录下所有源文件,并将名称保存到DIR_SRCS变量
aux_source_directory(. DIRSRCS)
#编译math目录内的头文件
include_directories(./math)
#添加math子目录
add_subdirectory(math)
#生成指定目标文件Demo.out
add_executable(Demo.out main.c)
#添加链接库
target_link_libraries(Demo.out MathFunctions)
html
#子目录下的CMakeLists.txt
# 查找当前目录下的所有源文件,并将名称保存到 DIRS 变量
aux_source_directory(. DIRS)
# 生成链接库 这里的MathFunctions要和根目录下CMakeLists.txt中target_link_libraries对应!
add_library (MathFunctions ${DIRS})
5.5 执行cmake
html
cmake CMakeList.txt所在位置 #执行cmake生成makefile文件
make #运行makefile编译