Linux从0到1——Linux环境基础开发工具的使用(上)
- 1. Linux软件包管理器yum
- 1.1 yum介绍
- 1.2 用yum来下载软件
- 1.3 更新yum源
- 2. Linux编辑器:vi/vim
- 2.1 vim的基本概念
- 2.2 vim的基本操作
- 2.3 vim正常模式命令集
- 2.4 vim底行模式命令集
- 2.5 视图模式:批量化注释
- 2.6 vim也支持多文件编辑
- 2.7 简单的vim配置
- 2.7.1 如何解决新用户无法sudo提权
- 2.7.2 基础配置
- 2.7.3 vim插件
- 3. Linux编译器:gcc/g++
- 3.1 快速上手
- 3.2 gcc/g++工作原理
- 3.3 动静态库概念与理解
- 3.3.1 库
- 3.3.2 动静态库
- 4. Linux项目自动化构建工具:make/Makefile
- 4.1 快速上手
- 4.2 小插曲:文件时间戳
- 4.3 make/Makefile具有依赖性的推导能力
- 4.4 make/Makefile语法拓展
1. Linux软件包管理器yum
1.1 yum介绍
1. 什么是软件包:
在Linux下安装软件, 一个通常的办法是下载到程序的源代码, 并进行编译, 得到可执行程序。但是这样太麻烦了, 于是有些人把一些常用的软件提前编译好, 做成软件包(可以理解成windows上的安装程序)放在一个服务器上, 通过包管理器可以很方便的获取到这个编译好的软件包, 直接进行安装。软件包和软件包管理器, 就好比 “App” 和 “应用商店” 这样的关系。
在早期,智能手机还没有普及的时候,大多数人在电脑上下载软件都是去浏览器上直接搜,直接下载。但是这样下载下来的软件就很容易出问题(有病毒)。现在不一样了,大家装软件的时候一般都用自带的软件商店,有了一个统一的入口(至少大家用手机是这样)。这些软件商店都有审核APP的功能,这样病毒软件就不容易被大家所下载了。
大家再思考一个问题,应用商店里的软件是在你的手机里吗?肯定不是,应用商店中的软件都安装在一个远端的服务器上。所以,应用商店其实就是一个客户端,其实我们现在使用的所有APP大多数都是客户端软件。这个远端的服务器,就是服务器端。
跟手机相关的这些软件,服务器,都和手机厂商有关。应用商店这款客户端软件,和服务器,实际上就是手机厂商提供的。如果手机厂商发现在自己服务器中上线的软件有问题,或者说差评很多,它是有权利把这款软件下架的。所以,yum
其实就相当于一个客户端软件-应用商店。
那么Linux下的软件服务器谁提供?难道是有人免费把软件写好放在一个免费的服务器中吗?别说,还真是。这就需要我们来理解一下yum
的生态了。一款操作系统的好坏,比如CentOS,ubuntu,主要要看它的生态。设想一个场景:老板让你帮忙挑一款操作系统部署环境,你挑出了一款操作系统,理由是什么?你可以说这款操作系统的社区很活跃,有很多bug都已经暴漏出来并且被修复了,更重要的是XXX大公司也在使用这款操作系统,大公司一般都是发现漏洞的先锋部队,等我们需要bug时,差不多也被他们解决了,直接照搬解决方案即可(场景结束)。如果说有人喜欢一款操作系统,他是绝对不希望这款操作系统没落的,所以有一些牛人们就在自愿的去开发一些软件,完善操作系统,来开源的让大家使用。
而且,只要有大公司在用这款操作系统,那么这家公司是绝对不会希望这款操作系统倒下的。所以他们会捐助那些开发Linux服务器的人,大公司也不差这点钱。所以Linux
不差钱,也不差人。
yum(Yellow dog Updater, Modified)
是Linux下非常常用的一种包管理器. 主要应用在Fedora, RedHat, Centos等发行版上。(ubuntu系统上的软件包管理器是apt
)
2. yum怎么知道去哪里下载软件:
yum
作为一个软件包安装工具,肯定知道去哪里下载软件,这个配置信息就在yum
下的文件中,我们来通过命令查看一下:
1.2 用yum来下载软件
1. 做一个小实验,下载sl
命令来跑一辆小火车:
通过命令yum list | grep sl
,查找我们需要安装的软件,就像在应用商店搜索一样:
这里就可以看到我们要下的软件,然后执行命令yum install sl
,将sl
下载下来,之后直接输入sl
按回车,就会出现一台奔跑的小火车:
输入命令yum remove sl
可以卸载下好的sl
。在执行这些命令时系统经常会提问你是否要执行该操作,如果你不想让他问你,可以使用-y
,如yum remove -y sl
。
2. 如何下载官方软件源中没有的软件?
有些同学可能下载不了sl
指令,这是因为官方的软件源中没有sl
指令。我们可以先使用命令yum install -y epel-release
下载扩展yum源,然后再yum install sl
下载指令。
1.3 更新yum源
CentOS的yum
源默认是国外的,也就是从国外的服务器上去下载软件,但是这样速度会很慢,我们希望从国内的服务器上去下载软件,这就需要更新yum
源。
我们不要直接修改它,先将他备份一下。这里我备份成了CentOS-base.repo.bak
。然后再修改CentOS-base.repo
配置文件。使用命令vim /etc/yum.repos.d/CentOS-Base.repo
:
修改圈起来的内容,这里我已经配置好了,大家可能跟我的不一样,抄一下就行了。
修改好之后再执行两条命令:yum clean all
和yum makecache
就可以了。一个是清空缓存,一个是重新制作缓存。
2. Linux编辑器:vi/vim
vi/vim
其实就是一款文本编辑器。vi/vim
的区别简单点来说,它们都是多模式编辑器,不同的是vim
是vi
的升级版本,它不仅兼容vi
的所有指令,而且还有一些新的特性在里面。例如语法加亮,可视化操作不仅可以在终端运行,也可以运行于x window
、mac os
、windows
。我们课堂上,统一按照vim
来进行讲解。
2.1 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
我这里一共有12种模式:six BASIC modes
和six ADDITIONAL modes
。
2.2 vim的基本操作
进入vim,在系统提示符号输入vim及文件名称后,就进入vim全屏幕编辑画面。例:vim test.c
。不过有一点要特别注意,就是你进入vim之后,是处于[正常模式],你要切换到[插入模式]才能够输入文字。
1. [正常模式]切换至[插入模式]
- 输入a
- 输入i
- 输入o
2. [插入模式]切换至[正常模式]
- 目前处于[插入模式],就只能一直输入文字,如果发现输错了字,想用光标键往回移动,将该字删除,可以先按一下「ESC」键转到[正常模式]再删除文字。当然,也可以直接删除。
3. [正常模式]切换至[底行模式]
shift + :
, 其实就是输入:
退出vim及保存文件,在[正常模式]下,按一下:
冒号键进入「Last line mode」,例如:w
(保存当前文件)wq
(输入wq
,保存并退出vim)q!
(输入q!
,不保存强制退出vim)
2.3 vim正常模式命令集
1. 插入模式:
- 按「i」切换进入插入模式「insert mode」,按“i”进入插入模式后是从光标当前位置开始输入文件;
- 按「a」进入插入模式后,是从目前光标所在位置的下一个位置开始输入文字;
- 按「o」进入插入模式后,是插入新的一行,从行首开始输入文字。
2. 从插入模式切换为命令模式:
- 按「ESC」键。
3. 移动光标:
- vim可以直接用键盘来控制光标的上下左右移动,但正规的vim是用小写英文字母「h」、「j」、「k」、「l」,分别控制光标左、下、上、右移一格,也可以直接用键盘上的箭头控制;
- 按「G」:移动到文章的最后;
- 按「 $ 」:移动到光标所在行的“行尾”;
- 按「^」:移动到光标所在行的“行首”;
- 按「w」:光标跳到下个字的开头;
- 按「e」:光标跳到下个字的字尾;
- 按「b」:光标回到上个字的开头;
- 按[gg]:进入到文本开始;
- 按[shift+g]:进入文本末端;
- 按「ctrl」+「b」:屏幕往“后”移动一页;
- 按「ctrl」+「f」:屏幕往“前”移动一页;
- 按「ctrl」+「u」:屏幕往“后”移动半页;
- 按「ctrl」+「d」:屏幕往“前”移动半页。
4. 删除文字:
- 「x」:每按一次,删除光标所在位置的一个字符;
- 「#x」:例如,「6x」表示删除光标所在位置的“后面(包含自己在内)”6个字符;
- 「X」:大写的X,每按一次,删除光标所在位置的“前面”一个字符;
- 「#X」:例如,「20X」表示删除光标所在位置的“前面”20个字符;
- 「dd」:删除光标所在行;
- 「#dd」:从光标所在行开始删除#行。
5. 复制:
- 「yw」:将光标所在之处到字尾的字符复制到缓冲区中;
- 「#yw」:复制#个字到缓冲区;
- 「yy」:复制光标所在行到缓冲区;
- 「#yy」:例如,「6yy」表示拷贝从光标所在的该行“往下数”6行文字;
- 「p」:将缓冲区内的字符贴到光标所在位置。注意:所有与“y”有关的复制命令都必须与“p”配合才能完成复制与粘贴功能。
- 「#p」:从光标往下的位置粘贴#次。
6. 替换:
- 「r」:替换光标所在处的字符,r前面也可以带#,表示替换#个字符;
- 「R」:替换光标所到之处的字符,直到按下「ESC」键为止。
7. 撤销上一次操作:
- 「u」:如果您误执行一个命令,可以马上按下「u」,回到上一个操作。按多次“u”可以执行多次回复;
- 「ctrl + r」: 撤销的恢复。
8. 更改:
- 「cw」:更改光标所在处的字到字尾处;
- 「c#w」:例如,「c3w」表示更改3个字跳至指定的行;
- 「ctrl」+「g」列出光标所在行的行号;
- 「#G」:例如,「15G」,表示移动光标至文章的第15行行首;
- 「~」:将光标后的一个字符进行大小写转化,同时移动光标。
9. 查找:
- 「#」:输入#,会标记当前光标所在单词,并将该单词出现的地方全部标红,按n可以一直向前寻找。
2.4 vim底行模式命令集
在使用末行模式之前,请记住先按「ESC」键确定您已经处于正常模式,再按「:」冒号即可进入末行模式。
1. 列出行号:
- 「set nu」: 输入「set nu」后,会在文件中的每一行前面列出行号。
跳到文件中的某一行; - 「#」:「#」号表示一个数字,在冒号后输入一个数字,再按回车键就会跳到该行了,如输入数字15,再回车,就会跳到文章的第15行。
2. 查找字符:
- 「/关键字」: 先按「/」键,再输入您想寻找的字符,如果第一次找的关键字不是您想要的,可以一直按「n」会往后寻找到您要的关键字为止;
- 「?关键字」:先按「?」键,再输入您想寻找的字符,如果第一次找的关键字不是您想要的,可以一直按「n」会往前寻找到您要的关键字为止。
3. 保存文件:
- 「w」: 在冒号输入字母「w」就可以将文件保存起来。
4. 离开vim:
- 「q」:按「q」就是退出,如果无法离开vim,可以在「q」后跟一个「!」强制离开vim;
- 「wq」:一般建议离开时,搭配「w」一起使用,这样在退出的时候还可以保存文件。
5. 在底行模式可以直接输入指令:
- 「! cmd」:需要先输入一个
!
,然后后面就可以跟想执行的指令,这样就不用频繁退出vim去操作命令行了。
2.5 视图模式:批量化注释
1. 注释:
以图中代码为例:
我们先在普通模式下按ctr+v
进入视图模式:
移动光标,选中多行:
输入shift+i
直接进入插入模式,不要移动光标:
输入//
:
再按Esc
退出视图模式,完成批量注释:
这个操作比较复杂,大家多多练习,熟练掌握。
2. 去掉注释:
还是ctr+v
进入视图模式:
移动光标选择区域:
输入d删除选中内容,完成批量化的注释删除:
2.6 vim也支持多文件编辑
1. 多文件编辑演示:
在底行模式下,输入:vs + filename
,就可以同时编辑多个文件。下面以同时编辑两个文件进行讲解,当然还可以再vs
一下再打开一个文件。这里输入的命令是vs code.c
,左边的文件就是code.c
:
无论打开多少个文件,光标只有一个,那么如何让光标在不同文件中进行切换呢?我们可以在普通模式(命令模式)下,输入ctr+ww
进行光标的切换。
如果进入插入模式或者底行模式,光标在哪,就是进入了那个文件的相应模式。
2. 小技巧:
如果我们在写代码的时候出现了错误,并且终端将错误所在的行数提示了出来,比如是code.c
第7行出错。我们可以通过vim code.c +7
直接将光标定位到文件的第7行,想定位到哪一行就加几。
2.7 简单的vim配置
2.7.1 如何解决新用户无法sudo提权
在之后的配置中,可能遇到普通用户无法使用sudo命令的情况,所以这里我们先解决一下。在Linux系统中有一个信任列表,也叫白名单,只有在这个白名单下的用户才有权使用sudo指令。在CentOS7
中,这个白名单的路径是/etc/sudoers
,我们接下来要做的就是将普通用户添加到这个白名单中去。
先su
切换成root
用户,然后输入指令vim /etc/sudoers
用vim打开白名单,将自己的用户添加进入(我的用户名是LHY)。
然后保存并退出,普通用户LHY就可以使用sudo
提权啦。
2.7.2 基础配置
1. 配置文件的位置
在目录/etc/
下面,有个名为vimrc
的文件,这是系统中公共的vim配置文件,对所有用户都有效。而在每个用户的主目录下,都可以自己建立私有的配置文件,命名为:.vimrc
。例如,/root
目录下,通常已经存在一个.vimrc
文件,如果不存在,则创建之。
切换用户成为自己,进入自己的主工作目录,执行 cd ~。打开自己目录下的.vimrc
文件(没有自己创建),执行vim .vimrc
,编辑该文件。
2. 写入常用配置选项,用来测试(双引号后面是注释):
set nu "显示行号
syntax on "设置语法高亮
set cursorline "设置行线
set tabstop=4 "设置 tab 键为4个空格的宽度
set shiftwidth=4 "设置自动缩进格式为4格
set autoindent "设置自动缩进
set cindent "使用 C/C++ 语言的自动缩进方式
保存并退出,再次使用vim编辑任意文件:
大家可以使用Tab
键测试一下是不是变成了缩进4个空格(默认是8个);现在的vim自带语法高亮,所以这个配置选项效果不明显;在用vim编写C/C++代码时,自动缩进也可以体现出来,大家可以自行测试一下。
网上也有很多配置vim的文章,大家可以自行查阅。
2.7.3 vim插件
完成了上面的基础配置,vim编写代码的效果还是很low的,我们还想让vim有自动补全单词等等一些功能,让vim向IDE一样方便,怎么办呢?这时就需要我们来下载各种插件了。
但是插件配置的学习成本太高,下面我们直接来执行一段脚本,一键完成vim的自动化部署。curl -sLf https://gitee.com/HGtz2222/VimForCpp/raw/master/install.sh -o ./install.sh && bash ./install.sh
,这段命令需要sudo执行(改配置仅适用于CentOS7
)。
上面的脚本是大牛提前写好的vim配置,免费放在了gitee上,我们直接下载即可。
可以看到,完成配置后,vim界面会变得非常酷炫,并且拥有自动补齐等各种功能。但是默认缩进是两个空格,这是阿里的规则。如果大家不习惯,可以找到.vimrc
文件,修改如下内容,将缩进改为4格。
3. Linux编译器:gcc/g++
格式 gcc [选项] 要编译的文件 [选项] [目标文件]
如果大家的电脑上没有装gcc或g++,可以用我们之前学过的yum下载一下。注意,安装g++时,使用的指令是yum install gcc-c++
,而不是yum install g++
。
3.1 快速上手
创建一个test.c
文件,在里面写上一段代码:
#include<stdio.h>int sum()
{int sum = 0;for(int i = 1; i <= 100; i++){sum += i;}return sum;
}int main()
{int result = sum();printf("result:%d\n", result);return 0;
}
使用gcc编译该代码,编译的过程中可能会出现如下问题:
这是因为版本问题,我们统一指定用c99来编译源码即可:
编译成功,并且运行成功。
我们还可以使用选项-o来指定编译后目标文件的名字:
3.2 gcc/g++工作原理
1. 预处理:
- 预处理功能主要包括宏定义,文件包含,条件编译,去注释等;
- 预处理指令是以#号开头的代码行;
- 实例:
gcc –E hello.c –o hello.i
; - 选项“-E”,该选项的作用是让 gcc 在预处理结束后停止编译过程;
- 选项“-o”是指目标文件,“.i”文件为已经过预处理的C原始程序。
// hello.c 文件的内容如下
#include <stdio.h> #define M 123#define V1 1
//#define V2 1int main()
{
#if V1printf("免费社区版\n");printf("hello Linux:%d\n", M);printf("hello Linux:%d\n", M);printf("hello Linux:%d\n", M);printf("hello C++\n");//printf("hello C++\n");//printf("hello C++\n");
#elif V2printf("专业版本\n");
#elseprintf("超级会员版\n");
#endifreturn 0;
}
执行预处理指令gcc –E hello.c –o hello.i
:
2. 编译(生成汇编):
- 在这个阶段中,gcc 首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,gcc 把代码翻译成汇编语言;
- 用户可以使用“-S”选项来进行查看,该选项只进行编译而不进行汇编,生成汇编代码;
- 实例:
gcc –S hello.i –o hello.s
3. 汇编(生成机器码):
- 汇编阶段是把编译阶段生成的“.s”文件转成目标文件;
- 读者在此可使用选项“-c”就可看到汇编代码已转化为“.o”的二进制目标代码了。
- 实例:
gcc –c hello.s –o hello.o
注意,虽然此时hello.o
文件是二进制的,但是它是不能执行的。
4. 链接(生成可执行文件或库文件):
- 在成功编译之后,就进入了链接阶段;
- 实例:
gcc hello.o –o hello
5. 总结:
上面只是让大家深入了解一下gcc/g++的工作流程,那么在实际应用中,我们只需要会gcc file -o filename
即可。
其中选型我们可以特殊记忆,gcc预处理、编译、汇编所用的选项是-E/-S/-c
,合起来就是我们键盘左上角的ESc
,只需要注意大小写即可;文件名后缀分别时.i/.s/.o
,合起来就是.iso
,镜像文件的后缀就是.iso
。
3.3 动静态库概念与理解
3.3.1 库
1. 什么是库?
我们现在所写的所有代码,都是站在巨人的肩膀上的,已经有人给我们写好了对应的可以直接使用的函数了(比如printf()
)。那么这些功能函数,在哪里?又以什么方式呈现给我们呢?这就要提一提库的概念了。
使用ldd
命令可以查看一个可执行程序所依赖的库有哪些:
我们在写代码时,头文件中包含的内容,是这些函数的声明,而库中所包含的,则是这些函数的具体实现。
我们的可执行程序=我们的代码+头文件+库。
Linux下一切皆文件,库也是文件。所以所谓的开发环境安装,就是安装下载并拷贝头文件和库文件到开发环境中的特定路径下,一定要能被编译器自己找到。
2. 库的命名:
以libc.so.6
为例,库的前缀都是lib
,以.so
为后缀的是动态库,以.a
为后缀的是静态库。libc.so.6
去掉前缀和后缀才是它真正的名字,就是c
。所以这个库其实就是c
标准库。
大多数的库都是动态库,静态库不多:
我的电脑中静态库只有这么多,动态库就太多了,这里就不再展示了。
3. 扩展:
在Windows中,也有动静态库的概念。其中xxxx.dll
,以.dll
结尾的是动态库;xxxx.lib
,以.lib
结尾的是静态库。
3.3.2 动静态库
1. 动态库:
动态库是C/C++或其他第三方库的所有方法的集合,被我们所写的程序以动态链接的方式,关联起来。库中所有的函数都有入口地址,所谓动态链接,其实就是把要链接的函数地址拷贝到我们的可执行程序的特定位置。
2. 静态库:
静态库也是C/C++或者其他第三方提供的所有方法的集合,被我们的程序以拷贝的方式(静态链接),将所需要的代码,直接拷贝到自己的可执行程序中。
3. 动静态库比较:
- 动态链接优缺点
- 优点:形成的可执行程序体积比较小,比较节省资源;
- 缺点:速度稍慢一些(因为有去库中找函数的这样一个过程,但这不是主要缺点);有强依赖性,动态库没了,所有的依赖这个库的程序都无法运行了。
可以看到,Linux中绝大多数命令都是用C语言写的,这些命令也都依赖于C标准库,所以一旦我们将这个库删掉,Linux系统也就接近报废了。
- 静态库优缺点
- 优点:可以无视库,独立运行;
- 缺点:体积大,浪费资源。
4. 实验验证:
现在有些Linux系统上默认是不安装静态库的,所以我们可以先安装一下:sudo yum -y install glibc-static
。
为什么系统一般不自带静态库,而选择动态库呢?就是因为静态链接的内存体积太大了,我们接受不了。
4. Linux项目自动化构建工具:make/Makefile
- 会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力。
- 一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,
makefile
定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作。 makefile
带来的好处就是——“自动化编译”,一旦写好,只需要一个make
命令,整个工程完全自动编译,极大的提高了软件开发的效率。make
是一个命令工具,是一个解释makefile
中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可见,makefile
已经成为了一种在工程方面的编译方法。make
是一条命令,makefile
是一个文件,两个搭配使用,完成项目自动化构建。
4.1 快速上手
1. 小实验:
我们先来创建一个makefile
或Makefile
文件,一般建议m大写。在里面写入内容(注意依赖方法前面一定要加一个Tab
):
什么是依赖环境和依赖方法呢?打个比方,你完成了找你爸要钱这个动作。那么这个过程中,你找你爸,就是依赖环境,要钱,就是完成的依赖方法。还有一个伪依赖环境,就是不写依赖环境,只写依赖方法,就像你把要来的钱花掉一样。
那么这个Makefile
有什么用呢?
Makefile
其实就是一个脚本文件,要配合命令make
来使用。我们可以看到,配置好Makefile
后,make
命令自动帮我们完成了将原文件编写成可执行程序的工作。执行make clean
指令,自动帮我们完成了可执行程序的清理工作。
既然我们可以通过make clean
来执行清理的依赖方法,那么可不可以用make mybin
来执行生成可执行程序的依赖方法呢?
答案是可以的。但是要注意,我们一般将文件的清理任务写在Makefile
文件的最下面,如果将clean
的逻辑写在最开头,那么我们再执行命令make
(不加任何参数),默认执行的就是clean
的依赖方法,因为make
是从上向下扫描Makefile
的,并且只执行形成的第一个目标文件。
4.2 小插曲:文件时间戳
1. 细节:
我们先来看一个现象,Makefile
按上面截图的内容不变,连续运行两次make
(保证mybin
文件已经被清理了),再运行两次清除。
修改一下源文件的内容,发现make
又可以执行了。
我们再修改一下Makefile
里的内容:
然后再多次执行make
,发现每次都成功执行了,不再有已经是最新文件,不让执行的限制:
大家可以大胆的猜测一下,就是和.PHONY
有关。.PHONY
后面跟的是伪目标,可以让其总是被执行。对于mybin
,可以看到的作用就是让其突破了有没有被修改的限制;对于clean
现阶段没有什么影响,但是建议在clean
前加上.PHONY
,标明clean
是一个伪目标。
那么又产生了一个新的问题,为什么在我们编译代码的时候,makefile
和make
总不让我们重新编译我们的代码?现在我们写的代码还是很小型的,不管是编译还是重新编译,它的速度都是很快的。但是设想一下,我们今后处理的项目可能有上万行代码,它编译的速度是非常慢的,所以重新编译代码将是一件很耗费资源的事情。为了节省资源,避免误操作,对于没有更改过的新代码,就不让你重新编译了。
那么,make
是怎么判断你是不是新文件的呢?判断的依据就是文件的修改时间。但是,单凭一个文件的修改时间是判别不出新旧的,只有和其他时间对比才能判别新旧,那么和谁对比呢?其实是拿源文件和可执行程序对比。
源文件是文件,我们形成的可执行程序也是文件。重新编译的本质,就是重新写入一个二进制可执行文件,它的修改时间理所当然的也会更改。并且,源文件的修改时间一定在可执行程序之前,因为可执行程序是后形成的。所以,如果源文件的修改时间比可执行程序早,那它就是新文件,不能重新编译;反之则是修改过的文件,可以重新编译。
2. 验证加讲解文件时间属性:
可以看到时间属性有三个,其中Access
表示对内容的最近访问时间,Modify
表示对内容的最近修改时间,Change
表示对属性的最近修改时间。
其中Change time
改变,可能只改变它自己,例如对文件的权限进行修改;对Modify time
改变,大多数情况下会和Change time
,Accsee time
联动,例如用vim修改文件,大小属性会变,访问时间也要变;Access time
改变,会和Change time
联动,因为Accsee time
也是属性,例如查看文件内容。
但是我们会发现,有时我们即使用cat查看了文件内容,Accsee
时间也不会改变,这又是为什么?一般而言,一个文件被查看的频率是非常高的,我们所看到的文件,都是在磁盘中存放的,更改时间的本质,其实就是访问磁盘。若Linux系统中充满大量访问磁盘的io操作,实则是变相的减慢了系统速度,所以系统做了一些特殊处理,对更改Accsee
时间,添加了次数限制,具体是多少完全看内核。
特殊记忆:文件有ACM
时间。
3. 更改文件时间戳:
可以使用touch
命令更改文件的时间戳。
直接touch + filename
可以更新文件的所有时间(ACM
时间)。细心的大家肯定发现了,Change
时间一直在跟着其他两个时间改变,这是因为时间属性也是属性,改变属性,Change
时间就会变。
4. 总结:
make
配合Makefile
可以做到,通过时间对比,不让有些代码进行重新编译;- 伪目标的作用是,可以让依赖方法总是被执行,不会被任何情况拦截。
4.3 make/Makefile具有依赖性的推导能力
重新编写Makefile
如下图(提前声明,实际应用中是严重不推荐这样写的,直接gcc
即可):
make
在执行Makefile
文件时,从上到下扫描,先看到mybin
,依赖环境是hello.o
,但是此时hello.o
不存在,依赖方法无法执行,先将其入栈,接着向下扫描;再看到hello.o
,依赖方法是hello.s
,不存在,依赖方法无法执行,也将其入栈,接着向下扫描;依次类推,依赖环境不存在就一直向下扫描。
直到扫描到hello.i
,它的依赖环境是hello.c
,hello.c
存在,执行依赖方法,然后往回推导,依次出栈,完成依赖方法。
执行make
和make clean
:
现阶段先了解到这里,我们已经会对单文件做自动化构建和清理了,当然后面还有对多文件的自动化构建和清理,现阶段我们暂时用不上。
4.4 make/Makefile语法拓展
1. 设置不显示提示信息:
在上面的实验中,我们在执行make
和make clean
时,会发现执行完成后会有一行提示信息。现在我们不想要这些提示信息了,并且想让其输出我们设置的信息。
只需要在依赖方法前加上@
,就不会打印提示信息了;并且我们可以通过echo
输出我们设置的信息,来实践一下:
2. Makefile支持设置变量(也可以理解成宏):
实践一下:
3. 依赖关系和目标文件可以简写:
依赖关系可以简写成$^
,目标文件可以简写成$@
。