引言
下面这个 C
语言的代码非常简单
#include <stdio.h>
int main()
{
printf("Hello World!.\n");
return 0;
}
在 Linux
下面,我们使用下面的命令编译就可以
gcc hello.c -o hello
但是随着项目的变大,势必会有越来越多的 .c
文件和 .h
头文件,再直接使用编译器指令就非常麻烦了,光输入文件名都会影响心情,而且还非常容易出错,比如下面的例子
gcc hello.c aaa.c bbb.c -lpthread -ltest1 -ltest2 -o hello
而且哪怕你只是修改一个文件,也需要重新编译所有的文件,白白浪费了很多的开发时间。要解决这个问题,最好的方式就是把工程的编译规则写下来,让编译器自动加载规则去进行编译。
要实现上述目标,需要2个工具,make
和 Makefile
,它们是搭配使用的,各司其职
-
make:它可以帮助我们找出项目里面修改变更过的文件,并根据依赖关系,找出受修改影响的其他相关文件,然后对这些文件按照规则进行单独的编译,这样一来,就能避免重新编译项目的所有的文件。
-
Makefile:定义编译的规则、依赖关系,
make
工具就能精准地进行编译工作
Makefile是什么
Makefile
是用于指定软件编译、链接的构建过程的文件,一般位于软件源代码的根目录下。通过定义一系列的规则,Makefile
告诉 make
工具应该如何编译和链接代码生成最终的可执行文件或库文件。
Makefile基本语法
Makefile
由一系列 rule
组成,rule
的基本格式是
target:prerequisites
command
这里,target
是所要生成的文件,prerequisites
是生成该 target
所依赖的文件或目标,command
是实际执行的命令。
Makefile示例
下面是一个简单的示例
app: main.o add.o
gcc main.o add.o -o app
main.o: main.c
gcc -c main.c
add.o: add.c
gcc -c add.c
这段 Makefile
包含了3个 rule
,它指定了 app
依赖 main.o
和 add.o
,后两个又依赖各自的源码文件。make
将自动根据依赖关系完成编译。
所以,这时候的编译命令就变的非常简单,直接输入 make
即可生成可执行文件 app
。
Makefile常用知识点
在 Makefile
中可以定义变量,例如
objects = main.o kbd.o command.o display.o
prog: $(objects)
cc $(objects) -o prog
使用 objects
变量表示多个目标文件,这样可以使语法更加简洁。
使用通配符可以批量指定一类目标,例如
.PHONY: clean
clean:
rm *.o
这里使用 *.o
指定了所有 .o
文件为 clean
目标的依赖,这样 clean
时可以删除所有的 .o
文件。这里使用 .PHONY
声明伪目标,这些目标不对应实际文件。
一个规则也可以指定多个目标,例如
bigoutput littleoutput : text.g
generate text.g -o bigoutput
generate text.g -o littleoutput
上述例子中同时生成了 bigoutput
和 littleoutput
。
使用静态模式可以在规则中引用目标名,例如
%.o : %.c
$(CC) -c $< -o $@
这个模式规则可以匹配所有的 .c
到 .o
的转换。
支持自定义函数,例如
upcase = $(subst a,A,$(1))
a.o : a.c
$(CC) -c $(call upcase,$<) -o $@
这里使用 upcase
函数将参数转换为大写。