【Linux】linux基础开发工具的使用

avatar
作者
猴君
阅读量:0

文章目录

在这里插入图片描述

1. linux编译器gcc/g++的使用

我们都知道,源文件要想得到一个可执行程序,必须经历以下四个阶段:

  • 预处理(进行宏替换)
  • 编译(生成汇编)
  • 汇编(生成机器可识别代码)
  • 连接(生成可执行文件或库文件)

在集成开发环境(IDE)中,这四步通常被封起来了,一般我们执行一段代码就会直接默认执行了这四步。

那么在linux下,gcc该如何完成呢?

  1. 预处理(进行宏替换)
  • 预处理功能主要包括宏定义,文件包含,条件编译,去注释等。
  • 预处理指令是以#号开头的代码行。
  • 实例: gcc -E hello.c -o hello.i
  • 选项“-E”,该选项的作用是让 gcc 在预处理结束后停止编译过程。
  • 选项“-o”是指目标文件,“.i”文件为已经过预处理的C原始程序。

在这里插入图片描述

  1. 编译(生成汇编)
  • 预处理结束后,在这个阶段中,gcc 首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作。
  • 在检查无误后,gcc 把代码翻译成汇编语言。
  • 用户可以使用“-S”选项来进行查看,该选项只进行编译而不进行汇编,仅生成汇编代码
  • 实例: gcc –S hello.i –o hello.s

在这里插入图片描述

  1. 汇编(生成机器可识别代码)
  • 汇编阶段是把编译阶段生成的“.s”文件转成目标文件
  • 读者在此可使用选项“-c”就可看到汇编代码已转化为“.o”的二进制目标代码
  • 实例: gcc –c hello.s –o hello.o

在这里插入图片描述

  1. 连接(生成可执行文件或库文件)
  • 在成功编译之后,就进入了链接阶段。
  • 实例: gcc hello.o –o hello

在这里插入图片描述

链接这里设计一个概念:函数库

我们的C程序中,并没有定义“printf”的函数实现,且在预编译中包含的“stdio.h”中也只有该函数的声明,而没有定义函数的实现,那么是在哪里实现的“printf”函数呢?
答案是:系统把这些函数实现都被做到名为 libc.so.6 的库文件中去了,在没有特别指定时,gcc 会到系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 库函数中去,这样就能实现函数“printf”了,而这也就是链接的作用。

而且函数库一般分为两种:静态库与动态库

  • 静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了,其后缀名一般为“.a”。
  • 动态库与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时与运行时链接文件加载库,这样可以节省系统的开销。动态库一般后缀名为“.so”,如前面所述的 libc.so.6 就是动态库。gcc 在编译时默认使用动态库。完成了链接之后,gcc 就可以生成可执行文件。

总结:
在这里插入图片描述

2. 项目自动化构建工具make/Makefile

一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作

  • makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。
  • make是一个命令工具,是一个解释makefile中指令的命令工具
  • make是一条命令,makefile是一个文件,两个搭配使用,完成项目自动化构建。

那我们就先来见一见make与makefile的使用:

首先要创建一个文件,名字可为makefile / Makefile,而且要事先准备好一份待编译的代码
在这里插入图片描述

在这里插入图片描述
此时,我们就不需要再单独写gcc命令了,只需要make一下,make就会自动找Makefile文件,然后解释文件中的命令,形成可执行程序。
此时我们仅有一个文件还看不出它的好处,如果我们有多个文件,仅仅只需要在Makefile中写一次每个文件的gcc命令,然后仅需要make,就可以生成可执行程序了。

下面我们来分析一下语法:
在这里插入图片描述

既然有构建,那就需要清理

此时clean的依赖列表为空
在这里插入图片描述

在这里插入图片描述

但是,此时多make几次你就会发现一个问题,他会提示你可执行程序已经是最新了,不支持编译了,这是为什么呢?

在这里插入图片描述

这是make的一种机制,由于在大型的工程中,代码编译一次的时间可能很长,如果你的源文件没有修改,那就没有必要再次编译,所以在make执行前会比较文件的时间。

可使用stat + 文件名查看文件的时间。

  • Modify表示文件内容的修改时间
  • Change表示文件属性的修改时间

在这里插入图片描述

所以,为了每次都可以编译,我们可以这样写:使用PHONY,后面跟一个伪目标名该命令会让伪目标对应的方法总是被执行
在这里插入图片描述
但我们一般不会对构建时设置PHONY,都是对清理时设置。
然而由于rm本身就不关心时间,所以写不写的效果都一样。但由于依赖方法可以是任意行指令,所以除了rm,clean后面可能还有其它命令,所以一般都加上。
在这里插入图片描述
在这里插入图片描述

由于make命令会回显命令,所以可以在命令前+@关闭回显。
在这里插入图片描述

注意:

执行make命令时,make会在当前目录下找名字叫“Makefile”或“makefile”的文件。
如果找到,它会在文件中找目标文件,如果目标文件名省略,它会找遇到的第一个目标文件,所以我们上面只写make就可以执行gcc命令(完整应该是:make demo)

到这里,我们就可以使用简单的make、makefile了。

但是如果要完整的写出编译过程。我们并不是使用demo.c源文件直接形成demo可执行文件的。
我们都是demo.c->demo.i->demo.s->demo.o->demo

在这里插入图片描述
其推导过程类似于栈,直到有依赖文件后就到栈的出口了。

但是平常我们也不会按照这种方法写,因为太麻烦了,我们一般会先生成 .o文件,然后再使用.o直接生成可执行文件
在这里插入图片描述

为了书写方便,makefile中引入了新的特殊符号:%、$、<

在这里插入图片描述

在Makefile中,也可以定义变量
在这里插入图片描述

执行make就会自动替换掉特殊符号

在这里插入图片描述

此时如果想改变形成的可执行程序名,可直接修改bin。

在这里插入图片描述

但我们的Makefile依然不是最终版本,src不想使用.o了,太麻烦,如果我们要用源文件形成目标文件该怎么写呢?
在这里插入图片描述

此时我们就可以使用一批源文件生成目标文件了

在这里插入图片描述

但如果我们要形成多个可执行程序呢?
假如我有两个.c文件,它们都包含main函数,那该怎么办呢?–定义多个变量呗
但是由于make默认只形成一个可执行,所以我们要采取特殊的方法

在这里插入图片描述

我们定义一个伪目标,该伪目标的依赖关系是两个可执行文件,没有依赖方法;因此makefile就会自动推导两个依赖关系,依次执行它们依赖方法,此时就达到了形成两个可执行的目的。

在这里插入图片描述

因此,以后再对代码进行编译时,可先写一个makefile,就可以简化操作。

同时编译两个.c文件
在这里插入图片描述

3. git版本控制器

3.1 提交本地至远程四步(三板斧)

  1. git colne

git clone + 仓库链接 (将git仓库克隆至本地)

  1. git add

git add + 文件名(将文件添加到git的暂存区)

  1. git commit

git commit -m + "文件描述"
(它用于将暂存区中的更改记录为一个新的提交。每次执行 git commit,都会在当前分支上创建一个新的提交节点,这个节点包含了自上次提交以来所做的所有更改。)

  1. git push

将本地仓库的更改推送到远程仓库

3.2 查看

  1. git log

git log 命令是 Git 版本控制系统中的一个非常有用的命令,它用于显示提交日志信息
这个命令可以显示出一个或多个分支上的提交记录,包括每次提交的哈希值、作者、日期和提交信息。

  1. git status

git status 命令用于显示当前工作目录和暂存区的状态。这个命令可以帮助你了解哪些文件已经被修改、哪些文件已经被添加到暂存区、以及哪些文件还没有被跟踪。

4. gdb调试工具

程序的发布方式有两种,debug模式和release模式;Linux gcc/g++出来的二进制程序,默认是release模式。

要使用gdb调试,必须在源代码生成二进制程序的时候, 加上-g选项
在这里插入图片描述

4.1 调试的启动与退出

若想启动调试,需使用 gdb + 可执行文件名

在这里插入图片描述
退出调试,在gdb下输入 q(quit)即可

4.2 源代码的显示与程序的运行

  • 显示源代码:gdb下输入 l (list) + 行号,每次会列10行。再按enter继续执行
  • 运行程序:gdb模式下,输入r (run)。

在这里插入图片描述

4.3 断点的设置、删除与查看

默认没有断点时,运行时会从头到尾执行完,若想让代码停下来,需要打断点。

设置断点的三种方式:

  • b (break) + 行号:指定行出打断点
  • b + 函数名:会在函数的第一条语句处打断点
  • b + 文件名 : 行号/函数:在指定文件的指定位置打断点

在这里插入图片描述
那我设置了断点以后如何查看呢?

查看断点信息:info / i + b

在这里插入图片描述

删除断点:delete/d + 断点编号

此时我们会发现,当一个断点删除后,其余断点的编号不会随之改变

在这里插入图片描述

而且再设置新的断点也不会使用之前的编号,即使所有断点全部被删除了。

在这里插入图片描述

而且如果中途退出了调试,所有的断点信息就没了。

4.4 逐过程、逐语句、查看变量

断点设置好以后,此时再次运行程序会跳至第一个断点处

  • 逐过程:n (next)
  • 逐语句:s (step)
  • 若当前语句不是函数调用时,n 与 s 等效。

在这里插入图片描述

在调试过程中,我们如何查看变量信息呢?

若想查看变量信息:

  • 查看变量内容:p + 变量名
  • 查看变量地址:p + &变量名

在这里插入图片描述
但此时在运行别的语句时,变量的信息不会一直显示,只有你输入 p + 变量名时才显示,那如何让变量一直显示呢?

  • display+ 变量名 : 常显示变量内容
  • undisplay + 变量编号: 取消常显示。此处的变量编号也不会被再次使用,除非退出再重新调试

在这里插入图片描述

取消常显示

在这里插入图片描述

4.5 快速执行代码块的三种方式

  1. until

直接运行至指定位置:until + 行号

在这里插入图片描述

  1. finish

运行完整个函数:finish

在这里插入图片描述

  1. continue / c

直接运行至下个断点处

在这里插入图片描述

4.6 其它

  1. 禁止与恢复断点

有时我们想让某个断点失效该怎么办呢?

  • disable + 断点编号 : 使某断点失效
  • enable + 断点编号: 恢复某个断点

在这里插入图片描述

在这里插入图片描述

  1. 调试时修改变量的值(类似于条件断点)

修改变量的值:set var 变量名 = 新的值

在这里插入图片描述

  1. 查看各级函数调用及参数

breaktrace:查看各级函数调用及参数(类似于vs中的调用堆栈)

在这里插入图片描述

  1. 查看局部变量的值

info / i + locals:查看当前函数内局部变量的值。

    广告一刻

    为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!