相关文章Make专栏https://blog.csdn.net/weixin_45791458/category_12383799.html默认情况下make命令会从makefile中遇到的第一个目标开始尝试构建。很多资料会把这句话简单概括为“make默认构建第一个目标”这个说法虽然大体没错但如果说得更准确一些应该是make默认构建的是makefile中的默认终极目标也就是在没有通过命令行显式指定目标时make最先打算更新的那个目标。之所以要强调“终极目标”而不是只说“第一个目标”是因为make在真正开始构建之前并不是机械地从上到下逐行执行命令而是先确定本次构建的最终目的再围绕这个目的去分析依赖关系并决定哪些文件需要更新、哪些命令需要执行。也就是说默认目标只是一个入口但它背后真正对应的是整个依赖图中的一个构建终点。make接下来所有的依赖检查、时间戳比较和命令执行本质上都是围绕这个终极目标展开的。在通常情况下这个默认终极目标就是makefile中遇到的第一个普通目标。例如下面的代码中默认终极目标就是target1target1:target2 echo Building target1 target2: echo Building target2当直接执行make时make会把target1当作本次构建的最终目标。由于target1依赖于target2所以它并不会一上来就执行target1下面的命令而是会先检查target2是否需要构建。如果target2不存在或者它本身是伪目标又或者它依赖的内容发生了变化那么make会先更新target2再回过头来尝试更新target1。还有一个细节也很容易被忽略那就是并不是写在最前面的任意目标都能成为默认终极目标。如果最前面的目标名以.开头通常它不会被当作默认目标除非它本身包含一个或多个斜杠/。这是GNU make手册里专门提到的一个例外。也正因为如此更准确的说法并不是“make永远从第一行的第一个冒号左边开始”而是“make会选择第一个合适的普通目标作为默认终极目标”。例如下面这段代码中虽然.target写在最前面但默认终极目标并不是.target而是后面的target.target:target echo Building .target target: echo Building target这里的.target并不会自动成为默认终极目标因此直接执行make时真正作为入口的是target。这个规则的意义在于很多以.开头的名字在makefile里通常承担的是特殊用途例如某些内部控制目标、辅助规则或者约定性的特殊标识make不希望把它们轻易当成默认构建入口。​​​​​​​除了使用makefile中的第一个合适目标作为默认终极目标之外命令行参数也可以直接覆盖这一行为。如果在执行make时显式给出了目标名那么make就不再使用makefile中的默认目标而是以命令行指定的目标作为本次构建的终极目标。例如下面这段代码中makefile默认目标仍然是target1target1:target2 echo Building target1 target2: echo Building target2但如果实际执行的是make target2那么本次构建的终极目标就变成了target2而不是target1。也就是说命令行参数的优先级高于makefile中的默认目标设置。这个行为其实很好理解因为一旦用户已经在命令行里明确告诉make“我要构建什么”那make自然就不应该再坚持使用makefile中预设的默认入口了。还有一种情况也值得特别说明就是一条规则中可以同时写多个目标。例如下面这样target1 target2: echo Building target1 2 target3: echo Building target3在这段代码中默认终极目标是target1而不是“target1和target2一起”。原因是虽然这一行规则同时声明了两个目标但从默认目标的角度看make只会取其中的第一个目标作为默认终极目标也就是target1。这个规则说明默认目标的确定是以“遇到的第一个有效目标名”为准而不是以“第一条规则整体”为一个不可分割单元来处理。如果希望显式修改makefile的默认终极目标而又不想依赖“把谁写在第一行前面”这种位置规则那么GNU make提供了一个更直接的方式即使用特殊变量.DEFAULT_GOAL。这个变量的值可以指定默认目标从而覆盖“第一个目标自动成为默认入口”的行为。例如下面的代码中虽然target1仍然写在前面但真正的默认终极目标已经被改成了target2.DEFAULT_GOAL target2 target1:target2 echo Building target1 target2: echo Building target2此时无法通过命令行指定终极目标make会优先构建target2而不是target1。也就是说.DEFAULT_GOAL提供了一种显式、稳定、可读性更强的方式来控制默认目标。相比单纯依赖目标在makefile中的排列顺序使用.DEFAULT_GOAL往往更适合规模稍大一些的makefile因为这样写出来的意图更加清晰别人阅读makefile时也能立刻知道“本文件默认构建的入口到底是什么”。下面的文章详细讲述了一个make命令是如何构建终极目标的包括如何检查文件是否需要更新等细节问题欢迎阅读。Make目标Target构建的详细和依赖项的处理过程个人总结https://mp.csdn.net/mp_blog/creation/editor/131850114参考资料GNU Make MANUAL(GNU make Version 4.4.1)