Makefile 笔记

Some Notes about Makefile

记录一下最近用Makefile的经验和教训
内容比较凌乱。放在这里供以后参考。

1. Target-specific variable的作用域

Target-specific variable指的是变量在某些特定目标下的值。用法是:

target … : variable-assignment

注意这里的变量作用域只是在Recipe部分,而不能在目标(Target)或者依赖(Prerequisites)部分。

target … : prerequisites …
recipe

就是说这个Target-specific变量的值仅在recipe中有效。

2. 除错的方法

用warning 函数,比如$(warning msg)。它可以出现在各个部分: 目标, 依赖,recipe,顶级变量, 都行 (参见[2]):

$(warning A top-level warning)

FOO := $(warning Right-hand side of a simple variable)bar
BAZ = $(warning Right-hand side of a recursive variable)boo

$(warning A target)target: $(warning In a prerequisite list)makefile $(BAZ)
$(warning In a command script)
ls
$(BAZ):

输出:
$ make
makefile:1: A top-level warning
makefile:2: Right-hand side of a simple variable
makefile:5: A target
makefile:5: In a prerequisite list
makefile:5: Right-hand side of a recursive variable
makefile:8: Right-hand side of a recursive variable
makefile:6: In a command script
ls
makefile

还可以配合这些参数–just-print (-n), –print-data-base (-p), and –warn-undefined-variables

3. 管理大型项目

大型项目的代码有层级结构。xieMakefile要注意代码精简,善用函数,尽量自动化,避免重复代码,检查变量的有效性。

例如:
create-output-directories := \
$(shell for f in $(modules); \
do \
$(TEST) -d $$f || $(MKDIR) $$f; \
done)

例如用call, eval, foreach等函数:

# use foreach and test
.PHONY: validate_build
validate_build:
test $(foreach f,$(RELEASE_FILES),-s $f -a) -e .

local_src := $(addprefix $(subdirectory)/,playlist.y scanner.l)

# create library
define make-library
libraries += $(BINARY_DIR)/$1
sources += $2

$(BINARY_DIR)/$1: $(call source-dir-to-binary-dir, \
$(subst .c,.o,$(filter %.c,$2)) \
$(subst .y,.o,$(filter %.y,$2)) \
$(subst .l,.o,$(filter %.l,$2)))
$(AR) $(ARFLAGS) $$@ $$^
endef
$(eval $(call make-library, $(subdirectory)/libdb.a, $(local_src)))


参考
[1]Target-specific variables. GNU make. (link)
[2]Debugging Makefiles, Managing Projects with GNU Make, 3rd Edition, Chapter 12. (link)
[3]C and C++, Managing Projects with GNU Make, 3rd Edition, Chapter 8. (Link)