Matthew Note

Makefile Notes

样板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
CC=g++ -g
LPTHREAD= -lpthread
TARGET=main
OBJS=ThreadPool.o \
main.o
all : $(TARGET)
echo "ALL Done"
#$^ 会一次返回所有结果
#$< 一次返回一个结果
$(TARGET) : $(OBJS)
$(CC) $(LPTHREAD) -o $@ $^
%.o : %.cpp
$(CC) -c $< -o $@
#这部分可以保证对头文件的依赖性,不然会导致头文件更新,对应的
#cpp没有被更新的情况
%.dep : %.cpp
$(CC) -M $< > $@ $(BOOST_LIB)
include $(OBJS:.o=.dep)
include $(TEST_OBJS:.o=.dep)
clean:
rm -f *.o main
echo "Remove Done"

在make中有四种方式对变量赋值:

:=运算符

MAKE_DEPEND := $(CC) -M 这种方式叫做“简单展开”,因为在读到makefile中的这一行时等号右边就立即被展开了, 等号右边引用的所有变量(如例子中的CC)也会被立即展开。其行为与一般编程和脚本语言相同。当等号右边引用的变量(如例子中的CC)还没有被定义时,它被展开成空(nothing)而不是空格之类。

=运算符

MAKE_DEPEND = $(CC) -M 这种方式叫做“递归展开”,直到该变量被使用时等号右边的内容才会被展开,其实叫做“迟滞展开”更合适。神奇的是,这种展开方式可以不按顺序定义变量。比如:

1
2
3
4
MAKE_DEPEND = $(CC) -M
...
# Some time later
CC = gcc

只要在此之前没有引用过MAKE_DEPEND就没问题。另外,不止是“迟滞展开”,事实上每次使用该变量,等号右边的内容都会被重新展开。

?=运算符

OUTPUT_DIR ?= $(PROJECT_DIR)/out 这种方式叫“条件展开”,只有当OUTPUT_DIR 还没有被定义过时才进行赋值,否则什么都不做。这种方式在处理环境变量是特别有用。

+=运算符

OUTPUT_DIR += $(PROJECT_DIR)/out “追加”方式。 其主要目的是给“递归展开”的变量追加内容。因为简单变量可以用simple := $(simple) new stuff的方式来追加内容;而对于递归展开的变量,recursive = $(recursive) new stuff会导致循环引用。这种情况只能用+=运算符。

Pattern模式

模式中的%大体上等效于shell中的*星号,他可以代表任意多个字符,不过模式中只能出现一次。

$$

Because dollar signs are used to start make variable references, if you really want a dollar sign in a target or prerequisite you must write two of them, ‘$$’ (see How to Use Variables). If you have enabled secondary expansion (see Secondary Expansion) and you want a literal dollar sign in the prerequisites list, you must actually write four dollar signs (‘$$$$’).

define

还有一种设置变量值的方法是使用define关键字。使用define关键字设置变量的值可以有换行,这有利于定义一系列的命令(前面我们讲过“命令包”的技术就是利用这个关键字)。

define指示符后面跟的是变量的名字,而重起一行定义变量的值,定义是以endef关键字结束。其工作方式和“=”操作符一样。变量的值可以包含函数、命令、文字,或是其它变量。因为命令需要以[Tab]键开头,所以如果你用define定义的命令变量中没有以[Tab]键开头,那么make就不会把其认为是命令。

下面的这个示例展示了define的用法:

1
2
3
4
define two-lines
echo foo
echo $(bar)
endef

origin function

The origin function is unlike most other functions in that it does not operate on the values of variables; it tells you something about a variable. Specifically, it tells you where it came from.

The syntax of the origin function is:

$(origin variable)
Note that variable is the name of a variable to inquire about, not a reference to that variable. Therefore you would not normally use a ‘$’ or parentheses when writing it. (You can, however, use a variable reference in the name if you want the name not to be a constant.)

The result of this function is a string telling you how the variable variable was defined:

‘undefined’
if variable was never defined.

‘default’
if variable has a default definition, as is usual with CC and so on. See Variables Used by Implicit Rules. Note that if you have redefined a default variable, the origin function will return the origin of the later definition.

‘environment’
if variable was inherited from the environment provided to make.

‘environment override’
if variable was inherited from the environment provided to make, and is overriding a setting for variable in the makefile as a result of the ‘-e’ option (see Summary of Options).

‘file’
if variable was defined in a makefile.

‘command line’
if variable was defined on the command line.

‘override’
if variable was defined with an override directive in a makefile (see The override Directive).

‘automatic’
if variable is an automatic variable defined for the execution of the recipe for each rule (see Automatic Variables).