Linux编程笔记2【个人用】

目录

[一、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) 多文件生成可执行文件)

二、使用虚拟机的共享文件夹

三、gdb调试器

[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命令)

四、make工程管理器

[4.1 makefile](#4.1 makefile)

[4.2 makefile的规则](#4.2 makefile的规则)

[4.3 自动变量](#4.3 自动变量)

五、cmake

[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编译