GNU Make 项目管理
通过描述源文件、中间文件、目标文件之间的关系, 将源代码转换成可执行文件的例行工作自动化。
# comment
target1 target2 target3 : prereq1 prereq2
command1
command2
command3
规则
通配符
依赖关系语境部分由 make 处理,命令部分由 shell 处理。
i.e *.[hc]
–> *.h
or *.c
假想工作目标
.PHONY: clean
clean:
rm -f *.o hello.c
尽管存在 clean 是最新的,仍然可执行 clean。
all |
执行编译程序的所有工作 |
install |
进行二进制程序的安装 |
clean |
清理产生的二制文件 |
distclean |
编译过程产生的任何文件 |
TAGS |
建立可供编辑器使用的标记表 |
info |
创建 GNU info 文件 |
check |
执行测试 |
uninstall |
卸载程序 |
具体工作目标、假想工作目标、空文件工作目标
自动变量
$@ |
工作目标的文件名 |
$* |
工作目标的主文件名(stem) |
$% |
工作目标的归档文件结构中的文件名元素,i.e. foo.a(bar.o) 则 $% = bar.o |
$+ |
所有必要条件的文件名(重复),在共享库循环引用时使用 |
$^ |
所有必要条件的文件名 (去重) |
$? |
时间在工作目标后的所有必要条件 |
$< |
第一个必要条件的文件名 |
后缀 D 表示目录部分,F 表示文件部分 i.e.
$(@D) $(<F)
搜索路径
VPATH = include src
# vpath <patterns> <dir list>
vpath %.h %.hpp include
vpath %.c %.cpp src src2
分类
内置规则是模式规则的实例,模式规则是一般规则的范化。
-
具体规则
-
隐含规则
- 模式规则
%.o: %.c $(COMPILE.c) $(OUTPUT_OPTION) $<
注意模式规则中 % 与通配符 * 的区别。
- 静态规则
%(OBJECTS): %.o: %.c $(CC) -c $(CFLAGS) $< -o $@
- 后缀规则:
# 双后缀 # %.o: %c .c.o: $(COMPILE.c) $(OUTPUT_OPTION) $< # 单后缀 # %: %.p .p: $(LINK.p) $^ $(LOADLIBES) $(LDLIBS) -o $@
其它
-
自动产生帮助
help: @ $(MAKE) --print-data-base --question | \ awk '/^[^.%][-A-Za-z0-9_]*:/{print substr($$1, 1, length($$1) - 1)}' | \ sort | \ pr --omit-pagination --width=80 --columns=4
-
自动产生依赖关系
include $(subst .c,.d,$(SOURCES)) %.d: %.cpp @set -e; rm -f $@; \ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ rm -f $@.$$$$
-
更新静态库
-lshared-lib
为必要条件将会尝试在-L /usr/lib
指定的路径中查找libshared-lib.a
,但不会查找规则来构建该文件。而libshared-lib.a
会在当前工作目录中查找规则来构建。libfoo.a: libfoo.a(foo.o) libfoo.a(bar.o)
-
双冒号规则: 规则不覆盖
hello:: hello.c hello:: foo.c
变量
命名
# 常量:命令行、环境变量
CC_NAME := gcc
# 变量:makefile
sources_files = *.c
# 函数:makefile
maybe-mk-dir = $(if $(wildcard $1),,$(MKDIR) $1)
类型
变量值会忽略赋值运算符右侧前导空格、保留后置空格。
- 简单变量
SIMPLE_VAR := 'simple var'
- 扩展变量
RECURSIVE_VAR = 'recursive var'
- 条件赋值
SIMPLE_VAR ?= 'null'
- 附加赋值
SIMPLE_VAR += 'null'
- 专属变量
libhello.so: LDFLAGS += -shared
libhello.so: hello.cpp
$(LINK.cpp) $^ $(OUTPUT_OPTION)
宏
定义
define create-jar
@echo Creating $@
endef
调用
# 1 使用变量的形式展开
$(create-jar)
# 2 通过内置函数宏展开
$(call create-jar)
由于 call
调用的宏不存在时,不产生任何作用,利用该特性可实现函数挂钩。
# $(call build-libs, object-files)
define build-libs
$(AR) $(ARFLAGS) $@ $1
$(call build-hook,$1)
endef
libfoo.a: build-hook = $(RANLIB) $@
libfoo.a: foo.o
$(call build-libs,$^)
扩展变量
- 简单变量被立即扩展
- 递归变量使用时展开
- 宏定义:名称立即扩展,主体使用时扩展
- 规则:工作目标与必要条件立即扩展,命令脚本使用时扩展
变量来源
- 命令行
- makefile
- 环境变量
- 自动产生
- 优先级:命令行(剔除 makefile 中的值) > 环境变量 -e(剔除 makefile 中的值) > makefile > 环境变量(替换内置变量) > 内置变量
override
当使用命令行时,保留使用 makefile 的值。--environment-overrides
环境变量会覆盖 makefile 的值。
条件指令
ifdef/ifndef
中的变量不需要添加美元符号 $
。ifeq/ifneq
的条件变量的形式有两种:调用符号 ($(AA),$(BB))
或者 空格符号 $(AA) $(BB)
。
ifdef COMPSEC
endif
ifndef COMPSEC
endif
ifeq $(AA) $(BB)
endif
ifneq $(AA) $(BB)
endif
函数
字符串函数
# 1. $(filter pattern...,text)
$(ui_library): $(filter ui/%.o,$(objects))
# 2. $(filter-out pattern...,text)
# 功能与 filter 相反
# 3. $(findstring string...,text)
# 返回 string
# 4. $(subst search-string,replace-string,text)
isouces := count_words.c counter.c lexer.c
objects := $(subst .c,.o,$(sources))
# 5. $(patsubst search-pattern,replace-pattern,text)
$(patsubst %/,%,$(directory-path))
# 6. $(words text)
# return word count
# 7. $(words n,text)
# return n's word
# 8. $(firstword text)
# equal to $(words 1,text)
# 9. $(wordlist start,end,text)
# return [start, end]'s text word
重要杂项
# 1. $(sort list)
# 排序并删除重复、前导空格
# 2. $(shell command)
# 扩展 command 到 shell 中运行,返回标准输出(换行被转换成空格)
文件名函数
# 1. $(wildcard pattern...)
# 通配符
# 2. $(dir list...)
# return directory path
# 3. $(notdir name...)
# return filename
# 4. $(suffix name...)
# return suffix, i.e. xxx.cpp --> .cpp
# 5. $(basename name...)
# return basename, i.e. xxx.cpp --> xxx
# 6. $(addsuffix suffix,name...)
# append suffix to name
# 7. $(addprefix prefix,name...)
# add prefix to name
# 8. $(join prefix-list,suffix-list)
# i.e. [a, b, c] join [.cpp, .cpp, .cpp] --> [a.cpp, b.cpp, c.cpp]
流程控制
# 1. $(if condition,then-part,else-part)
# 2. $(error text)
# 3. $(foreach var,list,body)
其它
# 1. $(strip text)
# 清除前后空格,多个空格由单空格替换
# 2. $(origin var)
# 返加变量来源 undefined default environment...
# 3. $(warning text)
# 4. $(eval text)
# 二次展开,未经求值
命令
命令修饰符
- @ 同
.SILENT
, 不要输出命令。 - - 同
.IGNORE
, 忽略错误。 - + 强制执行,忽略
--just-print
,常用于递归式 make。
空命令
header.h: ;
通过 ;
避免使用隐含规则。
命令环境
递归式 make
,命令行参数将通过 MAKEFLAGS
传递给子 make
。
对命令脚本求值
-
读取脚本并解释
ifdef/...
条件指令 -
扩展变量
-
对表达式求值
-
执行命令