【Linux】vim(附配置sudo)、yum、gcc、g++、gdb、make/Makefile工具汇总

一、Linux软件包管理 - yum

1、yum背景知识

(一)历史沉淀

我们在安装一个软件之前,需要先下载对应的软件包,但是这个软件包并不存在于我们本地的计算机磁盘,而是存在于远端服务器上;那么计算机如何知道该软件存在于具体的哪一台服务器上呢?

对于电脑来说,我们一般通过搜索对应软件的官网来得到相应软件包;对于手机来说,表面上我们通过手机自带的应用商店来下载软件包,但实际上应用商店里面并不存在软件包,而只是存在着对应软件官网的链接,最后我们的软件包还是从官网上下载的;

其次,这些软件包是由谁提供的呢?答案很明显,它们是由一些企业、组织或个人提供的;这些企业、组织以及个人为了某种利益编写出了软件包,然后将其放在了对应的服务器上。

yum (Yellow dog Updater, Modified) 是Linux下非常常用的一种包管理器;主要应用在 Fedora, RedHat,Centos 等发行版上;软件包和软件包管理器, 就好比 “App” 和 “应用商店” 这样的关系。

(二)认识yum

在Linux下安装软件的方法大概有以下三种:

1)下载到程序的源代码,自行进行编译,得到可执行程序。
2)获取rpm安装包,通过rpm命令进行安装。(未解决软件的依赖关系)
3)通过yum进行安装软件。(常用)

注意:一个服务器同一时刻只允许一个yum进行安装,不能在同一时刻同时安装多个软件。 

(三)yum软件本土化

我国的一些高校以及公司就 镜像了国外的软件服务,即把国外服务器上的软件拷贝到了国内自己公司的服务器上,使得我们可以直接访问国内的服务器来下载软件;

但是只拷贝软件还不行,因为 yum 中下载软件时默认访问的链接还是国外的,所以这些高校/公司还提供了一套国内的下载链接配置文件 – yum 源配置文件;

在Linux中,yum 源配置文件是存在于 /etc/yum.repos.d/ 目录下的 CentOS-Base.repo 文件:

ll /etc/yum.repos.d/

 如果你使用的是云服务器,那么 yum 源一般都是配置好的,虚拟机的配置方法会更麻烦一点,而且还需要利用ping值检查网络是否处于连接状态


2、yum三板斧基本使用

(一)查看软件包

yum list

但是这样出来的东西很多很杂 

我们可以通过 yum list 命令罗列出当前一共有哪些软件包;但由于包的数目非常之多, 所以我们一般使用 grep 命令来筛选出我们关注的包;如:

grep指令http://t.csdn.cn/g1aDI

yum list| grep 要搜索的内容

 注意事项:

  • 软件包名称构成:主版本号.次版本号.源程序发行号-软件包的发行号.主机平台.cpu架构;
  • “x86_64” 后缀表示64位系统的安装包,“i686” 后缀表示32位系统安装包,选择包时要和系统匹配;
  • “el7” 表示操作系统发行版的版本: “el7” 表示的是 centos7/redhat7,“el6” 表示 centos6/redhat6;
  • 最后一列中 base 表示的是 “软件源” 的名称, 类似于 “小米应用商店”, “华为应用商店” 这样的概念;

拓展:rzsz本地机器与云服务器之间的文件互传

rz:上传文件(其实Windows直接拖到xshell中也是可以的)

 

 sz:将xshell文件给到Linux 这个没有办法拖 因为Linux下的文件不像windows一样,是可以找到实体的

(二)安装软件

指令: sudo yum install(可以加-y) 软件名 

(其中 -y 代表不询问直接安装)(sudo是因为只有root才可以装)

 

 

安装完毕 

sl命令不同于ls命令,sl命令是以动画形式呈现小火车的趣味性命令,虽无实用价值,但亦可陶冶情操,愉悦心情。

有一些软件并没有被纳入 Centos、Ubuntu、Kail等相关生态平台的官方软件集合中,如果我们想使用这些软件,需要安装 非官方软件集合列表 – epel-realse

注意事项:

  • 安装软件时由于需要向系统目录中写入内容,一般需要 sudo 或者切到 root 账户下才能完成;
  • yum安装软件只能一个装完了再装另一个;正在yum安装一个软件的过程中,如果再尝试用yum安装另外一个软件,yum会报错;
  • 软件和软件之间是有关联的,即具有一定的耦合度; yum 为了解决软件之间相互依赖的问题,有时候在安装一个软件会连带安装其他一些软件。

(三)卸载软件

指令: sudo yum remove -y 软件名

注意:关于 yum 的所有操作必须保证主机 (虚拟机) 网络畅通;可以通过 ping 指令验证网络

ping + 网站名字 就可以查看现在网络是否健康

由于我将我的Linux配置成了 ctrl+c 是复制 ,那么也就是说 

ctrl+shift+c 就是强制退出执行程序的代码


 二、Linux编辑器 - vim(别用root配置)

为什么别用root配置 请看第5点

1、vim的基本概念

vim 是一个编辑器 和windows下的记事本没有任何区别

这个编辑器有一个好处 是一个功能强大 多模式的编辑器 

vim 一共有12种模式,我们目前掌握其中三种模式即可,分别是命令模式(command mode)、插入模式(Insert mode)和底行模式(last line mode),各模式的功能区分如下:

  • 正常/普通/命令模式 (Normal mode)

存在的意义:通过各种各样的命令,来简化操作,加快使用效率

控制屏幕光标的移动,字符、字或行的删除;

移动复制某区段以及进入Insert mode下,或者到 last line mode;

  • 插入模式 (Insert mode)

只有在Insert mode下,才可以做文字输入;

按「ESC」键可回到命令行模式,该模式是我们后面用的最频繁的编辑模式

  • 底行模式 (last line mode)

文件保存或退出,也可以进行文件替换,找字符串,列出行号等操作;

在命令模式下,输入 : 即可进入该模式;

我们可以在底行模式下输入 “ :help vim-modes” 来查看 vim 的所有模式。

2、vim模式下的切换

我们使用 vim 打开一个文件时默认处于命令模式,然后我们可以通过如下指令切换到其他模式:

vim test.c (后面写的是 touch的文件名字)

 打开是黑黑的这个 这个就是命令模式

【命令模式】切换至【插入模式】

  • 输入「i」:在当前光标处进入插入模式(我一般用i insert 多好记 但是也别忘了别的)
  • 输入「a」:在当前光标的后一位置进入插入模式
  • 输入「o」:在当前光标处新起一行进入插入模式

按完之后,左下角就是insert了

【命令模式】切换至【底行模式】

  • 输入「Shift+;」即可,实际上就是输入「:」

左下角变成这样,那么就是底行模式 

【插入模式】或【底行模式】切换至【命令模式】

  • 插入模式或是底行模式切换至命令模式都是直接按一下「Esc」键即可

 3、vim命令模式各命令汇总

(一)移动光标

  1. $ : 将光标移动到行尾;
  2. ^ :将光标移动到行首;
  3. G : 将光标移动到文件末尾;
  4. gg : 将光标移动到文件开头;
  5. n + G : 将光标移动到第 n 行;
  6. h j k l :将光标向 左 下 上 右 移动;j:jump 向下跳 k:king 皇帝至高无上

(二)复制粘贴

  1. yy :复制当前行 (nyy:从当前行开始向下复制n行);
  2. p :粘贴一次 (np:粘贴n次);

(三)撤销操作

  1. u : 撤销操作 (后退一步);
  2. ctrl + r:取消撤销操作 (前进一步);

(四)剪切

  1. dd : 删除当前行 (ndd:从当前行开始向下删除n行);
  2. ndd:剪切光标所在行开始往下的n行
  3. p:将已剪切的内容在光标的下一行粘贴上
  4. np:将已剪切的内容在光标的下一行粘贴n次

小羊注:vim 下的所有删除操作都相当于 Windows 下的剪切操作

(四)大小写切换

  1. ~ : 切换光标所在字符的大小写 (可点按,按一个切换一个)
  2. n~:完成光标所在位置开始往后的n个字符的大小写切换

(五)替换

  1. rx : 将光标所在字符替换为x字符 (nrx:将光标所在字符开始往后的n个字符都替换为x字符);
  2. R : 批量化替换,即切换为替换模式,用键盘输入的字符替换光标所在字符,且替换之后光标自动后移,等待替换下一个字符;我们最后需要输入 [Esc] 从替换模式切回命令模式;

(六)更改

  1. w :将光标跳转到下一个字的第一个字符处 (nw:将光标跳转到下n个字的第一个字符处);
  2. cw :更改光标所在处的字到字尾处,和 R 一样,此命令会让我们跳转到插入模式
  3. cnw:更改n个字;

 (七)删除

  1. x : 删除光标所在字符 (nx:删除光标所在字符开始往后的n个字符);
  2. X :删除光标所在字符的前一个字符 (nX:删除删除光标所在字符的前n个字符);
  3. dd : 删除当前行 (ndd:从当前行开始向下删除n行);

(八)翻页

  1. Ctrl+b:上翻一页
  2. Ctrl+f:下翻一页
  3. Ctrl+u:上翻半页
  4. Ctrl+d:下翻半页

4、vim底行模式各命令汇总

小羊注:在使用底行模式之前,记住先按「Esc」键确定你已经处于命令模式,再按「:」即可进入底行模式

(一)行号设置

  1. set nu:显示行号
  2. set nonu:取消行号

(二)保存退出

  1. w:保存文件。
  2. q:退出vim,如果无法离开vim,可在「q」后面跟一个「!」表示强制退出。
  3. wq:保存退出

(三)分屏指令

  1. vs 文件名:实现多文件的编辑。
  2. Ctrl+w+w:光标在多屏幕下进行切换。

(四)执行指令

  • !+指令:在不退出vim的情况下,可以在指令前面加上「!」就可以执行Linux的指令,例如查看目录、编译当前代码等。

将来提权sudo的时候 会用到!

5、vim的简单及一键配置

 在目录 /etc/ 下面,我们可以找到有一个名为 vimrc 的文件,这是系统中公共的vim配置文件,对所有用户都有效

所以我们要对 vim 进行一些其他的基本配置,使得我们能够在便捷的在vim中编写C/C++程序;特别注意:

虽然Linux中的所有用户使用的都是同一个vim程序,但是大家使用的是不同的vim配置,因为每个用户的家目录下都会有一个属于自己的 .vimrc 文件,这个文件中保存的就是专属于这个用户的 vim 配置。所以我在vim的基本使用上面写别用root,以免将来配置出现问题。

一些简单的vim配置:

  • 设置语法高亮: syntax on;
  • 显示行号: set nu;
  • 设置缩进的空格数为4: set shiftwidth=4;

先用vim进入.vimrc

之后检查发现已经全部写好


但是有没有一键配置的方法?? 答案是有的

curl -sLf https://gitee.com/HGtz2222/VimForCpp/raw/master/install.sh -o ./install.sh && bash ./install.sh

大家复制这个到xshell 并且执行 下面我和大家一起配置:

接着我们输入root密码:

 然后我们输入 “source ~/.bashrc” 或者重启终端即可使 vim 配置失效:

可以看到,配置完成后的 vim 不仅会显示当前模式、文件名、字符个数,还支持自动缩进、自动补齐 (语法、括号、引号等等)

 但是这里存在一个小问题:此处的自动缩进默认是两个字符,而我们编写C/C++程序时一般都要求缩进四个字符,所以我们需要打开 .vimrc 文件对默认缩进进行修改:

 

 至此,我们的 vim 一键配置就完成了!!!!! 欢呼!!!

 6、sudo提权

我们往往用su 或者 su- 来让我们变成root执行yum等等只有root才可以执行的命令

但是我们在提权的时候,我们的身份通过whoami查询后变成了root

sudo就是一个可以不改变身份但拥有root权力的短暂提权指令,但是往往都需要配置,这是不配置的情况:

那么这个时候就需要用vim打开文件进行配置了

vim(空格)/etc/sudoers

 注意vim后面要加空格

 在这波操作中注意事项:

1. xiao_yang并不在受信任的用户里面,所以得添加

2.因为是只读文件,这个时候感叹号就派上用场了,我先保存,之后再强制退出

现在,我们就可以在普通用户下使用 sudo 对指令进行提权了:

这个时候在配置完之后很容易发现,就成功可以提权啦!! 


三、Linux编译器 - gcc/g++

1、gcc/g++的作用

gcc和g++分别是GNU的C和C++的编译器,gcc和g++在执行编译的时候一般有以下四个步骤
1)预处理(头文件展开、去注释、宏替换、条件编译)。
2)编译(C代码翻译成汇编语言)。
3)汇编(汇编代码转为二进制目标代码)。
4)链接(将汇编过程产生的二进制代码进行链接)。

2、gcc/g++语法

语法: gcc/g++ 选项 文件

常用选项:

-E 只进行预处理,这个不生成文件,你需要把他重定向到一个输出文件里面(否则将把预处理后的结果打印到屏幕上,我们gcc -E 又加-o 就是因为全部写在屏幕上杂乱无章)


-S 编译到汇编语言,不进行汇编和链接,即只进行预处理和编译。

(照样不生成文件,也是打印在屏幕上的)


-c 编译到目标代码


-o 将处理结果输出到指定文件,该选项后需紧跟输出文件名。(也就是有生成文件的能力)


-static 此选项对生成的文件采用静态链接。


-g 生成调试信息(若不携带该选项则默认生成release版本)。


-shared 此选项将尽量使用动态库,生成文件较小。


-w 不生成任何警告信息。


Wall 生成所有警告信息。


-O0/-O1/-O2/-O3 编译器优化选项的四个级别,-O0表示没有优化,-O1为缺省值,-O3优化级别最高。

gcc/g++ 的安装:(大概率是都已经安装好了 latest)

sudo yum install -y gcc
yum install -y gcc-c++ libstdc++-devel

3、执行编译的四个步骤(Esc生成iso)

(一)预处理

gcc -E test.c -o test.i
  • 预处理功能主要包括头文件展开、去注释、宏替换、条件编译等。
  • 预处理指令是以#开头的代码行。
  • -E选项的作用是让gcc/g++在预处理结束后停止编译过程。
  • -o选项是指目标文件,“xxx.i”文件为已经过预处理的原始程序。

现在,我们在底行模式中 vs test.c 就可以同时看到俩个文件

 (二)编译

gcc -s test.i -o test.s
  • 在这个阶段中,gcc/g++首先检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,将代码翻译成汇编语言。

  • 用户可以使用-s选项来进行查看,该选项只进行编译而不进行汇编,生成汇编代码。

  • -o选项是指翻译到XXX文件,“xxx.s”文件为已经过翻译的原始程序。

 

 (三)汇编

gcc -c test.s -o test.o
  • 汇编阶段是把编译阶段生成的“xxx.s”文件转成目标文件
  • 使用-c选项就可以得到汇编代码转化为“xxx.o”的二进制目标代码了

(四)链接(不是连接)

gcc test.o -o test
  • 在成功完成以上步骤之后,就进入了链接阶段。
  • 链接的主要任务就是将生成的各个“xxx.o”文件进行链接,生成可执行文件。
  • gcc/g++不带-E、-S、-c选项时,就默认生成预处理、编译、汇编、链接全过程后的文件
  • 若不用-o选项指定生成文件的文件名,则默认生成的可执行文件名为a.out。

 注意: 链接后生成的也是二进制文件。

(五)一步到位


4、链接方式与函数库

(一)动态链接(去网吧)和静态链接(家里有笔记本玩)

我们在编写代码的时候,除了自己实现函数之外,我们还会去调用函数库中的代码,比如 scanf/printf/malloc/fopen;但是我们要明白,库中的代码是别人给我们写好供我们直接使用的,即我们只有该函数的调用,而没有函数的实现;

同时,程序在预处理、编译和汇编阶段处理的都是我们自己编写的代码,只有在链接的时候,库函数的实现才会和我们的代码关联起来 (符号表的重定位);所以,链接的本质是我们在调用库函数时如何与标准库相关联的问题

程序一共有两种链接方式:动态链接与静态链接

动态链接:是指执行代码时,如果遇到库函数调用就跳转到动态库中对应函数的定义处,然后执行该函数,执行完毕后再跳转回原程序并继续往下执行

优点:是形成的可执行程序小

缺点:是受到动态库变动 (删除、升级等) 的影响。

静态链接:直接将本程序内部要使用的库函数从对应的静态库中拷贝一份过来

优点:不与静态库产生关联,即不受静态库变动 (删除、升级等) 的影响

缺点:形成的可执行程序非常大

(二)动态库与静态库

函数库是一些事先写好的,用于给别人复用的函数的集合,函数库一般分为静态库和动态库两种:

静态库是指编译链接时,把需要的库文件代码全部拷贝到可执行文件中,因此生成的文件非常大,但在运行时也就不再需要库文件了

在Linux下其后缀名为 “.a”,在Windows下其后缀名为 “.lib”;

动态库也被称为共享库,它与静态库相反,在编译链接时并没有把相应的库文件代码加入到可执行文件中,而是在程序执行时由运行时链接文件来加载库,这样可以节省系统的开销,在Linux下其后缀名为 “.so”,在Windows下其后缀名为 “.dll”;

注:动态链接必须使用动态库,静态链接必须使用静态库;即进行动态链接时只能跳转到动态库中对应函数的实现处,进行静态链接时只能拷贝静态库中的函数。

(三)动态链接(默认)与静态链接(-static)

Linux中默认使用动态库进行动态链接:gcc默认生成的二进制程序,是动态链接的,这点可以通过 file 指令来验证

原因如下:

  • 程序形成的可执行程序大不仅仅是占用的磁盘空间大,其被运行时加载到内存所占用的内存空间也会非常大,而目前我们使用的机器的内存基本上都是8/16GB的,所以运行不了过大的可执行程序(静态程序大)
  • 虽然动态链接受函数库变动的影响,但是函数库一般很少会变动,即使变动也必须兼容以前的版本,所以影响不大(即使我去网吧,网吧影响我的情况很少,除非倒闭等等)

 Linux 一般都会自动安装C语言动态库,因为Linux下的大多数指令以及我们默认使用 gcc 编译得到的可执行程序都是进行动态链接,依赖C动态库的

但是C静态库、C++静态库可能就需要我们自己安装了

sudo yum install -y glibc-static
sudo yum install -y libstdc++-static

 虽然gcc和g++默认采用的是动态链接,但如果我们需要使用静态链接,带上-static选项即可

 gcc test.c -o test.s -static

 可以看到,以静态链接方式形成的可执行程序比动态链接形成的要大100~200倍,即一个动态链接只有100M的文件,静态链接就会变成十几个G,二者之间相差非常大


四、Linux调试器 - gdb的使用

1、debug 与 release

 1、debug版本:程序本身会被加入更多的调试信息,以便于进行调试。
 2、release版本:不会添加任何调试信息,是不可调试的。

在Linux当中gcc/g++默认生成的可执行程序是release版本的,是不可被调试的。如果想生成debug版本,就需要在使用gcc/g++生成可执行程序时加上-g选项

在这里插入图片描述

 对同一份源代码分别生成其release版本和debug版本的可执行程序,并通过ll指令可以看到,debug版本发布的可执行程序的大小比release版本发布的可执行程序的大小要大一点,其原因就是以debug版本发布的可执行程序当中包含了更多的调试信息

2、gdb命令汇总

(一)进入gdb

指令: gdb 文件名

(二)调试

  1. run/r:运行代码(启动调试)。
  2. next/n:逐过程调试:不进入函数,从n行直接到n+1行,F10
  3. step/s:逐语句调试:进入函数:F11
  4. until 行号:跳转至指定行。
  5. finish:执行完当前正在调用的函数后停下来(不能是主函数),可以很快的检查该函数是不是出现代码问题
  6. continue/c:运行到下一个断点处:F5
  7. set var 变量=x:修改变量的值为x。

(三)显示

  1. list/l n:显示从第n行开始的源代码,每次显示10行,若n未给出则默认从上次的位置往下显示.。
  2. list/l 函数名:显示该函数的源代码。
  3. print/p 变量:打印变量的值。
  4. print/p &变量:打印变量的地址。
  5. print/p 表达式:打印表达式的值,通过表达式可以修改变量的值。
  6. display 变量:相当于监视窗口,加入常显示
  7. display &变量:将变量的地址加入常显示。
  8. undisplay 编号:取消指定编号变量的常显示。
  9. bt:查看各级函数调用及参数,查看调用堆栈
  10. info/i locals:查看当前栈帧当中局部变量的值。

(四)断点

添加断点 和 删除断点是不一样的操作,添加直接行号 但是删除的时候 断点拥有自己的序号了已经 从0123开始

  1. break/b n:在第n行设置断点。
  2. break/b 函数名:在某函数体内第一行设置断点。
  3. info breakpoint/b:查看已打断点信息。
  4. delete/d 编号:删除指定编号的断点。
  5. disable 编号:关掉断点的使能(目的是为了保留断点痕迹,断点存在但不起作用)
  6. enable 编号:启用指定编号的断点。

(五)退出gdb

  • quit/q:退出gdb。

 五、Linux项目自动化创建工具 - make/makefile的使用

1、make/Makefile的重要性

  • 会不会写Makefile,从侧面说明了一个人是否具备完成大型工程的能力
  • 一个工程的源文件不计其数,按照其类型、功能、模块分别放在若干个目录当中,Makefile定义了一系列的规则来指定:哪些文件需要先编译,哪些文件需要后编译,甚至于进行更复杂的功能操作
  • Makefile带来的好处就是“自动化编译”,一旦写好,只需一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率
  • mak是一个命令工具,是一个解释Makefile当中指令的命令工具,一般来说,大多数的IDE都有这个命令,例如:Delphi的make,Visual
  • C++的nmake,Linux下GNU的make。可见,Makefile都成为了一种在工程方面的编译方法。
  • make是一条命令,Makefile是一个文件,两个搭配使用,完成项目自动化构建

2、如何编写makefile(依赖关系很重要)

编写 makefile,最重要的是编写 依赖关系和依赖方法

当我们和老爸要钱的时候:依赖关系:我是你儿子;方法:打电话

依赖关系:指一个文件依赖另外一个文件,即想要得到一个文件,目录下必须先有另外一个文件

例如,test.o文件是由test.c文件通过预处理、编译以及汇编之后生成的文件,所以test.c文件的改变会影响test.o,所以说test.o文件依赖于test.c文件

依赖方法:则是指如何根据依赖文件来得到目标文件

例如,test.o依赖于test.c,而test.c通过gcc -c test.c -o
test.o指令就可以得到test.o,那么test.o依赖于test.c的依赖方法就是gcc -c test.c -o test.o

编写mkfile的时候,也有一些需要注意的地方,小羊注:

  • makefile 的文件名必须是 makefile/Makefile,不能是其他名称,否则 make 识别不了;
  • 依赖文件可以有多个,也可以没有;
  • 依赖方法必须以 [Tab] 键开头,特别注意不能是四个空格;

步骤一: 在源文件所在目录下创建一个名为Makefile/makefile的文件

 步骤二:编写Makefile文件 (vim Makefile)
Makefile文件最简单的编写格式是,先写出文件的依赖关系,然后写出这些文件之间的依赖方法,依次写下去

 如上:mytest依赖 test.c,依赖方法是 gcc 编译,clean 不依赖任何文件,依赖方法是 rm -f 指令;其中 .PHONY 修饰 clean 表示其是一个伪目标,总是被执行 (具体细节下文解释)

 编写完毕Makefile文件后保存退出:wq,然后在命令行当中执行make指令便可以生成可执行程序,以及该过程产生的中间产物

3、make的工作原理

单纯对例子的粗略解释:

mytest: test.c
    gcc test.c -o mytest

这个规则告诉 Make 工具如何构建目标 `mytest`。它表示 `mytest` 依赖于 `test.c` 这个文件。如果 `test.c` 文件的修改时间比 `mytest` 更新(或者 `mytest` 不存在),那么 Make 会执行接下来的命令来构建 `mytest`。

.PHONY: clean
clean:
    rm -f mytest

这个规则定义了一个伪目标 `.PHONY` 和一个目标 `clean`。`.PHONY` 用于声明 `clean` 是一个伪目标,即不是真正的文件。`clean` 目标用于清理构建生成的中间文件和目标文件,以及最终生成的可执行文件 `mytest`。执行 `make clean` 命令时,Make 会执行 `clean` 目标的命令,即删除名为 `mytest` 的文件。单纯写make的时候不会执行clean

工作流程:

1. 当你执行 `make` 命令时,Make 工具会寻找当前目录下的 `Makefile` 文件。

2. Make 读取 `Makefile` 中的规则,并检查目标 `mytest` 是否需要重新构建。它发现目标 `mytest` 依赖于 `test.c`,并且 `test.c` 存在或者其修改时间较 `mytest` 更新,所以 `mytest` 需要重新构建。

3. Make 执行 `gcc test.c -o mytest` 命令来编译 `test.c` 并生成可执行文件 `mytest`。

4. 如果你执行 `make clean` 命令,Make 工具会执行 `clean` 目标的命令,即删除 `mytest` 文件。

`Makefile` 文件的目的是让构建过程自动化和简化。通过定义适当的规则和依赖关系,Make 工具可以只编译需要更新的文件,从而加快构建过程,并确保项目的正确性和一致性。

(一)make的使用

在Linux下,我们输入 make 命令后,make 会在当前目录下找寻名为 “Makefile” 或 “makefile” 的文件;如果找到,它会把文件中的第一个目标文件作为最终的目标文件;如果找不到,就打印提示信息;在上面的C语言例子中,makefile 中一共有两个目标文件

没有生成clean,虽然clean也是目标文件:

这样就可以执行俩段代码:

 

 (二)make的依赖性

修改一下makefile文件:

test.out:test.o
	gcc test.o -o test.out 
test.o:test.s
	gcc -c test.c -o test.o
test.s:test.i
	gcc -S test.i -o test.s
test.i:test.c
	gcc -E test.c -o test.i

.PHONY:clean
clean:
	rm -f test.i test.s test.o test.out

我们知道,我们输入 make 命令后,make 会在当前目录下找寻名为 “Makefile” 或 “makefile” 的文件;如果找到,它会把文件中的第一个目标文件作为最终的目标文件 (上面例子中的 test.out),但是如果 test.out 所依赖的 test.o 文件不存在,那么 make 会在当前文件中找目标为 test.o 文件的依赖性,再根据该一个规则来生成 test.o 文件 (类似于数据结构栈 – 后进先出);

如果 test.o 的依赖文件也不存在,则继续执行该规则,直到找到存在依赖文件的目标文件,得到目标文件后层层返回形成路径上的其他目标文件;或者最后被依赖的文件找不到,直接退出并报错;

这就是整个 make 的依赖性,make 会一层又一层地去找文件的依赖关系,直到最终编译出最开始我们需要的目标文件。

在上面的例子中,test.out 依赖的 test.o 不存在,make 会去寻找以 test.o 为目标文件的依赖关系;test.o 依赖的 test.s 也不存在,make 又会去找 以 test.s 为目标文件的依赖关系;然后 test.s 依赖 test.i,最后,test.i 的依赖文件 test.c 终于存在了,make 就会根据 test.i 的依赖方法形成 test.i,再逐步形成 test.s、test.o,直到最后形成 test.out

 (三)项目清理

在 makefile 中,我们常用 clean 来作为项目清理的目标文件,同时,由于项目清理不需要依赖其他文件,所以 clean 也不存在依赖关系

clean 没有被第一个目标文件直接或间接关联,那么它后面所定义的命令将不会被自动执行,所以我们需要显示指定 : make clean

 最后,像 clean 这种目标文件,我们一般都会用 .PHONY 将其设置为伪目标,

伪目标的特性是:

该目标文件总是被执行

(四).PHONY伪目标

当我们对同一个源文件多次 make,我们会发现第一次程序正常编译,但第二次及以后就不再编译,而是提示:“make: `test.out’ is up to date.”

但是当我们把 test.c 中的内容修改过后,我们发现尽管可以再次 make 了,但是仍然不能多次 make

实际上,上面这种现象是 make 为了防止我们对已经编译好且未做修改的源文件重复编译而浪费时间(不要认为编译时间很短);也就是说,如果 test.c 已经编译得到了 test.out,并且我们并没有对 test.c 做改动,那么我们再次 make 时 make 不会被执行;实际上 make 这样做是很有必要的,因为在工作中,编译一个工程往往需要几十分钟甚至几个小时,如果我们 make 每次都重新编译,势必会浪费很多时间。

那么 make 是如何判断源程序不需要重新编译的呢?答案是根据文件的修改时间 (modify time) 来判定。

在Linux中,文件一共有三种时间:stat + 文件名字

访问时间 (Access):当我们查看文件内容后该时间改变,比如 cat、vim、less;
修改时间 (Modify):当我们修改文件内容后改时间改变,比如 nano、vim;
改动时间 (Change):当我们修改文件属性或权限后改时间改变,比如 nano/vim (文件大小改变),chmod/chown/chown (文件权限改变);

make 则是根据可执行程序的修改时间 (modify time) 与源文件的修改时间的对比来判断源程序是否需要重新编译

注:make 判断源文件是否需要重新编译只与源文件的修改时间变动有关,与源文件的内容改动无关,我们可以通过 touch 命令来验证:(touch file:如果 file 已存在,则更新 file 的所有时间)

但是这里touch不是Makefile生成的文件 而是冒号后面的文件 被依赖的文件

所以说:.PHONY 的作用其实和touch很类似,就是修改文件时间,从而使得程序被执行

 我们也可以使用 .PHONY 来修饰 test.out,使得 test.out 每次都被重新编译

 


完结撒花! Linux工具的基本使用到这里告一段落,希望大家多多指点!!!

猜你喜欢

转载自blog.csdn.net/weixin_62985813/article/details/132073493