Makefile 文件不仅存在于源码根目录下,在其他的子目录下也基本都有 Makefile 文件。在执行编译时,Make 工具会解析根目录下 Makefile 文件进行编译,而根目录的 Makefile 会调用子目录下的 Makefile,子目录下又有子目录,层层调用。Makefile 需要按照一定的格式语法规则进行书写。如果你是做 Linux 应用开发的人员,那么写 Makefile 就是必备技能,就需要深谙 Makefile 语法规则。对于我们 Linux 平台初级开发人员,很少需要我们去写一个复杂的 Makefile 文件,只是在做平台移植的时候可能需要去简单修改或者阅读 Makefile 文件,所以呢,下面我们就简单了解一下 Makefile 基本格式规则。
目标就是我们需要生成的文件,依赖就是生成目标文件所需要的其他文件,称为依赖文件。
基本语法规则:
targets(目标):dependent_files(依赖文件)
command(执行的命令)
#示例:
app:app.o fun1.o fun2.o
gcc -o app app.o fun1.o fun2.o
app.o:app.c
gcc -c app.c
fun1.o:fun1.c fun1.h
gcc -c fun1.c
fun2.o:fun2.c fun2.h
gcc -c fun2.c
clean:
rm -rf *.o app
第一行:通过app.o fun1.o fun2.o依赖文件连接为目标文件
第二行:通过依赖文件app.c编译为目标文件
下面几行亦是如此
正常情况下不运行clean除非执行 make clean
变量的名称 = 变量值
变量的值将会是整个 Makefile 中最后被指定的值。
变量的名称 := 变量值
变量的值决定于它在 Makefile 中的位置,而不是整个 Makefile 展开后最终的值。
变量的名称 ?= 变量值
如果变量未定义,则使用该变量值定义变量。如果该变量已经被定义赋值,则该赋值语句无效,使用原有值.
a ?= 123
b ?= $(a) string
a ?= 678
target:
@echo "a = $(a)"
@echo "b = $(b)"
# a = 123
# b = 123 string
变量的名称 += 变量值
a := 123
b := $(a) string
a += $(b)
target:
@echo "a = $(a)"
@echo "b = $(b)"
# a = 123 123 string
# b = 123 string
系统变量或者叫环境变量,包含了常见编译器、汇编器的名称及其编译选项,我们在编译之前使用 . /opt/fsl-imx-x11/4.1.15-2.0.0/environment-setup-cortexa7hf-neon-poky-linux-gnueabi 主要就是设置这些系统环境变量的值。
下面列出常见的系统变量及其部分默认值
AR:库文件维护程序的名称,默认值为 ar;
AS:汇编程序的名称,默认值为 as;
CC:C 编译器的名称,默认值为 cc;
CPP:C 预编译器的名称,默认值为$(CC) –E;
CXX:C++编译器的名称,默认值为 g++;
FC:FORTRAN 编译器的名称,默认值为 f77;
RM:文件删除程序的名称,默认值为 rm –f;
ARFLAGS:库文件维护程序的选项,无默认值;
ASFLAGS:汇编程序的选项,无默认值;
CFLAGS:C 编译器的选项,无默认值;
CPPFLAGS:C 预编译的选项,无默认值;
CXXFLAGS:C++编译器的选项,无默认值;
FFLAGS:FORTRAN 编译器的选项,无默认值;
比较 arg1 和 arg2 值是否相同,如果相同则执行 text-if-true,否则执行 text-if-false。
判断 variable 是否为空,如果非空则为真,执行 text-if-true,否则执行 text-if-false。
test : main.c sub.c sub.h
gcc -o test main.c sub.c
#第一行 test目标文件依赖main.c sub.c sub.h
#第二行 编译链接main.c sub.c文件到test
test : main.o sub.o
gcc -o test main.o sub.o
main.o : main.c
gcc -c -o main.o main.c
sub.o : sub.c
gcc -c -o sub.o sub.c
clean:
rm *.o test -f
test : main.o sub.o
gcc -o test main.o sub.o
%.o : %.c
gcc -c -o $@ $<
clean:
rm *.o test -f
test : main.o sub.o
gcc -o test main.o sub.o
%.o : %.c
gcc -c -o $@ $<
sub.o : sub.h
clean:
rm *.o test -f
objs := main.o sub.o
test : $(objs)
gcc -o test $^
# 需要判断是否存在依赖文件
# .main.o.d .sub.o.d
dep_files := $(foreach f, $(objs), .$(f).d)
dep_files := $(wildcard $(dep_files))
# 把依赖文件包含进来
ifneq ($(dep_files),)
include $(dep_files)
endif
%.o : %.c
gcc -Wp,-MD,.$@.d -c -o $@ $<
clean:
rm *.o test -f
distclean:
rm $(dep_files) *.o test -f
# File: Makefile
src := $(shell ls *.c)
objs := $(patsubst %.c,%.o,$(src))
test: $(objs)
gcc -o $@ $^
%.o:%.c
gcc -c -o $@ $<
clean:
rm -f test *.o
上述 Makefile 中
@
、
@、
@、^、
<
称为自动变量。
<称为自动变量。
<称为自动变量。@表示规则的目标文件名;
表
示所有依赖的名字,名字之间用空格隔开;
^表示所有依赖的名字,名字之间用空格隔开;
表示所有依赖的名字,名字之间用空格隔开;<表示第一个依赖的文件名。‘%’是通配符,它和一个字符串中任意个数的字符相匹配。
第一行 src 变量的值为‘main.c sub.c’。
第二行 objs 变量的值为‘main.o sub.o’,是 src 变量经过 patsubst 函数处理后得到的。