版主
主题
回帖0
积分10609
阅读权限200
注册时间2008-11-22
最后登录1970-1-1
在线时间 小时
|
在Makefile中可以使用函数来处理变量,从而让我们的命令或是规则更为的灵活和具有智能。make所支持的函数也不算很多,不过已经足够我们的操作了。函数调用后,函数的返回值可以当做变量来使用。/ \8 j! U$ Z% H2 g& Q
一、函数的调用语法; }. r3 M- T5 x: _1 k9 c7 M
函数调用,很像变量的使用,也是以“$”来标识的,其语法如下:) U. _. s( x: X5 k+ [$ T
$($ Q" o: `* V; D% C. ]7 ~
)
+ O, h% z5 a2 y4 {3 m |或是" N3 e( ~3 u& S! H/ G4 q+ H0 @
${
) o) u% R% \' ]: m7 U}8 {1 j7 d7 @' z- I: K
这里,就是函数名,make支持的函数不多。是函数的参数,参数间以逗号“,”分隔,而函数名和参数之间以“空格”分隔。函数调用以“$”开头,以圆括号或花括号把函数名和参数括起。感觉很像一个变量,是不是?函数中的参数可以使用变量,为了风格的统一,函数和变量的括号最好一样,如使用“$(subst8 C; H ^" R) \; d
a,b,$(x))”这样的形式,而不是“$(subst a,b,${x})”的形式。因为统一会更清楚,也会减少一些不必要的麻烦。
% y1 K9 ~8 D* q( U: @1 j9 a还是来看一个示例:3 x( L! V# o# S
comma:= ,
( g9 o( R. O/ @. \* M% ?* [( ~ empty:=3 R: \! D+ ^; s8 Q$ D, C
space:= $(empty) $(empty), B) j% H7 L$ C( S! ~/ P
foo:= a b c
0 U5 h/ c% f9 ~/ N0 { bar:= $(subst $(space),$(comma),$(foo))
$ ~5 r9 y% Q! }/ C6 g, X在这个示例中,$(comma)的值是一个逗号。$(space)使用了$(empty)定义了一个空格,$(foo)的值是“a b c”,$(bar)的定义用,调用了函数“subst”,这是一个替换函数,这个函数有三个参数,第一个参数是被替换字串,第二个参数是替换字串,第三个参数是替换操作作用的字串。这个函数也就是把$(foo)中的空格替换成逗号,所以$(bar)的值是“a,b,c”。
& r s: b8 M5 a- f l' G2 d4 \二、字符串处理函数: N7 d4 b) g# b3 x1 r
$(subst
9 M% G+ }* T, X, X,,) + i) p- b9 w! y/ ]
名称:字符串替换函数——subst。
# x$ ^8 O+ b2 F8 M4 T1 o 功能:把字串中的字符串替换成。
" |- n: U( O* t5 u0 I; M 返回:函数返回被替换过后的字符串。1 I2 E: S4 z8 o8 o4 b
示例:
9 d7 }; Z% A3 v$ H" {" X# ^ , n6 ^* P! \ V; s6 W, h
$(subst ee,EE,feet on the street),6 S% R" K# T0 e7 i
- W6 ?5 K( X c# j 把“feet on the street”中的“ee”替换成“EE”,返回结果是“fEEt/ F, B% q9 j! B% f* y# d; c
on the strEEt”。
3 z9 G# R0 o$ x$(patsubst ,,) : @) \, q C y, N8 {4 ]
名称:模式字符串替换函数——patsubst。
$ a. I5 C3 ^) c& ?' F+ Y* L2 ^$ n" p 功能:查找中的单词(单词以“空格”、“Tab”或“回车”“换行”分隔)是否符合模式,如果匹配的话,则以替换。这里,可以包括通配符“%”,表示任意长度的字串。如果中也包含“%”,那么,中的这个“%”将是中的那个“%”所代表的字串。(可以用“\”来转义,以“\%”来表示真实含义的“%”字符)
* N/ n9 p" t! |. k7 f7 P6 N4 m' e 返回:函数返回被替换过后的字符串。( m2 q- K( n% e# S
示例:
, e% E7 B( s$ o9 v
4 Y/ {# ~% ?; g [$(patsubst %.c,%.o,x.c.c bar.c)$ i0 T3 i! h/ ~1 J6 W
把字串“x.c.c
+ H3 T+ h3 k8 P# S' Kbar.c”符合模式[%.c]的单词替换成[%.o],返回结果是“x.c.o# F* F. w8 _5 H% n0 x
bar.o”% d/ ?6 v+ q: M% y1 g' W1 j2 n
备注:
+ J i% n' Z' }/ x 这和我们前面“变量章节”说过的相关知识有点相似。如:/ }& T& N$ Y+ z! @/ j) P
“$(var:=)”
6 [# F: T/ K3 k 相当于
1 Y6 A4 U7 \' h$ x5 I, V+ m5 D “$(patsubst' `/ Y" Q/ r: C: t0 P5 [+ k& c
,,$(var))”,0 {& ?( x1 D! G& I* i% D
而“$(var:. d+ L. Y* t' R& |6 n" T0 F7 J
=)”9 p. G) j2 p! N9 s9 R2 S" W) \7 c
则相当于4 C; k$ o# f: z$ D/ `. X4 x
“$(patsubst; J% a4 c8 j. A- R2 p8 ~
%,%,$(var))”。
1 E4 O; b8 c% ]5 x7 B- U1 V- X 例如有:objects = foo.o& P' T; Q' F7 `+ @" d/ W2 A, U: ~2 @
bar.o baz.o,
* ~6 m# V7 H+ j2 K/ N 那么,“$(objects:.o=.c)”和“$(patsubst: f' ^' ?5 T5 I5 U; s7 k9 c
%.o,%.c,$(objects))”是一样的。) Q! K5 T6 [8 _* d
$(strip )4 y$ C! p+ M+ n/ K
名称:去空格函数——strip。
w# F: u3 ?# T- ?+ Z 功能:去掉字串中开头和结尾的空字符。
# s) Y' D: f7 F9 ] 返回:返回被去掉空格的字符串值。
* q" i7 q7 @: K, Z" v6 ^ _ 示例:' t( l) z; U* M5 ^, _4 |
5 N6 `3 s* t4 ?7 s4 a3 S $(strip a b c )
% ?1 j7 E8 h/ h 把字串“a b+ }5 q2 e1 U" _. q; q: @( I
c ”去到开头和结尾的空格,结果是“a b c”。% q3 i* x% o: D! |+ |* |) d0 _
$(findstring ,)
- [6 O( y4 ~% b5 h# ^* e* i 名称:查找字符串函数——findstring。; ]( g& A T! m8 O- C0 [9 Z7 H' p
功能:在字串中查找字串。" B8 ]' r: L& J3 Y: D7 V2 H8 a
返回:如果找到,那么返回,否则返回空字符串。" y3 `( p; V& D! p. e0 I
示例:
9 f- [8 I, ?1 w- K E4 R7 N $ X: m( T8 g& w) G& g$ ^$ ~
$(findstring a,a b c): o. P9 a+ v: z. t3 l+ M H
$(findstring a,b c)! Y3 S8 y- E2 b7 ^
第一个函数返回“a”字符串,第二个返回“”字符串(空字符串)
- d4 H1 k0 T& [& J7 y/ n$(filter
# @/ ]0 j; k3 {, F) e& Z,)
# e) @3 ] g+ s$ g 名称:过滤函数——filter。
- [. V( W W2 P 功能:以模式过滤字符串中的单词,保留符合模式的单词。可以有多个模式。3 y, v5 g$ x+ `, m8 ~. D8 P; E
返回:返回符合模式的字串。5 j9 k3 n% m( }" i
示例:
s- o9 `; Y y: a sources
; c' m& v6 `9 I* O+ |) C:= foo.c bar.c baz.s ugh.h
% }$ y6 |5 ~0 c. g foo: $(sources)) k% j1 u( L/ P9 R
! J2 X% M" ~, k. z( a6 h! D: V
cc $(filter %.c %.s,$(sources)) -o foo
( ]: Q3 |. d' _ % O7 l5 C/ } N
$(filter %.c %.s,$(sources))返回的值是“foo.c bar.c baz.s”。; d( { y$ x* U) X- W U8 u
$(filter-out
4 J m) ] Q5 Y% q% [,)! ?: y s9 n0 @$ w3 Y
名称:反过滤函数——filter-out。
G* A4 d9 J$ L/ [: T" [+ B$ X! c 功能:以模式过滤字符串中的单词,去除符合模式的单词。可以有多个模式。2 w& q% l( f5 p2 @; y6 {
返回:返回不符合模式的字串。
, k4 C, l' \! Q X 示例:
! x5 B5 x6 D: {+ `: @6 B* v' M# v9 N 3 H7 @' T1 b7 w3 T( q3 M$ d
objects=main1.o foo.o main2.o bar.o% T1 j [2 _; b& ]" ]1 R: [
mains=main1.o main2.o
$ T2 |/ r/ g* f
6 @$ F4 G. X( O) l5 @) U! |- ~+ s6 } $(filter-out $(mains),$(objects)) 返回值是“foo.o4 e. a* j8 \* Q5 [1 g
bar.o”。
4 k. n6 b) n% V8 o0 E& | % E; }/ ^! n) [; F' `$ h2 h
$(sort )5 G! e7 _ w9 v. ~
名称:排序函数——sort。功能:给字符串中的单词排序(升序)。返回:返回排序后的字符串。示例:$(sort foo bar lose)返回“bar foo lose”。备注:sort函数会去掉中相同的单词。: j0 w& O6 P& {- e
$(word ,)
! o/ r6 Y) g9 c) M" A8 X4 C Y名称:取单词函数——word。功能:取字符串中第个单词。(从一开始)返回:返回字符串中第个单词。如果比中的单词数要大,那么返回空字符串。示例:$(word 2, foo bar baz)返回值是“bar”。
- R/ b: u$ Z3 f+ r) O$(wordlist& c" ^, K) l: f; S5 E% Y& o3 Y
,,) " \( v( c0 D" _& j6 k, \, f
名称:取单词串函数——wordlist。) \; _( d# N* {4 E! O+ _
功能:从字符串中取从开始到的单词串。和是一个数字。: V, e* m2 t& c6 W' v5 u
返回:返回字符串中从到的单词字串。如果比中的单词数要大,那么返回空字符串。如果大于的单词数,那么返回从开始,到结束的单词串。
- {7 V, v* B% z( H4 m2 M 示例: $(wordlist 2, 3, foo bar baz)返回值是“bar1 k6 ~1 j" l/ j# O7 g
baz”。5 _1 Z! \; Z' y' z! j2 t
$(words )) G( o- D4 [2 b# K: z. f
名称:单词个数统计函数——words。( O. ]5 g; z- m. T; n
功能:统计中字符串中的单词个数。, Y$ Y* ^. W4 i+ I# y& R
返回:返回中的单词数。+ I' l/ f. u+ }! z7 P) B
示例:$(words, foo bar baz)返回值是“3”。: v; o! w5 x8 p/ Z( z" s
备注:如果我们要取中最后的一个单词,我们可以这样:$(word8 B; x0 ~# w( |5 T: o5 ?' i
$(words ),)。
2 |5 m9 q, k6 E$(firstword )
' W% b1 A- k% Z- I% }3 q 名称:首单词函数——firstword。
5 l+ J$ r8 i9 ]8 |5 J; h+ d 功能:取字符串中的第一个单词。
4 n' N' |) z0 ^ 返回:返回字符串的第一个单词。
. e. T+ |& j: p, M' [6 A 示例:$(firstword foo bar)返回值是“foo”。
. p6 q% D. k; C: N& d$ d 备注:这个函数可以用word函数来实现:$(word
3 [6 Q; l6 C! C$ G i1,)。
4 I5 O: }8 I2 _( A# p( J以上,是所有的字符串操作函数,如果搭配混合使用,可以完成比较复杂的功能。这里,举一个现实中应用的例子。我们知道,make使用“VPATH”变量来指定“依赖文件”的搜索路径。于是,我们可以利用这个搜索路径来指定编译器对头文件的搜索路径参数CFLAGS,如:
/ i2 T( E. w" S, j, N0 A" y override CFLAGS += $(patsubst5 @% t* R2 Y% E- S/ Y
%,-I%,$(subst :, ,$(VPATH)))5 ?$ R- ] \' g5 V% @* q; S% H0 p
如果我们的“$(VPATH)”值是“src:../headers”,那么“$(patsubst
, R1 Y: H% [0 N) r%,-I%,$(subst :, ,$(VPATH)))”将返回“-Isrc -I../headers”,这正是cc或gcc搜索头文件路径的参数。; ~2 }, ?* ~7 w8 d/ X
三、文件名操作函数9 }3 ^$ }; J. l! F4 f. i$ j+ B& t* y
下面我们要介绍的函数主要是处理文件名的。每个函数的参数字符串都会被当做一个或是一系列的文件名来对待。
7 R- _; f, d4 I4 }! `$(wildcard )9 k, Y) k8 P. s5 Y5 ~$ w7 }. _ H
名称:文件名展开函数——wildcard 。6 B3 E. G% E3 g3 X
功能:功能是展开成一列所有符合由其参数描述的文件名,文件间以空格间隔。+ c" O" w& I Y3 S) r' c. h4 M. R
返回:函数返回展开后的文件名列表。7 `$ x3 c( E9 T9 p, p3 O5 g
3 F: O, u0 d$ w) B2 I9 |' N3 w
示例:
+ q! O* a6 h! J+ q& |' S
# F; B% ~0 w6 a4 z- b $(wildcard *.c)
8 m% W# o, { e( T , H# Z2 a4 ]& j5 z1 \& O; Q1 I/ T
返回结果是一个所有以 '.c' 结尾的文件的列表。
% w+ o& ^" r! _% A: [; @$(dir ) 6 U, u- }- d- N0 P) D- {
名称:取目录函数——dir。; Z* u0 O% i+ r2 E2 O5 S
功能:从文件名序列中取出目录部分。目录部分是指最后一个反斜杠(“/”)之前的部分。如果没有反斜杠,那么返回“./”。; u( t% w) P3 n: e' D
返回:返回文件名序列的目录部分。
4 J/ w4 }; w* P( d3 _( t* ` 示例: $(dir src/foo.c hacks)返回值是“src/
5 S3 j! e, c, x! G6 @3 P./”。
/ t" R9 Z4 M* Y+ l7 q+ h/ ?$(notdir ) ' `9 d1 m3 w% W! I J
名称:取文件函数——notdir。
- y, k1 ^4 c( }7 n9 e+ j 功能:从文件名序列中取出非目录部分。非目录部分是指最后一个反斜杠(“/”)之后的部分。 Z0 A3 |' C0 Q( G$ A
返回:返回文件名序列的非目录部分。& y2 ?8 S. I0 X% o9 o$ ^
示例: $(notdir src/foo.c hacks)返回值是“foo.c
0 S/ F6 D& M* y) ^) s7 Ohacks”。
: A. G$ o% k9 G: ?# l
: z/ F) m, U' f9 k$(suffix )
v$ E+ Q) h- F- m 6 A& d7 {. _8 P9 q. ~3 j" ]* K
名称:取后缀函数——suffix。5 F! j0 i3 l% W' W* ~# i& z1 Y/ a
功能:从文件名序列中取出各个文件名的后缀。
! Q) H7 B/ I- ]* }( M 返回:返回文件名序列的后缀序列,如果文件没有后缀,则返回空字串。
7 E3 R1 r4 W8 y" ?- @. m7 T 示例:$(suffix src/foo.c src-1.0/bar.c hacks)返回值是“.c
/ N( X7 ^4 D. N, I! W/ s6 @' [.c”。
% s/ d& L8 R, W- `4 g$(basename )
: F7 i; q0 }' W7 L# M* I 名称:取前缀函数——basename。) T' T, O g' _ T1 b/ j
功能:从文件名序列中取出各个文件名的前缀部分。: @' `6 s+ |! q2 [8 z
返回:返回文件名序列的前缀序列,如果文件没有前缀,则返回空字串。
6 Y [; {! {/ M8 H- f# E5 z 示例:$(basename src/foo.c src-1.0/bar.c hacks)返回值是“src/foo9 x. J% f2 r" C, _( `
src-1.0/bar hacks”。
' p. h) G! d" B$ T8 `9 b$(addsuffix( k4 W% B4 Y' y; O2 G7 _. \+ T2 s6 z5 W
,)
+ v4 ~, ]9 ^2 p* s6 g1 U0 z 名称:加后缀函数——addsuffix。9 A4 u1 i8 d2 M' J- j" @
功能:把后缀加到中的每个单词后面。, \' B V, W1 a/ y q& N: S/ }
返回:返回加过后缀的文件名序列。6 {: q2 C* b: N. r
示例:$(addsuffix .c,foo bar)返回值是“foo.c* ~. A( Z! ~6 q
bar.c”。: _( s8 }9 R+ \' I% Z$ w* {
$(addprefix
$ ^0 X& e7 u$ S- p: r- }! \,) . g/ m" ]8 ~8 P0 _; o- {
名称:加前缀函数——addprefix。& j$ O( i+ r( X. ^/ T# p x
功能:把前缀加到中的每个单词后面。8 W& `7 T' [6 m/ L
返回:返回加过前缀的文件名序列。
1 ]) e3 o3 A' Q( N 示例:$(addprefix src/,foo bar)返回值是“src/foo+ T" r, g* m- x7 T: \( ~/ i7 ^
src/bar”。
3 [- Y6 I+ `6 Y: ?( O8 l$(join ,)
% J6 F D' ~/ y/ F8 J& {- {1 [; l 名称:连接函数——join。4 p9 ?4 w' O0 I$ v* V
功能:把中的单词对应地加到的单词后面。如果的单词个数要比的多,那么,中的多出来的单词将保持原样。如果的单词个数要比多,那么,多出来的单词将被复制到中。/ t) s0 \1 L9 \- f9 f6 r( w
返回:返回连接过后的字符串。
0 W |( k0 I. N) @% D8 o 示例:$(join aaa bbb , 111 222 333)返回值是“aaa111
1 M+ }4 D/ k/ E2 I2 }bbb222 333”。
8 B2 N- [) F8 [8 L6 K1 F
3 s& s1 \5 ]/ @# I5 A% c9 x四、foreach 函数4 e+ f* Z& F A1 P E9 n! @
6 n$ n; i' [3 B* U$ J) M$ z& ?! ~8 y6 z
foreach函数和别的函数非常的不一样。因为这个函数是用来做循环用的,Makefile中的foreach函数几乎是仿照于Unix标准Shell(/bin/sh)中的for语句,或是C-Shell(/bin/csh)中的foreach语句而构建的。它的语法是:+ r7 S( O- L' t( H2 _! h8 K1 P
& M* n& s/ }7 k1 d $(foreach( h9 o# i. n' ]: Q( d
,,)
' C+ r1 x6 p) _! e8 W% M: N
4 V# v: i' I, ~ t5 q& [7 i这个函数的意思是,把参数中的单词逐一取出放到参数所指定的变量中,然后再执行所包含的表达式。每一次会返回一个字符串,循环过程中,的所返回的每个字符串会以空格分隔,最后当整个循环结束时,所返回的每个字符串所组成的整个字符串(以空格分隔)将会是foreach函数的返回值。
' ^# }$ v, U' H" d3 ] l. m* S2 }' F
所以,最好是一个变量名,可以是一个表达式,而中一般会使用这个参数来依次枚举中的单词。举个例子:
- s- t0 I4 }1 L6 q6 f, c
1 u$ N9 \9 ]6 n7 l names := a b c d; ~% s2 @. W. C( ]% h0 s3 z7 _/ A0 ^
files := $(foreach n,$(names),$(n).o)- O/ A! _! E4 C+ Y0 }) k: i! f
! u3 y4 `7 T0 @
上面的例子中,$(name)中的单词会被挨个取出,并存到变量“n”中,“$(n).o”每次根据“$(n)”计算出一个值,这些值以空格分隔,最后作为foreach函数的返回,所以,$(files)的值是“a.o b.o c.o d.o”。
! n, B2 m+ S3 V( j; |$ F
X' v. S! T5 R: S2 s A注意,foreach中的参数是一个临时的局部变量,foreach函数执行完后,参数的变量将不在作用,其作用域只在foreach函数当中。( R$ B1 Z, d' B
u$ k0 E9 u* P: c9 G8 @; Z6 r
; l/ F6 C0 x5 K4 p% p" \' c) M! P五、if 函数
" p1 g, Y: y2 s! Q, I' u; w0 n$ y: S' v5 t1 d
if函数很像GNU的make所支持的条件语句——ifeq(参见前面所述的章节),if函数的语法是:
$ y/ Z1 U( A+ Q
3 \, }: ]3 l! ]# y7 v- T $(if ,)
) e1 _5 G6 A/ K& }4 }
5 a8 l. E& T1 r3 F% U" j5 U2 `或是6 W/ i8 Z- }+ N* E
1 X! Q+ D2 x9 K; n/ B $(if
2 }; O7 o \# [4 b3 [,,)6 k& s, x! T8 E" k
8 ^0 B" D9 Y, U2 V2 Q7 I# u* \
可见,if函数可以包含“else”部分,或是不含。即if函数的参数可以是两个,也可以是三个。参数是if的表达式,如果其返回的为非空字符串,那么这个表达式就相当于返回真,于是,会被计算,否则会被计算。
: c; D* L- F* A0 c( x' W+ g
( A! n2 T" i( V7 u) t而if函数的返回值是,如果为真(非空字符串),那个会是整个函数的返回值,如果为假(空字符串),那么会是整个函数的返回值,此时如果没有被定义,那么,整个函数返回空字串。
0 r6 `3 H2 ?4 b6 Y
; T4 h% o$ G7 m3 E5 _所以,和只会有一个被计算。
: D, U4 c/ w) B# q
! a) y) U! Z, i8 }8 V+ N# [. I( p- o) s0 l% p
六、call函数
/ A$ X2 s6 a! R5 @/ l5 W
9 x6 Y2 d$ `# t# y- ~call函数是唯一一个可以用来创建新的参数化的函数。你可以写一个非常复杂的表达式,这个表达式中,你可以定义许多参数,然后你可以用call函数来向这个表达式传递参数。其语法是:3 K) w1 G3 e5 n) c9 @& U% N* N) N
- h# G! I3 Y! l5 \. n; u$ j $(call
; ?0 d7 p& d' b( y+ |5 l! D,,,...)" }+ d" h9 u" w5 w6 B2 H- T. j8 v
- r5 q7 M3 e/ V9 X3 C7 S当make执行这个函数时,参数中的变量,如$(1),$(2),$(3)等,会被参数,,依次取代。而的返回值就是call函数的返回值。例如:& w3 U6 ?$ r# E8 v: h$ W
reverse = $(1) $(2)
8 y5 c h" q, C5 G foo = $(call reverse,a,b)9 d4 E: Z2 M; o$ g' T5 Q
那么,foo的值就是“a b”。当然,参数的次序是可以自定义的,不一定是顺序的,如:3 `& L$ o. C" S5 \- r. y) U
1 `! ?: L. f) r( R* [ reverse =
0 D: _7 A& m, J) h# i) l$(2) $(1)
, b9 h# x* l0 M( `( ] foo = $(call reverse,a,b)
3 l" S x/ q# M9 p此时的foo的值就是“b a”。; B. V/ ~( H: J3 U9 ]+ u
+ \9 n- b( L3 j: d3 i
' y% V( `" h9 k! r6 _' f七、origin函数- x& j/ O+ r. W
origin函数不像其它的函数,他并不操作变量的值,他只是告诉你你的这个变量是哪里来的?其语法是:/ l. R, U3 Z5 U' \
& H/ c. ^# `0 V v/ V2 i
$(origin )
& S: l0 b+ H0 M- i+ ^
5 ]( s; ?6 N* ?% B9 I" b" e. v注意,是变量的名字,不应该是引用。所以你最好不要在中使用“$”字符。Origin函数会以其返回值来告诉你这个变量的“出生情况”,下面,是origin函数的返回值:
! a* R: l9 L8 C' C
6 a9 e- a8 P+ r1 V% v“undefined”
+ i- V2 h0 N. I% a6 I* g0 X; c 如果从来没有定义过,origin函数返回这个值“undefined”。, C' H. N0 m: t
" s' G+ W7 u$ r( A+ m
“default”
& j: W; u e3 i 如果是一个默认的定义,比如“CC”这个变量,这种变量我们将在后面讲述。
2 w8 Y8 X% M3 R8 n, N' b! R; \) _$ s/ H8 h7 j
“environment”- l5 X" z3 X% x& {3 Y
如果是一个环境变量,并且当Makefile被执行时,“-e”参数没有被打开。- V' C, F" t+ j$ [; M* _ u
' Q) W& B; D* a5 I1 K
“file”
& t/ F0 w. @- u* c6 Z0 ~" @6 c 如果这个变量被定义在Makefile中。
2 ?! ?5 w3 ` K4 R* p2 ]+ E0 h+ @0 U2 h$ T
“command
& k$ K) I6 |- S yline”
8 O9 T, {6 k+ N! M: g1 m& u 如果这个变量是被命令行定义的。# _" W/ H, L( i) L* U( t$ s) C2 k$ q
, J. F3 x, G+ |“override”, ^7 S+ I# B) H: M2 w; a
如果是被override指示符重新定义的。) c/ A" @% R: z
" @* d% o# g6 P. Q
“automatic”3 n+ M+ w: p* A" X- s1 _
如果是一个命令运行中的自动化变量。关于自动化变量将在后面讲述。
4 _ S0 Q8 z! r2 b! d( ]& o7 {! a: ]. `* [. W, j6 _
这些信息对于我们编写Makefile是非常有用的,例如,假设我们有一个Makefile其包了一个定义文件Make.def,在Make.def中定义了一个变量“bletch”,而我们的环境中也有一个环境变量“bletch”,此时,我们想判断一下,如果变量来源于环境,那么我们就把之重定义了,如果来源于Make.def或是命令行等非环境的,那么我们就不重新定义它。于是,在我们的Makefile中,我们可以这样写:: K4 e) k+ ^/ H6 k7 `& K! f
0 ?, C @! L V' E ifdef bletch
7 ^* u6 c2 v/ v8 H3 I2 { ifeq "$(origin bletch)"
/ Z& {3 @" |' c" |3 |# Q"environment"( Y- r1 ]- ^% U( C; }7 a
bletch = barf, gag, etc.4 j+ s' T/ E" C9 |6 O
endif
8 g6 e' n8 [$ O4 v% j$ h( i endif# G8 i' s! L* T1 U( O! i9 \
( O$ E- W* B* R' J' H$ a" L7 ?
当然,你也许会说,使用override关键字不就可以重新定义环境中的变量了吗?为什么需要使用这样的步骤?是的,我们用override是可以达到这样的效果,可是override过于粗暴,它同时会把从命令行定义的变量也覆盖了,而我们只想重新定义环境传来的,而不想重新定义命令行传来的。* x9 ^5 y8 }) w& l9 T2 W
1 s9 b7 a' u9 k; m" E5 X/ ]
* V1 \+ E7 a; s0 d
八、shell函数8 d' { ]/ ]- V; T
2 g8 h" m* h9 v* T. J, |
shell函数也不像其它的函数。顾名思义,它的参数应该就是操作系统Shell的命令。它和反引号“`”是相同的功能。这就是说,shell函数把执行操作系统命令后的输出作为函数返回。于是,我们可以用操作系统命令以及字符串处理命令awk,sed等等命令来生成一个变量,如:
6 T& E$ d; L( u# R& V1 j$ x3 n- }4 q# B6 E3 [. V% j9 x
contents := $(shell cat foo)
& c5 t {/ ?- N
) J y4 T( K1 g8 N; A8 B2 R/ Q! g files := $(shell echo *.c)
4 c0 K: V1 ]; v2 N8 F7 J5 |& w% D
# R) i0 p# |6 |. W" O: C; s注意,这个函数会新生成一个Shell程序来执行命令,所以你要注意其运行性能,如果你的Makefile中有一些比较复杂的规则,并大量使用了这个函数,那么对于你的系统性能是有害的。特别是Makefile的隐晦的规则可能会让你的shell函数执行的次数比你想像的多得多。
6 l/ Y0 u/ j: H3 ~& E7 F
+ F' t3 v0 L7 E5 C) U |
|