Make基础 Make:根据指定的Makefile文件构建 新文件
1 2 $ make [-f makefile] [<target>]
make默认寻找当前目中GNUmakefile
/makefile
/Makefile
文件作为配置
文件
默认用makefile中首个目标文件作为最终目标文件 ,否则
使用<target>
作为目标文件
Make参数
-b
/-m
:忽略和其他版本make兼容性
-B
/--always-make
:总是更新/重编译所有目标
-C <dir>
/--directory=<dir>
:指定读取makefile的目录,
相当于$ cd <dir> && make
指定多个-C <dir>
,make将按次序合并为最终目录
-C
时,-w
选项自动打开
--debug[=<options>]
:输出make调试信息
a
:all,输出所有调试信息
b
:basic,基本信息
v
:verbose,基本信息之上
i
:implicit,所有隐含规则
j
:jobs,执行规则中命令的详细信息,如:PID、返回码
m
:makefile,make读取、更新、执行makefile的信息
-d
:等价于--debug=a
-e
/--environment-overrides
:环境变量覆盖makefile中值
-f <file>
/--file=<file>
/--makefile=<file>
:指定
makefile
可以多次传递参数-f <filename>
,所有makefile合并
传递给make
-h
/--help
:帮助
-i
/--ignore-errors
:忽略执行时所有错误
-I <dir>
/--include-dir=<dir>
:搜索include
makefile
路径
-j [<jobsum>]
/-jobs[=<jobsum>]
:指定同时运行命令数
进程数
默认同时运行尽量多命令
多个-j
时最后者生效
-k/--keep-going
:出错不停止运行
-l <load>
/--load-average[=<load>]
--max-load[=<load>]
:make命令负载
-n
/--just-print
/--dry-run
/--recon
:仅输出执行
过程中命令序列,不执行
-o <file>
/--old-file=<file>
/--assume-old=<file>
:
不重新生成指定的<file>
,即使目标依赖其
-p
/--print-data-base
:输出makefile中所有数据:规则、
变量等
1 2 3 4 $ make -qp # 只想输出信息,不执行makefile $ make -p -f /dev/null # 查看执行makefile前的预设变量、规则
-q
/--question
:不执行命令、不输出,仅检查指定目标
是否需要更新
-r
/--no-builtin-rules
:禁用make任何隐含规则
-R
/--no-builtin-variables
:禁用make任何作用于变量上
的隐含规则
-s
/--silent
/quiet
:禁止显示所有命令输出
-S
/--no-keep-going
/--stop
:取消-k
作用
-t
/--touch
:修改目标日期为最新,即组织生成目标的命令
执行
-v
/--version
:版本
-w
/--print-directory
:输出运行makefile之前、之后信息
--no-print-directory
:禁止-w
选项
-W <file>
/--what-if=<file>
/--new-file=<file>
/--assume-file=<file>
联合-n
选项,输出目标更新时的运行动作
没有-n
,修改<file>
为当前时间
--warn-undefined-variables
:有未定义变量是输出警告信息
步骤
读入所有makefile
读入被include
其他makefile
初始化(展开)文件中变量、函数,计算条件表达式
展开模式规则%
、推导隐式规则、分析所并规则
为所有目标文件创建依赖关系链
根据依赖关系,决定需要重新生成的目标
执行生成命令
相关环境变量
Makefile基本语法 控制符号
引用其他Makefile
<filename>
可以是默认shell的文件模式,包含通配符、路径
include
之前可以有空格,但是不能有<tab>
(命令提示)
make寻找其他makefile,将其内容放当前位置
若文件没有明确指明为绝对路径、相对路径,make会在以下目录
中寻找
-I
、--include-dir
参数
/usr/local/bin/include
、/usr/include
make会include
环境变量MAKEFILES 中文件
不建议使用环境变量MAKEFILES
,会影响所有make
文件未找到,make会生成一条警告信息,但继续载入其他文件,
完成makefile读取之后,make会重试寻找文件,失败报错
可以使用-include
/sinclude
代替,忽略include过程
中的任何错误
Makefile显式规则 1 2 <target>: <prerequisite> [tab]<commands>
<target>
:目标
<prerequisites>
:前置条件
<commands>
:命令,和前置条件至少存在一个
1 2 a.txt: b.txt c.txt cat b.txt c.txt > a.txt
Target 目标:make的目标
目标通常是文件名,指明需要构建的对象
不是文件名的目标称为伪目标,视为某种操作
多目标 多目标规则意义是多个目标共享规则 依赖、声明命令,并
不是需要同时生成 多个目标
需要多目标中的任何一个 时,多目标规则就会被应用,其中
命令被执行
每次只生成单独目标 的多目标规则,目标之间只是单纯的
可以合并简化 规则中的命令
1 2 3 4 5 6 7 8 9 bigoutput littleoutput: text.g generate text.g -$(subst output,,$@ ) > $@ bigoutput: text.g generate text.g -big > bigoutput littleoutput: text.g generate text.g -little > littleoutput
同时生成多个目标 的多目标规则,多个目标应该满足
需要同时生成、不能单独修改 ,否则没有必要定义为多目标
,当然这其实也是合并简化 规则中的命令
1 2 %.tab.c %.tab.h: %.y bison -d $<
Phony Target todo 伪目标:目标是某个操作的名字,每次执行都会执行命令
1 2 3 4 .PHONY : clean clean: rm *.o
若省略.PYHONY
,要求当前目中不存在同名文件,否则make
认为目标已存在,不会执行命令
GNU规范 GNU推荐makefile中包含的伪目标、命名
all
:编译所有目标
clean
:删除所有被make创建的文件
install
:安装已编译好程序,即将目标执行文件拷贝到指定
目标中
print
:列出改变过的源文件
tar
:打包源程序备份
dist
:创建压缩文件
tags
:更新所有目标,以备完整地编译使用
check
/test
:测试makefile流程
静态库 目标archive(member)
:指定静态库文件、及其组成
1 2 3 4 5 6 7 8 9 10 11 12 13 foolib(hack.o kludge.o): hack.o kludge.o ar cr foolib hack.o kludge.o foolib(hack.o): hack.o ar cr foolib hack.l kudge.o foolib(kludge.o): kludge.o ar cr foolib kludge.o foolib(*.o): hack.o kludge.o
Prerequisites 前置条件/依赖:生成目标的依赖
通常是一组空格分隔的文件名,为空则说明目标的生成和其他
文件无关
指定目标是否重新构建的判断标准,只要有一个前置文件不存在
、有过更新(时间戳比较),目标就需要更新
若前置文件不存在,则需要建立以其作为目标的规则用于生成,
make target
时会自动调用
1 2 source: file1 file2 file3
Commands 命令:更新、构建文件的方法
在linux下默认使用环境变量SHELL
(/bin/sh
)执行命令,
在MS-DOS下没有SHELL
环境变量,会在PATH
环境变量中寻找
,并自动加上.exe
、.bat
、.sh
等后缀
<tab>
每行命令前必须有一个<tab>
,否则需要使用提前声明
1 2 3 .RECIPEPREFIX=> all: > echo Hello, world
Shell进程 每行 命令在单独的shell进程中执行,其间没有继承关系
(即使是同一个规则中)
多条命令可以使用;
分隔
1 2 var-kept: export foo=bar; echo "foo=[$$foo]"
可类似python\
换行
1 2 3 var-kept: export foo=bar; \ echo "foo=[$$foo]"
使用.ONESHELL
命令
1 2 3 4 .ONESHELL var-kept: export foo=bar echo "foo=[$$foo]"
嵌套执行Make 大工程中不同模块、功能源文件一般存放在不同目录,可以为每个
目录单独建立makefile
利于维护makefile,使得其更简洁
利于分块/分段编译
最顶层、调用make执行其他makefile的makefile称为总控
1 2 3 4 5 6 7 8 9 10 subsystem: cd subdir && $(MAKE) subsystem: $(MAKE) -C subdir subsystem: cd subdir && $(MAKE) -w MAKEFLAGS=
搜索路径 VPATH
VPATH
:makefile中定义的特殊环境变量,指明寻找依赖文件、
目标文件的路径
vpath
vpath
:make关键字,指定不同模式 文件不同搜索目录
1 2 3 4 5 6 7 vpath <pattern> <directories> vpath %.h ../headers # 指明`<pattern>`模式文件搜索目录 vpath <pattern> # 清除`<pattern>`模式文件搜索目录设置 vpath # 清除所有`vapth`设置
<pattern>
中使用%
匹配0或若干字符
vpath
可以重复为某个模式指定不同搜索策略,按照出现顺序
先后执行搜索
隐含规则
常用隐含规则 编译C
目标:<n>.o
依赖包含:<n>.c
生成命令
1 $(CC) -c $(CPPFLAGS) $(CFLAGS)
编译CPP
目标:<n>.o
依赖包含<n>.cc
/<n>.c
生成命令
1 $(CXX) -c $(CPPFLAGS) $(CFLAGS)
编译Pascal
编译Fortran/Ratfor
目标:<n>.o
依赖包含:<n>.f
/<n>.r
生成命令
1 2 3 4 5 6 $(FC) -c $(FFLAGS) $(FC) -c $(FFLAGS) $(CPPFLAGS) $(FC) -c $(FFLAGS) $(RFLAGS)
预处理Fortran/Ratfor
目标:<n>.f
依赖包含:<r>.r
/<n>.F
生成命令
1 2 3 4 $(FC) -F $(CPPFLAGS) $(FFLAGS) $(FC) -F $(FFLAGS) $(RFLAGS)
转换Ratfor、有预处理的Fortran至标准Fortran
编译Modula-2
目标:<n>.sym
/<n>.o
依赖包含:<n>.def
/<n>.mod
生成命令1 2 3 4 $(M2C) $(M2FLAGS) $(DEFFLAGS) $(M2C) $(M2FLAGS) $(MODFLAGS)
汇编汇编
目标:<n>.o
依赖包含:<n>.s
生成命令:默认使用编译器as
预处理
目标:<n>.s
依赖包含:<n>.S
生成命令:默认使用预处理器cpp
链接object
目标:<n>
依赖包含:<n>.o
生成命令:默认使用C工具链中链接程序ld
1 $(CC) <n>.o $(LOADLIBS) $(LDLIBS)
Yacc C
Lex C
Lex Ratfor
创建Lint库
目标:<n>.ln
依赖包含:<n>.c
/<n>.y
/<n>.l
生成命令
1 $(LINT) $(LINTFLAGS) $(CPPFLAGS) -i
创建静态链接库
目标:<archive>(member.o)
依赖包含:member
生成命令
1 ar cr <archive> member.o
即使目标传递多个memeber.o
,隐含规则也只会解析出把首个
.o
文件添加进静态链接库中的命令
1 2 3 4 (%.o): %.o $(AR) rv $@ $* .o
隐含规则使用变量 隐含规则使用的变量基本都是预先设置的变量
makefile中改变
make命令环境变量传入
设置环境变量
-R
/--no-builtin-variable
参数取消变量对隐含规则作用
命令
AR
:函数打包程序,默认ar
AS
:汇编语言编译程序,默认as
CC
:C语言编译程序,默认cc
CXX
:C++语言编译程序,默认c++
/g++
CPP
:C程序预处理器,默认$(CC) -E
/cpp
FC
:Fortran、Ratfor编译器、预处理程序,默认f77
PC
:Pascal语言编译程序,默认pc
LEX
:Lex文法分析器程序(针对C、Ratfor),默认lex
YACC
:Yacc文法分析器程序(针对C、Ratfor),默认
yacc -r
GET
:从SCCS
文件中扩展文件程序,默认get
CO
:从RCS
文件中扩展文件程序,默认co
MAKEINFO
:转换Texinfo .texi
到Info程序,默认
makeinfo
TEX
:转换TeX至Tex DVI程序,默认tex
TEXI2DVI
:转换Texinfo至Tex DVI程序,默认texi2dvi
WEAVE
:转换Web至TeX程序,默认weave
TANGLE
:转换Web至Pascal程序,默认tangle
CTANGEL
:转换C Web至C,默认ctangle
RM
:删除文件命令,默认rm -f
命令参数 未指明默认值则为空
ARFLAGS
:静态链接库打包程序AR参数,默认rv
ASFLAGS
:汇编语言汇编器参数
CFLAGS
:C编译器参数
CXXFLAGS
:C++编译器参数
CPPFLAGS
:C预处理参数
LDFLAGS
:链接器参数
FFLAGS
:Fortran编译器参数
RFLAGS
:Fatfor的Fortran编译器参数
LFLAGS
:Lex文法分析器参数
YFLAGS
:Yacc文法分析器参数
COFLAGS
:RCS命令参数
GFLAGS
:SCCS get
参数
隐含规则链 make会努力自动推导 生成目标的一切方法,无论中间目标
数量,都会将显式规则、隐含规则结合分析以生成目标
模式规则 模式规则:隐式规则可以看作内置 模式规则
目标定义包含%
,表示任意长度非空字符串
依赖中同样可以使用%
,但是其取值取决于目标
命令中不使用模式%
,使用自动化变量
静态模式 静态模式:给定目标候选范围 的模式,限制规则只能应用在以
给定范围文件作为目标的情况
1 2 <target>: <target-pattern>: <prereq-patterns> <commands>
<target>
:目标候选范围,可含有通配符
<target-pattern>
:所有目标文件 满足的模式
<prereq-pattern>
:目标相应依赖
简单例子
1 2 3 4 5 6 7 8 9 10 11 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
静态模式+filter
函数筛选范围
1 2 3 4 5 files = foo.elc bar.o lose.o $(filter %.o,$(files) ) : %.o: %.c $(CC) -c $(CFLAGS) $< -o $@ $(filter %.elc,$(files) ) : %.elc: %.el emacs -f batch-byte-compile $<
重载内建隐含规则 1 2 3 4 5 %.o: %c $(CC) -c $(CPPFLAGS) $(CFLAGS) -D $(date) %o: %c
后缀规则
双后缀规则:定义一对目标文件后缀、依赖后缀
单后缀规则:定义一个依赖后缀
1 2 3 4 5 6 .c.o: $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $< .c: $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<
后缀规则中不能有任何依赖文件,否则不是后缀规则,后缀被
认为是目标文件
后缀规则中必须有命令,否则没有任何意义,这不会移去内建
的隐含规则
后缀规则定义中的后缀需要是make所认识的,可以使用伪目标
.SUFFIXES
修改make认识的后缀
1 2 3 4 .SUFFIXES: .SUFFIXES: .c .o .h
后缀规则是老式定义隐含规则的方法,会被逐步取代,事实上
后缀规则在makefile载入后会被转换为模式规则
模式规则搜索算法 设目标为src/foo.o
将目标目录部分、文件名部分分离,得到src/
、foo.o
搜索所有模式规则列表,创建目标和src/foo.o
匹配的模式
规则列表
若模式规则列表中有目标匹配所有文件的模式(如%
),
则从列表中移除其他模式
移除列表中没有命令的规则
对列表中首个模式规则
将src/foo.o
或foo.o
匹配目标,推断%
匹配非空部分
茎S
把依赖中%
替换为茎S,如果依赖项中没有包含目录,
尝试将src
添加在其前
检查所有依赖文件存在、理当存在(文件被定义为其他规则
的目标文件、显式规则的依赖文件)
若有依赖文件存在、理当存在或没有依赖文件,此规则被
采用,退出算法
若没有找到合适模式规则,则检查列表中下个规则是否可行
若没有模式规则可以使用,检查.DEFAULT
规则存在性,存在
则应用
变量、赋值 Makefile中定义的变量类似C++/C中的宏
在shell中需要$$处应使用两个
$$$,一个$
被escape,则
shell解释时仍然保留一个$
,如:变量、函数等都需要
赋值 Makefile内自定义变量
1 2 3 4 5 6 7 txt = Hello World test: @echo $(txt) echo ${txt}
define
define
可以换行定义变量
1 2 3 4 5 6 7 8 9 10 define run-yacc yacc $(firstword $^ ) ; \ mv y.tab.c $@ endef foo.c: foo.y $(run-yacc)
override
若变量由make命令行参数-e
设置,makefile中默认忽略对其
赋值
需要显式使用override
关键字设置
1 2 3 override <variable> = <value>override <variable> := <value>override define <variable>
export
上级makefile中变量可以显式export
传递到下层makefile中,
但是不会覆盖下层中定义的变量(除指定-e
参数)
1 2 3 4 5 6 7 8 9 export <variable>[=value] unexport <variable> export variable = value variable = value export variable
export
后面不指定具体传递变量,表示传递所有变量
MAKEFLAGS
、SHELL
两个变量总是会传递到下级makefile中
系统环境变量 make运行时系统环境变量、命令行环境变量可以被载入makefile
默认makefile中定义变量覆盖系统环境变量
-e
参数则表示makefile中变量被覆盖
Target-Specific Variable 目标/局部变量:作用范围局限于规则、连带规则中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <target ...>: [override ] <variable-assignment> prog: CFLAGS = -g prog: prog.o foo.o bar.o $(CC) $(CFLAGS) prog.o foo.o bar.o prog.o: prog.c $(CC) $(CFLAGS) prog.c foo.o: foo.c $(CC) $(CFLAGS) foo.c bar.o: bar.c $(CC) $(CFLAGS) bar.c
Pattern-Specific Variable 模式变量:给定模式,变量定义在符合模式的所有目标 上
1 2 3 <pattern ...>: [override ]<variable-assignment> %.o: CFLAGS = -o
Implicit Variables 内置变量:主要是为了跨平台的兼容性
$(CC)
:当前使用的编译器
1 2 output: $(CC) -o output input.c
$(MAKE)
:当前使用的Make工具
$(MAKECMDGOLA)
:make目标列表
Automatic Variables 自动化变量:应用规则时被自动赋予相应值(一般是文件)的变量
自动化变量只应出现在规则的命令 中
自动化变量值与当前规则有关
其中$@
、$*
、$<
、$%
扩展后只会为单个文件,$?
、
$^
、$+
扩展后可能是多个文件
1 2 3 dest/%.txt: src/%.txt @[ -d test ] || mkdir dest cp $< $@
D、F
7个自动化变量可以搭配D
、F
取得相应路径中目录名、
文件名
新版本GNU make可以使用函数dir
、notdir
代替D
/F
D
/dir
:目录带有最后/
,若为当前目录则为./
F
/nodir
:文件名
对可能会扩展为多文件的$?
、$^
、$+
,D
/F
处理后
返回同样是多个目录/文件
1 2 3 4 5 6 7 8 9 10 11 12 13 $(@D) $(dir $@ ) $(@F) $(nodir $@ ) $(?D) $(dir $? ) $(?F) $(nodir $? )
控制语句 if
1 2 3 4 5 6 7 8 <conditional-directive> <text-if-true> [ else <text-if-false> ] endif
ifeq
:比较参数是否相等
ifneq
:比较参数是否不等
1 2 3 4 5 6 ifeq ($(CC) , gcc) libs=$(libs_for_gcc) else libs=$(normal_libs) endif
ifdef
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 bar = foo = $(bar) ifdef foo frobozz = yes else frobozz = no endif foo = ifdef foo frobozz = yes else frobozz = no endif
ifndef
<conditional-directive>, else, endif
行可以有多余空格,
但是不能以<tab>
开头,否则被认为是命令
make在读取makefile时就计算表达式值、选择语句,所以最好
别把自动化变量放入条件表达式中
make不允许把条件语句分拆放入两个文件中
for
1 2 3 4 5 6 7 8 9 10 11 LIST = one two three all: for i in $(LIST) ; do \ echo $$i; // 这里传递给shell的变量,需要`$$` escape done all: for i in one two three; do echo $$i; done
内建函数 1 2 $(function parameters) ${function paremeters}
Make控制函数 提供一些函数控制make执行
检测运行makefile的运行时信息,根据信息决定make继续执行
、停止
error
产生错误并退出make,错误信息<text>
1 2 3 4 5 6 7 8 9 10 $(error <text...>) ifdef ERROR_001$(error error is $(ERROR_001) ) endif ERR = $(error found an error ) .PHONY : errerr: err: ; $(ERR)
warning
类似error
函数,输出警告信息,继续make
其他函数 shell
执行shell命令的输出作为函数返回值
1 srcfiles := $(shell echo src/{00..99}.txt)
函数会创建新shell执行命令,大量使用函数可能造成性能下降
,尤其makefile的隐晦规则可能让shell函数执行次数过多
wildcard
在变量中展开通配符 *
1 2 3 srcfiles := $(wildcard src/*.txt)
字符串处理函数 subst
文本替换
1 2 3 4 5 $(subst <from>,<to>,<text>) $(subst ee,EE,feet on the street)
patsubst
模式匹配的替换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 $(patsubst <pattern>,<replacement>,<text>) $(patsubst %.c,%o,x.c.c bar.c) foo := a.o b.o c.o $(variable: <pattern>=<replacement>) bar := $(foo:%.o=%.c) $(variable: <suffix>=<replacement>) bar := $(foo:.o=.c)
strip
去字符串头、尾空格
1 2 $(strip <string>) $(strip a b c)
findstring
在<in>
中查找<find>
,找到返回<find>
,否则返回空串
1 2 $(findstring <find>,<in>) $(findstring a,a b c)
filter
以<pattern>
模式过滤<text>
字符串中单词,返回符合模式的
单词
1 2 3 4 5 6 $(filter <pattern..>,<text>) sources := foo.c bar.c baz.s ugh.h foo: $(sources) cc $(filter %.c %.s, $(sources) ) -o foo
filter-out
以<pattern>
模式过滤<text>
字符串中单词,返回不符合模式的
单词
1 2 3 4 objects := main1.o foo.o main2.o bar.o mains=main1.o main2.o $(filter -out $(mains) , $(objects) )
sort
对<list>
中单词升序排序
1 2 3 4 $(sort <list>) $(sort foo bar lose)
word
取字符串<text>
中第<n>
个单词
1 2 3 4 $(word <n>,<text>) $(word 2, foo bar baz)
wordlist
从<text>
中取<s>-<e>
单词(闭区间)
1 2 3 4 $(wordlist <s>,<e>,<text>) $(wordlist 2, 3, foo bar baz)
words
统计<text>
中单词个数
1 2 3 4 $(word <text>) $(word, foo bar baz)
firstword
取<text>
中首个单词
1 2 3 4 $(firstword <text>) $(firstword foo bar)
文件名操作函数 dir
从文件名序列 中取出目录部分
1 2 3 4 $(dir <names...>) $(dir src/foo.c hacks)
notdir
从文件名序列 中取出非目录部分(最后/
之后部分)
1 2 3 4 $(notdir <names...>) $(notdir src/foo.c hacks)
suffix
从文件名序列 中取出各文件名后缀
1 2 3 4 $(suffix <names...>) $(suffix src/foo.c src-1.0/bar.c hacks)
basename
从文件名序列 中取出各文件名“前缀”(除后缀外部分)
1 2 3 4 $(basename <names...>) $(basename src/foo.c src-1.0/bar.c hacks)
addsuffix
把后缀<suffix>
添加到文件名序列 中每个单词后
1 2 3 4 $(addsuffix <suffix >,<names...>) $(addsuffix .c, foo bar)
addprefix
把后缀<prefix>
添加到文件名序列 中每个单词后
1 2 3 4 $(addprefix <prefix>,<names...>) $(addprefix src/, foo bar)
join
把<list2>
中单词对应 添加到<list1>
中单词后
1 2 3 4 $(join <list1>,<list2>) $(join aaa bbb, 111 222 333)
控制函数 foreach
循环函数,类似于Bash中的for
语句
把<list>
中单词逐一取出放到参数<var>
所指定的变量中
再执行<text>
所包含的表达式,每次返回一个字符串
循环结束时,返回空格分隔的整个字符串
1 2 3 4 5 $(foreach <var>,<list>,<text>) names := a b c d files := $(foreach n,$(names) ,$(n) .o)
if
类似于make中的ifeq
<condition>
为真(非空字符串),计算<then-part>
返回值
<condition>
为假(空字符串),计算<else-part>
、返回空
字符串
1 $(if <condition>,<then-part>,[<else-part>])
call
创建新的参数化函数 的函数
创建表达式<expression>
,其中可以定义很多参数
用call
函数向其中传递参数,<expression>
返回值即call
返回值
1 2 3 4 5 6 7 8 $(call <expression>,<param1>,<param2>,...> reverse = $(1) $(2)foo = $(call reverse,a,b) reverse = $(2) $(1) foo = $(call reverse,a,b)
<expression>
要先创建为变量,然后不带$
传递
origin
返回变量的来源
undefined
:<variable>
未定义
default
:make默认定义变量
environment
:环境变量,且-e
选项未开
file
:定义在makefile中
command line
:命令行定义环境变量
override
:override
关键字定义
atomatic
:命令运行中自动化变量
1 2 3 4 5 6 7 $(origin <variable>) ifdef bletchifeq "$(origin bletch)" "environment" bletch = barf, gag, etc endif endif
Makefile技巧 案例 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 edit: main.o kdd.o command.o display.o \ insert.o search.o files.o utils.o cc -o edit main.o kbd.o command.o dispaly.o\ insert.o search.o files.o utils.o main: main.c defs.h cc -c main.c kbd.o: kbd.c defs.h cc -c kbd.c command.o: command.c defs.h command.h cc -c command.c display.o: display.o defs.h buffer.h cc -c display.c insert.o: insert.c defs.h buffer.h cc -c insert.c search.o: search.c defs.h buffer.h cc -c search.c files.o: files.c defs.h buffer.h command.h cc -c files.c utils.o utils.c defs.h cc -c utils.c clean: rm edit main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o .PHONY : edit clean
利用变量简化目标 1 2 3 4 5 6 objects = main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o edit: $(objects) cc -o edit $(objects)
隐式模式自动推导 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 objects = main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o edit: $(objects) cc -o edit $(objects) main.o: defs.h kbd.o: defs.h command.h command.o: defs.h command.h display: defs.h buffer.h insert.o: defs.h buffer.h search.o: defs.h buffer.h files.o: defs.h buffer.h command.h utils.o: defs.h clean: rm edit $(objects) .PHONY : clean
利用变量提取依赖 1 2 3 4 5 6 7 8 9 10 11 12 13 objects = main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o edit: $(objects) cc -o edit $(objects) $(objects) : defs.hkbd.o command.o files.o: command.h display.o insert.o search.o files.o: buffer.h clean: rm edit $(objects) .PHONY : clean
自动生成依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 %.d: %.c @set -e; rm -f $@ ; \ $(cc) -M $(CPPFLAGS) $< > $@ .$$$$; \ sed 's,/($* /)/.o[ :]*,/1.o $@ : ,g' < $@ .$$$$ > $@ ; \ rm -f $@ .$$$$ source = foo.c bar.c include $(sources: .c=.d)