目录
Linux软件包管理器 - yum
在开始说yum之前,我们先从Linux的角度解释什么是软件包
在Linux下安装软件, 一个通常的办法是下载到程序的源代码, 并进行编译, 得到可执行程序.
但是这样太麻烦了, 于是有些人把一些常用的软件提前编译好, 做成软件包(可以理解成windows上的安 装程序)放在一个服务器上, 通过包管理器可以很方便的获取到这个编译好的软件包, 直接进行安装.
软件包和软件包管理器, 就好比 "App" 和 "应用商店" 这样的关系. yum(Yellow dog Updater, Modified)是Linux下非常常用的一种包管理器. 主要应用在Fedora, RedHat, Centos等发行版上.
Linux下安装软件包的方式
在Linux下安装软件包的方法大概有以下三种:
1)下载到程序的源代码,自行进行编译,得到可执行程序。
2)获取rpm安装包,通过rpm命令进行安装。(未解决软件的依赖关系)
3)通过yum进行安装软件。(常用)
那么解释一下,这三种方法,放到windows的环境下,是怎么样的
1)我们看到在GitHub上,看到一个非常不错的开源项目软件,你很想尝试一下,你也可以直接下载别人打包好的安装包。也可以直接把别人的代码拿过来,然后放到自己的编译器下,自己进行编译使用,得到可执行程序。这个过程就是方法1;
2)在Windows中,通常通过下载.exe(可执行程序)或.msi(Windows安装包)文件进行安装。这些安装包通常自带图形化的安装向导,简化了安装过程,用户只需要运行安装程序即可。然而,类似于RPM包的缺点,Windows安装包也有可能在安装时没有自动处理所有的依赖关系,尤其是一些比较老旧或者需要额外配置的程序。
举个例子,假如你下载了一个软件的安装包(.exe文件),它可能会提示缺少某些依赖(如特定的C++运行库、.NET Framework等),你就需要手动安装这些依赖项。
3)简单明了,就是直接去电脑自带的软件商店去下载。,我的电脑下的就是这个。
认识yum
yum(Yellowdog Updater, Modified)是Linux系统中的一个包管理工具,也是的前端软件包管理器,主要用于自动从软件仓库下载RPM包并且安装和更新软件包,并自动解决软件包的依赖关系。它通常用于基于RPM的Linux发行版,如CentOS、RHEL和Fedora。
注意:一个服务器同一时刻只允许一个yum进行安装,不能在同一时刻同时安装多个软件。
因为yum是从服务器上下载RPM包,所以在下载时必须联网,可以通过ping指令判断当前云服务器是否联网。
同样在Windows下,也可以使用这样的指令查看自己想打游戏前,网络的延迟是否正常(看后面的time=...ms)。
查找软件包
使用yum list指令,可以罗列出可供下载的全部软件。
可以看到还是有很多很多的。
说明一下:
1)第一列为软件包名称,其内容包括:主版本号.次版本号.源程序发行号-软件包的发行号.主机平台.cpu架构。
2)"x86_64"后缀表示64位系统的安装包,"i686"后缀表示32位系统安装包,选择包时要和系统匹配(是要与你的云服务器匹配,不是与你的主机电脑匹配!!!)。
3)"el7"表示操作系统发行版的版本,“el7"表示的是"centos7/redhat7”,“el6"表示"centos6/redhat6”。
4)最后一列表示的是“软件源”的名称,类似于“小米应用商店”,“华为应用商店”这样的概念。
由于包的数目可能非常之多, 这里我们需要使用 grep 命令只筛选出我们关注的包. 例如:
yum list | grep 软件名
这里我们以从中查找lrzsz为例。
lrzsz可以将Windows当中的文件上传到Linux当中,也可以将Linux当中的文件下载到Windows当中,实现云服务器和本地机器之间进行信息互传。
需要用到的指令:
yum list | grep lrzsz
他上面的那一句话意思为: “元数据超过两周没有更新。要安装 yum-cron 吗?还是运行:yum makecache fast?”
这样我们就可以查看我们所关注的lrzsz的相关软件包。
安装软件
指令: sudo yum install 软件名
sudo yum install lrzsz
yum会自动找到都有哪些软件包需要下载,这时候我们需要做的就是敲“y”确认安装,等待一些时间后,就会出现“complete”字样时,这时就说明安装完成。
但是我这里已经安装过了,他显示的就不会显示 “complete”字样,也不需要一直按y
注意事项:
1) yum命令需要sudo权限,因为安装、更新和删除软件包需要修改系统级别的文件和目录,这些操作需要管理员权限。使用sudo可以授权普通用户临时获得管理员权限,确保这些系统管理操作的安全性和合规性。
2)yum安装软件只能一个装完了再装另一个,正在使用yum安装一个软件的过程中,如果再尝试用yum安装另外一个软件,yum会报错。
如何实现本地机器和云服务器之间的文件互传
既然已经安装了lrzsz,那么就顺便展示一下其怎么使用,从的可以互传文件
指令: rz -E
通过该指令可选择需要从本地机器上传到云服务器的文件。
当我们打完这个指令时,就会跳出这个windows窗口,然后我们选择我们要互传的文件,就完成了从本机到云服务器的操作了。
指令: sz 文件名
该指令可将云服务器上的文件下载到本地机器的指定文件夹。
当我们按下这个指令的时候,同样会跳出一个这样的一个windows的窗口,然后选择想要传到的路径即可。
卸载软件
指令: sudo yum remove 软件名
就比如说我们卸载刚才下载的lrzsz,那么只需要运行这段指令
sudo yum remove lrzsz
yum就会自动卸载该软件,同样还会卸载其各种的依赖关系,这时我们只需要敲“y”确认卸载,当出现“complete”字样时,说明卸载完成。
Linux编辑器 - vim
vim的基本概念
vim在我们做开发的时候,主要解决我们编写代码的问题,本质上就是一个多模式的文本编辑器。
我们这里主要介绍vim最常用的三种模式:命令模式、插入模式、底行模式。
1、正常/普通/命令模式(Normal mode)。
在命令模式下,我们可以控制屏幕光标的移动,字符、字或行的删除,复制粘贴,剪贴等操作。
2、插入模式(Insert mode)。
只有在插入模式下才能进行文字输入,该模式是我们使用最频繁的编辑模式。
3、末行/底行模式(Command mode)。
在底行模式下,我们可以将文件保存或退出,也可以进行查找字符串等操作。在底行模式下我们还可以直接输入vim help-modes查看当前vim的所有模式。
其实除此之外还有很多模式,这里就只介绍三个最常用的。
vim下各模式的切换
首先我们要进入vim模式,要使用如下指令
指令: vim 文件名
vim test.c
进入vim后默认为命令模式(普通模式),要输入文字需切换到插入模式,就可以想在vs下敲代码了。
【命令模式】切换至【插入模式】
1)输入「i」:在当前光标处进入插入模式。
2)输入「a」:在当前光标的后一位置进入插入模式。
3)输入「o」:在当前光标处新起一行进入插入模式。
【命令模式】切换至【底行模式】
1)输入「Shift+;」即可,实际上就是输入「:」。
【插入模式】或【底行模式】切换至【命令模式】
1)插入模式或是底行模式切换至命令模式都是直接按一下「Esc」键即可。
vim命令模式各命令汇总
【移动光标】
1)按「k」:光标上移。
2)按「j」:光标下移。
3)按「h」:光标左移。
4)按「l」:光标右移。
5)按「$」:移动到光标所在行的行尾。
6)按「^」:移动到光标所在行的行首。
7)按「gg」:移动到文本开始。
8)按「Shift+g」:移动到文本末尾。
9)按「n+Shift+g」:移动到第n行行首。
10)按「n+Enter」:当前光标向下移动n行。
11)按「w」:光标从左到右,从上到下的跳到下一个字的开头。
12)按「e」:光标从左到右,从上到下的跳到下一个字的结尾。
12)按「b」:光标从右到左,从下到上的跳到上一个字的开头
【删除】
1)按「x」:删除光标所在位置的字符。
2)按「nx」:删除光标所在位置开始往后的n个字符。
3)按「X」:删除光标所在位置的前一个字符。
4)按「nX」:删除光标所在位置的前n个字符。
5)按「dd」:删除光标所在行。
6)按「ndd」:删除光标所在行开始往下的n行。
【复制粘贴】
1)按「yy」:复制光标所在行到缓冲区。
2)按「nyy」:复制光标所在行开始往下的n行到缓冲区。
3)按「yw」:将光标所在位置开始到字尾的字符复制到缓冲区。
4)按「nyw」:将光标所在位置开始往后的n个字复制到缓冲区。
5)按「p」:将已复制的内容在光标的下一行粘贴上。
6)按「np」:将已复制的内容在光标的下一行粘贴n次。
【剪切】
1)按「dd」:剪切光标所在行。
2)按「ndd」:剪切光标所在行开始往下的n行。
3)按「p」:将已剪切的内容在光标的下一行粘贴上。
4)按「np」:将已剪切的内容在光标的下一行粘贴n次。
【撤销】
1)按「u」:撤销。
2)按「Ctrl+r」:恢复刚刚的撤销。
【大小写切换】
1)按「~」:完成光标所在位置字符的大小写切换。
2)按「n~」:完成光标所在位置开始往后的n个字符的大小写切换。
【替换】
1)按「r」:替换光标所在位置的字符。
2)按「R」:替换光标所到位置的字符,直到按下「Esc」键为止。
【更改】
1)按「cw」:将光标所在位置开始到字尾的字符删除,并进入插入模式。
2)按「cnw」:将光标所在位置开始往后的n个字删除,并进入插入模式。
【翻页】
1)按「Ctrl+b」:上翻一页。
2)按「Ctrl+f」:下翻一页。
3)按「Ctrl+u」:上翻半页。
4)按「Ctrl+d」:下翻半页。
vim底行模式各命令汇总
在使用底行模式之前,记住先按「Esc」键确定你已经处于命令模式,再按「:」即可进入底行模式。
【行号设置】
1)「set nu」:显示行号。
2)「set nonu」:取消行号。
【保存退出】
1)「w」:保存文件。
2)「q」:退出vim,如果无法离开vim,可在「q」后面跟一个「!」表示强制退出。
3)「wq」:保存退出。
【分屏指令】
1)「vs 文件名」:实现多文件的编辑。
2)「Ctrl+w+w」:光标在多屏幕下进行切换。
【执行指令】
1)「!+指令」:在不退出vim的情况下,可以在指令前面加上「!」就可以执行Linux的指令,例如查看目录、编译当前代码等。
先进入命令模式下
选择多行:按下Ctrl + v进入可视模式(Visual Block Mode),然后使用H, J, K, L键(或箭头键)选择你要注释的多行。
进入插入模式:选中多行后,按下Shift + i进入插入模式。
批量注释:在选中的每一行前面插入注释符号(例如//,为c语言与c++的注释符号)。此时你会看到光标在每一行的开始位置。
退出插入模式:输入完注释符号后,按下Esc键退出插入模式,所有选中的行前都将自动添加注释符号。
vim的简单配置
【配置文件的位置】
1)在目录/etc/下面,有个名为vimrc的文件,这是系统中公共的配置文件,对所有用户都有效。
2)在每个用户的主目录/home/xxx下,都可以自己建立私有的配置文件,命名为“.vimrc”,这是该用户私有的配置文件,仅对该用户有效。
例如,普通用户在自己的主目录下建立了“.vimrc”文件后,在文件当中输入set nu指令并保存,下一次打开vim的时候就会自动显示行号。
vim的配置比较复杂,某些vim配置还需要使用插件,建议不要自己一个个去配置。比较简单的方法是直接执行以下指令(想在哪个用户下让vim配置生效,就在哪个用户下执行该指令,不推荐直接在root下执行):
curl -sLf https://gitee.com/HGtz2222/VimForCpp/raw/master/install.sh -o ./install.sh && bash ./install.sh
然后按照提示输入root密码
然后等待安装配置,最后手动执行source ~/.bashrc即可。
配置完成后,像什么自动补全、行号显示以及自动缩进什么的就都有了,就可以像再vs下敲代码了,如果跟自己以前使用的习惯不一样,也可以自己修改。
只需要执行下面的指令,找到配置的文件,自己使用刚才的vim知识,对应修改即可。
vim ~/.vimrc
Linux编译器 - gcc/g++
gcc/g++的作用
gcc和g++分别是GNU(GNU是一个自由软件的项目,其旨在创建一个完全自由的操作系统)的C和C++的编译器,gcc和g++在执行编译的时候一般有以下四个步骤:
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 编译器优化选项的四个级别,-O0表示没有优化,-O1为缺省值,-O3优化级别最高。
预处理
gcc -E test.c -o test.i
这里的 -E 就是告诉gcc/g++,从现在开始进行程序的编译,将预处理的工作做完就停止下来,不要往后走了!
预处理功能主要包括头文件展开、去注释、宏替换、条件编译等。
预处理指令是以#开头的代码行。
-E选项的作用是让gcc/g++在预处理结束后停止编译过程。
-o选项是指目标文件,“xxx.i”文件为已经过预处理的原始程序。
编译
gcc -S test.i -o test.s
这里的 -S 是告诉gcc/g++,从现在开始进行程序的翻译,将编译工作做完,就停下来。
在编译过程中,GCC/G++ 首先会检查源代码的规范性,确认是否存在语法错误等问题,以确定代码的正确性。在没有错误的情况下,编译器将源代码翻译成汇编语言。
用户可以使用 -S 选项来查看编译后的汇编代码。该选项会停止在编译阶段,只生成汇编文件,而不继续进行汇编或链接操作。编译器会生成一个以 .s 为后缀的文件,表示代码已经被翻译为汇编语言。
另外,-o 选项用来指定输出文件的名称。如果不指定该选项,默认的输出文件名将为 xxx.s,其中 xxx 是源文件名(去掉扩展名)。
汇编
gcc -c test.s -o test.o
这里的 -c 告诉gcc/g++,从现在开始进行程序的翻译,将汇编工作做完,就停下来。
汇编阶段是把编译阶段生成的“xxx.s”文件转成目标文件。
使用-c选项就可以得到汇编代码转化为“xxx.o”的二进制目标代码了。
链接
gcc test.o -o test// 这里的test就是可执行程序名,自己可以根据自己喜好自己设定
在成功完成以上步骤之后,就进入了链接阶段。
链接的主要任务就是将生成的各个“xxx.o”文件进行链接,生成可执行文件。
gcc/g++不带-E、-S、-c选项时,就默认生成预处理、编译、汇编、链接全过程后的文件。
若不用-o选项指定生成文件的文件名,则默认生成的可执行文件名为a.out。
注意: 链接后生成的也是二进制文件。
静态库与动态库
我们最后的一步链接,就需要链接动态库或者静态库!!!
在规定上一个文件是由你书写头文件,对应的头文件提供方法的伤命,库文件提供方法的实现+你的代码,这就形成了一个你的文件。
在windows下动态库后缀为 .dll, 静态库为 .lib
函数库一般分为静态库和动态库两种:
静态库是指编译链接时,把库文件的代码全部加入到可执行文件当中,因此生成的文件比较大,但在运行时也就不再需要库文件了,静态库一般以.a为后缀。
动态库与之相反,在编译链接时并没有把库文件的代码加入到可执行文件当中,而是在程序运行时由链接文件加载库,这样可以节省系统的开销,动态库一般以.so为后缀。
动态库与静态库相对比
动态库因为是共享库,有效的节省了资源(磁盘空间,内存空间,网络空间等)【优点】动态库一旦缺失,导致各个程序都无法运行【缺点】
静态库,不依赖库,程序可以独立运行【优点】,体积大比较消耗资源【缺点】
动态链接:
优点:省空间(磁盘的空间,内存的空间),bin体积小,加载速度快。
缺点:依赖动态库,程序可移植性较差。
静态链接:
优点:不依赖第三方库,程序的可移植性较高。
缺点:浪费空间。
gcc和g++默认生成的二进制程序是动态链接的,我们可以使用file指令进行查看。
指令:file 文件名
其次,我们还可以使用ldd指令查看动态链接的可执行文件所依赖的库。
指令:ldd 文件名
(图中的/lib64/libc.so.6就是当前云服务器当中的C标准库)。
虽然gcc和g++默认采用的是动态链接,但如果我们需要使用静态链接,带上-static选项即可。
gcc test.c -o test_s -static
但是如果是第一次尝试,那么他会报错,如下:
还拿上面的例子解释,我们进行静态链接,其实就是去电脑店配好电脑后,安装到宿舍里面,但是如果我们没有在宿舍装好,那肯定是不能上网的,这也很好理解。通俗的来讲就是,你没电脑怎么上网啊。
用官方的话就是:
缺少静态库:
CentOS 7 默认安装的是动态链接的 C 库 (glibc),而静态库 (libc.a) 需要单独安装。
你可以检查是否已经安装了静态版本的 C 库。静态库文件通常位于 /usr/lib/ 或 /usr/lib64/ 目录下。如果没有,你可以尝试安装 glibc-static 包。
然后对应按y,然后看到Complete!字样时表示安装完成。然后再执行上面的操作就可以静态链接了。
这段指令的本质就是改变了优先级,使得先使用静态库,在混合的库的情况下,所有的链接将全变为静态链接!!!
sudo yum install glibc-static
此时生成的可执行文件就是静态链接的了。
我们可以查看源代码相同,但链接方式不同而生成的两个可执行程序test和test_s的大小 ,相差的还是蛮多的。
这也证明了,如果直接去网吧上网确实比宿舍上网节省空间!动态链接比较节省空间,而静态链接比较浪费空间。
如果无静态库,但还是要用-static,则是不行,会出现报错。
无动态态库,仅有静态库,而且gcc可以找到静态库,gcc 会默认调用静态库。其余情况下,默认调用动态库。遵循规则就是:有动用动,无动用静,全无报错
对于库,不一定是纯静态或者动态的,一般是存在混合的。
Linux调试器 - gdb
gdb使用须知
程序发布方式:
1、debug版本:程序本身会被加入更多的调试信息,以便于进行调试,这个版本是程序员所用的版本,文件大一点。
2、release版本:不会添加任何调试信息,是不可调试的,也叫做发行版本,文件小一点。
在Linux当中gcc/g++默认生成的可执行程序是release版本的,是不可被调试的。如果想生成debug版本,就需要在使用gcc/g++生成可执行程序时加上-g选项。
gcc test.c -o test_g -g
gdb命令汇总
【进入gdb】
指令: gdb 文件名
【调试】
1)「run/r」:运行代码(启动调试)。
2)「next/n」:逐过程调试。
3)「step/s」:逐语句调试。
4)「until 行号」:跳转至指定行。
5)「finish」:执行完当前正在调用的函数后停下来(不能是主函数)。
6)「continue/c」:运行到下一个断点处。
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」:查看当前栈帧当中局部变量的值。
【断点】
1)「break/b n」:在第n行设置断点。
2)「break/b 函数名」:在某函数体内第一行设置断点。
3)「info breakpoint/b」:查看已打断点信息。
4)「delete/d 编号」:删除指定编号的断点。
5)「disable 编号」:禁用指定编号的断点。
6)「enable 编号」:启用指定编号的断点。
【退出gdb】
1)「quit/q」:退出gdb
Linux项目自动化构建工具 - make/Makefile
make/Makefile的重要性
会不会写Makefile,从侧面说明了一个人是否具备完成大型工程的能力。
一个工程的源文件不计其数,按照其类型、功能、模块分别放在若干个目录当中,Makefile定义了一系列的规则来指定:哪些文件需要先编译,哪些文件需要后编译,甚至于进行更复杂的功能操作。
Makefile带来的好处就是“自动化编译”,一旦写好,只需一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。
mak是一个命令工具,是一个解释Makefile当中指令的命令工具,一般来说,大多数的IDE都有这个命令,例如:Delphi的make,Visual
C++的nmake,Linux下GNU的make。可见,Makefile都成为了一种在工程方面的编译方法。
make是一条命令,Makefile(也可以使用makefile效果一样)是一个文件,两个搭配使用,完成项目自动化构建。
依赖关系和依赖方法
在使用make/Makefile前我们首先应该理解各个文件之间的依赖关系以及它们之间的依赖方法。
依赖关系:在我们日常生活中,你与你的父亲就是存在依赖关系。比方说,你作为一个大学生,每个月初,都会给你的爸爸打电话,要生活费。你打过去电话,叫一声爸,你把就立马反应过来是你,但是你的舍友给你爸打电话叫一声爸,你爸还会以为骚扰电话,会直接挂断。如果哪一个月,你爸跟你说,这个月的家里面有些情况,没有太多钱了,就少给你点吧,按以前的一半吧。这个过程,你就依赖于你爸,有依赖关系。而你的同学不可以依赖于你爸,就没有依赖关系。那一个月家里面有情况,影响了你爸,从而导致影响了你,这就是依赖关系所产生的影响。
那么把这个概念转化为Linux下就为:文件A的变更会影响到文件B,那么就称文件B依赖于文件A。
拿前面的编译的内容举例,我们生成test.i文件就是依赖于test.c文件所生成的。如果把test.c修改了,那么test.i也会产生影响。
依赖方法: 如果文件B依赖于文件A,那么通过文件A得到文件B的方法,就是文件B依赖于文件A的依赖方法。也就是上面举例的,你可以通过打电话,找到你爸。
那么把这个概念转化为Linux下的编译部分就为: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。
多文件编译
当你的工程当中有多个源文件的时候,应该如何进行编译生成可执行程序呢?
首先,我们可以直接使用gcc指令对多个源文件进行编译,进而生成可执行程序。
gcc -o test test.c main.c main.h
这里的main.h可加可不加(尽量不要加),因为编译器通过源文件的内容可以知道所需的头文件名字,而通过头文件的包含方式(“尖括号”包含和“双引号”包含),编译器可以知道应该从何处去寻找所需头文件。
这个程序我是实现了打印5+6的结果,没有加换行。
通常在多文件编译时,不会直接从源文件生成最终的可执行文件,而是会将每个源文件分别编译成目标文件(*.o 文件),然后再通过链接(gcc)将这些目标文件链接成最终的可执行程序。
原因:
若是直接使用源文件生成可执行程序,那么其中一个源文件进行了修改,再生成可执行程序的时候就需要将所以的源文件重新进行编译链接。
而若是先用每个源文件各自生成自己的二进制文件,那么其中一个源文件进行了修改,就只需重新编译生成该源文件的二进制文件,然后再将这些二进制文件通过链接生成可执行程序即可。
随着源文件数量的增加,每次重新生成可执行程序时所需的 gcc 指令长度和数量也会随之增加。此时,使用 make 工具和 Makefile 文件能够显著减少我们的工作量。
步骤一: 在源文件所在目录下创建一个名为Makefile/makefile的文件。
步骤二: 编写Makefile文件。
Makefile文件最简单的编写格式是,先写出文件的依赖关系,然后写出这些文件之间的依赖方法,依次写下去。但也要记清楚他的独特书写方式。
编写完毕Makefile文件后保存退出,然后在命令行当中执行make指令便可以生成可执行程序,以及该过程产生的中间产物。
Makefile文件的简写方式:
$@:表示依赖关系中的目标文件(冒号左侧)。
$^:表示依赖关系中的依赖文件列表(冒号右侧全部)。
例如以上Makefile文件可以简写为:
make原理
make会在当前目录下找名字为“Makefile”或“makefile”的文件。
如果找到,它会找文件当中的第一个目标文件,在上面的例子中,它会找到test这个文件,并把这个文件作为最终的目标文件。
如果test文件不存在,或是test所依赖的后面的test.o文件和main.o文件的文件修改时间比mytest文件新,那么它就会执行后面的依赖方法来生成mytest文件。
如果test所依赖的test.o文件不存在,那么make会在Makefile文件中寻找目标为test.o文件的依赖关系,如果找到则再根据其依赖方法生成test.o文件(类似于堆栈的过程)。
当然,你的test.c文件和main.c文件是存在的,于是make会生成test.o文件和main.o文件,然后再用test.o文件和main.o文件生成最终的mytest文件。
make会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件。
在寻找的过程中,如果出现错误,例如最后被依赖的文件找不到,那么make就会直接退出,并报错。
项目清理
在我们每次重新生成可执行程序前,都应该将上一次生成可执行程序时生成的一系列文件进行清理,但是如果我们每次都手动执行一系列指令进行清理工作的话,未免有些麻烦,因为每次清理时执行的都是相同的清理指令,这时我们可以将项目清理的指令也加入到Makefile文件当中。
像clean这种,没有被第一个目标文件直接或间接关联,那么它后面所定义的命令将不会被自动执行,但我们可以显示要make执行。
一般将这种clean的目标文件设置为伪目标,用.PHONY修饰,伪目标的特性是:总是被执行。
如果我们把 clean 放在 Makefile 的第一个位置,并且 Makefile 的默认目标是 clean,那么在调用 make 指令时就会自动执行 clean 目标,而不需要显式地使用 make clean。
在 Makefile 中,第一个目标 是默认目标。当你执行 make 命令时,默认会尝试构建第一个目标。如果你把 clean 作为第一个目标,make 就会自动执行 clean 的规则,而不需要明确指定 make clean。
clean:
rm -f *.o test
test: test.o main.o
gcc -o $@ $^
test.o: test.c
gcc -c $^ -o $@
main.o: main.c
gcc -c $^ -o $@
默认目标 是 clean,因为它是 Makefile 中的第一个目标。
当你运行 make 时,它会自动执行 clean 规则,删除所有的 .o 文件和 test 可执行文件。
你不需要显式运行 make clean,因为 clean 是默认目标。
Makefile里主要包含了五个东西:显式规则、隐晦规则、变量定义、文件指示和注释, B选项是正确的
显式规则说明了,如何生成一个或多个目标文件。
make有自动推导的功能,所以隐晦的规则可以让我们比较粗糙地简略地书写makefile,比如源文件与目标文件之间的时间关系判断之类
在makefile中可以定义变量,当makefile被执行时,其中的变量都会被扩展到相应的引用位置上,通常使用 $(var) 表示引用变量
文件指示。包含在一个makefile中引用另一个makefile,类似C语言中的include; 根据这一项可以推导D选项是错误的。
注释,makefile中可以使用 # 在行首表示行注释