一、导入
1、编写文件a.c
#include <stdio.h>
int main(void)
{
func();
return 0;
}
2、编写文件b.c
#include <stdio.h>
void func(void)
{
printf("Hello World.\n");
}
3、linux环境下执行命令:
gcc -o test a.c b.c
4、在当前目录下会生成一个test的可执行文件,在linux环境下执行命令运行test
./test
5、分析:通过gcc -o test a.c b.c 命令行对a.c、b.c进行编译、链接生成test可执行程序还是比较简单的,这是因为文件数量少,可以这样用, 但是当文件数量很多时(如几千几万个量级), 没必要每次对所有文件都编译、链接,可以仅对改动的文件进行编译,生成.o文件, 然后再对所有.o文件进行链接生成可执行程序文件。
6、上述分析,可以借助编写Makefile文件来实现。
二、Makefile语法及常用功能
1、Makefile的核心——规则:
目标:依赖1 依赖2...
[TAB]命令
2、执行场景:
当“目标文件”不存在,
或
某个依赖文件比目标文件“新”,
则:执行“命令”
3、对上述a.c b.c编写Makefile文件
1) 在与a.c、b.c同级目录下,新建Makefile文件,编写内容如下:
test : a.o b.o
gcc -o test a.o b.o
a.o : a.c
gcc -c -o a.o a.c
b.o : b.c
gcc -c -o b.o b.c
clean:
rm *.o test
2)linux环境下执行 make 和 make clean命令,观察目录内文件变化:
运行make命令后,目录内生成test可执行程序文件,通过./test命令即可运行该程序;
运行make clean 命令, 目录内左右 .o 和 test 文件被清除。
4、Makefile的语法
1)通配符:%.o
- $@ 表示目标
- $< 表示第一个依赖文件
- $^ 表示所有依赖文件
使用通配符修改上述Makefile文件,如下:
test: a.o b.o
gcc -o test $^
%.o : %.c
gcc -c -o $@ $<
clean:
rm *.o test
问题及分析:当前文件夹中若有同名的clean文件时,make clean命令将不会被执行,可以使用假想目标:.PHONY来解决。
2) 假想目标:.PHONY
如下:
test: a.o b.o
gcc -o test $^
%.o : %.c
gcc -c -o $@ $<
clean:
rm *.o test
.PHONY: clean
说明:添加 .PHONY: clean 后,就不会判断名为clean的文件是否存在,而是直接执行make clean命令。
3)即时变量、延时变量,export
简单变量(即使变量):
A := xxx # A的值即可确定,在定义时即确定
B = xxx # B的值使用到时才确定
:= # 即时变量
= # 延时变量
?= # 延时变量,如果是第一次定义才起效果,如果在前面该变量已定义则忽略该句
+= # 附加, 它是即时变量还是延时变量取决于前面的定义
三、Makefile语法及常用功能
a. $(foreach var, list, text)
b. $(filter pattern..., text) #在text中取出符合pattern格式的值
$(filter-out pattern..., text) #在text中取出不符合pattern格式的值
c. $(wildcard pattern) #pattern定义了文件名的格式,
#wildcard取出其中存在的文件
d. $(patsubst pattern, replacement, $(var)) #从列表中取出每一个值,
#如果符合pattern
#则替换为replacement
四、Makefile实例
1、改进:支持头文件依赖
(详细介绍可以参考这篇博客: http://blog.csdn.net/qq1452008/article/details/50855810)
gcc -M c.c //打印出依赖
gcc -M -MF c.d c.c //把依赖写入文件c.d
gcc -c -o c.o c.c -MD -MF c.d //编译c.o, 把依赖写入文件c.d
自动添加依赖文件, 举例:
objs = a.o b.o c.o
#从objs列表中取出符合%的值(此处取出所有),然后替换为替换为.%.d
dep_files := $(patsubst %, .%.d, $(objs))
#取出dep_files中存在的文件,即取出所有依赖文件
dep_files := $(wildcard $(dep_files))
test: $(objs)
gcc -o test $^
#判断是否包含依赖文件,若不包含,则执行include包含依赖文件命令
ifneq ($(dep_files),)
include $(dep_files)
endif
c.o : c.c c.h
#编译%.o,把依赖写入文件%.d
%.o : %.c
gcc -c -o $@ $< -MD -MF .$@.d
clean:
rm *.o test
distclean:
rm $(dep_files)
.PHONY: clean
2、添加CFLAGS
#将所有警告设置成错误提醒, 设置所有头文件路径到 ./ 即当前路径查找 CFLAGS = -Werror -I./
objs = a.o b.o c.o
#从objs列表中取出符合%的值(此处取出所有),然后替换为替换为.%.d
dep_files := $(patsubst %, .%.d, $(objs))
#取出dep_files中存在的文件,即取出所有依赖文件
dep_files := $(wildcard $(dep_files))
#将所有警告设置成错误提醒, 设置所有头文件路径到 ./ 即当前路径查找
CFLAGS = -Werror -I./
test: $(objs)
gcc -o test $^
#判断是否包含依赖文件,若不包含,则执行include包含依赖文件命令
ifneq ($(dep_files),)
include $(dep_files)
endif
c.o : c.c c.h
#编译%.o,把依赖写入文件%.d
%.o : %.c
gcc -c -o $@ $< -MD -MF .$@.d
clean:
rm *.o test
distclean:
rm $(dep_files)
.PHONY: clean