接10-Makefile
gcc hello_main.c hello_func.c -o hello_main -I .
新增的"-I ."是告诉编译器头文件路径在该文件夹。
使用Makefile编译
可以想像到,只要把gcc的编译命令按格式写入到Makefile,就能直接使用make编译,而不需要每次手动直接敲gcc编译命令。
后续需要调整只需要在Makefile文件里修改即可。
Makefile示例文件:
#hello_main目标 依赖于 hello_main.c 和 hello_func.c 文件
hello_main:hello_main.c hello_func.c
gcc hello_main.c hello_func.c -o hello_main -I .
#clean目标,用来删除编译生成的文件
clean:
rm -f *.o hello_main
编辑好Makefile文件后保存。
如上图所示,有了Makefile后,我们实际上只需要执行一下make命令就可以完成整个编译流程。图中还演示了make会对目标文件和依赖进行更新检查,当依赖文件有改动时,才会再次执行命令更新目标文件。
目标与依赖
下面再总结一下Makefile中跟目标相关的语法:
[目标1]:[依赖]
[命令1]
[命令2]
[目标2]:[依赖]
[命令1]
[命令2]
- 目标:指make要做的事情,可以是一个简单的代号,也可以是目标文件,需要顶格书写,前面不能有空格或Tab。一个Makefile可以有多个目标,写在最前面的第一个目标,会被Make 程序确立为“默认目标”,例如前面的targeta、hello_main。
- 依赖:要达成目标需要依赖的某些文件或其它目标。例如前面的targeta依赖于targetb和targetc,又如在编译的例子中,hello_main依赖于hello_main.c、hello_func.c 源文件,若这些文件更新了再编译会重新进行编译。
- 命令1,命令2⋯命令n:make达成目标所需要的命令。只有当目标不存在或依赖文件的修改时间比目标文件还要新时,才会执行命令。要特别注意命令的开头要用“Tab”键,不能使用空格代替,有的编辑器会把Tab键自动转换成空格导致出错,若出现这种情况请检查自己的编辑器配置。
伪目标
在Makefile中编写的目标,在make看来其实都是目标文件,例如make在执行的时候由于在目录找不到targeta文件,所以每次make targeta的时候,它都会去执行targeta的命令,期待执行后能得到名为targeta的同名文件。如果目录下真的有targeta、targetb、targetc的文件,即假如目标文件和依赖文件都存在且是最新的,那么maketargeta就不会被正常执行了,这会引起误会。
为了避免这种情况,使用“.PHONY”前缀来区分目标代号和目标文件,并且这种目标代号被称为“伪目标”。
使用.PHONY定义伪目标
hello_main:hello_main.c hello_func.c
gcc hello_main.c hello_func.c -o hello_main -I .
.PHONY:clean
clean:
rm -f *.o hello_main
如果以上代码中不写“.PHONY:clean”语句,并且在目录下创建一个名为clean的文件,那么当执行“makeclean”时,clean 的命令并不会被执行。
默认规则
make有一条默认规则,当找不到xxx.o文件时,会查找目录下同名的xxx.c文件进行编译。根据这样的规则可把Makefile改为:
hello_main:hello_main.o hello_func.o
gcc hello_main.o hello_func.o -o hello_main
# 以下是make的默认规则,下面两行可以不写
# hello_main.o:hello_main.c
# gcc hello_main.c -c
# 以下是make的默认规则,下面两行可以不写
# hello_func.o:hello_func.c
# gcc hello_func.c -c
使用修改后的Makefile编译结果如下图所示:
从make的输出可看到,它先执行了两条额外的“cc”编译命令,这是由make默认规则执行的,它们把C代码编译生成了同名的.o文件,然后make根据Makefile的命令链接这两个文件得到最终目标文件hello_main。