makefile示例
一、Makefile 基本结构
Makefile 是make读入的唯一配置文件,
i:由make工具创建的目标体(target),通常是目标文件或可执行文件
ii:要创建的目标体所依赖的文件(dependency_file)
iii:要创建每个目标体时需要运行的命令(command)
注意:命令行前面必须是一个“TAB键”,否则编译错误为:*** missing separator. Stop.
Makefile格式
target: dependency file
<TAB>command
例子:
hello.o: hello.c hello.h
gcc -c hello.c -o hello.o
二:Makefile变量
下面有一个例子:
temp:f1.o f2.o main.o
gcc f1.o f2.o main.o -o temp
f1.o:f1.c f1.h
gcc -Wall -O -g -c f1.c -o f1.o
f2.o:f2.c f2.h
gcc -Wall -O -g -c f2.c -o f2.o
main.o:main.c
gcc -Wall -O -g -c main.c -o main.o
.PHONY : clean
clean:
rm *.o temp
注释:-Wall:表示允许发出gcc所有有用的报警信息
-c:只是编译不链接,生成目标文件“ .o”
-o file:表示把输出文件输出到file里
更多的用man工具
1、变量定义
变量定义的方式: VAR=var VAR:=var 变量使用: $(VAR)
类似于编程语言的宏;
如果你要使用真实的“$”字符,那么你需要写成“$$”
OBJS = f1.o f2.0 main.o CC = gcc CFLAGS = -Wall -O -g temp:$(OBJS) $(CC) $(OBJS) -o temp f1.o:f1.c f1.h $(CC) $(CFLAGS) -c f1.c -o f1.o f2.o:f2.c f2.h $(CC) $(CFLAGS) -c $< -o $@ main.o:main.c $(CC) $(CFLAGS) -c main.c -o main.o .PHONY : clean clean: rm *.o temp
.PHONY : clean
比如“clean”这个目标,一个“伪目标”,我们并不生成“clean”这个文件。“伪目标”并不是一个文件,只是一个标签,由于“伪目标”
不是文件,所以make无法生成它的依赖关系和决定它是否要执行。我们只有通过显式地指明这个“目标”才能让其生效。
当然,“伪目标”的取名不能和文件名重名,不然其就失去了“伪目标”的意义了。
当然,为了避免和文件重名的这种情况,我们可以使用一个特殊的标记“.PHONY”来显式地指明一个目标是“伪目标”,向make说明,
不管是否有这个文件,这个目标就是“伪目标”。
2、追加变量值
追加变量值:我们可以使用“+=”操作符给变量追加值
如果变量之前没有定义过,那么,“+=”会自动变成“=”,如果前面有变量定义,那么“+=”会继承于前次操作的赋值符。
OBJS = f1.o f2.0 main.o OBJS += f3.o
3、自动化变量
$@ 表示规则中的目标文件集。在模式规则中,如果有多个目标,那么,"$@"就是匹配于目标中模式定义的集合。 $< 依赖目标中的第一个目标名字。如果依赖目标是以模式(即"%")定义的,那么"$<"将是符合模式的一系列的文件集。注意,其是一个一个取出来的。 $% 仅当目标是函数库文件中,表示规则中的目标成员名。例如,如果一个目标是"foo.a(bar.o)",那么,"$%"就是 "bar.o","$@"就是"foo.a"。如果目标 不是函数库文件(Unix下是[.a],Windows下是[.lib]),那么,其值为空。 $? 所有比目标新的依赖目标的集合。以空格分隔。 $^ 所有的依赖目标的集合。以空格分隔。如果在依赖目标中有多个重复的,那个这个变量会去除重复的依赖目标,只保留一份。 $+ 这个变量很像"$^",也是所有依赖目标的集合。只是它不去除重复的依赖目标。
4、变量中的变量
foo = $(bar) bar = $(ugh) ugh = Huh? $(foo)的值为Huh? echo $(foo)来进行查看
5、条件变量
还有一个比较有用的操作符是“?=”,先看示例:
FOO ?= bar
其含义是,如果FOO没有被定义过,那么变量FOO的值就是“bar”,如果FOO先前被定义过,那么这条语句将什么也不做,其等价于:
ifeq ($(origin FOO), undefined) FOO = bar endif
6、关于命令的变量
AR 函数库打包程序。默认命令是“ar”。 AS 汇编语言编译程序。默认命令是“as”。 CC C语言编译程序。默认命令是“cc”。 CXX C++语言编译程序。默认命令是“g++”。 CO 从 RCS文件中扩展文件程序。默认命令是“co”。 CPP C程序的预处理器(输出是标准输出设备)。默认命令是“$(CC) –E”。
RM 删除文件命令。默认命令是“rm –f”
7、关于命令参数的变量
ARFLAGS 函数库打包程序AR命令的参数。默认值是“rv”。 ASFLAGS 汇编语言编译器参数。(当明显地调用“.s”或“.S”文件时)。 CFLAGS C语言编译器参数。 CXXFLAGS C++语言编译器参数。 COFLAGS RCS命令参数。 CPPFLAGS C预处理器参数。( C 和 Fortran 编译器也会用到)
LDFLAGS 链接器参数。(如:“ld”)
如下面的例子:
CROSS_COMPILE = #指定编译器种类,为空,使用的就是gcc;类似于arm_linux_gnu_
LDFLAGS := -lm -lfreetype -lvga #指定编译器链接(根据实际项目手动修改)
TARGET := show_file #编译后的程序名(根据实际项目手动修改)
CFLAGS = -Wall -O -g
CC = $(CROSS_COMPILE)gcc
STRIP = $(CROSS_COMPILE)strip #优化工具
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump
OBJS:= $(patsubst %.c, %.o, $(SRC))
all :$(OBJS)
$(CC) $(OBJS) -o $(TARGET) $(LDFLAGS) #将编译好的 .o文件链接生成我们的目标文件
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
.PHONY : clean
clean:
rm *.o temp
目标中的"%"定义表示对文件名的匹配,"%"表示长度任意的非空字符串。例如:"%.c"表示以".c"结尾的文件名
三、make参数
“-I <dir>” 指定一个被包含 makefile 的搜索目标。可以使用多个“-I”参数来指定多个目录
CFLAGS += -I include
Makefile里面获取相对路径必须在pwd前面加shell,然后把shell pwd当一个变量来引用,书写形式是:$(shell pwd),比如说:
CFLAGS += -I$(shell pwd)/include
四、关键字
1、模式字符串替换函数——patsubst
$(patsubst <pattern>,<replacement>,<text>)
- 功能:查找<text>中的单词(单词以“空格”、“Tab”或“回车”“换行”分隔)是否符合模式< pattern>,如果匹配的话,则以<replacement>替换。这里,<pattern>可以包括通配符 “%”,表示任意长度的字串。如果<replacement>中也包含“%”,那么,<replacement>中的这个 “%”将是<pattern>中的那个“%”所代表的字串。(可以用“\”来转义,以“\%”来表示真实含义的“%”字符)
- 返回:函数返回被替换过后的字符串
$(patsubst %.c,%.o,x.c bar.c)
把字串“x.c bar.c”符合模式 %.c 的单词替换成 %.o ,返回结果是“x.o bar.o”
2、扩展通配符------wildcard
在Makefile规则中,通配符会被自动展开。但在变量的定义和函数引用时,通配符将失效。这种情况下如果需要通配符有效,就需要使用函数“wildcard”
一般我们可以使用“$(wildcard *.c)”来获取工作目录下的所有的.c文件列表。
可以使用“$(patsubst%.c,%.o,$(wildcard *.c))”,首先使用“wildcard”函数获取工作目录下的.c文件列表;之后将列表中所有文件名的后缀.c替换为.o。
这样我们就可以得到在当前目录可生成的.o文件列表。
SRC = $(wildcard *.c) $(wildcard app/*.c)
OBJS:= $(patsubst %.c, %.o, $(SRC))
推荐好文:跟我一起写Makefile