Linux环境开发工具使用(yum、vim、gcc、g++、gdb、make/Makefile)
Linux软件包管理器 - yum
Linux下安装软件的方式
  1. 在gitee或者GitHub上面下载程序的源码,自行进行编译得到可执行程序(工作中常用)
  2. 获取rpm安装包,通过rpm命令进行安装
  3. 通过yum进行安装软件(常用)
什么是软件包

我们知道在Linux下安装软件,可以采用下载程序的源代码,并对其进行编译,得到可执行程序。

但是这样做太麻烦了,于是有些人把一些常用的软件提前编译好,做成软件包(可以理解成windows上的安装程序)放在一个服务器上,通过软件包管理器可以很方便的获取到这个编译好的软件包,直接进行安装。

软件包和软件包管理器,就好比我们手机上面“App”和“应用市场”这样的关系

yum(Yellow dog Updater,Modified)是Linux下常用的一种软件包管理器,主要应用在Fedora,RedHat,Centos等发行版上。

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

由于yum是在服务器上下载软件包的,因此在下载时我们必须保证当前主机(虚拟机)是联网的,我们可以通过ping指令来判断当前云服务器是否联网。

在这里插入图片描述

查看软件包

我们可以通过yum list命令来罗列出当前一共有哪些安装包,但是由于安装包的数目可能非常的多,这里我们使用我们前面学的grep命令来筛选出我们关注的安装包。例如:

[root@izuf65cq8kmghsipojlfvpz ~]# yum list | grep vim

在这里插入图片描述

上面的这个操作相当于我们在手机上面搜索我们想要下载的软件。

注意一下:

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

指令: sudo yum install 软件名

[mlf@izuf65cq8kmghsipojlfvpz ~]$ sudo yum install lrzsz

yum会自动找到都有哪些软件包需要下载, 这时候敲 “y” 确认安装

出现"complete"字样时,说明安装完成。

在这里插入图片描述

注意:

  • 安装软件时由于需要向系统目录中写入内容, 一般需要 sudo 或者切到 root 账户下才能完成.
  • yum安装软件只能一个装完了再装另一个. 正在yum安装一个软件的过程中, 如果再尝试用yum安装另外一个软件, yum会报错.
如何实现本地机器和云服务器之间的文件互传

因为我们上面已经安装了lrzsz,下面我们就来说一下lrzsz如何使用。

指令: rz - E

通过该指令我们可以将本地的文件上传到云服务器上

在这里插入图片描述

在这里插入图片描述

指令: sz 文件名

该指令可以将云服务器上的文件下载到本地机器的指定文件夹

在这里插入图片描述

如何卸载软件

指令: sudo yum remove 软件名

[mlf@izuf65cq8kmghsipojlfvpz ~]$ sudo yum remove lrzsz

当输入上述指令后,yum会自动卸载该软件,这时候它也会想安装的时候一样询问你是否确定卸载(安装),敲y即确认卸载(安装),敲n则表示否,当出现"complete"字样时,表示卸载完成。

Linux编辑器-vim
vim的基本概念

这里要说一个概念:我们一般是通过编辑器来编写代码,通过编译器来编译代码,通过调试器来调试代码的。

在Windows下,我一般是使用vs2013这个软件来编写代码、编译代码、以及调试代码的。这个时候大家会有点好奇假如像上面所说的那样,编写代码、编译代码、调试代码分别需要编辑器、编译器和调试器。那么为什么我没有像上面说的那样用三个软件来完成上面的三个操作呢?

这是因为我们的vs2013它是一个集成开发工具,它可以同时完成编写代码、编译代码以及调试代码的功能。

那么在我们Linux中,我们是通过什么来编写代码、编译代码和调式代码的呢?

在这里插入图片描述

因此这里我们就可以知道vim是Linux中的一共文本编辑器,它可以用来进行代码编写

vim它有好多种模式,但是我们只讲三种比较常用的模式: 分别是命令模式(command mode)、插入模式(Insert mode)和底行模式(last line mode), 各模式的功能区如下:

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

控制屏幕光标的移动,字符、字或行的删除,移动复制某区段及进入Insert mode下,或者到 last line mode

  • 插入模式(Insert mode)

只有在Insert mode下,才可以做文字输入,按「ESC」键可回到命令行模式。该模式是我们后面用的最频繁的编辑模式。

  • 底行模式(last line mode)

文件保存或退出,也可以进行文件替换,找字符串,列出行号等操作。 在命令模式下,shift+;(也就是我们的:)即可进入该模式。要查看你的所有模式:打开vim,底行模式直接输入

:help vim-modes

vim下三种模式的切换

指令: vim 文件名

[mlf@izuf65cq8kmghsipojlfvpz ~]$ vim test.c

需要注意的是:我们进入vim之后,默认是处于命令模式(正常模式),我们要想输入文字就得切换到我们的插入模式才行。

在这里插入图片描述

[命令模式]切换至[插入模式]

  • 输入i:在当前光标处进入插入模式

  • 输入a:在当前光标的下一个位置进入插入模式

  • 输入o:在当前光标的下一行行首位置进入插入模式

[命令模式]切换至[底行模式]

  • 输入Shift+;(也就是:)即可从命令模式进入底行模式

[插入模式]或[底行模式]切换至[命令模式]

  • 要想在插入模式或者底行模式下切回至命令模式,只需要按一下[Esc]键即可
vim命令模式命令集
移动光标
  • vim可以直接用键盘上的光标来上下左右移动,但正规的vim是用小写英文字母「h」、「j」、「k」、「l」,分别控制光标左、下、上、右移一格。大家可能觉得通过这四个字母来控制上下左右移动并不好记,那么我来教给大家一个记忆的方法:

​ 「h」、「j」、「k」、「l」这四个键,h与l分别在他们四个之中处于最左以及最右的位置,因此h键可以控制光标左移一格,而l键可以控制光标右移一格,那么j与k我们又怎么记忆呢?j想象成jump,这个单词意思是跳跃,跳跃肯定也就是从上往下,因此就有着向下的意思,所以j键可以控制光标下移一格,至于我们的k键也比较好记,我们把它想象成king,这个单词的意思是国王,国王在一个国家里他的身份低位都是最高的,因此就有着向上的意思,所以k键可以控制光标上移一格。

  • 按「$」:移动到光标所在行的“行尾”
  • 按「^」:移动到光标所在行的“行首”
  • 按「w」:光标从左往右,从上到下跳到下个字的开头
  • 按「e」:光标从左往右,从上到下跳到下个字的结尾
  • 按「b」:光标从右往左,从下到上回到上个字的开头
  • 按「#l」:光标移到该行的第#个位置,如:5l,56l
  • 按[gg]:进入到文本开始
  • 按[shift+g]:进入文本末端
  • 按「ctrl」+「b」:屏幕往“后”移动一页
  • 按「ctrl」+「f」:屏幕往“前”移动一页
  • 按「ctrl」+「u」:屏幕往“后”移动半页
  • 按「ctrl」+「d」:屏幕往“前”移动半页
删除
  • 「x」:每按一次,删除光标所在位置的一个字符
  • 「#x」:例如,「6x」表示删除光标所在位置的“后面(包含自己在内)”6个字符
  • 「X」:大写的X,每按一次,删除光标所在位置的“前面”一个字符
  • 「#X」:例如,「20X」表示删除光标所在位置的“前面”20个字符
  • 「dd」:删除光标所在行
  • 「#dd」:从光标所在行开始删除#行
复制粘贴
  • 「yy」:复制光标所在行到缓冲区。
  • 「#yy」:例如,「6yy」表示拷贝从光标所在的该行“往下数”6行文字。
  • 「p」:将缓冲区内的字符贴到光标所在位置。注意:所有与“y”有关的复制命令都必须与“p”配合才能完成复制与粘贴功能。
  • 「yw」:将光标所在之处到字尾的字符复制到缓冲区中。
  • 「#yw」:复制#个字到缓冲区
剪切
  • 「dd」:剪切光标所在行
  • 「#dd」:剪切从光标所在行开始往下的#行
  • 「p」:将已剪切的内容粘贴到光标的下一行
  • 「#p」:将已剪切的内容粘贴#次到光标的下一行
替换
  • 「r」:替换光标所在处的字符。
  • 「R」:替换光标所到之处的字符,直到按下「ESC」键为止。
大小写切换
  • 「~」:将光标所在处的字符替换成大写(或者小写)。
  • 「#~」:将光标开始往后的#个字符替换成大写(或者小写)。
撤销
  • 「u」:如果您误执行一个命令,可以马上按下「u」,回到上一个操作。按多次“u”可以执行多次回复。
  • 「ctrl + r」: 撤销的恢复
更改
  • 「cw」:将光标所在位置开始到字尾的字符删除,并进入插入模式、
  • 「c#w」:将光标所在位置开始到字尾的#个字符删除,并进入插入模式
vim底行模式命令集

在使用底行模式之前,请记住先按「ESC」键确定您已经处于正常模式,再按「:」冒号即可进入底行模式。

列出行号
  • 「set nu」: 输入「set nu」后,会在文件中的每一行前面列出行号。
  • 「set nonu」: 输入「set nonu」后,取消显示行号。
保存退出
  • 「w」: 在冒号输入字母「w」就可以将文件保存起来
  • 「q」:按「q」就是退出,如果无法离开vim,可以在「q」后跟一个「!」强制离开vim。
  • 「wq」:一般建议离开时,搭配「w」一起使用,这样在退出的时候还可以保存文件。
查找字符
  • 「/关键字」: 先按「/」键,再输入您想寻找的字符,如果第一次找的关键字不是您想要的,可以一直按「n」会往后寻找到您要的关键字为止。
  • 「?关键字」:先按「?」键,再输入您想寻找的字符,如果第一次找的关键字不是您想要的,可以一直按「n」会往前寻找到您要的关键字为止。
  • 注:/是从左往右,从上往下查找字符,?是从右往左,从下往上查找字符。
分屏指令
  • 「vs 文件名」:实现多文件的编辑
  • 「Ctrl+w+w」:光标在多文件下切换,类似于在windows下Alt+Tab的功能。
执行指令
  • 「!+指令」:在不退出vim的情况下,我们照样可以执行指令,我们只需要在底行模式下输入!+指令就可以执行当前指令了。
vim的简单配置

配置文件的位置

  1. 在目录 /etc/ 下面,有个名为vimrc的文件,这是系统中公共的vim配置文件,对所有用户都有效。
  2. 而在每个用户的主目录下,都可以自己建立私有的配置文件,命名为:“.vimrc”。例如,/root目录下,通常已经存在一个.vimrc文件,如果不存在,则创建之。
  3. 切换用户成为自己执行su,进入自己的主工作目录,执行 cd ~
  4. 打开自己目录下的.vimrc文件,执行 vim .vimrc

常用配置选项,用来测试

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

vim的配置比较复杂,某些配置可能还需要使用插件,建议不要自己一个个去配置,我们可以执行以下指令来配置(想在哪个用户下让vim配置生效, 就在哪个用户下执行这个指令. 强烈 “不推荐” 直接在 root 下执行)

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

需要按照提示输入 root 密码.

在这里插入图片描述

然后等待安装配置,最后手动执行source ~/.bashrc即可

在这里插入图片描述

配置完成后,像自动补全,行号显示以及自动缩进等功能就都有了。

Linux编译器 - gcc/g++

gcc和g++分别是GNU的C和C++的编译器

C与C++的编译器在生成一个可执行程序时一般会有以下四个步骤:

  1. 预处理:头文件展开、去掉注释、宏替换、条件编译等。
  2. 编译:将C代码翻译形成汇编代码
  3. 汇编:将汇编代码转换为二进制代码
  4. 链接:将目标文件和系统库进行链接形成可执行程序
gcc/g++的语法

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

常用选项:

1)-E: 只激活预处理,这个不生成文件,你需要把它重定向到一个输出文件里面(否则将把文件预处理后的结果打印到屏幕上)

2)-S: 编译到汇编语言不进行汇编和链接

3)-c: 编译到目标代码

4)-o: 将处理结果输出到指定文件,该选项后紧跟输出文件名

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

6)-g: 生成调试信息(若不加该选项中,则默认生成release版本。无法调试)

7)-shared:此选项将尽量使用动态库,所以生成文件比较小,但是需要系统由动态库.

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

9)-Wall:生成所有警告信息。

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

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

在这里插入图片描述

在这里插入图片描述

编译
[root@izuf65cq8kmghsipojlfvpz ~]# gcc -S file.i -o file.s
  • 在这个阶段中,gcc 首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,gcc 把代码翻译成汇编语言。
  • 用户可以使用“-S”选项来进行查看,该选项只进行编译而不进行汇编,生成汇编代码。

在这里插入图片描述

汇编
[root@izuf65cq8kmghsipojlfvpz ~]# gcc -c file.s -o file.o
  • 汇编阶段是把编译阶段生成的“.s”文件转成目标文件
  • 读者在此可使用选项“-c”就可看到汇编代码已转化为“.o”的二进制目标代码了

在这里插入图片描述

链接
[root@izuf65cq8kmghsipojlfvpz ~]# gcc file.o -o file
  • 在成功编译之后,就进入了链接阶段。
  • 链接的主要任务就是将生成的各个xxx.o的文件链接起来,生成可执行文件
  • gcc/g++不带-E、-S、-c选项时,就默认生成预处理、编译、汇编、链接全过程后的文件
  • 如果不用-o选项指定生成文件的文件名,那么默认生成的可执行文件的文件名为a.out

在这里插入图片描述

在这里插入图片描述

静态库与动态库

函数库一般分为静态库和动态库两种:

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

那么我们应该如何区理解动态库与静态库呢?

下面我来给大家讲一个故事来帮助大家理解动态库与静态库

不知道大家以前有没有去过网吧,在我小学的那个时候网吧还不是很流行,当时隔老远才会有一家网吧。

在小学的时候老师在放学回家之前总会给我们布置一些作业,回到家做作业的时候发现有的作业不会做,翻书也找不到答案。这个时候呢我就跑去网吧,去上网看看能不能找到相应的资料或者答案,找到了答案之后我便回家了。 这里的网吧就是我们的动态库,而我们的作业就相当于我们的程序。

由于你每次查阅资料都要去网吧,并且每次去网吧就得花上你20-30分钟的路程,在去网吧的这个路上就已经花费很多时间了,然后你爸觉得儿子学习这么认真并且也不应该浪费这么多时间在去网吧的路上,因此你爸给你买了一台新的电脑或者说从网吧里面淘了一台二手的电脑给你。这个时候老师给我们布置作业,我们要是遇到不会的作业我们就不必再跑到网吧去查资料或者答案了,因为我们自己现在家里就有一台电脑,电脑有着我们想查阅的一切资料或答案,因此我们要想查资料和答案就不必再跑去网吧了,我们只需要打开家里的电脑就可以查阅了。 这里家里的电脑就相当于时我们的静态库,而我们的作业就相当于我们的程序。

动态链接:

优点:程序体积比较小,比较省系统资源(磁盘和内存)

缺点:比较依赖动态库,一旦库缺失,所有依赖的程序都不可运行。

静态链接:

优点:不依赖第三方库,程序的可移植性好

缺点:程序的体积非常大,浪费系统空间

gcc/g++默认生成的二进制程序,是动态链接的,这点可以通过file命令来查看。

在这里插入图片描述

其次我们还可以通过ldd指令来查看动态链接的可执行程序所依赖的库

在这里插入图片描述

虽然说gcc/g++默认生成的二进制程序是动态链接的,但是如果想生成的二进制程序是静态链接的话只需在后面加上-static即可

[root@izuf65cq8kmghsipojlfvpz ~]# gcc -static file.c -o file_st

大家在使用这个命令的时候可能会由于当前云服务器上面没有下载静态库而导致出错,因此我们需要先使用下面这两条命令分别下载gcc/g++静态库之后再去静态链接就不会出错了

  yum install glibc-static
  yum install glibc-static libstdc++-static

可以看到我们生成的file_st可执行程序就是静态链接的了。

在这里插入图片描述

我们还可以发现静态链接与动态链接的可执行程序的文件大小是相差很大的。

在这里插入图片描述

这也证明我们上面说的:动态链接的可执行程序体积比较小省空间和资源,静态链接的可执行程序体积是非常大的,有点浪费空间。

Linux调试器-gdb
背景

程序的发布方式有以下两种:

1.debug版本:程序本身会被加入一些调试信息,以便进行调试。

2.release版本:程序不会添加任何调试信息,是不可调试的。

在Linux当中gcc/g++默认生成的可执行程序是release版本,它是不可调试的,我们如果想调试的话就必须得生成debug版本,想生成debug版本就得在gcc/g++后面加上-g选项。

我们下面对同一个文件分别生成它的debug版本与release版本,我们来对比以下这两这个版本的可执行程序有什么区别

在这里插入图片描述

我们可以看到debug版本的可执行程序比release版本的可执行程序的大小要大一些,这就是我们上面说的debug版本中会假如一些调试信息,因此它会比release版本的可执行程序大。

gdb命令集
显示
  • list/l 行号:显示binFile源代码,接着上次的位置往下列,每次列10行。
  • list/l 函数名:列出某个函数的源代码。
  • print/p 表达式:打印表达式的值,通过表达式可以修改变量的值或者调用函数
  • print/p 变量:打印变量的值
  • print/p &变量:打印变量的地址
  • display 变量名:跟踪查看一个变量,每次停下来都显示它的值
  • undisplay 编号:取消对先前设置的那些变量的跟踪
调试
  • r或run:运行程序(开始调试)。
  • n 或 next:逐过程调试(相当于vs调试时的F10)
  • s或step:逐语句调试(相当于vs调试时的F11)
  • set var = x:修改变量var的值为x
  • until X 行号:跳至X行
  • continue(或c):跳到下一个断点处(相当于vs调试时的F5)
  • finish:执行完当前正在调用的函数,然后停下来等待命令(注意不能是主函数)
断点
  • break(b) 行号:在某一行设置断点
  • break 函数名:在某个函数开头设置断点
  • info break :查看断点信息。
  • delete breakpoints:删除所有断点
  • delete breakpoints n:删除编号为n的断点
  • disable breakpoints n:禁用编号为n的断点
  • enable breakpoints n:启用编号为n的断点
退出
  • quit\q:退出gdb
Linux项目自动化构建工具-make/Makefile

make与Makefile的重要性

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

在使用make/Makefile之前我们首先应该理解两个概念–什么是依赖关系?什么是依赖方法?

依赖关系: 决定了能不能这样做,比如说:生活中隐形的依赖关系——你是你爸的儿子,你管你爸叫爸爸。

在文件当中如何理解依赖关系呢?

比如说一个test.o文件它是通过test.c文件经过预处理、编译、汇编等过程得到的,我们就说test.o文件是依赖于test.c文件的。简单来说就是我们知道通过test.c可以得到test.c这个文件,那么我们就称test.c是依赖于test.o的

依赖方法: 决定了如何做,我要干什么。比如说:你打电话给你爸说:爸这个月生活费用完了,给我打点生活费。因为你是你爸的儿子所以你可以去问你爸要生活费,你去问你爸要生活费的过程就是依赖方法。

在文件当中如何理解依赖方法呢?

比如说我们的test.o是依赖test.c文件的,我们通过gcc -c test.c-o test.o指令可以得到test.o文件,那么我们称test.o依赖于test.c的依赖方法就是gcc -c test.c-o test.o。简单来说就是我们知道test.o是依赖于test.c的,通过test.c得到test.o的这个方法或者指令就称作它的依赖方法。

多文件编译

假如说我们现在有两个或者三个源文件,我们应该如何进行编译生成可执行程序呢?

方法一:

通过使用gcc指令对多个源文件进行编译进而生成可执行程序

在这里插入图片描述

但是我想说的是使用这种方法对多文件进行编译并不好,第一个文件多了敲起来麻烦,第二个只要其中有一个文件被修改了那么再生成可执行程序的时候所有的文件都得重新编译,假如说以后到了公司里面,有上百万的文件编译起来估计就得半个小时或者一个小时,当你或者你的同时不小心修改了一个小文件,然后你们想再去生成可执行程序,那就得去重新编译一下,这么一个小小的举动就得花费半个小时甚至是一个小时,这是一种极大的浪费。

方法二:

每个源文件各自生成自己的二进制文件,然后再将这些二进制文件链接起来生成可执行程序

在这里插入图片描述

注意: 编译链接的时候不需要加上头文件,因为编译器通过源文件的内容可以知道自己所需的头文件名字,而通过头文件的包含方式(“尖括号”包含和”双引号“包含),编译器可以知道应该从何处去寻找所需头文件。

虽然上面说了第二种方法比第一种方法更优,但是它还是存在一些弊端。随着源文件个数的增多,我们重新生成可执行程序时,所需输入的gcc指令的长度也会随之增加。

为了解决这个问题make/Makefile登场了。

make/Makefile的使用

第一步:在Linux中创建一个名为Makefile/makefile的文件

在这里插入图片描述

第二步:编写Makefile

Makefile文件最简单的编写格式是先写出各文件之间的依赖关系,如何写出这些文件的依赖方法,依次写下去。

在这里插入图片描述

第三步:编写完Makefile之后进入命令模式保存退出,然后在外面执行make指令便可以生成可执行程序。

在这里插入图片描述

Makefile文件还有一种简写方式:

  • $@:表示依赖关系中的目标文件(冒号的左侧)
  • $^:表示依赖关系中的依赖文件列表(冒号右侧全部)
  • $<:表示依赖关系中的第一个依赖文件(冒号右侧第一个)

因此我们可以写成这样:

在这里插入图片描述

注意:依赖关系不成立,依赖方法不执行

make原理
  1. make会在当前目录下找名字叫“Makefile”或“makefile”的文件。
  2. 如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,他会找到“test”这个文件,并把这个文件作为最终的目标文件。
  3. 如果test文件不存在,或是test所依赖的后面的test.o和qwe.o文件的文件修改时间要比test这个文件新(可以用touch测试),那么,他就会执行后面所定义的命令来生成test这个文件。
  4. 如果test所依赖的test.o与qwe.o文件不存在,那么make会在当前文件中找目标为main.o和qwe.o文件的依赖性,如果找到则再根据那一个规则生成hello.o和qwe.o文件。(这有点像一个堆栈的过程)
  5. 当然,你的test.c和qwe.c文件是存在的啦,于是make会生成 test.o与qwe.o 文件,然后再用 test.o与qwe.o 文件生成make的终极任务,也就是执行文件hello了。
  6. 这就是整个make的依赖性,make会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件。
  7. 在找寻的过程中,如果出现错误,比如最后被依赖的文件找不到,那么make就会直接退出,并报错,而对于所定义的命令的错误,或是编译不成功,make根本不理。
项目清理
  • 工程是需要被清理的,但是我们执行依次make生成可执行程序都要我们手动去清理的话这样太麻烦了,因此我们可以将项目清理的指令放到Makefile中

在这里插入图片描述

  • 像clean这种,没有被第一个目标文件直接或间接关联,那么它后面所定义的命令将不会被自动执行,不过,我们可以显示要make执行。即命令——“make clean”,以此来清除所有的目标文件,以便重编译。

在这里插入图片描述

  • 一般我们这种clean的目标文件,我们将它设置为伪目标,用.PHONY修饰 ,伪目标的特性是:总是被执行的。
Linux第一个小程序 - 进度条
行缓冲区概念

首先我们通过运行两段代码来感受一下缓冲区的存在

在这里插入图片描述

对于上面这段代码,在Linux上会先输出字符串hello Makefile然后再休眠3秒程序运行结束。

你觉得下面这段代码的运行结果是什么呢?

在这里插入图片描述

这段代码的运行结果是:先休眠了3秒,然后打印字符串hello Makefile最后程序运行结束,这个现象也就证明了缓冲区的存在。

我们这段代码与上面的代码仅仅只是少了一个’\n’,但是运行结果却截然不同。

C(任何语言)程序再运行的时候,默认都是从上到下依次执行,除非for,函数,if等。上面的代码一定是先执行立printf(字符串被写入到了C程序的缓冲区当中,但并没有被输出!!!),在执行sleep。sleep结束,缓冲区内容被刷新,则才看到字符串的输出。

缓冲区就是一块内存,它有三种刷新策略:行刷新/程序结束自动刷新/强制刷新。

行刷新——’\n’

强制刷新——fflush(stdout)

\r与\n

\r: 回车,使光标回到本行行首

\n: 换行,使光标移动到下一行的位置。

而我们常说的回车其实是这里的\r+\n。

进度条代码以及效果展示

在这里插入图片描述

效果展示:

在这里插入图片描述

本内容为合法授权发布,文章内容为作者独立观点,不代表开发云立场,未经允许不得转载。

CSDN开发云