Make:目标(Target)构建的详细和依赖项的处理过程(个人总结)

张开发
2026/4/4 15:09:08 15 分钟阅读
Make:目标(Target)构建的详细和依赖项的处理过程(个人总结)
相关文章Make专栏https://blog.csdn.net/weixin_45791458/category_12383799.html这段时间在用makefile所以自己探究了一下make的工作过程并经过实验总结了一些规律。对于一个规则的处理如下首先make会检查规则中的目标文件是否存在和依赖项的情况即四种可能出现的情况1、如果目标文件不存在同时也没有依赖文件项也就是冒号后面为空那么该规则的命令一定会执行因为对于make来说它找不到任何现成文件可以说明这个目标已经是最新的所以唯一能做的就是直接执行命令去尝试生成目标或者完成这个动作。2、如果目标文件存在同时也没有依赖文件项那么该规则的命令一定不会执行因为既然目标已经存在而规则又没有告诉make“它依赖于谁”那么make就会认为没有任何证据表明它已经过时自然也就没有必要重复执行这条规则下面的命令。3、如果目标文件不存在同时有依赖文件项也就是冒号后面至少列出一个依赖那么make不会直接盲目执行当前规则的命令而是会先去检查并处理这些依赖项。只有当依赖项都检查完成后make才会回到当前目标并且由于目标文件本身不存在所以当前规则的命令最终一定会执行。4、如果目标文件存在同时也有依赖文件项那么make仍然会先检查并处理所有依赖项等依赖项处理结束后再根据目标文件与依赖文件的时间关系决定当前规则的命令是否执行。也就是说这种情况下当前规则下面的命令不一定执行而是要看依赖项是否比目标更新。上面这四条看上去是在描述目标文件是否存在、规则命令是否执行之间的关系但如果再往深一点看就会发现make真正的工作重点其实不在“当前目标”本身而在“依赖项的递归检查和处理”。因为对于make来说一个目标之所以可能需要更新通常不是因为它自己突然“变旧了”而是因为它依赖的某个东西发生了变化。所以理解make关键要理解它是如何处理依赖项的。在真正处理依赖项时make会从左到右依次检查当前规则中列出的每一个依赖项并且这种检查不是简单看一眼文件在不在而是会继续判断该依赖项是否也是某条规则的目标。如果是那么这个依赖项本身也可能需要进一步构建于是make会继续递归处理它。换句话说make的执行方式更像是深度优先地展开一棵依赖树而不是平铺地按文件书写顺序一路往下执行。依赖项的检查是从左至右对各个依赖项进行检查并可能会根据结果处理其他规则只有一个依赖项的检查完毕才会开始下一个依赖项的检查分为下面三种情况1、如果该依赖项对应的文件当前不存在那么make会继续在当前makefile中查找是否存在“以这个依赖项为目标”的规则。如果找到了make就会先递归处理这条规则也就是先想办法把这个缺失的依赖项构建出来如果找不到make就会报错因为它知道当前目标依赖这个文件但又没有办法生成它。2、如果该依赖项对应的文件当前存在那么make仍然会继续检查当前makefile中是否存在“以这个依赖项为目标”的规则。因为即使文件现在存在也不代表它一定是最新的make仍然可能需要通过那条规则去更新它。只有在确认依赖项已经处理完成之后make才会继续看下一个依赖项。如果没有以该依赖项文件为目标的规则则视为该依赖项检查完毕是否执行规则的命令取决于第三点。3、如果所有依赖项文件在检查时都存在即都满足第二点则make会在所有依赖项文件检查完毕后对目标文件和所有依赖项文件进行修改时间的对比如果有一个依赖项比目标文件新则会执行规则的命令否则不会执行规则的命令。下面结合几个具体例子来看。例1main:main.o gcc -o main main.o main.o:main.c gcc -c main.c -o main.o sleep 5 gcc -o main main.o sleep 5对于以上的makefile如果main文件不存在则一定会在最后执行gcc -o main main.o命令如规则处理的第三点所说。如果main.o不存在而main存在也一定会在最后执行gcc -o main main.o构建如规则处理的第四点和依赖项的检查的第一点所说。极端情况下即使你在main.o规则的命令中创建了main.o和main并使main新于main.o因为此时对于main和main.o的比较不会进行在检查到main.o不存在时gcc -o main main.o就注定要执行如规则处理的第四点所说。例2clean: echo clean对于以上的makefile正常情况下clean文件总是不存在的所以每当make clean时都会执行echo clean命令但如果人为使clean文件存在时make clean时会告诉你clean已经是最新因此需要伪目标的引入。例3clean: clean1 echo clean clean1: echo clean1对于以上的makefile即使clean文件存在make clean依然可以顺利执行两条echo命令因为clean1文件不存在所以目标为clean的规则的命令一定会在规则的所有依赖项文件被处理后执行。假如clean1和clean文件都存在则会根据他们两个的修改时间决定是否执行echo clean至于echo clean1命令是不会执行的因为在这种情况下clean1规则的目标文件clean1存在且该规则无依赖项如规则处理的第二点所说。例4main: main.o gcc -o main main1.o main.o: main.c gcc -c main.c -o main1.o以上的文件在每次执行make时都会尝试构建main.o因为main.o这个规则命令设置的问题只会构建main1.o。这就表示了make在执行命令时不会尝试理解命令所以一个正确的命令是好的makefile的前提。顺带一提如果在这里人为插入一个main.o则make时main.o对应规则的命令是否执行取决于main.o和main.c修改时间的对比而main对应规则的命令是否执行取决于main和main.o修改时间的对比。

更多文章