什么是软件包管理器?
- 在linux 下安装软件,一个通用的办法就是下载源代码。然后编译,形成可执行程序,但是这样太麻烦了
- 所以就有软件包管理器出现。别人吧软件写好打包放在服务器上,我们要安装,通过软件包管理器从服务器上下载到本地。
- 软件就是app,软件包管理器就像应用商店。
- linux下软件包管理器yum/apt就像一个客户端,从服务器上下载软件。
- yum(Yellow dog Updater, Modified)是Linux下⾮常常⽤的⼀种包管理器. 主要应⽤在Fedora, RedHat, Centos等发⾏版上.
- Ubuntu:主要使⽤apt(Advanced Package Tool)作为其包管理器。apt同样提供了⾃动解决依 赖关系、下载和安装软件包的功能。
linux软件的生态
一个操作系统为什么要有完整的生态
怎么样评估一个操作系统好?
首先,光有一个强大的操作系统不够,还必须要完整的生态,因为这样才会有更多人使用。一个操作系统是否完整,要看它的生态是否完善。

操作系统生态必须有社区论坛,强大的官网文档,丰富的软件体系。维护更新速度快。对客户要有针对性。
当一个开源的操作系统,别人为了使用它,不让他黄,肯定会有程序员去写丰富的软件,还有unbantu,等系统。这样社区论坛也热闹,官网文档也强。

所以我们下载软件,就可以通过软件包管理器,yum/apt,去查找软件,下载,再直接安装。yum/apt是怎么直接在几亿台服务器找到软件的了,因为软件服务器的路径会写在软件包管理器下文件里面。
但是有防火墙不能直接访问外网,或者下载速度慢。所以,有很多公司搞了镜像软件包服务器。
他们把软件下载国内的服务器。yum/apt文件下的路径也会被修改成国内的服务器。

.conf是文件的后缀,存放配置文件的。
软件依赖是什么?
就是我们下载安装一个软件,还会依赖其他软件来运行。比如vs2022,来需要在vs环境下安装c++等的编译环境。但是yum/apt在服务器下载,安装软件,解决这个问题。
yum/apt的具体操作
yum/apt是软件包管理器。它的作用是在服务器下载软件并安装。
他们怎么获取软件的服务器的。在配置文件下存放许多软件的镜像地址。叫做软件源。
软件源又分为稳定软件源和扩展软件源。
稳定软件源是放软件测试稳定,可靠的软件放在服务器上,存放的是服务器的地址。
扩展软件源是还没有成熟,或者稳定的软件。当软件完善之后也会放在稳定软件的服务器上。

像linux系统配置的软件源的服务器地址一般都是指向国外的。所以我们要更新配置软件源,将一个新的文件替换原来的软件源。
首先我们先备份原来的标准源
sudo cp /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup//把.repo备份一份,原文件也在
再拷贝一个新的一份文件做备份。
wget:获取网址。
cpp
# 使用 wget 下载阿里云的 CentOS-7.repo 文件,
# 并用 -O 把它直接保存并覆盖到 /etc/yum.repos.d/CentOS-Base.repo
sudo wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
但是清除旧缓存,不然yum,找不到国内服务器地址,还有旧的缓存。
cpp
yum clean all
最后更新缓存
cpp
yum makecache
上面就是更新软件源的方法。就是用新文件替换了旧的文件存放软件包服务器的地址。
apt的查看软件包的指令
cpp
root@iZwz9c6v6ajdocnv9xkh8rZ:~# apt search lrzsz
Sorting... Done
Full Text Search... Done
cutecom/jammy 0.30.3-1build1 amd64
Graphical serial terminal, like minicom
lrzsz/jammy,now 0.12.21-10 amd64 [installed]
Tools for zmodem/xmodem/ymodem file transfer

更详细的看软件包(show)
cpp
root@iZwz9c6v6ajdocnv9xkh8rZ:~# apt show lrzsz
Package: lrzsz
Version: 0.12.21-10
Priority: optional
Section: universe/comm
Origin: Ubuntu
Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
Original-Maintainer: Martin A. Godisch <godisch@debian.org>
Bugs: https://bugs.launchpad.net/ubuntu/+filebug
Installed-Size: 531 kB
Depends: libc6 (>= 2.15)
Suggests: minicom
Homepage: https://ohse.de/uwe/software/lrzsz.html
Download-Size: 74.8 kB
APT-Manual-Installed: yes
APT-Sources: http://mirrors.cloud.aliyuncs.com/ubuntu jammy/universe amd64 Packages
Description: Tools for zmodem/xmodem/ymodem file transfer
Lrzsz is a cosmetically modified zmodem/ymodem/xmodem package built
from the public-domain version of Chuck Forsberg's rzsz package.
.
These programs use error correcting protocols ({z,x,y}modem) to send
(sz, sx, sb) and receive (rz, rx, rb) files over a dial-in serial port
from a variety of programs running under various operating systems.
yum查看软件包的指令
cpp
yum list | grep lrzsz
lrzsz.x86_64 0.12.20-36.el7 @base
也可以search
cpp
yum search lrzsz
yum和apt安装软件的指令
cpp
sudo yum install 软件
sudo apt install 软件
cpp
sudo yum install -y 软件
sudo apt install -y 软件
•
yum/apt 会⾃动找到都有哪些软件包需要下载, 这时候敲 "y" 确认安装.
•
出现 "complete" 字样或者中间未出现报错, 说明安装完成.
注意事项:
•
安装软件时由于需要向系统⽬录中写⼊内容, ⼀般需要 sudo 或者切到 root 账⼾下才能完成.
•
yum/apt安装软件只能⼀个装完了再装另⼀个. 正在yum/apt安装⼀个软件的过程中, 如果再尝试⽤
yum/apt安装另外⼀个软件, yum/apt会报错.
•
如果 yum / apt报错, 请⾃⾏百度
卸载软件
cpp
sudo yum remove -y 软件
sudo apt remove -y 软件
y跟上面一样
vim编辑器
三种模式
1.命令模式
输入许多命令,可以编写文件。进入默认是命令模式。
【yy】复制这一行.
p\]粘贴,前面可以加数字多少行复制。 【gg】回到文本开头。 【G】回到文本末尾 \[\^\]回到行开头 【$】回到行尾 【h】向左 【j】向下 【k】向上 【l】向右 \[dd\]删除行 \[x\]删除单个字符 【u】撤销 【crtl+r】对撤销取消 【行号+shift+g】跑到对应的行上 【w】单词为单位,向前查找 【b】单词为单位,向后查找。 批量化注释,批量化去注释crtl+v进入视图。然后j下移选择多少行。再shift+i进入插入模式。再在开头输入//最后esc退出,就批量注释了。删除注释就是crtl+v,选择要取消注释的,然后按d就可以了。 shift+\~大小写转换 \[r\]替换光标那的字符。 \[shift+r\]光标后面的都可以替换。 \[u\]撤销 ctrl+r:对撤销动作取消。 shift+zz:保存并退出。 ### 底行模式 set nu:对每行都写上行号。 w:保存,wq:保存并退出。q!:强制退出。wq!保存强制退出 ```cpp jcm@iZwz9c6v6ajdocnv9xkh8rZ:~$ gcc t.c jcm@iZwz9c6v6ajdocnv9xkh8rZ:~$ ls -l total 24 -rwxrwxr-x 1 jcm jcm 15960 Mar 11 19:54 a.out drwxrwxr-x 2 jcm jcm 4096 Mar 8 21:07 dir -rw-rw-r-- 1 jcm jcm 283 Mar 11 19:54 t.c -rw-rw-r-- 1 jcm jcm 0 Mar 8 20:53 tess.c -rw-rw-r-- 1 jcm jcm 0 Mar 10 20:34 test.c -rw------- 1 jcm jcm 0 Mar 8 20:59 txt10.c -rw------- 1 jcm jcm 0 Mar 8 20:59 txt1.c -rw------- 1 jcm jcm 0 Mar 8 20:59 txt2.c -rw------- 1 jcm jcm 0 Mar 8 20:59 txt3.c -rw------- 1 jcm jcm 0 Mar 8 20:59 txt4.c -rw------- 1 jcm jcm 0 Mar 8 20:59 txt5.c -rw------- 1 jcm jcm 0 Mar 8 20:59 txt6.c -rw------- 1 jcm jcm 0 Mar 8 20:59 txt7.c -rw------- 1 jcm jcm 0 Mar 8 20:59 txt8.c -rw------- 1 jcm jcm 0 Mar 8 20:59 txt9.c ``` 编译之后,生成了a.out文件。在执行文件的时候,就算文件在当前路径下。我们也并不能只给文件名,linux找不到。 ```cpp a.out//找不到 ./a.out//应该这样给。 或者给绝对路径,从根目录开始 ``` ```bash jcm@iZwz9c6v6ajdocnv9xkh8rZ:~$ ./a.out hello world hello world hello world hello world hello world hello world hello world hello world hello world ``` 一般都要退出文件编译,再运行gcc t.c 然后执行./a.out文件,这样太慢了。 我们可以在底行模式加个!加gcc t.c 然后!./a.out就可以同样执行代码,还不会退出。 > 当我们需要几个文件的时候.h .c我们编译完.c,再退出编译.h。太慢了。我们底行输入vs 文件就可以进行分屏操作   不仅可以分两屏,还可以分三屏更多。 底行模式还有常用的就是/,在文本查找内容进行高亮。 %s/被替换/新文件/g,可以替换文本中的内容。  ### 补充的指令 ## vim配置 为了使vim更好用,我们可以在.vimrc文件里面配置一些命令,然后当我们vim的时候,就会打开.vimrc,生效我们的配置命令。推荐每个用户配置在自己的家目录下,不配置在root下  ## gcc/g++编译器 gcc:编译c语言的 g++:编译c++的 编译器:就是把源文件编译成可执行的二进制文件。 ##### 1 预处理 gcc -E code.c -o code.i。进行预处理。 预处理又分为:头文件展开。宏替换。去掉注释。条件编译。(头文件展开就是把头文件里面的内容拷贝到源文件。去掉注释,就是把注释的内容去掉。)使语言变成干净的语言。 jcm@iZwz9c6v6ajdocnv9xkh8rZ:~$ gcc -E jcm.c -o jcm.i ###### 条件编译 为什么要条件编译? 条件编译的主要用途 1. 根据不同平台或环境编译代码:可以针对不同的操作系统或硬件架构编写特定的代码。 2. 调试和发布版本的区分:在调试版本中可以包含调试信息,而在发布版本中则可以排除这些信息。 3. 多版本控制:根据不同的需求或功能选择性地编译某些模块或功能。  多版本控制,就是有些商业化软件会有基础版和专业版。基础版和专业版的公共代码一样。 利用条件编译就可以只实现一套代码。条件编译控制输出哪部分的代码。这样代码维护起来方便  ##### 2 翻译 将c语言翻译成汇编语言 ```bash jcm@iZwz9c6v6ajdocnv9xkh8rZ:~$ gcc -S jcm.i -o jcm.s ``` ##### 3 汇编 将汇编-》obj目标文件(可重定位的二进制文件) ```bash jcm@iZwz9c6v6ajdocnv9xkh8rZ:~$ gcc -c jcm.s -o jcm.o ``` ##### 4链接 将目标文件与c语言的标准库里面的内容链接 ```bash jcm@iZwz9c6v6ajdocnv9xkh8rZ:~$ gcc jcm.o -o jcm.exe jcm@iZwz9c6v6ajdocnv9xkh8rZ:~$ ./jcm.exe hellojcm@iZwz9c6v6ajdocnv9xkh8rZ:~$ ls -l ``` ##### 解释的命令 -o就是把文件变成其他名称。-E就是预处理 -S就是翻译 -c就是汇编 ##### 最后建议 > ```bash > > jcm@iZwz9c6v6ajdocnv9xkh8rZ:~$ touch hello{1..20}.c > jcm@iZwz9c6v6ajdocnv9xkh8rZ:~$ gcc -c hello{1..20}.c > jcm@iZwz9c6v6ajdocnv9xkh8rZ:~$ ls -l > total 164 > -rw-rw-r-- 1 jcm jcm 17956 Mar 13 17:04 code.i > -rw-rw-r-- 1 jcm jcm 1560 Mar 13 17:05 code.o > -rw-rw-r-- 1 jcm jcm 738 Mar 13 17:04 code.s > drwxrwxr-x 2 jcm jcm 4096 Mar 8 21:07 dir > -rw-rw-r-- 1 jcm jcm 0 Mar 13 17:33 hello10.c > -rw-rw-r-- 1 jcm jcm 936 Mar 13 17:33 hello10.o > -rw-rw-r-- 1 jcm jcm 0 Mar 13 17:33 hello11.c > -rw-rw-r-- 1 jcm jcm 936 Mar 13 17:33 hello11.o > -rw-rw-r-- 1 jcm jcm 0 Mar 13 17:33 hello12.c > -rw-rw-r-- 1 jcm jcm 936 Mar 13 17:33 hello12.o > -rw-rw-r-- 1 jcm jcm 0 Mar 13 17:33 hello13.c > -rw-rw-r-- 1 jcm jcm 936 Mar 13 17:33 hello13.o > -rw-rw-r-- 1 jcm jcm 0 Mar 13 17:33 hello14.c > -rw-rw-r-- 1 jcm jcm 936 Mar 13 17:33 hello14.o > -rw-rw-r-- 1 jcm jcm 0 Mar 13 17:33 hello15.c > -rw-rw-r-- 1 jcm jcm 936 Mar 13 17:33 hello15.o > -rw-rw-r-- 1 jcm jcm 0 Mar 13 17:33 hello16.c > -rw-rw-r-- 1 jcm jcm 936 Mar 13 17:33 hello16.o > -rw-rw-r-- 1 jcm jcm 0 Mar 13 17:33 hello17.c > -rw-rw-r-- 1 jcm jcm 936 Mar 13 17:33 hello17.o > -rw-rw-r-- 1 jcm jcm 0 Mar 13 17:33 hello18.c > -rw-rw-r-- 1 jcm jcm 936 Mar 13 17:33 hello18.o > -rw-rw-r-- 1 jcm jcm 0 Mar 13 17:33 hello19.c > -rw-rw-r-- 1 jcm jcm 936 Mar 13 17:33 hello19.o > -rw-rw-r-- 1 jcm jcm 0 Mar 13 17:33 hello1.c > -rw-rw-r-- 1 jcm jcm 936 Mar 13 17:33 hello1.o > -rw-rw-r-- 1 jcm jcm 0 Mar 13 17:33 hello20.c > -rw-rw-r-- 1 jcm jcm 936 Mar 13 17:33 hello20.o > -rw-rw-r-- 1 jcm jcm 0 Mar 13 17:33 hello2.c > -rw-rw-r-- 1 jcm jcm 936 Mar 13 17:33 hello2.o > -rw-rw-r-- 1 jcm jcm 0 Mar 13 17:33 hello3.c > -rw-rw-r-- 1 jcm jcm 936 Mar 13 17:33 hello3.o > -rw-rw-r-- 1 jcm jcm 0 Mar 13 17:33 hello4.c > -rw-rw-r-- 1 jcm jcm 936 Mar 13 17:33 hello4.o > -rw-rw-r-- 1 jcm jcm 0 Mar 13 17:33 hello5.c > -rw-rw-r-- 1 jcm jcm 936 Mar 13 17:33 hello5.o > -rw-rw-r-- 1 jcm jcm 0 Mar 13 17:33 hello6.c > -rw-rw-r-- 1 jcm jcm 936 Mar 13 17:33 hello6.o > -rw-rw-r-- 1 jcm jcm 0 Mar 13 17:33 hello7.c > -rw-rw-r-- 1 jcm jcm 936 Mar 13 17:33 hello7.o > -rw-rw-r-- 1 jcm jcm 0 Mar 13 17:33 hello8.c > -rw-rw-r-- 1 jcm jcm 936 Mar 13 17:33 hello8.o > -rw-rw-r-- 1 jcm jcm 0 Mar 13 17:33 hello9.c > -rw-rw-r-- 1 jcm jcm 936 Mar 13 17:33 hello9.o > ``` > > gcc -c会把.c文件形成同名的.o文件。最后我们再把.o文件链接。这样提高了编译效率  ## 链接为什么要有库?库是什么? 在链接的时候为什么要用库?因为这样提高了效率,不然每个程序员要用的时候都要自己去实现,浪费。 库是什么?库是别人写好的代码集合。 库在哪里了?linux下centos和unbantu的路径不同。  *** ** * ** ***  编译出来的文件,默认是动态库。我们可以把它修改成静态库 ```bash jcm@iZwz9c6v6ajdocnv9xkh8rZ:~$ gcc yu.c -o yu -statically ``` ```bash jcm@iZwz9c6v6ajdocnv9xkh8rZ:~$ file yu yu: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, BuildID[sha1]=758cbf26757fe7b843d260ddb19e9cb26157182a, for GNU/Linux 3.2.0, not stripped ``` 这样就是一个静态链接了。 ### 动态库和静态库的优缺点    ## 自动化构建-make/makefile * 会不会写makefile,从⼀个侧⾯说明了⼀个⼈是否具备完成⼤型⼯程的能⼒ * ⼀个⼯程中的源⽂件不计数,其按类型、功能、模块分别放在若⼲个⽬录中,makefile定义了⼀ 系列的规则来指定,哪些⽂件需要先编译,哪些⽂件需要后编译,哪些⽂件需要重新编译,甚⾄ 于进⾏更复杂的功能操作makefile带来的好处就是⸺"⾃动化编译",⼀旦写好,只需要⼀个make命令,整个⼯程完全 ⾃动编译,极⼤的提⾼了软件开发的效率。 * make是⼀个命令⼯具,是⼀个解释makefile中指令的命令⼯具,⼀般来说,⼤多数的IDE都有这 个命令,⽐如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可⻅,makefile 都成为了⼀种在⼯程⽅⾯的编译⽅法  ```cpp jcm@iZwz9c6v6ajdocnv9xkh8rZ:~$ make gcc -E code.c -o code.i gcc -S code.i -o code.s gcc -c code.s -o code.o gcc code.o -o code jcm@iZwz9c6v6ajdocnv9xkh8rZ:~$ ls -l total 1000 -rwxrwxr-x 1 jcm jcm 15960 Mar 15 21:05 code -rw-rw-r-- 1 jcm jcm 68 Mar 15 21:05 code.c -rw-rw-r-- 1 jcm jcm 17950 Mar 15 21:05 code.i -rw-rw-r-- 1 jcm jcm 1496 Mar 15 21:05 code.o -rw-rw-r-- 1 jcm jcm 659 Mar 15 21:05 code.s drwxrwxr-x 2 jcm jcm 4096 Mar 8 21:07 dir -rw-rw-r-- 1 jcm jcm 56 Mar 13 17:07 jcm.c -rwxrwxr-x 1 jcm jcm 15960 Mar 13 17:09 jcm.exe -rw-rw-r-- 1 jcm jcm 17934 Mar 13 17:08 jcm.i -rw-rw-r-- 1 jcm jcm 1496 Mar 13 17:09 jcm.o -rw-rw-r-- 1 jcm jcm 675 Mar 13 17:08 jcm.s -rw-rw-r-- 1 jcm jcm 203 Mar 15 21:03 makefile -rw-rw-r-- 1 jcm jcm 60 Mar 13 21:16 test.c -rw-rw-r-- 1 jcm jcm 1504 Mar 13 21:16 test.o -rw-rw-r-- 1 jcm jcm 102 Mar 11 21:04 t.h -rwxrwxr-x 1 jcm jcm 900344 Mar 14 19:09 yu -rw-rw-r-- 1 jcm jcm 165 Mar 14 17:52 yu.c jcm@iZwz9c6v6ajdocnv9xkh8rZ:~$ vim makefile jcm@iZwz9c6v6ajdocnv9xkh8rZ:~$ make clean rm -f code code.o code.s code.i jcm@iZwz9c6v6ajdocnv9xkh8rZ:~$ ls -l total 956 -rw-rw-r-- 1 jcm jcm 68 Mar 15 21:05 code.c drwxrwxr-x 2 jcm jcm 4096 Mar 8 21:07 dir -rw-rw-r-- 1 jcm jcm 56 Mar 13 17:07 jcm.c -rwxrwxr-x 1 jcm jcm 15960 Mar 13 17:09 jcm.exe -rw-rw-r-- 1 jcm jcm 17934 Mar 13 17:08 jcm.i -rw-rw-r-- 1 jcm jcm 1496 Mar 13 17:09 jcm.o -rw-rw-r-- 1 jcm jcm 675 Mar 13 17:08 jcm.s -rw-rw-r-- 1 jcm jcm 203 Mar 15 21:03 makefile -rw-rw-r-- 1 jcm jcm 60 Mar 13 21:16 test.c -rw-rw-r-- 1 jcm jcm 1504 Mar 13 21:16 test.o -rw-rw-r-- 1 jcm jcm 102 Mar 11 21:04 t.h -rwxrwxr-x 1 jcm jcm 900344 Mar 14 19:09 yu -rw-rw-r-- 1 jcm jcm 165 Mar 14 17:52 yu.c ``` make自动执行,make clean执行下面删除方法。 看了上面的代码,肯定不知道.PHONY是干什么的,它是伪目标,修饰的目标文件和依赖方法总是被执行。什么是总是被执行,那我们先谈谈什么是不总是被执行。 jcm@iZwz9c6v6ajdocnv9xkh8rZ:~$ make gcc -E code.c -o code.i gcc -S code.i -o code.s gcc -c code.s -o code.o gcc code.o -o code jcm@iZwz9c6v6ajdocnv9xkh8rZ:~$ ls -l total 1000 -rwxrwxr-x 1 jcm jcm 15960 Mar 15 23:55 code -rw-rw-r-- 1 jcm jcm 68 Mar 15 21:05 code.c -rw-rw-r-- 1 jcm jcm 17950 Mar 15 23:55 code.i -rw-rw-r-- 1 jcm jcm 1496 Mar 15 23:55 code.o -rw-rw-r-- 1 jcm jcm 659 Mar 15 23:55 code.s drwxrwxr-x 2 jcm jcm 4096 Mar 8 21:07 dir -rw-rw-r-- 1 jcm jcm 56 Mar 13 17:07 jcm.c -rwxrwxr-x 1 jcm jcm 15960 Mar 13 17:09 jcm.exe -rw-rw-r-- 1 jcm jcm 17934 Mar 13 17:08 jcm.i -rw-rw-r-- 1 jcm jcm 1496 Mar 13 17:09 jcm.o -rw-rw-r-- 1 jcm jcm 675 Mar 13 17:08 jcm.s -rw-rw-r-- 1 jcm jcm 203 Mar 15 21:03 makefile -rw-rw-r-- 1 jcm jcm 60 Mar 13 21:16 test.c -rw-rw-r-- 1 jcm jcm 1504 Mar 13 21:16 test.o -rw-rw-r-- 1 jcm jcm 102 Mar 11 21:04 t.h -rwxrwxr-x 1 jcm jcm 900344 Mar 14 19:09 yu -rw-rw-r-- 1 jcm jcm 165 Mar 14 17:52 yu.c jcm@iZwz9c6v6ajdocnv9xkh8rZ:~$ make make: 'code' is up to date. jcm@iZwz9c6v6ajdocnv9xkh8rZ:~$ make make: 'code' is up to date. jcm@iZwz9c6v6ajdocnv9xkh8rZ:~$ make make: 'code' is up to date. 先编译了code.c,然后继续make编译code.c,他不会执行,它提示code是新的。那他怎么知道code是最新的 它是通过看modify时间来看的,如果源文件的时间比可执行程序旧,就不会继续执行编译,因为编译也需要时间。 jcm@iZwz9c6v6ajdocnv9xkh8rZ:~$ stat code.c File: code.c Size: 68 Blocks: 8 IO Block: 4096 regular file Device: fc03h/64515d Inode: 398067 Links: 1 Access: (0664/-rw-rw-r--) Uid: ( 1001/ jcm) Gid: ( 1001/ jcm) Access: 2026-03-15 21:05:22.544538587 +0800 Modify: 2026-03-15 21:05:18.828394051 +0800 Change: 2026-03-15 21:05:18.828394051 +0800 Birth: 2026-03-15 21:05:18.828394051 +0800 jcm@iZwz9c6v6ajdocnv9xkh8rZ:~$ stat code File: code Size: 15960 Blocks: 32 IO Block: 4096 regular file Device: fc03h/64515d Inode: 398059 Links: 1 Access: (0775/-rwxrwxr-x) Uid: ( 1001/ jcm) Gid: ( 1001/ jcm) Access: 2026-03-15 23:55:05.384575948 +0800 Modify: 2026-03-15 23:55:05.384575948 +0800 Change: 2026-03-15 23:55:05.384575948 +0800 Birth: 2026-03-15 23:55:05.364575170 +0800 modify时间的改变是通过修改文件的内容。 access是通过访问文件。 change是修改文件的属性。 但是access虽然cat也是访问,但是修改access是有规律的,不可能你访问一次就修改时间,修改时间,要缓存在磁盘上,io操作。修改文件内容access会改变。如果每次读取(例如用 cat 查看)都立即将更新后的 atime 写回磁盘,会导致大量的磁盘 I/O,极大地降低系统性能。因为 atime 的修改和文件内容修改不同,它非常频繁且通常不那么关键。 当我们工程目标文件也用PHONY修饰,总是可以执行。  ```cpp jcm@iZwz9c6v6ajdocnv9xkh8rZ:~$ make gcc -E code.c -o code.i gcc -S code.i -o code.s gcc -c code.s -o code.o gcc code.o -o code jcm@iZwz9c6v6ajdocnv9xkh8rZ:~$ make gcc code.o -o code jcm@iZwz9c6v6ajdocnv9xkh8rZ:~$ make gcc code.o -o code jcm@iZwz9c6v6ajdocnv9xkh8rZ:~$ make gcc code.o -o code ``` 那么code就会一直被链接,如果写出gcc code.c -o code。那么会一直编译,编译时间长,效率降低。 > *.PHONY:让make忽略源⽂件和可执⾏⽬标⽂件的M时间对⽐* 小结:最佳实践:clean可以被PHONY修饰,但是形成工程可执行文件不能被修饰。 gcc是通过比较源文件和可执行目标文件modify来对比,通过这个来查看是否执行,提升编译效率。 #### 更适用的makefile 假如我们有许多文件.c都要编译成可执行程序,如果按上面一个一个编译太麻烦了。  我们使用变量替换,我们就可以编译很多文件, ```cpp jcm@iZwz9c6v6ajdocnv9xkh8rZ:~/lesson1$ make code10.c -> code10.o code1.c -> code1.o code2.c -> code2.o code3.c -> code3.o code4.c -> code4.o code5.c -> code5.o code6.c -> code6.o code7.c -> code7.o code8.c -> code8.o code9.c -> code9.o code.c -> code.o code10.o code1.o code2.o code3.o code4.o code5.o code6.o code7.o code8.o code9.o code.o-> code ``` 上面中的$是变量引用,在定义变量的时候,后面不是字符串,都要加$,比如makefile的函数或者变量。$\^代表所有的依赖文件,$@代表目标文件。$\<代表每一个依赖文件。所以在编译形成.o的时候是每一个文件编译一个.o。 ```cpp BIN=proc.exe # 定义变量 CC=gcc #SRC=$(shell ls *.c) # 采⽤shell命令⾏⽅式,获取当前所有.c⽂件名 SRC=$(wildcard *.c) # 或者使⽤ wildcard 函数,获取当前所有.c⽂件名 OBJ=$(SRC:.c=.o) # 将SRC的所有同名.c 替换 成为.o 形成⽬标⽂件列表 LFLAGS=-o # 链接选项 FLAGS=-c # 编译选项 RM=rm -f # 引⼊命令 $(BIN):$(OBJ) @$(CC) $(LFLAGS) $@ $^ # $@:代表⽬标⽂件名。 $^: 代表依赖⽂件列表 @echo "linking ... $^ to $@" %.o:%.c # %.c 展开当前⽬录下所有的.c。 %.o: 同时展开同 名.o @$(CC) $(FLAGS) $< # %<: 对展开的依赖.c⽂件,⼀个⼀个的交给gcc。 @echo "compling ... $< to $@" # @:不回显命令 .PHONY:clean clean: $(RM) $(OBJ) $(BIN) # $(RM): 替换,⽤变量内容替换它 .PHONY:test test: @echo $(SRC) @echo $(OBJ) ``` *** ** * ** *** *** ** * ** *** 我们在修改其中一个文件了 ```cpp jcm@iZwz9c6v6ajdocnv9xkh8rZ:~/lesson1$ make code10.c -> code10.o code1.c -> code1.o code2.c -> code2.o code3.c -> code3.o code4.c -> code4.o code5.c -> code5.o code6.c -> code6.o code7.c -> code7.o code8.c -> code8.o code9.c -> code9.o code.c -> code.o code10.o code1.o code2.o code3.o code4.o code5.o code6.o code7.o code8.o code9.o code.o-> code jcm@iZwz9c6v6ajdocnv9xkh8rZ:~/lesson1$ vim code.c jcm@iZwz9c6v6ajdocnv9xkh8rZ:~/lesson1$ make code.c -> code.o code10.o code1.o code2.o code3.o code4.o code5.o code6.o code7.o code8.o code9.o code.o-> code ``` 当我们再次编译的时候。只有code.c编译成code.o。因为其他的code1..2.c都已经编译过一次了。 这就是为什么在设计自动化工程的时候要先编译在链接,而不是直接ggc code.c -o code。因为这样都要编译一次,编译也需要时间。