一、概述
Makefile中主要包含的内容有:
1、注释
2、文件包含
3、变量定义
4、条件判断
5、函数
6、规则
二、注释
只提供单行注释, 凡是以#开头的行都认为是注释行。
#this is a comment
三、文件包含
include的用法,include后面跟一个Makefile文件名. 这样我们可以写一个公共Makefile,包含一些公共变量的定义,其他目录下的Makefile可以把这个公共Makefile文件包含进去。
-include ../Makefile.param (之前的“-”表示包含失败不停止)
四、变量定义
1、变量的基础
在Makefile中,变量定义主要有如下几种方式:
#方式一:定义多行变量
define variable
value
value
endef
#方式二:
variable = value
#方式三:
variable := value (直接展开)
#方式四:
variable += value (追加变量)
#方式五:
variable ?= value
变量的引用可以采用$(variable)和${variable}两种方式。
2、变量的高级应用
变量的替换引用:$(VAR:A=B)把变量VAR中的所有有A的地方都替换为B,如
foo := a.o b.o c.o
bar := $(foo:.o=.c)
override指示符:常规变量,会被执行make命令的参数变量覆盖,比如:
CFLAGS=-o
如果执行make时使用make CFLAGS=O2,那么CFLAGS会变为o2,为了解决这个问题,可以使用override指示符
override CFLAGS=01
这样,参数变量中指定的内容不会覆盖Makefile中定义的变量。
目标指定变量和模式指定变量:变量都是全局的,而目标指定变量和模式指定变量都是对某个目标或者某种模式局部的,如:
#目标指定变量
foo:CFLAGS+=-O2
#模式指定变量
%.o:CFLAGS+=O1
五、条件判断
条件判断有如下四种形式:
#1
ifeq
do something
else
do something
endif
#2
ifneq
do something
else
do something
endif
#3
ifdef
do something
else
do something
endif
#4
ifndef
do something
else
do something
endif
六、函数
1、文本处理函数
subst
patsubst
strip
findstring
filter
filter-out
sort
word
words
wordlist
firstword
2、文件名处理
dir
notdir
suffix
basename
addsuffix
addprefix
wildcard
3、其他
foreach
if
eval
value
七、规则
1、显示规则
规则的三要素都直接写出来的。
2、隐式规则
所谓隐式规则就是make会自动为一些目标推导依赖。下面列出c和c++相关的隐含规则:
1、编译c的隐含规则:<n>.o的目标的依赖会自动推导为<n>.c,并用命令$(CC) -c $(CPPFLAGS) $(CFLAGS)来生成.
2、编译c++的隐含规则:<n>.o的目标的依赖会自动推导为<n>.cc,并用命令$(CXX) -c $(CPPFLAGS) $(CFLAGS)来生成。
3、链接Object文件的隐含规则:<n>目标依赖于<n>.o,链接命令是$(CC) $(LDFLAGS)<n>.o $(LOADLIBES)$(LDLIBS),这一规则对多个依赖文件也是适用的,如x:y.o x.o z.o,但是依赖中至少要有同名的。
隐含规则通常都使用一些系统变量,先列出如下:
1、AR:默认是ar
2、CC:默认是cc
3、CXX:默认是g++
4、CPP:c程序的预处理器,默认是$(CC) -E
5、RM:删除文件,默认是rm -f
关于命令参数的变量:
1、ARFLAGS:打包程序AR的参数,默认是rv
2、CFLAGS:C语言的编译参数
3、CXXFLAGS:C++语言的编译器参数
4、CPPFLAGS:C预处理器参数
5、LDFLAFS:链接器参数
3、模式规则
隐含规则整体感觉太玄,但是可以用模式规则来定义隐含规则,它的目标中必须有%号,如:
%.o:%.c
Command
这个就是模式规则,这个规则表明,所有<n>.c到<n>.o的编译都使用Command,而不是内建的默认命令。
4、静态模式规则
静态模式规则是模式规则中的一种特例,模式规则是对所有的符合模式的都起作用,而静态模式规则是对特定的目标是用的一种模式规则,如
objects = foo.o bar.o
all: $(objects)
$(objects): %.o: %.c
$(CC) -c $(CFLAGS) $< -o $@
#相当于
foo.o : foo.c
$(CC) -c $(CFLAGS) foo.c -o foo.o
bar.o : bar.c
$(CC) -c $(CFLAGS) bar.c -o bar.o
其中%.o:%.c这个模式规则是只对objects这个目标起作用的。
5、自动化变量
在写一些规则的时候,需要有个变量可以自动的赋值为目标或依赖,下面列举几个常用的自动化变量:
1、$@:规则中所有的目标文件集
2、$<:依赖的第一个文件,如果依赖是以模式定义的,那就表示所有依赖文件集
3、$^:规则中的依赖文件集,并且是做了重复删除的
4、$+:跟$^一样,就是没做重复删除。
八 例子
根据项目的大小,可以把项目建成平铺式(小型项目)和嵌套式(大型项目),而这两种项目的Makefile文件也会稍有不同,前者通常一个Makefile就可以,放在顶层目录,而后者需要分不同模块写几个不同的Makfile,通过一个顶层的Makefile来包含。下面介绍一个可以用在通常平铺项目中的通用Makefile:
#以下定义目录结构
SRC_DIR := ./src
INC_DIR := ./include/a /
./include/b /
./include
LIB_DIR := ./lib
#以下定义编译工具链
CROSS=arm-hismall-linux-
CC=$(CROSS)gcc
AR=$(CROSS)ar
RANLIB=$(CROSS)ranlib
RM=rm -f
#以下定义编译参数
CFLAGS :=
DEPENDFLAG :=-MM
LIB=$(foreach dir, $(LIB_DIR), -L$(dir))
LIBFLAGS=-lprint
INC=$(foreach dir, $(INC_DIR), -I$(dir))
#以下定义文件变量
SRCS=$(foreach dir, $(SRC_DIR), $(wildcard $(dir)/*.c))
OBJS=$(SRCS:.c=.o)
DEPENDS=$(SRCS:.c=.d)
TARGET=test
#下面定义规则
all:$(TARGET)
%.d:%.c
@set -e; rm -f $@;/
$(CC) $(DEPENDFLAG) $(INC) $< |/
sed "s?//(.*//):?$(basename $<).o $(basename $<).d:?g"/
> $@;/
%.o:%.c
$(CC) -o $@ -c $< $(INC)
$(TARGET):$(OBJS)
$(CC) -o $@ $< $(LIB) $(LIBFLAGS)
-include $(DEPENDS)
.PHONY:clean
clean:
$(RM) $(OBJS) $(DEPENDS) $(TARGET)