makefile中的自动化变量 $@,$%,$
9 i2 {4 H; L' [6 w, Y0 H
t0 y% d" n+ j& T; v自动化变量 ( Q- V% h5 S3 z/ M
模式规则中,规则的目标和依赖文件名代表了一类文件名;规则的命令是对所有这0 G6 H, k8 w+ g
一类文件重建过程的描述,显然,在命令中不能出现具体的文件名,否则模式规则失去
4 ]- r% [# w) R% f6 j意义。那么在模式规则的命令行中该如何表示文件,将是本小节的讨论的重点。
6 ~. W8 |% u) d- i' d. ?( u假如你需要书写一个将.c 文件编译到.o 文件的模式规则,那么你该如何为gcc 书写, o" m( {) p: n5 l
正确的源文件名?当然了,不能使用任何具体的文件名,因为在每一次执行模式规则时4 V C( Y$ }0 b' a8 a& g
源文件名都是不一样的。为了解决这个问题,就需要使用“自动环变量”,自动化变量$ m1 q- q; |2 A) T9 W$ G" H0 u$ Z
的取值是根据具体所执行的规则来决定的,取决于所执行规则的目标和依赖文件名。 ) ]; h7 w$ h- u' U1 ]3 o7 L, r: p& F
下面对所有的自动化变量进行说明:
4 K2 |( _& o3 q: b$ D! n$@ / K% X& h" f, w* l! Y q8 t5 I G$ |8 S
表示规则的目标文件名。如果目标是一个文档文件(Linux中,一般称.a 文件为7 L8 O$ @8 ]6 y/ p) Y
文档文件,也称为静态库文件),那么它代表这个文档的文件名。在多目标模式
4 I3 A# c- U2 H5 {+ y规则中,它代表的是哪个触发规则被执行的目标文件名。 " M% \8 k( W1 A$ i
$% 3 K1 ?2 G3 A9 Z( w5 h
当规则的目标文件是一个静态库文件时,代表静态库的一个成员名。例如,规则
0 R+ I/ R$ {6 z的目标是“foo.a(bar.o)”,那么,“ $%”的值就为“bar.o”,“ $@ ”的值为“foo.a”。
. C0 P$ ]7 W# n; C; r( e% \ n如果目标不是静态库文件,其值为空。 0 q7 f5 G7 V& `% x# w% D. `7 f; t# ~
$<
! r, h* v: S) p9 f+ q( J3 A. J规则的第一个依赖文件名。如果是一个目标文件使用隐含规则来重建,则它代表
9 R& Y; F& ~& i+ ]9 J由隐含规则加入的第一个依赖文件。 " \8 b3 l3 e+ e8 K& P: X- \9 @
$?
) y X# @4 T6 a- B; q1 o- W' F2 M6 P2 U$ I所有比目标文件更新的依赖文件列表,空格分割。如果目标是静态库文件名,代 表的是库成员(.o 文件)。 ) K' l( L& p5 m2 z* ~, W
$^
+ j5 h# T0 Q: q/ Z规则的所有依赖文件列表,使用空格分隔。如果目标是静态库文件,它所代表的
0 F& Z. Q9 \! I7 Q只能是所有库成员(.o 文件)名。一个文件可重复的出现在目标的依赖中,变量
$ @6 G% k/ W; K“$^”只记录它的一次引用情况。就是说变量“$^”会去掉重复的依赖文件。
' ~. S6 v- C$ M! D4 G8 b$+ 5 ?+ ?3 N; \7 ?" I
类似“$^”,但是它保留了依赖文件中重复出现的文件。主要用在程序链接时库
V8 L3 w% P3 r: M' A' N& x的交叉引用场合。
6 r" b0 `4 k. ^$ ^: e' t0 N$* 6 q9 a" ^+ \8 w$ B6 O- L2 W
在模式规则和静态模式规则中,代表“茎”。“茎”是目标模式中“% ”所代表的" k" r0 \0 x% m! n! i8 r
部分(当文件名中存在目录时,“茎”也包含目录(斜杠之前)部分,可参考 10.5.4 6 o) k" B/ v& x/ }4 B: f2 x7 q
模式的匹配 一小节)。例如:文件“dir/a.foo.b”,当目标的模式为“a.%.b ”时,
( z5 J. a9 z" @0 Q3 n, I" b0 z7 t“$* ”的值为“dir/a.foo ”。“茎”对于构造相关文件名非常有用。 6 m, w3 m/ P+ Y9 S8 K( z
自动化变量“$* ”需要两点说明: % `" j( b8 R; w! c! L6 D
? 对于一个明确指定的规则来说不存在“茎”,这种情况下“$* ”的含义发! a# M: v) g5 }
生改变。此时,如果目标文件名带有一个可识别的后缀(参考 10.7 后
& @9 N0 T9 x, `" b w缀规则 一节),那么“$* ”表示文件中除后缀以外的部分。例如:“foo.c”" N2 p; x2 O: y" t, F- S
则“$* ”的值为:“foo ”,因为.c 是一个可识别的文件后缀名。GUN make
/ T3 A3 e7 N# z对明确规则的这种奇怪的处理行为是为了和其它版本的make兼容。通' h$ G; y6 v" B( j- Q- l. @0 c
常,在除静态规则和模式规则以外,明确指定目标文件的规则中应该避9 P& U: |* S# W
免使用这个变量。
4 B; k# J3 e% P. U? 当明确指定文件名的规则中目标文件名包含不可识别的后缀时,此变量% Y, _7 W* w- N
为空。
! N$ D1 l, V5 v4 G$ D% F0 P自动化变量“$?”在显式规则中也是非常有用的,使用它规则可以指定只对更新0 r4 J* T6 C x
以后的依赖文件进行操作。例如,静态库文件“libN.a ”,它由一些.o 文件组成。这个规
# H' k% ?. o& J8 u, m4 y$ f则实现了只将更新后的.o 文件加入到库中:
2 l9 M m, T" t; K 9 Z6 A1 |3 g: F
lib: foo.o bar.o lose.o win.o ; s# t( W* A+ X" ?$ m" m* Q, N
ar r lib $? 1 o! v. q, z* F% _4 M
( P5 x& C: e: f1 s
以上罗列的自动量变量中。其中有四个在规则中代表文件名($@ 、$<、$%、$* )。
6 T% j( [( B k% ]% N0 \+ J而其它三个的在规则中代表一个文件名列表。GUN make 中,还可以通过这七个自动化 变量来获取一个完整文件名中的目录部分和具体文件名部分。在这些变量中加入“D”4 ?) M5 J2 G: R U
或者“F”字符就形成了一系列变种的自动环变量。这些变量会出现在以前版本的make/ y5 z5 ~5 j& {0 d4 C1 Q
中,在当前版本的make中,可以使用“dir”或者“notdir”函数来实现同样的功能(可0 C6 h$ Q5 H1 K; C
参考 8.3 文件名处理函数 一节)。 / k h6 { T# H9 y0 v5 m# ~& N2 v
$(@D) 3 b- w- ~7 c4 c# f( T7 R, S
表示目标文件的目录部分(不包括斜杠)。如果“$@ ”是“dir/foo.o ”,那么“$(@D) ”' a. q" n# B3 k/ j3 |$ ~2 A
的值为“dir”。如果“$@ ”不存在斜杠,其值就是“. ”(当前目录)。注意它和 函
% M* f; J" m5 x! d1 H数“dir”的区别!
, T0 P) Y1 m- K+ j" Q; X' E$(@F)
s6 |: A/ e! y( z* O! {6 F目标文件的完整文件名中除目录以外的部分(实际文件名)。如果“$@ ”为
4 V: q4 C# k( G4 i: j“dir/foo.o ”,那么“$(@F) ”只就是“foo.o”。“$(@F) ”等价于函数“$(notdir 4 P) U( I5 ]4 s* q5 T
$@) ”。 . x* ?, A. q; Y, g
$(*D) ) t% N. x% w' Y2 P) s. Y
$(*F) ?* u* `# w2 [- G( B4 M
分别代表目标“茎”中的目录部分和文件名部分。 & v+ W5 ~8 Y% n+ t/ i3 ^, ]& G
$(%D) ! ?7 G7 R/ P# L/ B& W
$(%F)
2 q, \- j) x, ~( n当以如“archive(member) ”形式静态库为目标时,分别表示库文件成员/ b: p* l' t% A
“member”名中的目录部分和文件名部分。它仅对这种形式的规则目标有效。
5 t, K" W7 @3 ^* z l3 a! r$(<d) ; m' }" r1 R7 W" t' \& ?
$(<f) - t8 T( b- k! s, U
分别表示规则中第一个依赖文件的目录部分和文件名部分。
5 }! C; j4 R4 @3 ]$(^D)
8 [5 Q0 m- @: }$(^F)
5 f8 d4 g! e. j分别表示所有依赖文件的目录部分和文件部分(不存在同一文件)。 1 ?7 y1 d& ]- ?
$(+D)
, M- j# R5 H3 x1 [+ @$ K- i$ N2 U$(+F)
5 S/ x% @( f0 [. W3 B分别表示所有依赖文件的目录部分和文件部分(可存在重复文件)。
" G3 j, g7 v& [$(?D)
! s1 I% U6 I" g9 ]2 V! ]$(?F) 3 P7 `- s; @ j) f
分别表示被更新的依赖文件的目录部分和文件名部分 在讨论自动化变量时,为了和普通变量(如:“CFLAGS ”)区别,我们直接使用了- J' T* n: q& O" c! Y" ]7 Q; |
“$<”的形式。这种形式仅仅是为了和普通变量进行区别,没有别的目的。其实对于; K& W& ?7 l/ @
自动环变量和普通变量一样,代表规则第一个依赖文件名的变量名实际上是“< ”,我
; s* M8 @- _2 w8 w y& q们完全可以使用“$(<) ”来替代“$<”。但是在引用自动化变量时通常的做法是“$<”,/ F) }4 `/ f! |1 Y
因为自动化变量本身是一个特殊字符。
I" S) h) n$ tGUN make同时支持“Sysv”特性,允许在规则的依赖列表中使用特殊的变量引
( B; g" Z: e9 A8 a9 r0 Z) I用(一般的自动化变量只能在规则的命令行中被引用)“$$@”、“$$(@D)”和“$$(@F)”' r0 R% r3 n+ r5 |* a
(注意:要使用“$$”),它们分别代表了“目标的完整文件名”、“目标文件名中的目
! B6 }. g7 C" N& M录部分”和“目标的实际文件名部分”。这三个特殊的变量只能用在明确指定目标文件
) X. F4 o$ q" }" q# k- {) V名的规则中或者是静态模式规则中,不用于隐含规则中。另外Sysv make 和GNU make) U3 s& \, |' A4 U
对规则依赖的处理也不尽相同。Sysv make对规则的依赖进行两次替换展开,而GUN 3 q+ X* U( d! N; `4 }" ?$ Z
make对依赖列表的处理只有一次,对其中的变量和函数引用直接进行展开。
6 Q5 L* [/ J9 ^8 q$ E自动化变量的这个古怪的特性完全是为了兼容Sysv 版本的makefile文件。在使用* u7 V1 h+ z+ b0 ] n4 @7 y6 C. M
GNU make 时可以不考虑这个,也可以在Makefile中使用伪目标“.POSIX ”来禁止这一
# V- z1 i5 G7 t9 o特性
+ u, C) u F: \ |