3_【Linux】三、Linux 环境基础及开发工具使用(上篇)
「前言」文章的内容大致是Linux下开发工具vim、gcc/g++、Makefile的基本使用。
一、开发工具
假设有人问你在什么环境下写代码 ?
你的回答:vs2019
那人又问你在什么环境下调试代码?
你的回答:vs2019
那人又再次问你在什么环境下编译、链接代码?
你的回答:vs2019
这里所回答的 vs2019 是一个集成开发环境,也就是我们所说的 IDE。我们学习 C/C++ 之前都使用的的开发环境都是集成开发环境,就是一些常用的编译器,如 vs2019、vscode等等
集成开发的编译器集成了代码的编写功能、分析功能、编译功能、调试功能等一体化功能。而在Linux 上的环境不是集成开发环境,它们都是独立的,比如编写代码一般使用 vim,编译代码一般使 gcc(编译C语言)、g++(编译C/C++)等,调试代码一般使用 GDB 等,维护项目关系用 make/Makefile 等
二、Linux编辑器 - vim使用
vi/vim 的区别简单点来说,它们都是多模式编辑器,不同的是 vim 是 vi 的升级版本,它不仅兼容 vi 的所有指令,而且还有一些新的特性在里面
例如语法加亮,可视化操作不仅可以在终端运行,也可以运行于x window、 mac os、windows
这里介绍 vim 编辑器的使用
2.1 vim 的基本概念
vim有十二种模式之多,这里就讲解 vim 的三种模式(目前掌握这3种即可),分别是命令模式(command mode)、插入模式(Insert mode)和底行模式(last line mode),各模式的功能区分如下:
(1)正常/普通/命令模式(Normal mode)
- 控制屏幕光标的移动,字符、字或行的删除,移动复制某区段及进入Insert mode下,或者到 last line mode
(2)插入模式(Insert mode)
- 只有在Insert mode下,才可以做文字输入,按「
ESC」键可回到命令行模式。该模式是我们后面用的最频繁的编辑模式。
(3)末行模式(last line mode)
- 文件保存或退出,也可以进行文件替换,找字符串,列出行号等操作。 在命令模式下,
shift+:即可进入该模式 - 要查看所有模式:打开
vim,底行模式直接输入:help vim-modes
2.2 vim的基本操作
Linux命令行输入 vim,进入 vim,进入之后画面相同或类似则说明 vim 正常,可以直接使用
vim

(1)进入 vim,在系统提示符号输入vim及文件名称后,就进入vim全屏幕编辑画面
[fy@VM-4-14-centos code_98]$ vim [文件名]
不过有一点要特别注意,就是你进入vim之后,是处于【正常模式】,你要切换到【插入模式】才能够输入文字(模式显示在左下角)
注:后面跟的文件假如不存在则直接创建
(2)【正常模式】切换至【插入模式】
输入a 或输入i 或输入o

(3)【插入模式】切换至【正常模式】
- 目前处于【插入模式】,就只能一直输入文字,如果想切换回【正常模式】可以先按一下「
ESC」键转到【正常/命令模式】
(4)【正常模式】切换至【末行模式】
- 「
shift + ;」, 其实就是输入「:」,换成【末行模式】

(5)退出 vim 及保存文件,在【命令模式】下,按【:】进入【末行模式】,再输入以下选项
:w(保存当前文件):wq(存盘并退出 vim): q!(不存盘强制退出 vim):wq!(强制保存并退出)
注意插入模式不能转换成底模式,底行模式转插入模式也是如此,模式切换图如下:

2.3 vim正常模式命令集
(1)插入模式
- 按「i」切换进入插入模式「insert mode」,按
i进入插入模式后是从光标当前位置开始输入文件 - 按「a」进入插入模式后,是从目前光标所在位置的下一个位置开始输入文字
- 按「o」进入插入模式后,是插入新的一行,从行首开始输入文字
(2) 从插入模式切换为命令模式
- 按「
ESC」键
(3)移动光标
- vim 可以直接用键盘上的光标来上下左右移动,但正规的vim是用小写英文字母「h」、「j」、「k」、「l」,分别控制光标左、下、上、右移一格
- 按「 $ 」:移动到光标所在行的“行尾”
- 按「^」:移动到光标所在行的“行首”
- 按「w」:光标跳到下个字的开头
- 按「e」:光标跳到下个字的字尾
- 按「b」:光标回到上个字的开头
- 按「nl」:光标移到该行的第n个位置,n为具体的数字,如:5l,56l
- 按[gg]:进入到文本开始
- 按[「shift+g」 = G]:进入文本末端
- 按「ctrl」+「b」:屏幕往“后”移动一页
- 按「ctrl」+「f」:屏幕往“前”移动一页
- 按「ctrl」+「u」:屏幕往“后”移动半页
- 按「ctrl」+「d」:屏幕往“前”移动半页
(4)删除文字
- 「x」:每按一次,删除光标所在位置的一个字符
- 「nx」:例如,「6x」表示删除光标所在位置的“后面(包含自己在内)”6个字符,n为具体的数字
- 「X」:大写的X,每按一次,删除光标所在位置的“前面”一个字符
- 「nX」:例如,「20X」表示删除光标所在位置的“前面”20个字符,n为具体的数字
- 「dd」:删除光标所在行
- 「#dd」:从光标所在行开始删除#行
(5)复制
- 「yw」:将光标所在之处到字尾的字符复制到缓冲区中
- 「nyw」:复制n个字到缓冲区,n为具体的数字
- 「yy」:复制光标所在行到缓冲区
- 「nyy」:例如,「6yy」表示拷贝从光标所在的该行“往下数”6行文字,n为具体的数字
- 「p」:将缓冲区内的字符贴到光标所在位置
- 注意:所有与“y”有关的复制命令都必须与“p”配合才能完成复制与粘贴功能
(6)撤销上一次操作
- 「u」:如果您误执行一个命令,可以马上按下「u」,回到上一个操作按多次“u”可以执行多次回复
- 「ctrl + r」: 撤销的恢复
(7)替换
- 「r」:替换光标所在处的字符。
- 「R」:替换光标所到之处的字符,直到按下「ESC」键为止
(8)更改
- 「cw」:更改光标所在处的字到字尾处
- 「c#w」:例如,「c3w」表示更改3个字,#为具体数字
(9)跳至指定的行
- 「ctrl」+「g」列出光标所在行的行号。
- 「#G」:例如,「15G」,表示移动光标至文章的第15行行首,#为具体数字
(10)切换大小写
- 「shift + ~」:切换大小写
注:打颜色是比较常用的
2.4 vim末行模式命令集
在使用末行模式之前,请记住先按「ESC」键确定您已经处于正常模式,再按「:」冒号即可进入末行模式(所有的符号都是英文的)
(1)列出行号
- 「set nu」: 输入「set nu」后,会在文件中的每一行前面列出行号
- 「set nonu」: 输入「set nonu」后,文件中的每一行前面行号会取消
(2) 跳到文件中的某一行
- 「#」:「#」号表示一个数字,在冒号后输入一个数字,再按回车键就会跳到该行了,如输入数字15,再回车,就会跳到文章的第15行
(3) 查找字符
- 「/关键字」: 先按「/」键,再输入您想寻找的字符,如果第一次找的关键字不是您想要的,可以一直按「n」会往后寻找到您要的关键字为止
- 「?关键字」:先按「?」键,再输入您想寻找的字符,如果第一次找的关键字不是您想要的,可以一直按「n」会往前寻找到您要的关键字为止
- / 是从文本的开头开始往下查找,? 是从文本结尾开始往上查找
(4) 保存文件
- 「w」: 在冒号输入字母「w」就可以将文件保存起来
(5) 离开vim
- 「q」:按「q」就是退出,如果无法离开vim,可以在「q」后跟一个「!」强制离开 vim
- 「wq」:一般建议离开时,搭配「w」一起使用,这样在退出的时候还可以保存文件
(6) 分屏
- 「vs 文件名」:可以在当前窗口下新增一个窗口进行分屏
- 「ctrl + ww」可以将光标定位到另一个窗口,注意退出 vim 的窗口是光标所在的窗口
(7) 不退出vim 执行Linux 命令
- 底行模式下 ![命令],不退出 vim 执行相应的命令(执行命令行,编译,运行,查看 man 等等)

2.5 简单vim配置
没有进行配置的 vim对我们非常不友好,写代码也不方便。所有我们需要对 vim 进行配置
2.5.1 配置文件的位置
- root 用户在目录
/etc/下面,有个名为vimrc的文件,这是系统中公共的vim配置文件,对所有用户都有效 - 而在每个普通用户的主目录下,都可以自己建立私有的配置文件,命名为:
.vimrc。例如,/root目录下,通常已经存在一个.vimrc文件,如果不存在,则创建之,普通用户在家目录下也是如此 - 切换用户成为自己的,进入自己的主工作目录,执行
cd ~ - 打开自己目录下的
.vimrc文件,执行vim .vimrc,没有则创建.vimrc文件
2.5.2 常用配置选项 -- 测试
- 设置语法高亮:
syntax on - 显示行号:
set nu - 设置缩进的空格数为
4: set shiftwidth=4 - 网上搜索可有更多 vim的配置选项,这里只列出几个
这里的vim 是自己配置的,(有耐心的可以自己慢慢配置)

2.5.3 使用插件(新学者不推荐)
要配置好看的vim,原生的配置可能功能不全,可以选择安装插件来完善配置,保证用户是你要配置的用户,接下来:
- 安装
TagList插件,具体步骤百度
这一种方法挺麻烦的,接下来还有一种比较简便的方法
2.5.4 gitee(推荐)

支持环境:目前只支持 Centos7 x86_64
项目简介:
本项目主要目标是帮助对vim配置方法不熟悉的新手封装的一键式vim环境安装包。主要针对终端 vim用户,适合远程ssh连接 Linux服务器进行开发的场景(例如使用阿里云服务器或者腾讯云服务器等)
安装
在 shell 中执行指令(想在哪个用户下让vim配置生效,就在哪个用户下执行这个指令. 强烈 "不推荐" 直接在 root 下执行)
curl -sLf https://gitee.com/HGtz2222/VimForCpp/raw/master/install.sh -o ./install.sh && bash ./install.sh
需要按照提示输入 root 密码,您的 root 密码不会被上传,请放心输入
卸载方法
在安装了 VimForCpp 的用户下执行:
bash ~/.VimForCpp/uninstall.sh
详细安装步骤请点击这里 ,该作者对 vim 有详细介绍
2.5.5 vim配置参考资料(github)
三、关于sudo提升权限问题
这是在 Linux权限中遗留的问题 ,曾经我们在普通用户的操作中,想使用 sudo 来短期提升权限,却并不能如愿,这是因为默认这个用户是不受信任的。先来解释 sudo
3.1 sudo 简介
sudo 是 Linux 系统管理指令,是允许系统管理员让普通用户执行一些或者全部的 root 命令的一个工具,如halt,reboot,su等等。这样不仅减少了 root 用户的登录和管理时间,同样也提高了安全性。sudo 不是对 shell 的一个代替,它是面向每个命令的
sudo 的作用
提升普通用户的权限,普通用户就可以干一些超级用户才能干的事,该权限有使用时间限制,时间到了再次输入自己的用户密码就可以继续使用 sudo,sudo 默认存活期为5分钟
3.2 赋予普通用户 sudo 权限
(1)先 su - 切换成 root,在 root 下操作
(2)vim /etc/sudoers 打开配置文件,进去之后是这样子的

(3)给文本加上行号,set nu
(5)大概在100行左右,命令模式输入 100G,则跳转到100行,图中圈起来的则是要改的

(6)这时候光标停留在 107 行,命令模式下输入yyp复制 107 行这个,然后修改前面的 %wheel 即可,把它改成自己的用户名字就可以了,其他的不用改。

(7)改完之后切换成命令模式保存并退出就可以了,注意这里退出并保存需要 wq!,保存退出后大功构成,赋予权限的普通用户就可以使用 sudo 命令了。
四、Linux编译器 - gcc/g++使用
4.1 背景知识
在学习 C语言的时候,已经学习过了。C语言学的时候大多数认识理论,现在要将学习的理论进行实践
vim 是用来编辑代码,gcc/g++ 则是用来编译代码,gcc用来编译 C语言,g++既可编译C++,也可编译 C语言
- 预处理(去注释,进行宏替换,头文件展开,条件编译...)
- 编译(生成汇编)
- 汇编(生成机器可识别代码,也叫可重定向二进制目标文件)
- 链接(链接多个
.o/.obj文件,生成可执行文件或库文件)
在此之前,我们可以使用命令gcc -v、g++ -v 查看 gcc、g++ 有没有安装:
gcc -v
g++ -v
显示有相关信息则安装好了


如果显示没有安装,输入下面这条指令即可安装:
sudo yum install -y gcc-c++
4.2 gcc如何完成上述工作?
格式: gcc [选项] 要编译的文件 [选项] [目标文件]
gcc选项:
-E只激活预处理,这个不生成文件,你需要把它重定向到一个输出文件里面-S编译到汇编语言不进行汇编和链接-c编译到目标代码-o文件输出到 文件-static此选项对生成的文件采用静态链接-g生成调试信息。GNU 调试器可利用该信息-shared此选项将尽量使用动态库,所以生成文件比较小,但是需要系统由动态库O0O1O2O3- 编译器的优化选项的4个级别,
-O0表示没有优化,-O1为缺省值,-O3优化级别最高 -w不生成任何警告信息-Wall生成所有警告信息
如何生成可执行程序?
gcc/g++ [要编译的文件]

生成的 a.out 就是可执行程序,可以直接运行
那问题又来了,怎么执行呢?
- 表名当前路径
- 表明可执行程序的名字
例如:. /表示当前路径下,a.out 表示要执行的程序
./a.out

4.2.1 预处理
- 预处理功能主要包括去注释,进行宏替换,头文件展开,条件编译等
- 预处理指令是以#号开头的代码行
- 实例:
gcc –E test.c –o test.i - 选项
-E,该选项的作用是让 gcc 在预处理结束后停止编译过程 - 选项
-o是指目标文件,.i文件为已经过预处理的C原始程序
例如:test.c
#include<stdio.h>
#define N 100
int main()
{
printf("hello world1\n");
printf("hello world2\n");
printf("hello world3\n");
//printf("hello world4\n");
//printf("hello world5\n");
printf("hello world6\n");
printf("%d\n", N);
return 0;
}
gcc –E test.c -o test.i ,-E选项的作用是让 gcc 在预处理结束后停止编译过程,-o是指生成的目标文件,.i文件为已经过预处理的C原始程序
gcc –E test.c -o test.i
打开 test.i,下面宏定义后面多了个分号,无视即可

按shift g == G 翻到末尾

与 test.c 进行对比,宏确实进行了替换,注释确实去掉了,头文件确实展开(前面的八百多行)

4.2.2 编译(生成汇编)
- 在这个阶段中,gcc 首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,gcc 把代码翻译成汇编语言
- 用户可以使用
-S选项来进行查看,该选项只进行编译而不进行汇编,生成汇编代码 - 实例:
gcc –S test.i –o test.s
gcc –S test.i –o test.s,-S,该选项只进行编译而不进行汇编,生成汇编代码,编译完成就停下来,-o是指生成的目标文件,.s文件为已经过编译生成了汇编代码
打开编译后的.s文件

4.2.3 汇编(生成机器可识别代码)
- 汇编阶段是把编译阶段生成的
.s文件转成目标文件.o - 在此可使用选项
-c就可看到汇编代码已转化为.o的二进制目标代码了 - 实例:
gcc –c test.s –o test.o
gcc –c test.s –o test.o ,-c选项把汇编代码转换成二进制代码,汇编完成就停下来,-o是指生成的目标文件,.o文件为已经过汇编转换成了机器可识别代码,也就是二进制代码,该 .o文件的全称是可重定向目标文件
在Windows 下生成的是.obj文件
打开.o文件:

4.2.4 链接(生成可执行文件或库文件)
- 在成功编译之后,就进入了链接阶段,链接完成就生成了可执行文件(在Windows下是以
.exe结尾的)或库文件 - 实例:
gcc test.o –o mytest

进行运行:

4.2.5 gcc选项记忆
为了方便记忆,我们可以看看键盘的左上角的 Esc 键,它刚好对应我们的 -E、-S、-c 选项;而生成的文件的后缀刚好对应镜象文件的后缀 .iso
4.3 静态库和动态库
在进行链接的时候涉及到一个重要的概念:函数库
- 在 C程序中,并没有定义“printf”的函数实现,且在预编译中包含的“stdio.h”中也只有该函数的声明,而没有定义函数的实现,那么,是在哪里实“printf”函数的呢?
- 最后的答案是:系统把这些函数实现都被做到名为
libc.so.6的库文件中去了,在没有特别指定时,gcc 会到系统默认的搜索路径/usr/lib下进行查找(在Linux下),也就是链接到libc.so.6库函数中去,这样就能实现函数“printf”了,而这也就是链接的作用
函数库一般分为静态库和动态库两种
ldd 命令查看可执行程序所依赖的库,格式 ldd [可执行程序]
例如:

file 命令则辨别可执行程序的类型,是静态库还是动态库
格式:file [可执行程序]
例如:

4.3.1 静态库
静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了
在 Linux 其后缀名一般为 .a,在Windows下其后缀一般为 .lib
4.3.2 动态库
动态库与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,这样可以节省系统的开销
在 Linux下动态库一般后缀名为.so,如前面图中的 libc.so.6 就是动态库;在Windows下其后缀一般为 .dll
gcc/g++ 在编译时默认使用动态库
完成了链接之后,gcc/g++ 就可以生成可执行文件,如: gcc test.o –o mytest 生成的 mytest
小故事帮助理解:
- 比如小明是一个新入学的大一新生,因为家里比较穷,没有钱买电脑。小明因为有上网的需求,因为环境不熟悉,所以问了学长附近的网吧,随后就按照学长所说路线找到了网吧,小明上网上够了就回学校了。小明没有电脑只能依赖网吧的电脑上网,这叫依赖关系,学长所提供的去网吧的路径,依赖这条路径找到网吧,这叫依赖方法,这就叫动态链接。动态链接就是将库中我需要的方法的地址填入我的可执行程序中,与外界建立关联,我需要的时候就顺着库中的方法的地址找到我所需要的,这样的动态链接可以节省资源
- 小明到大二了,经过打工赚够了买电脑的钱,小明高高兴兴的买了一台电脑。当小明想上网的时候就打开他的电脑,不用去网吧了。小明为什么不去网吧了?因为他买了一台电脑,这叫依赖方法。小明在宿舍依赖他自己的电脑上网,这叫依赖关系。静态链接就是将库中的方法实现,真的拷贝到我们的可执行程序中,没有与外界建立关联,这种静态链接比较占用资源
- gcc/g++ 默认形成的可执行程序是动态链接的
动态链接所占用空间大小(同一代码):

静态链接所占用空间大小(同一代码),如何使用静态库?
gcc test.c -o mytest-s -static 此选项对生成的文件采用静态链接
注意:使用 -static 首先要安装静态库,因为Linux下没自带有,输入如下指令进行安装,输入用户密码即可进行安装
//C语言静态库安装
sudo yum install -y glibc-static
//C++静态库安装
sudo yum install -y libstdc++-static
接下来 gcc test.c -o mytest-s -static 此选项对生成的文件采用静态链接,执行后生成的文件明显比动态链接所生成的文件大得多

- 动态链接的生成的可执行程序的体积往往比较小,但是它依赖第三方库,有一定的风险,万一找不到第三方库,程序就无法运行
- 静态链接虽然生成的可执行程序的体积较大,但是它不依赖第三方库,即使没有第三方的库,程序照样也能运行
- 总的来说,两者既有优点,也有缺点,看在哪种场景下使用
五、Linux项目自动化构建工具 - make/Makefile
以前我们写一些 C/C++小项目的时候,项目都是编译器帮我们维护的,在Linux下则需要我们自己维护,维护的工具就是 make/makefile
5.1 背景
5.1.1 多个源文件带来的问题
在编写c/c++测试程序时,我们习惯每次修改一处代码,然后就马上编译运行来查看运行的结果。这种编译方式对于小程序来说是没有多大问题的,可对于大型程序来说,由于包含了大量的源文件,如果每次改动一个地方都需要编译所有的源文件,这个简单的直接编译所有源文件方式对程序员来说简直是噩耗
看一个例子:
// 1.c 包含的头文件
#include "1.h"
// 2.c 包含的头文件
#include "1.h"
#include "2.h"
// 3.c 包含的头文件
#include "2.h"
#include "3.h"
- 如果只修改了头文件
3.h,则源文件1.c和2.c都无需编译,因为它们不依赖这个头文件。而对3.c来说,由于它包含了3.h,所以在头文件3.h改动后,就必须得新编译,因为3.c依赖于3.h - 而如果改动了
2.h可是忘记重新编译2.c,那么最终的程序就可能无法正常工作 make/makefile工具就是为了解决上述问题而出现的,它会在必要时重新编译所有受改动影响的源文件
5.1.2 另一方面
- 会不会写
makefile,从一个侧面说明了一个人是否具备完成大型工程的能力 - 一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,
makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作 makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可见,makefile都成为了一种在工程方面的编译方法make是一条命令,makefile是一个文件,两个搭配使用,完成项目自动化构建
5.2 make命令和makefile 文件、理解依赖关系和依赖方法
首先明确一点:
-
make是一条命令,它可以帮我们自动化构建项目 -
makefile是一个文件,自动化构建项目的过程是它完成的,makefile的m既可大写也可小写 -
make命令功能虽然十分强大,但是光凭其自身无法构建应用程序的。这时,makefile就出来了,它告诉make应用程序如何构建的。make命令和makefile文件的结合提供了一个在管理项目的十分强大的工具,它们不仅用于控制源文件的编译,而且还提供了将应用程序安装到目标目录等其他功能
用以下代码测试,只有 test.c 一个源文件
#include<stdio.h>
int main()
{
printf("hello world\n");
return 0;
}
接下来在该路径下 vim makefile

先写要生成目标的名称,然后紧跟一个冒号,接着紧跟源文件名字,接着是换行,换行之后回退到顶格,再按下 tab 键,不能敲四个空格,按tab键后紧跟需要编译的文件,最后保存退出
mytest:test.c
gcc test.c -o mytest

接下来直接 make 就可以了

最后执行程序

到这里暂停一下,依赖关系和依赖方法上面也讲到,陈述一下这里的依赖关系和依赖方法。
- 依赖关系定义了应用程序里面每个文件与其他源文件之间的关系。我们都知道
test.c生成mytest,这里的生成关系是正向的,反过来mytest是依赖于test.c,这就是这里的依赖关系。 - 而依赖方法则表明是谁生成的可执行程序,依赖这种方法而生成可执行程序。上面的
test.c就是依赖于 gcc 而生成的mytest,这里的 gcc 就是依赖方法 - 在
makefile里面,依赖关系和依赖方法总是成对出现的 make默认执行第一对关系方法,如果有多对要执行其中一对,则make+要执行的名称即可,因为make默认从上到下执行Makefile里面的关系方法对

5.3 原理
make是如何工作的,在默认的方式下,也就是我们只输入make命令:
make会在当前目录下找名字叫Makefile或makefile的文件- 如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,他会找到
test.c这个文件,并把这个文件作为最终的目标文件 - 如果
mytest文件不存在,或是mytest所依赖的后面的test.c文件的文件修改时间要比mytest这个文件新(可以用 touch 测试),那么,他就会执行后面所定义的命令来生成mytest这个文件 - 如果
mytest所依赖的test.c文件不存在,那么make会在当前文件中找目标为test.c文件的依赖性,如果找到则再根据那一个规则生成test.c(这里的test .c 是我自己写的,想一下上面的预处理,编译,汇编,链接生成的文件就懂了) 文件(这有点像一个堆栈的过程) - 当然,你的C文件和H文件是存在的,于是
make会生成test.c(这里的test .c是我自己写的,想一下上面的预处理,编译,汇编,链接生成的文件就懂了)文件,然后再用test.c文件声明make的终极任务,也就是执行文件mytest了 - 这就是整个
make的依赖性,make会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件 - 在找寻的过程中,如果出现错误,比如最后被依赖的文件找不到,那么
make就会直接退出,并报错,而对于所定义的命令的错误,或是编译不成功,make根本不理 make只管文件的依赖性,即,如果在我找了依赖关系之后,冒号后面的文件还是不在,那么对不起,我就不工作啦
5.3 项目清理
一个项目不仅需要能生成文件,还要能清理文件。那如何清理?
首先,打开 makefile 文件,在紧接着下一行输入如下(按tab键取空格,不要打空格),然后保存退出
.PHONY:clean
clean:
rm -f mytest
clean 的依赖文件(依赖关系)可以为空,rm -f mytest 为依赖方法

输入 make clean,即可清理

- 工程是需要被清理的
- 像
clean这种,没有被第一个目标文件直接或间接关联,那么它后面所定义的命令将不会被自动执行,不过,我们可以显示要make执行。即命令——make clean,以此来清除所有的目标文件,以便重编译 - 但是一般我们这种
clean的目标文件,我们将它设置为伪目标,用.PHONY修饰,伪目标的特性是,总是被执行的 - 可以将我们的 mytest目标文件声明成伪目标,测试一下
5.3.1 解释 .PHONY
.PHONY 称为伪目标,它总是被执行的
怎么理解呢?
我们在生成 mytest 之后继续make,进行生成:

这是为什么呢?这是因为生成的文件已经是最新的版本了,直接提示你不用再更新了,已经是最新的版本了
那再如,一直执行 make clean 呢?结果如下:

结果说明它总能被执行,不管文件有没有。这是为什么呢么?没错,就是因为 .PHONY 伪目标的原因,这下能理解伪目标总被执行了吧。如果给 mytest 添加伪目标,它也会一直会被执行,不管你是不是最新版
这里是习惯上给 clean 添加上伪目标的
5.3.2 makefile 如何得知可执行程序是最新的?
答案是根据文件的最近修改时间来的
接下来要了解什么是 AMC时间?
输入 stat 文件 查看 AMC时间

Access:文件最近访问时间
- 对于文件来说,当我们用编辑器打开file,或使用
cat、more、less、grep sed等等命令读取文件内容,以及使用file、cp命令操作文件,或执行可执行文件时,Access时间会被更新,空文件也不例外 - 对于目录来说,只进入目录不会更新其
Access时间,但是通过ls查看目录内容时,Access时间就会更新 - 使用
ls -lu查看文件时,会显示出来文件的Access时间
Modify:文件的内容最后一次被修改的时间
- 当更改一个文件的内容时,此文件的
modify时间记录会被更新 Modify时间更新时,Access和Change时间都会得到相应的更新
Change:改变时间
- 主要是指文件的状态或属性的改变
- 对一个文件或目录进行
mv、chown、chcgrp等操作后,change时间会更新
这里暂时没有进行测试
5.5 多文件项目的构建
这里我已经建好三个文件了

vim makefile 进行编写:
mytest:test.o main.o
gcc -o mytest test.o main.o
test.o:test.c
gcc -c test.c -o test.o
main.o:main.c
gcc -c main.c -o main.o
.PHONY:clean
clean:
rm -f *.o mytest
make 执行
删除项目
这里的多项目操作可以看上面的原理,帮助理解
--------------- END ---------------
「 作者 」 枫叶先生
「 更新 」 2022.9.13
「 声明 」 余之才疏学浅,故所撰文疏漏难免,
或有谬误或不准确之处,敬请读者批评指正。
3_【Linux】三、Linux 环境基础及开发工具使用(上篇)
http://114.132.213.38:6250/archives/09588221-838b-48c2-b849-092bba0fe9a8
评论