学习书籍原地址《跟我一起写Makefile》,感谢原作者的付出!
Makefile总述
一、Makefile里有什么
主要包含 :显示规则、隐晦规则、变量定义、文件指示和注释。
- 显示规则
显示规则说明如何生成一个或多个目标文件,写Makefile的时候都是在写显示规则。 - 隐晦规则
因为make的自动推导功能,可以将Makefile简化。 - 变量的定义
变量一般都为字符串,类似于c的宏,调用时使用$(变量名)格式调用。 - 文件指示
包括三个部分:
1) 在一个Makefile中引用另一个Makefile,就像include;
2)根据某些情况指定Makefile中的有效部分,就像#if;
3)定义一个多行命令。 - 注释
Make中只有行注释,用“#”字符进行注释。
二、Makefile的文件名
默认情况下,make会在目录下寻找名字为“GNUmakefile”、“makefile”和“Makefile”的文件。
最好使用“Makefile”,首字母大写,有种醒目的感觉;最好不要使用“GNUmakefile”,只有GNU的make对这个文件名敏感;有些make只对“makefile”敏感。
若要自定义文件名,可以在make后加上“-f”或者“–file”参数来指定你的自定义Makefile。
make -f myMake.Linux
或者
make --file myMake.Linux
三、引用其他的Makefile
语法:
include <filename>
filename可以使当前操作系统Shell的文件模式(可以包含路径和通配符)
在include前可以有一些空字符,但不能是[TAB]键开始;include可以同时包含几个Makefile,和变量差不多。例如:
-
目录下有多个.mk后缀的Makefile文件(a.mk b.mk c.mk):
include *.mk
等价于
include a.mk b.mk c.mk
-
满足1的基础上,定义一个变量$(makefiles),里面包含了d.mk和e.mk:
#定义变量 makefiles = d.mk e.mk
则要包含所有的Makefile文件,可以这样写:
#包含所有makefile include *.mk $(makefiles)
等价于
include a.mk b.mk c.mk d.mk e.mk
当make执行时,会将include所指出的其他Makefile的内容暂时安置在当前位置,就像c/c++的#include。如果文件都没有指定绝对路径或是相对路径的话,make会在当前目录下首先寻找,如果当前目录下没有找到,那么:
-
如果make后有“-I”或者“–include-dir”参数,make会在参数指定的目录下寻找。
-
如果目录/include(一般是/usr/local/bin或者/usr/include) 存在的话,make也会去找。
-
如果文件没有找到,make会生成一条警告信息,然后继续载入其他文件,完成Makefile的读取后,make会再次重新查找没有找到的文件,如果还是没有,那么make会生成致命信息,退出运行。可以在include前加一个“-”号让make忽略那些找不到的文件,继续执行下去:
-include <filename>
“-”在之前的clean命令中使用过,它的意思是:无论在命令执行过程中出现什么错误,都不要报错并继续执行。
-include和其他版本的make兼容的相关命令是sininclude,作用相同。
四、环境变量MAKEFILES
MAKEFILES变量作用和include类似,其值是其他的Makefile,空格分隔。与include不同的地方在于用这个方法引入的Makefile里的“target”不会起作用,如果MAKEFILES中定义的文件有错误,make也不会报错。
建议不要使用MAKEFILES,因为当你使用这个变量,并且make时,所有的Makefile都会被影响。如果有时候Makefile出现的异常,可以看看当前环境中有没有这个变量。
五、make的工作方式
GNU make(其他的make类似):
-
第一阶段
- 读取所有的Makefile;
- 读入被include的其它Makefile;
- 初始化文件中的变量;
- 推导隐晦规则,并分析所有规则;
- 为所有的目标文件创建依赖关系链。
-
第二阶段
- 根据依赖关系,决定哪些目标要重新生成;
- 执行生成命令。
在第一个阶段中,make会将定义的变量在当前位置展开,但make并不会完全马上展开,如果变量出现在依赖关系的规则中,那么仅当这条依赖被决定要使用了,变量才会在其内部展开。