makefile中的自动化变量 $@,$%,$
3 t% E2 G' w X% T+ c8 R1 d& C: U" {7 q) g; i* y6 i
自动化变量 5 P( m6 ?0 _# X# r( n
模式规则中,规则的目标和依赖文件名代表了一类文件名;规则的命令是对所有这
2 r* I5 o# S% l' f一类文件重建过程的描述,显然,在命令中不能出现具体的文件名,否则模式规则失去
" l2 s% H% Q2 _7 ^# b' e& h( F& k意义。那么在模式规则的命令行中该如何表示文件,将是本小节的讨论的重点。
2 T$ f0 P! k, O/ H- n$ H7 X8 j4 k5 y假如你需要书写一个将.c 文件编译到.o 文件的模式规则,那么你该如何为gcc 书写# [9 R9 y! Y$ b& o/ ^
正确的源文件名?当然了,不能使用任何具体的文件名,因为在每一次执行模式规则时
% A% T) G- D! g2 Z% F& {源文件名都是不一样的。为了解决这个问题,就需要使用“自动环变量”,自动化变量0 `6 F' K- f4 l3 y7 M; m' x
的取值是根据具体所执行的规则来决定的,取决于所执行规则的目标和依赖文件名。
) U5 u& w6 ]0 C' Z" f下面对所有的自动化变量进行说明: 3 R" ?/ Q! `. R3 X% Y
$@
* ^& g- a1 c4 G' f! }表示规则的目标文件名。如果目标是一个文档文件(Linux中,一般称.a 文件为
' s2 [6 C$ q4 J) f/ [/ ~/ b文档文件,也称为静态库文件),那么它代表这个文档的文件名。在多目标模式
- U4 }. Y8 |3 ~2 p& f3 C3 W规则中,它代表的是哪个触发规则被执行的目标文件名。
( |# |: S. E! q3 {& S( T$%
/ @: @% ?7 u# G4 a" u) I当规则的目标文件是一个静态库文件时,代表静态库的一个成员名。例如,规则3 z, x& I5 L# i1 G
的目标是“foo.a(bar.o)”,那么,“ $%”的值就为“bar.o”,“ $@ ”的值为“foo.a”。
8 ^7 f5 S5 U( O: ~* ?/ ?如果目标不是静态库文件,其值为空。 2 D% q9 _; [; E) N- Y/ ~* n6 R
$<
9 z9 {9 X& K L' d规则的第一个依赖文件名。如果是一个目标文件使用隐含规则来重建,则它代表
% F1 {9 G& h' l- y+ b5 z$ m. H6 z由隐含规则加入的第一个依赖文件。 " @& x$ M# f5 u
$?
' i1 T a- X* l" `, A所有比目标文件更新的依赖文件列表,空格分割。如果目标是静态库文件名,代 表的是库成员(.o 文件)。 3 _4 X) o- {: A. Z2 f0 g
$^
, W) K& ]7 k9 c4 q6 k; v规则的所有依赖文件列表,使用空格分隔。如果目标是静态库文件,它所代表的
# Q% J$ {2 l& h+ b4 n只能是所有库成员(.o 文件)名。一个文件可重复的出现在目标的依赖中,变量0 P6 c! c! L" _0 n: h
“$^”只记录它的一次引用情况。就是说变量“$^”会去掉重复的依赖文件。
# d0 y, E; u# l$+ / A9 s( @9 I. v. ~/ J
类似“$^”,但是它保留了依赖文件中重复出现的文件。主要用在程序链接时库
! X% V3 T2 V. U9 A: H1 m' B的交叉引用场合。
5 A9 _( l2 Z3 n. O4 z8 y$*
$ Z' k1 e! ?% P8 l* k$ Z. k5 D在模式规则和静态模式规则中,代表“茎”。“茎”是目标模式中“% ”所代表的2 }0 J5 e, z5 R' T3 i
部分(当文件名中存在目录时,“茎”也包含目录(斜杠之前)部分,可参考 10.5.4
8 g* G5 n* F; `模式的匹配 一小节)。例如:文件“dir/a.foo.b”,当目标的模式为“a.%.b ”时,2 h$ f: }- z* Y3 y8 U+ w8 Q
“$* ”的值为“dir/a.foo ”。“茎”对于构造相关文件名非常有用。
* s; R- [2 Z/ N: C& m9 z( H0 X( ^自动化变量“$* ”需要两点说明: ; X' O( n: v' _! ~
? 对于一个明确指定的规则来说不存在“茎”,这种情况下“$* ”的含义发
& u$ o7 b! o. M% b( D! {: }3 {! R生改变。此时,如果目标文件名带有一个可识别的后缀(参考 10.7 后& U) m! d( m$ M( j) V. N1 W8 T9 ?
缀规则 一节),那么“$* ”表示文件中除后缀以外的部分。例如:“foo.c”) r I q# ? ]/ E7 L! q, H
则“$* ”的值为:“foo ”,因为.c 是一个可识别的文件后缀名。GUN make
# J2 N& Q2 m( [1 F% z对明确规则的这种奇怪的处理行为是为了和其它版本的make兼容。通$ u8 K7 x( l% P2 w" l! D+ @
常,在除静态规则和模式规则以外,明确指定目标文件的规则中应该避1 b {3 ~3 `& ?4 B, y" T K
免使用这个变量。
6 N5 a- z9 S5 J& M# K) c? 当明确指定文件名的规则中目标文件名包含不可识别的后缀时,此变量$ B) j, W9 I/ _5 y! Q' t5 A" h8 u" \
为空。 6 s; @9 s; ]; J# A! V4 B( E$ D
自动化变量“$?”在显式规则中也是非常有用的,使用它规则可以指定只对更新+ M, i. B* F' n
以后的依赖文件进行操作。例如,静态库文件“libN.a ”,它由一些.o 文件组成。这个规9 Z! K" E8 z4 m/ f+ v1 S2 j
则实现了只将更新后的.o 文件加入到库中: - z( _+ _+ n) `0 ]0 `# w: \
: ]: Z8 a4 U' o& X
lib: foo.o bar.o lose.o win.o & I* W. W3 K3 d+ ~% n
ar r lib $? - x) J( l0 s7 f
) u1 l5 X1 A H. k8 d' f8 m以上罗列的自动量变量中。其中有四个在规则中代表文件名($@ 、$<、$%、$* )。
: T5 I1 |4 ~ a而其它三个的在规则中代表一个文件名列表。GUN make 中,还可以通过这七个自动化 变量来获取一个完整文件名中的目录部分和具体文件名部分。在这些变量中加入“D”2 H6 n% o2 x- `6 _8 F
或者“F”字符就形成了一系列变种的自动环变量。这些变量会出现在以前版本的make
0 z; H7 x, }; U中,在当前版本的make中,可以使用“dir”或者“notdir”函数来实现同样的功能(可
6 P, F) H( W+ g/ S( B参考 8.3 文件名处理函数 一节)。 ' A6 f7 {" Z: y0 q3 c: N/ K
$(@D) w/ n, M- K: D, K3 m8 v7 T6 V
表示目标文件的目录部分(不包括斜杠)。如果“$@ ”是“dir/foo.o ”,那么“$(@D) ”$ p; E/ r# d/ I9 W$ q
的值为“dir”。如果“$@ ”不存在斜杠,其值就是“. ”(当前目录)。注意它和 函4 L7 T( n7 e% h1 I
数“dir”的区别!
- i/ W) e# N" l8 \# a4 |$(@F)
3 H, W+ g, {8 C- w* R* m$ f! ?, u目标文件的完整文件名中除目录以外的部分(实际文件名)。如果“$@ ”为
0 ]# D* J& ^6 o( S1 |6 ]3 n“dir/foo.o ”,那么“$(@F) ”只就是“foo.o”。“$(@F) ”等价于函数“$(notdir
; }; \' k2 w3 ^. ?, J2 @& j$@) ”。 0 {7 O8 N8 [1 T' Q! h! ^
$(*D) / x m. {* H5 r$ g& S# H# t! K
$(*F) ( w3 R. J9 R9 g1 k7 _+ W4 D
分别代表目标“茎”中的目录部分和文件名部分。
& w8 O1 a5 K9 C! g) u0 U0 U4 U9 m$(%D)
6 w/ [2 D( ^, O" O, O9 K$ P$(%F)
4 D# d3 t+ n1 ?( G8 @4 {: ~5 L当以如“archive(member) ”形式静态库为目标时,分别表示库文件成员8 T5 p6 a, U9 g" E/ B2 G) H. ^
“member”名中的目录部分和文件名部分。它仅对这种形式的规则目标有效。
4 ?2 ?/ J& J3 l; M0 I$(<d) ) r3 f+ y8 h# _; r2 K$ m
$(<f) + V O) y/ K0 L3 Q! t4 S& T, [: i1 g
分别表示规则中第一个依赖文件的目录部分和文件名部分。 + ~! k! \0 ]% `
$(^D)
3 T. S+ i7 W+ l1 u' z$(^F) . k, d, B3 k; [% N! Y- U
分别表示所有依赖文件的目录部分和文件部分(不存在同一文件)。 & c5 u) {9 S0 O9 f, m, }8 ?
$(+D) " c6 W' [- x- D: ?2 t+ F
$(+F)
: G/ J; d2 H) `" X% |分别表示所有依赖文件的目录部分和文件部分(可存在重复文件)。 : r# x4 y2 a0 o! o; g" g/ x
$(?D) 2 n- A( @, y: ]* c- Z7 ]1 z
$(?F)
: k/ i/ k1 L5 x' D! e9 |分别表示被更新的依赖文件的目录部分和文件名部分 在讨论自动化变量时,为了和普通变量(如:“CFLAGS ”)区别,我们直接使用了
2 \3 u# D# X5 Z8 ] N, }2 R“$<”的形式。这种形式仅仅是为了和普通变量进行区别,没有别的目的。其实对于9 r( ~7 H! h4 v
自动环变量和普通变量一样,代表规则第一个依赖文件名的变量名实际上是“< ”,我
+ H# G; {% B: {/ p们完全可以使用“$(<) ”来替代“$<”。但是在引用自动化变量时通常的做法是“$<”,
2 v; ~$ T, ~) Q6 C' M! K! [4 F因为自动化变量本身是一个特殊字符。
- o8 b3 @2 s5 @GUN make同时支持“Sysv”特性,允许在规则的依赖列表中使用特殊的变量引
5 @# r/ A" M a) p用(一般的自动化变量只能在规则的命令行中被引用)“$$@”、“$$(@D)”和“$$(@F)”
& H; o* J' N5 t(注意:要使用“$$”),它们分别代表了“目标的完整文件名”、“目标文件名中的目
$ ]& i$ \ S$ X' u& q5 F7 k, V; o( m录部分”和“目标的实际文件名部分”。这三个特殊的变量只能用在明确指定目标文件
# b D U- y/ O L8 f名的规则中或者是静态模式规则中,不用于隐含规则中。另外Sysv make 和GNU make
, c/ l4 y7 } b对规则依赖的处理也不尽相同。Sysv make对规则的依赖进行两次替换展开,而GUN ! `; R( [5 K6 b7 a
make对依赖列表的处理只有一次,对其中的变量和函数引用直接进行展开。 8 |& n* V& @$ l. \$ v1 v. K' p
自动化变量的这个古怪的特性完全是为了兼容Sysv 版本的makefile文件。在使用
' B3 Y4 E) h$ ]2 M3 dGNU make 时可以不考虑这个,也可以在Makefile中使用伪目标“.POSIX ”来禁止这一
5 {' z5 U8 c2 d- a特性 8 n' p0 V" G: n, f+ m/ [1 I
|