版主
主题
回帖0
积分10609
阅读权限200
注册时间2008-11-22
最后登录1970-1-1
在线时间 小时
|
在Makefile中可以使用函数来处理变量,从而让我们的命令或是规则更为的灵活和具有智能。make所支持的函数也不算很多,不过已经足够我们的操作了。函数调用后,函数的返回值可以当做变量来使用。
- c5 S$ n/ }; Z( M一、函数的调用语法1 j; r5 r F7 S% H
函数调用,很像变量的使用,也是以“$”来标识的,其语法如下:& H+ Z$ U, x7 \9 T7 _, \; b/ n7 r
$(/ C0 u6 C2 M* i
)0 ~, `( n5 I# H* ~$ o
或是
8 ?/ E# N2 f3 M' N) `+ n$ X9 J ${# T8 d. i: j4 T6 e V
}; y% l: Q! i: L8 j; \- h
这里,就是函数名,make支持的函数不多。是函数的参数,参数间以逗号“,”分隔,而函数名和参数之间以“空格”分隔。函数调用以“$”开头,以圆括号或花括号把函数名和参数括起。感觉很像一个变量,是不是?函数中的参数可以使用变量,为了风格的统一,函数和变量的括号最好一样,如使用“$(subst( ~- @9 h% x2 _4 V0 _# C0 _. n
a,b,$(x))”这样的形式,而不是“$(subst a,b,${x})”的形式。因为统一会更清楚,也会减少一些不必要的麻烦。
1 B' b Q! g* o) H* U4 C还是来看一个示例:
c8 z. c- z1 x comma:= ,
7 G5 I0 ^9 l1 _" n empty:=* q2 `% o) k% w( |9 P
space:= $(empty) $(empty)
4 [& |0 Q4 f5 U9 h% {+ a foo:= a b c Z; h$ R" g) m
bar:= $(subst $(space),$(comma),$(foo)), I+ a: ?5 k9 O& [ S% I. |
在这个示例中,$(comma)的值是一个逗号。$(space)使用了$(empty)定义了一个空格,$(foo)的值是“a b c”,$(bar)的定义用,调用了函数“subst”,这是一个替换函数,这个函数有三个参数,第一个参数是被替换字串,第二个参数是替换字串,第三个参数是替换操作作用的字串。这个函数也就是把$(foo)中的空格替换成逗号,所以$(bar)的值是“a,b,c”。% U! N' ?7 t8 x; G; J
二、字符串处理函数
1 ?( |. L/ o9 O. ~ X" I! P; Y$(subst) P- y$ ^4 ~' s. T H# V! R+ T7 o
,,)
" f1 @) `7 c2 F! p! ^6 i 名称:字符串替换函数——subst。9 [+ s5 ?- M0 H& h
功能:把字串中的字符串替换成。
2 ^8 l. g N# ` 返回:函数返回被替换过后的字符串。
; M" q: J$ Y& Y* _+ ] 示例:
9 ]" `. ~; \& {+ ]7 @: E3 Y3 W # L/ K! i# A0 [! `; E% k5 ?$ v
$(subst ee,EE,feet on the street),
G% v2 R0 B& [& p, N: _ ) u. |. q' }* }) W1 [9 h8 q; G+ j
把“feet on the street”中的“ee”替换成“EE”,返回结果是“fEEt
! r4 Y% B+ c% a( [6 ?+ D0 \: y Qon the strEEt”。/ Z; t) R- F# o* }
$(patsubst ,,) 9 a7 |0 q I/ }2 i9 R- W
名称:模式字符串替换函数——patsubst。
( b+ d0 T5 Y4 [" B% P) b2 d# l* ^ 功能:查找中的单词(单词以“空格”、“Tab”或“回车”“换行”分隔)是否符合模式,如果匹配的话,则以替换。这里,可以包括通配符“%”,表示任意长度的字串。如果中也包含“%”,那么,中的这个“%”将是中的那个“%”所代表的字串。(可以用“\”来转义,以“\%”来表示真实含义的“%”字符)
/ e9 m* f1 m6 M: Y3 p+ m 返回:函数返回被替换过后的字符串。3 r4 o; V# [! E/ b: l: F: \* R5 C
示例:' B/ }7 h) L% A9 ?! W
" R( p. ]6 R" d9 i. o% K
$(patsubst %.c,%.o,x.c.c bar.c). j7 X9 c: g& X0 ~- |
把字串“x.c.c! h: P, Z6 [# h% ?* D: q) Q
bar.c”符合模式[%.c]的单词替换成[%.o],返回结果是“x.c.o- v4 |6 ~: W4 l* _7 ^
bar.o”
0 R/ J* v3 X3 G! H 备注:) |7 w+ d2 m4 y: e
这和我们前面“变量章节”说过的相关知识有点相似。如:/ D D! }; @: v" y0 {$ i! n7 a; I" e
“$(var:=)”7 r3 f: C1 E3 s1 F1 ?0 U) u
相当于) ?4 ]3 t! t) u) h" m8 Q
“$(patsubst8 w" r$ q. D3 q
,,$(var))”,
5 H( Y# K @# I 而“$(var:
- x1 K# j, c1 q, a$ Y=)”2 t% N# c. R7 h" [* v( Y! D5 f
则相当于
8 h6 G4 M' @6 R2 O “$(patsubst, ]; M5 i; @/ c
%,%,$(var))”。
5 n5 M: Q, X# x# t, m# j+ d 例如有:objects = foo.o9 {7 O, L$ H& C+ a% X8 p
bar.o baz.o,
* D w2 \! v( m8 |, Y 那么,“$(objects:.o=.c)”和“$(patsubst/ o1 `/ p6 O5 Q, j$ b
%.o,%.c,$(objects))”是一样的。6 F" `3 s& W# Z$ T. f2 m3 m
$(strip )
5 W! V5 ?7 |6 K/ E 名称:去空格函数——strip。
& _9 H3 B/ {+ q) _6 S1 d: ^ 功能:去掉字串中开头和结尾的空字符。
% z h; f4 S, s3 E+ `( V( c 返回:返回被去掉空格的字符串值。
$ q y% o! _1 p# \) z. m* b8 h 示例:" Q2 V. o5 f1 @! F! z5 a) v
( ~6 z. B) Z) w3 H6 L
$(strip a b c )$ w$ h5 o1 ^$ d* r9 c
把字串“a b G7 Z. W F8 u
c ”去到开头和结尾的空格,结果是“a b c”。
: t# M/ O) M* e/ R$(findstring ,)
6 p# V N F, @8 { 名称:查找字符串函数——findstring。
# C6 h5 S- ]2 {; c) [3 b 功能:在字串中查找字串。; w' `2 q' W9 ^' w3 G: E i2 o+ N
返回:如果找到,那么返回,否则返回空字符串。
2 n9 d9 a |/ ]+ u9 x0 N 示例:: p/ Z0 W, o' {2 n* _& S
1 m0 A4 a$ X5 a! `' J
$(findstring a,a b c)
4 p& b$ G$ H3 Y $(findstring a,b c)4 B- g7 Z4 u- R" f# ]; Q3 G
第一个函数返回“a”字符串,第二个返回“”字符串(空字符串)$ E" K) Q2 q0 o- p9 v; j+ Q9 A
$(filter7 u* Y4 P; {, k8 U" N% O
,)6 e4 |: I- f4 g0 ?& W
名称:过滤函数——filter。2 e7 v) E) q; Q; A7 i
功能:以模式过滤字符串中的单词,保留符合模式的单词。可以有多个模式。. E# O7 D/ _- N! t
返回:返回符合模式的字串。
n3 ]# m' ]" } O" r 示例:7 K, o! l' k- q
sources- r$ |8 h- K3 t+ X/ _. o& ?4 P
:= foo.c bar.c baz.s ugh.h% s* z2 f) N5 P r- f
foo: $(sources)
" }4 g: I, E! I8 |$ i0 `
0 ]6 x. ^8 B+ ?' Tcc $(filter %.c %.s,$(sources)) -o foo
0 G3 K, F6 p0 e4 L3 b
/ }/ E+ ]1 o3 F$(filter %.c %.s,$(sources))返回的值是“foo.c bar.c baz.s”。3 H+ b4 n) | E! x
$(filter-out
% Q/ G. X" l% m, H4 Y* z" g/ ~' d" A,)8 {2 M1 O% W0 M
名称:反过滤函数——filter-out。
6 X4 _2 R5 v& z( I, x: V- p" y 功能:以模式过滤字符串中的单词,去除符合模式的单词。可以有多个模式。
8 T. ?9 A7 v6 E$ s% ^ 返回:返回不符合模式的字串。- }, G8 P) q* |) i
示例:4 O$ e7 {$ J- A+ a) `1 l$ x$ ?( r
: J7 T# c9 |0 |7 A9 qobjects=main1.o foo.o main2.o bar.o- v4 b- a# k" U6 B7 Y) n
mains=main1.o main2.o: b$ q; K! o1 y1 p: l: Z" l
! H% ~0 f3 W7 m8 W
$(filter-out $(mains),$(objects)) 返回值是“foo.o: L& S, Z' N3 F. E5 o
bar.o”。
, ^' c$ S F# L. a+ x, a! m2 ] - i% s6 D" ^: R: m4 N
$(sort )
% X E. q& |9 K1 M名称:排序函数——sort。功能:给字符串中的单词排序(升序)。返回:返回排序后的字符串。示例:$(sort foo bar lose)返回“bar foo lose”。备注:sort函数会去掉中相同的单词。+ n- N7 w& ` |7 y) E7 d
$(word ,)6 L0 y6 W" P) P# Z1 b
名称:取单词函数——word。功能:取字符串中第个单词。(从一开始)返回:返回字符串中第个单词。如果比中的单词数要大,那么返回空字符串。示例:$(word 2, foo bar baz)返回值是“bar”。0 q, o z. u) ~7 w, H
$(wordlist; y7 H1 B+ ]0 q
,,)
) I; [( u- _/ D1 P 名称:取单词串函数——wordlist。
4 D5 V9 _! N* g, V$ g1 z5 I4 [: Q2 d 功能:从字符串中取从开始到的单词串。和是一个数字。# h2 M. Z1 K n8 {/ t
返回:返回字符串中从到的单词字串。如果比中的单词数要大,那么返回空字符串。如果大于的单词数,那么返回从开始,到结束的单词串。
5 c; t- M' I. {7 x6 g# P 示例: $(wordlist 2, 3, foo bar baz)返回值是“bar' d' z" l1 t, x3 K& m" ]6 H
baz”。
; X4 N* _4 D% M# G2 n& `$(words )
h1 m6 V! x, A0 K 名称:单词个数统计函数——words。
% p& M* h6 x4 j4 n$ ]* g 功能:统计中字符串中的单词个数。' a7 h7 e: X3 A2 x9 O* }
返回:返回中的单词数。
4 u; P9 h8 `# f* S) |2 K. ` 示例:$(words, foo bar baz)返回值是“3”。
+ i: d0 |4 x9 x 备注:如果我们要取中最后的一个单词,我们可以这样:$(word
! q( T6 x% L- ?5 K0 L0 g ?) {$(words ),)。
3 ?: Y+ `* P* h: o( E$(firstword )
" s7 _& g6 c" V' P0 I 名称:首单词函数——firstword。1 |% q0 F3 x; Z7 i% |$ W
功能:取字符串中的第一个单词。: C; a. I" X6 s7 {6 ?1 k
返回:返回字符串的第一个单词。: f' F) V: H! k2 i& v- U
示例:$(firstword foo bar)返回值是“foo”。1 V1 I1 W. x, V- K7 W7 @2 ^
备注:这个函数可以用word函数来实现:$(word o5 U' n7 X- m9 X% Y* a
1,)。! a6 C- E7 E+ X! b' b5 |) g2 t
以上,是所有的字符串操作函数,如果搭配混合使用,可以完成比较复杂的功能。这里,举一个现实中应用的例子。我们知道,make使用“VPATH”变量来指定“依赖文件”的搜索路径。于是,我们可以利用这个搜索路径来指定编译器对头文件的搜索路径参数CFLAGS,如:
) I6 ?7 Q$ H6 b* I override CFLAGS += $(patsubst2 \$ Q2 o) r' ?& u7 ~- F
%,-I%,$(subst :, ,$(VPATH)))
! N) e B' n5 i0 ] 如果我们的“$(VPATH)”值是“src:../headers”,那么“$(patsubst* Z( w# @3 J+ g7 n
%,-I%,$(subst :, ,$(VPATH)))”将返回“-Isrc -I../headers”,这正是cc或gcc搜索头文件路径的参数。0 y& F. W# S1 d" O0 W$ X r; e
三、文件名操作函数3 w X+ b" Q% c( O
下面我们要介绍的函数主要是处理文件名的。每个函数的参数字符串都会被当做一个或是一系列的文件名来对待。3 I2 @0 S4 v/ t
$(wildcard )
- B) F/ M ]- O0 M: v. ^: p; x3 h名称:文件名展开函数——wildcard 。
+ f+ J+ C m. L Z- s! Q0 F 功能:功能是展开成一列所有符合由其参数描述的文件名,文件间以空格间隔。
( T9 t' l* L# z$ E. P& p 返回:函数返回展开后的文件名列表。! k E% b1 @7 G! K
# k9 y$ o5 w& i3 p2 C1 R示例:
; B5 A: [0 C. G* |0 S# h/ l ( e4 l. j f* J T8 J5 x
$(wildcard *.c)* D% \( m$ `2 ^8 x+ a3 m; [
1 s7 D/ w& w8 A a9 D$ W$ D
返回结果是一个所有以 '.c' 结尾的文件的列表。 $ t! u3 o! z+ Q) p% k$ R/ P
$(dir )
) r" b, n% {- M0 i) j; x/ j! P4 k 名称:取目录函数——dir。3 Y/ U; R+ D7 \ z9 {5 _ v( G
功能:从文件名序列中取出目录部分。目录部分是指最后一个反斜杠(“/”)之前的部分。如果没有反斜杠,那么返回“./”。
$ w, T. {$ d' V4 o9 _ 返回:返回文件名序列的目录部分。4 u7 H' t) _) m8 l
示例: $(dir src/foo.c hacks)返回值是“src/9 ?- {; W# E! o J- E/ A
./”。
# m6 N. ?# \1 E* [: `" w2 ?5 k3 S! v9 I$(notdir )
+ D- ~3 o3 H7 k3 R6 E C 名称:取文件函数——notdir。
. l G8 V: ?5 `5 v8 f: ? 功能:从文件名序列中取出非目录部分。非目录部分是指最后一个反斜杠(“/”)之后的部分。1 E! @6 |5 j: j1 {* h+ {) t
返回:返回文件名序列的非目录部分。1 s8 X' n" M5 S/ l% k- M6 w& B
示例: $(notdir src/foo.c hacks)返回值是“foo.c
' T# F1 x, J" X$ `" t9 P& `, x% ehacks”。
) ?4 ^) m% O$ ^ W p1 F% A4 Q& E
7 t8 P8 O, f/ w( Z H$(suffix )
& ?! T$ N, w+ v7 e 6 v0 q) c( ]/ E" W+ d
名称:取后缀函数——suffix。$ m9 L( ~; k$ [! ]& [9 O
功能:从文件名序列中取出各个文件名的后缀。
# z( j8 m+ v2 S8 Y+ T* c2 G8 a 返回:返回文件名序列的后缀序列,如果文件没有后缀,则返回空字串。
% n6 I J6 x$ z9 j 示例:$(suffix src/foo.c src-1.0/bar.c hacks)返回值是“.c- f) d# q" k7 p& F7 j, G" V
.c”。' J" P- J, D' b ^0 P; F
$(basename )1 O4 e" D- t' x+ \+ L, R
名称:取前缀函数——basename。 l* V8 `# G7 @6 A( V
功能:从文件名序列中取出各个文件名的前缀部分。, m& T9 p- }3 x w
返回:返回文件名序列的前缀序列,如果文件没有前缀,则返回空字串。: F; A! [6 S4 g. U& K+ r8 R
示例:$(basename src/foo.c src-1.0/bar.c hacks)返回值是“src/foo1 C8 m) R1 T) K9 R
src-1.0/bar hacks”。
' [, q, B7 d6 ]2 |2 ^# Z- T+ w; ?# o$(addsuffix
+ ?1 T" A, m- ^0 W,)
% J" U5 J5 z7 x/ a# Y 名称:加后缀函数——addsuffix。
t ^/ V! S3 o. W7 G0 F 功能:把后缀加到中的每个单词后面。+ \/ L' i+ y/ Q4 H% V
返回:返回加过后缀的文件名序列。% d1 _' C2 F+ @: ?/ Q1 ~: g
示例:$(addsuffix .c,foo bar)返回值是“foo.c
7 L. U Y( R! U+ Z- hbar.c”。: v7 w/ @4 r# B! j
$(addprefix7 U* g! ~$ y7 ?' } @
,)
" \- ?2 h0 L, _" E3 E, f/ n2 W$ e 名称:加前缀函数——addprefix。
$ `# a; h% d+ W( H3 L, X$ K D 功能:把前缀加到中的每个单词后面。( @0 E( u( N- C
返回:返回加过前缀的文件名序列。 Y: A, i' r0 N7 J" B- r6 z
示例:$(addprefix src/,foo bar)返回值是“src/foo
! M' _* u+ i# c/ X. Q, {src/bar”。9 G/ R+ Y# a; u/ j9 i5 M
$(join ,)
& O0 a! n6 }- m 名称:连接函数——join。
. D6 g m' b/ D 功能:把中的单词对应地加到的单词后面。如果的单词个数要比的多,那么,中的多出来的单词将保持原样。如果的单词个数要比多,那么,多出来的单词将被复制到中。0 M: F* T$ U' D6 p
返回:返回连接过后的字符串。4 y- V3 ^; Z6 B+ f" [4 r, ^
示例:$(join aaa bbb , 111 222 333)返回值是“aaa111
4 Y9 [& {; c9 R5 n- `0 i dbbb222 333”。2 H1 j1 W* H- \) F! k" _+ n
$ f9 p% f' ` u6 p& K四、foreach 函数/ A c- ]5 g; ?
8 `! {, x( _: z' R. }6 f* |& R+ K+ sforeach函数和别的函数非常的不一样。因为这个函数是用来做循环用的,Makefile中的foreach函数几乎是仿照于Unix标准Shell(/bin/sh)中的for语句,或是C-Shell(/bin/csh)中的foreach语句而构建的。它的语法是:# B" L3 q! q6 y$ Z7 R( ?
( r) t# z. k' G& n! N9 b
$(foreach
& L, Z& b' G+ B6 V2 C1 \,,)8 F, L3 U$ j3 q2 L9 B* o
/ A# S4 N2 Q. @! E. A5 M* v这个函数的意思是,把参数中的单词逐一取出放到参数所指定的变量中,然后再执行所包含的表达式。每一次会返回一个字符串,循环过程中,的所返回的每个字符串会以空格分隔,最后当整个循环结束时,所返回的每个字符串所组成的整个字符串(以空格分隔)将会是foreach函数的返回值。
. L: F- E- Q# Y5 j& C7 Z. H' P7 A: I7 I9 z y) H( ^
所以,最好是一个变量名,可以是一个表达式,而中一般会使用这个参数来依次枚举中的单词。举个例子:9 h5 a5 m$ y, j8 g. N
3 Z$ l, N6 x" M3 _& O& p3 u names := a b c d2 ]$ s% V' N/ S0 p
files := $(foreach n,$(names),$(n).o)
* R- W* w5 w+ F6 N( V' E7 K3 ~4 Y8 _' R! ]! l
上面的例子中,$(name)中的单词会被挨个取出,并存到变量“n”中,“$(n).o”每次根据“$(n)”计算出一个值,这些值以空格分隔,最后作为foreach函数的返回,所以,$(files)的值是“a.o b.o c.o d.o”。; l$ o$ I' u8 C' w3 }; i/ H( d/ m
3 L! S( z2 d) I2 ~0 I1 }注意,foreach中的参数是一个临时的局部变量,foreach函数执行完后,参数的变量将不在作用,其作用域只在foreach函数当中。
& D$ ^9 h0 S5 f* K: ^% E1 E1 |
( ]% d; R. Y" D3 d' _& d7 \% c# O1 p" M" j8 O
五、if 函数8 E; U" R% v1 i
S. c" }% g0 i- v) A# B5 d- l% Xif函数很像GNU的make所支持的条件语句——ifeq(参见前面所述的章节),if函数的语法是:
1 A0 P0 w0 m' b% u3 `
3 M& i8 `7 w h( v! |! v $(if ,)
: c) R2 Q1 d2 U% W, f; ^* @. _7 ^ o' [' c/ F R
或是
% L3 s! H s5 J6 M. ~. N' X0 G' \5 y/ k, t' J
$(if
' ^1 D5 u3 p2 Q& t& p,,)
6 u6 E% D( c# A, D) `, x
Z" Q; g' F) Y+ V1 Z可见,if函数可以包含“else”部分,或是不含。即if函数的参数可以是两个,也可以是三个。参数是if的表达式,如果其返回的为非空字符串,那么这个表达式就相当于返回真,于是,会被计算,否则会被计算。( \- Z+ u- O$ R# a* z$ R
9 L! D! H/ C+ F6 A8 x而if函数的返回值是,如果为真(非空字符串),那个会是整个函数的返回值,如果为假(空字符串),那么会是整个函数的返回值,此时如果没有被定义,那么,整个函数返回空字串。5 z7 ?) E1 m f; i4 l2 B3 n
0 p# B+ ~6 k3 l: R
所以,和只会有一个被计算。$ H9 f0 h) V$ W6 F, w% z8 ~. r
. s0 _1 w, s: ?0 e) y, b4 [% Y9 e; ^0 p" b: Q/ \" e
六、call函数5 y! [+ o+ v" D+ X7 Z( F
6 m5 [5 W4 e7 ]$ w& x# W
call函数是唯一一个可以用来创建新的参数化的函数。你可以写一个非常复杂的表达式,这个表达式中,你可以定义许多参数,然后你可以用call函数来向这个表达式传递参数。其语法是:/ t }5 N- m0 F
' H8 ?* F0 G' @% \( W% g $(call
$ ~1 E# v/ g8 D1 I) h,,,...)8 O/ s4 X% b+ ^3 H G
) y- U3 k: \& F4 O. O" |' R当make执行这个函数时,参数中的变量,如$(1),$(2),$(3)等,会被参数,,依次取代。而的返回值就是call函数的返回值。例如:
. N6 M2 V% I; l4 S reverse = $(1) $(2)0 G5 w( E! r8 w! m" j
foo = $(call reverse,a,b)' G& q7 E! f8 b9 a
那么,foo的值就是“a b”。当然,参数的次序是可以自定义的,不一定是顺序的,如:5 v. B6 \$ P1 F
# |& f6 T+ k9 [# X4 p
reverse =
2 m3 `1 G8 m D* V7 G, |* v0 Q$(2) $(1)* M- |3 r) J1 w2 Y: f- v
foo = $(call reverse,a,b)
9 m; e: f% E- l E! b此时的foo的值就是“b a”。0 C- Q4 {; e5 l6 I- r: L7 B$ U
! `+ \' [' E# b( q7 K
$ k3 R) r8 Y' A% c' X七、origin函数5 b& f( o/ [& E5 N) w/ O' Y
origin函数不像其它的函数,他并不操作变量的值,他只是告诉你你的这个变量是哪里来的?其语法是:6 c, L& r: Z8 s/ b. w. ~: ?
% c* g; Y3 S! A z; P+ ?
$(origin )
9 b5 b6 l! ]0 t! F. `. |
0 V! q8 s+ M$ [6 u, u注意,是变量的名字,不应该是引用。所以你最好不要在中使用“$”字符。Origin函数会以其返回值来告诉你这个变量的“出生情况”,下面,是origin函数的返回值:" {4 U; Y& _! Y
' x8 v z6 G1 g5 j8 ]
“undefined”/ O% k0 y" A) k+ ]8 L4 r
如果从来没有定义过,origin函数返回这个值“undefined”。
! S$ U! l3 x, }0 R s# B
/ d4 _* \ F: I+ M' Z9 g4 T( P“default”( i3 J% c9 |2 W0 B- i+ t: k9 W
如果是一个默认的定义,比如“CC”这个变量,这种变量我们将在后面讲述。
* K. p# E. v e8 @+ |2 T, v
: B6 [) v. M% q$ f6 u“environment”
6 Q7 ]. |* e# `( R, ] 如果是一个环境变量,并且当Makefile被执行时,“-e”参数没有被打开。, a) f: ~) Z* V
6 K$ n0 I, [# ?1 s3 t4 k
“file”& _% O1 A' x" k- T
如果这个变量被定义在Makefile中。
, X* w0 g5 Z: P7 F8 _$ r, P6 i+ L# I+ `* a5 s5 z5 v
“command
6 l2 Z+ z7 x ?% V( x, @line”# J* n6 T- R& W s9 Z& q
如果这个变量是被命令行定义的。
# ?( y. M3 C+ W
4 t- ~5 o2 f, g5 [) j1 A' @ T“override”
: S, L5 N! e$ B 如果是被override指示符重新定义的。, f3 ~$ Y P4 R3 L, S( n* h3 d
- m) D$ b2 v4 T9 m- Y; S8 B
“automatic”
7 X) F8 a+ P( f# \ 如果是一个命令运行中的自动化变量。关于自动化变量将在后面讲述。5 ~( X8 j. P' w0 @ O8 Q+ s
: q! ]0 T& h) D- U% k# |, x
这些信息对于我们编写Makefile是非常有用的,例如,假设我们有一个Makefile其包了一个定义文件Make.def,在Make.def中定义了一个变量“bletch”,而我们的环境中也有一个环境变量“bletch”,此时,我们想判断一下,如果变量来源于环境,那么我们就把之重定义了,如果来源于Make.def或是命令行等非环境的,那么我们就不重新定义它。于是,在我们的Makefile中,我们可以这样写:
" r; S- I8 ?3 a4 P/ }6 t' S( h! d2 i
ifdef bletch& l9 v2 T8 P# s B: ?) n5 P
ifeq "$(origin bletch)" i1 c* ?9 D0 e+ ~7 O
"environment"/ n0 V. \- @# k8 S+ ?
bletch = barf, gag, etc.
: l* C! ?( ?) C0 N endif
: h; f3 X7 v, T; R0 c endif5 L- x0 h1 g7 O# G0 u
/ |: m5 G* Q4 L0 g% E当然,你也许会说,使用override关键字不就可以重新定义环境中的变量了吗?为什么需要使用这样的步骤?是的,我们用override是可以达到这样的效果,可是override过于粗暴,它同时会把从命令行定义的变量也覆盖了,而我们只想重新定义环境传来的,而不想重新定义命令行传来的。
: d2 H! A& }% p7 ?1 n" V% K, Y7 i* C; K5 Z g
- p1 A( e% N3 {7 j" N* k2 g
八、shell函数
' h* R2 |. r+ g3 S
/ ]( H8 W/ t0 x. p5 r3 ~shell函数也不像其它的函数。顾名思义,它的参数应该就是操作系统Shell的命令。它和反引号“`”是相同的功能。这就是说,shell函数把执行操作系统命令后的输出作为函数返回。于是,我们可以用操作系统命令以及字符串处理命令awk,sed等等命令来生成一个变量,如:
( D# q. C' V M0 _* I: B# v: _: [
contents := $(shell cat foo)
6 f, p& X; S& T |6 ?' O+ Y9 r+ {1 F
. r8 Y7 J% d( h1 X7 h9 \& K files := $(shell echo *.c)
, m h0 Q$ `: w; M1 T0 \# b2 r" f4 V- [' J/ g( M) p! p/ D: I: D+ N( S1 G# B9 w
注意,这个函数会新生成一个Shell程序来执行命令,所以你要注意其运行性能,如果你的Makefile中有一些比较复杂的规则,并大量使用了这个函数,那么对于你的系统性能是有害的。特别是Makefile的隐晦的规则可能会让你的shell函数执行的次数比你想像的多得多。
0 c; w/ |+ m0 F* ` . t. K: M9 f$ j! f
|
|