简单的Makefile
在linux上用makefile编译一个hello.c文件,可用gcc编译器。
gcc hello.c -o hello
只能编译一个文件,非常不方便!
首先,创建文本文档,取名Makefile(无后缀),#是注释!
第一层:显示规则
目标文件 : 依赖文件
[TAB]指令
第一个目标文件是我的最终目标!(.c—预编译—.i—编译—.s—汇编—.o—链接—.exe的倒叙)
hello:hello.o
gcc hello.o -o hello
hello.o:hello.s
gcc -c hello.s -o hello.o
hello.s:hello.i
gcc -S hello.i -o hello.s
hello.i:hello.c
gcc -E hello.c -o hello.i
make命令就生成了hello.exe!
伪目标:.PHONY:
.PHONY: //规定
clear: //自定义
rm -rf hello.o hello.S hello.i hello
make clear就删除了这些文件!
第二层:变量(类似宏定义)
=(替换)
+=(追加)
:=(恒等于)
比如要编译circle.c、cube.c、main.c这3个文件 按照正常写法:
test:circle.o cube.o main.o
gcc circle.o cube.o main.o -o test
circle.o:circle.c
gcc -c circle.c -o circle.o
cube.o:cube.c
gcc -c cube.c -o cube.o
main.o:main.c
gcc -c circle.c -o circle.o
.PHONY:
clearall:
rm -rf circle.o cube.o main.o test
clear:
rm -rf circle.o cube.o main.o
替换一些:
TAR = test
CC := gcc
OBJ = circle.o cube.o main.o
$(TAR):$(OBJ)
$(CC) $(OBJ) -o $(TAR)
circle.o:circle.c
gcc -c circle.c -o circle.o
cube.o:cube.c
gcc -c cube.c -o cube.o
main.o:main.c
gcc -c circle.c -o circle.o
.PHONY:
clearall:
rm -rf $(OBJ) test
clear:
rm -rf $(OBJ)
第三层:隐含规则
%.c 、%.o 任意的.c文件或者任意的.o文件
*.c 、*.o 所有的.c文件或者所有的.o文件
%.o:%.c
$(CC) -c %.c -o %.o
第四层:通配符
$@ 所有的目标文件
$^ 所有的依赖文件
$< 所有的依赖文件的第一个文件
最后程序:
TAR = test
CC := gcc
OBJ = circle.o cube.o main.o
RMRF := rm -rf
$(TAR):$(OBJ)
$(CC) $^ -o $@
%.o:%.c
$(CC) -c $^ -o $@
.PHONY: //规定
clearall: //自定义
$(RMRF) $(OBF) $(TAR)
clear: //自定义
$(RMRF) $(OBF)
第五层:函数
参考B站 @C语言Plus,自学用,侵删!
如何编译实际项目?(参考之前的笔记【nginx】服务器程序框架初步)
【make命令的工作原理】
去当前目录读取一个叫做makefile的文件(文本文件),根据这个makefile文件里的规则把源代码编译成可执行文件,开发者的任务就是要把这个makefile文件写出来。
【makefile文件】
文本文件,utf8编码格式,没有扩展名,一般放在根目录下(也会根据需要放在子目录)。
makefile里边定义了怎么去编译整个项目的编译、链接规则,实际上makefile文件就是一个我们编译工程要用到的各种源文件等等的一个依赖关系描述,也有类似autotools自动生成makefile。
【makefile文件的编写】
nginx根目录下放三个文件:
makefile:编译项目的入口脚本,编译项目从这里开始,起总体控制作用;
config.mk:配置脚本,被makefile文件include,单独分离出来是为了应付一些可变的东西,一般变动的东西都往这里;
common.mk:最重要最核心的编译脚本,定义makefile的编译规则,依赖规则等,各个子目录中都用到这个脚本来实现对应子目录的.c文件的编译。
每个子目录下都有一个makefile文件,每个makefile文件都会包含根目录下的common.mk从而实现自己这个子目录下的.c文件的编译,现在的makefile不支持目录中套子目录(只能深度为1)。子目录下makefile文件如下:
BIN = //子目录中只生成.d和.o文件,不要求生成可执行文件,所以为空!
include $(BUILD_ROOT)/common.mk
【注意】app/link_obj临时目录,存放.o目标文件,app/dep:存放.d开头的依赖关系文件,make之后在app目录下自动生成。
【makefile脚本用法介绍】
直接在根目录下make,会在app目录中生成两个中间文件夹和根目录下的一个可执行文件nginx。
make后若想删除这两个多余的文件夹可以make clean,这其实是执行了根目录下makefile文件中的如下两行:
clean:
#-rf:删除文件夹,强制删除
rm -rf app/link_obj app/dep nginx
rm -rf signal/*.gch app/*.gch
make原理大致如下:
【makefile脚本具体实现讲解】
从common.mk讲起(因为所有子目录的makefile也用到了common.mk),SRCS扫描所有目录下.c文件!
all:$(DEPS) $(OBJS) $(BIN) //以冒号分界:左侧为目标,右侧为依赖
make流程:在根目录下make,先找到makefile文件,for循环遍历所有文件夹进行make(这里include了config.mk),这时里面的make会include common.mk文件并利用其规则生成依赖,并连接每个.o文件生成最后的可执行文件(只有app下的makefile的bin是等于nginx的)。
将来增加新目录时:
a)修改根目录下的config.mk来增加该目录,注意app目录要放在最后,是有顺序的;
b)在对应的目录下放入makefile文件,内容参考signal目录下的makefile文件即可。