Linux从0到1——Linux环境基础开发工具的使用(上)

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 allyum makecache就可以了。一个是清空缓存,一个是重新制作缓存。


2. Linux编辑器:vi/vim


在这里插入图片描述

vi/vim其实就是一款文本编辑器。vi/vim的区别简单点来说,它们都是多模式编辑器,不同的是vimvi的升级版本,它不仅兼容vi的所有指令,而且还有一些新的特性在里面。例如语法加亮,可视化操作不仅可以在终端运行,也可以运行于x windowmac oswindows。我们课堂上,统一按照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 modessix 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 1
 
int main()
{
#if V1
    printf("免费社区版\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 V2
    printf("专业版本\n");
#else
    printf("超级会员版\n");
#endif
    return 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. 小实验:

我们先来创建一个makefileMakefile文件,一般建议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是一个伪目标。

那么又产生了一个新的问题,为什么在我们编译代码的时候,makefilemake总不让我们重新编译我们的代码?现在我们写的代码还是很小型的,不管是编译还是重新编译,它的速度都是很快的。但是设想一下,我们今后处理的项目可能有上万行代码,它编译的速度是非常慢的,所以重新编译代码将是一件很耗费资源的事情。为了节省资源,避免误操作,对于没有更改过的新代码,就不让你重新编译了。

那么,make是怎么判断你是不是新文件的呢?判断的依据就是文件的修改时间。但是,单凭一个文件的修改时间是判别不出新旧的,只有和其他时间对比才能判别新旧,那么和谁对比呢?其实是拿源文件和可执行程序对比。

源文件是文件,我们形成的可执行程序也是文件。重新编译的本质,就是重新写入一个二进制可执行文件,它的修改时间理所当然的也会更改。并且,源文件的修改时间一定在可执行程序之前,因为可执行程序是后形成的。所以,如果源文件的修改时间比可执行程序早,那它就是新文件,不能重新编译;反之则是修改过的文件,可以重新编译。

2. 验证加讲解文件时间属性:

在这里插入图片描述

可以看到时间属性有三个,其中Access表示对内容的最近访问时间,Modify表示对内容的最近修改时间,Change表示对属性的最近修改时间。

其中Change time改变,可能只改变它自己,例如对文件的权限进行修改;对Modify time改变,大多数情况下会和Change timeAccsee 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.chello.c存在,执行依赖方法,然后往回推导,依次出栈,完成依赖方法。

执行makemake clean

在这里插入图片描述

现阶段先了解到这里,我们已经会对单文件做自动化构建和清理了,当然后面还有对多文件的自动化构建和清理,现阶段我们暂时用不上。


4.4 make/Makefile语法拓展


1. 设置不显示提示信息:

在上面的实验中,我们在执行makemake clean时,会发现执行完成后会有一行提示信息。现在我们不想要这些提示信息了,并且想让其输出我们设置的信息。

在这里插入图片描述

只需要在依赖方法前加上@,就不会打印提示信息了;并且我们可以通过echo输出我们设置的信息,来实践一下:

在这里插入图片描述

2. Makefile支持设置变量(也可以理解成宏):

在这里插入图片描述

实践一下:

在这里插入图片描述

3. 依赖关系和目标文件可以简写:

在这里插入图片描述

依赖关系可以简写成$^,目标文件可以简写成$@


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/452792.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【全志H616】-2 写一个自己的串口

【全志H616】-2 写一个自己的串口 1、基本命令 重启 sudo rebootLinux系统下一个文件夹的文件复制到另一个文件夹下 cp flags.c /home/user05/lab09/flags_revised.c //复制当前文件夹下的 flags.c 文件到 lab09 文件夹下flags_recised.c 文件cp oled_demo.c /home/orangep…

在图片上进行标记

文章目录 需求分析 需求 底图是一张图片&#xff0c;要在图上做标记&#xff0c;对标记的位置有交互行为鼠标滚顶页面&#xff0c;标记位置不发生变化页面发生缩放&#xff0c;标记位置不发生变化 分析 <template><divv-loading"loading"class"point-m…

什么是智慧公厕?对公共厕所智能实时监测管理控制,城市管理更高效智能

公共厕所一直以来都是城市管理的难题之一&#xff0c;但随着智慧科技的发展和应用&#xff0c;智慧公厕成为了解决这一问题的利器。智慧公厕是一种信息化的新型公共厕所&#xff0c;通过全面感知平台实时监测公共厕所的使用状态&#xff0c;并将数据转化为可视、可算、可管的数…

读取txt文件并统计每行最长的单词以及长度

读取txt文件并统计每行最长的单词以及长度 题目 在 D:\\documant.txt 文本中,文件中有若干行英文文本,每行英文文本中有若干个单词&#xff0c;每个单词不会跨行出现每行至多包含100个字符,要求编写一个程序,处理文件,分析各行中的单词,找到每行中的最长单词&#xff0c;分别…

互联网剧本杀小程序,如何创新发展提高收益

近年来&#xff0c;剧本杀深受年轻人的喜欢&#xff0c;一度成为了大众的社交方式&#xff0c;剧本杀为年轻人提供了一个全新的娱乐游戏和社交为一体的模式。 不过随着剧本杀市场入局的人越来越多&#xff0c;市场的发展也迎来了“拐点”&#xff0c;剧本杀逐渐趋向高质量发展…

190基于matlab的tfrSTFT时频分布图

基于matlab的tfrSTFT时频分布图&#xff0c;计算时间序列的STFT时频分布图&#xff0c;得到瞬时频率。通过GUI可以调节图像的展示样式。程序已调通&#xff0c;可直接运行。 190 STFT时频分布图 瞬时频率 能量谱 (xiaohongshu.com)

openGauss使用BenchmarkSQL进行性能测试(上)

一、前言 本文提供openGauss使用BenchmarkSQL进行性能测试的方法和测试数据报告。 BenchmarkSQL&#xff0c;一个JDBC基准测试工具&#xff0c;内嵌了TPC-C测试脚本&#xff0c;支持很多数据库&#xff0c;如PostgreSQL、Oracle和Mysql等。 TPC-C是专门针对联机交易处理系统…

软考高项总结:第16章采购管理(一)

一、管理基础 1、项目采购管理包括从项目团队外部采购或获取所需产品、服务或成果的各个过程。例如合同、订购单、协议备忘录(MOA)和服务水平协议(SLA)。被授权采购项目所需货物、服务的人员可以是项目团队、管理层或组织采购部的成员。 2、协议可以是合同、服务水平协议(SL…

基于AM62X+FPGA/MCU的B码对时定制化整机解决方案

什么是IRIG-B码对时 IRIG-B(inter-range instrumentationgroup-B)码是一种时间同步标准&#xff0c;通常用于精确的时间测量和数据同步&#xff0c;广泛应用于电力、通信、航空等领域。 IRIG-B码为每秒一帧的时间串码&#xff0c;一帧串码中包含100个码元&#xff0c;频率为1K…

git svn混用

背景 项目代码管理初始使用的svn, 由于svn代码操作&#xff0c;无法在本地暂存&#xff0c;有诸多不便&#xff0c;另外本人习惯使用git. 所以决定迁移至git管理 迁移要求&#xff1a; 保留历史提交记录 迁移流程 代码检出 git svn svn_project_url git代码提交 修改本…

可回馈式直流电子负载原理是怎样的

可回馈式直流电子负载可以将电能回馈到电网中&#xff0c;从而实现对电源系统的测试和分析。其工作原理主要包括以下几个方面&#xff1a; 1. 能量转换&#xff1a;可回馈式直流电子负载通过内部的功率开关管将输入的直流电转换为交流电&#xff0c;然后通过变压器将电压升高或…

【阿里云系列】-部署ACK集群的POD应用日志如何集成到日志服务(SLS)中

介绍 我们在实际部署应用到阿里云的ACK集群后&#xff0c;由于后期应用服务的持续维护诉求可能需要跟踪排查问题&#xff0c;此时就要具备将应用的历史日志存档便于后期排查问题 处理方式 为了解决以上的普遍需求&#xff0c;需要将ACK中的应用日志采集到SLS的Logstore中,然…

SpringBoot实战项目——博客笔记项目

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、项目介绍二、项目的整体框架 2.1 数据库模块 2.2 前端模块 2.3 后端模块三、项目图片展示四、项目的实现 4.1 准备工作 4.…

HarmonyOS-页面跳转Router实例演示

本文将以APP的登录和修改昵称为例演示官网的几种页面跳转、返回以及这些流程携带参数&#xff0c;实例的形式记录学习HarmonyOS的页面跳转。 “页面路由指在应用程序中实现不同页面之间的跳转和数据传递。HarmonyOS提供了Router模块&#xff0c;通过不同的url地址&#xff0c;…

47、C++/引用,函数重载,类相关学习20240312

一、自己封装一个矩形类(Rect)&#xff0c;拥有私有属性:宽度(width)、高度(height)&#xff0c; 定义公有成员函数: 初始化函数:void init(int w, int h) 更改宽度的函数:set_w(int w) 更改高度的函数:set_h(int h) 输出该矩形的周长和面积函数:void show()。 代码&…

在 Rust 中使用 Serde 处理json

在 Rust 中使用 Serde 处理json 在本文中&#xff0c;我们将讨论 Serde、如何在 Rust 应用程序中使用它以及一些更高级的提示和技巧。 什么是serde&#xff1f; Rust中的serde crate用于高效地序列化和反序列化多种格式的数据。它通过提供两个可以使用的traits来实现这一点&a…

数字孪生+工业互联网标识解析,打造智能工厂新标杆!

当前&#xff0c;工业4.0浪潮愈发澎湃&#xff0c;加快数字化、网络化、智能化发展成为了制造业转型升级的必然要求。 51WORLD基于数字孪生技术与工业互联网标识解析体系&#xff0c;打造了一个集协同化供应、个性化定制、智能化生产于一体的全连接产线孪生平台&#xff08;以…

AndroidStudio设计登录页源码(音悦app)

目录 一、代码 二、效果 一、代码 1.在activity_main.xml里的代码 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent&quo…

(一)RabbitMQ实战——rabbitmq的核心组件及其工作原理介绍

前言 RabbitMQ是一个开源的消息代理软件&#xff0c;它实现了高级消息队列协议&#xff08;AMQP&#xff09;标准&#xff0c;提供可靠的消息传递机制。RabbitMQ可以用于在应用程序之间传递消息&#xff0c;实现不同应用系统之间的解耦和通信。它支持多种编程语言&#xff0c;…

11.Java---语法总结之一个小项目

图书管理系统 Java学习了很久了,今天将运用之前学习的所有东西整理做个小小的小项目. 1.首先是各种包和操作方法建好 2.然后是项目的大框架搭好 3.然后就开始实现各个部分了 看看最后的运行结果吧! 管理员测试 1.登录&显示图书的运行结果 2.查找&新增图书的运行结…