版主
主题
帖子
积分10609
阅读权限200
注册时间2008-11-22
最后登录1970-1-1
在线时间 小时
|
在Makefile中可以使用函数来处理变量,从而让我们的命令或是规则更为的灵活和具有智能。make所支持的函数也不算很多,不过已经足够我们的操作了。函数调用后,函数的返回值可以当做变量来使用。
6 i& j, T! s1 Q [# _0 {1 L一、函数的调用语法6 G T3 e, p ^+ m8 i
函数调用,很像变量的使用,也是以“$”来标识的,其语法如下:0 }& j; k. V9 j0 B
$(( N4 S$ H7 ^9 w7 n4 z/ q% p- t. ?
)/ r3 b9 A! n" \# i2 q
或是% {* s$ f: |. n$ J0 ^/ e
${
7 x( G: w0 s' B+ [2 t) u$ O}* j- ~! [/ ^0 h; P+ A8 W! w
这里,就是函数名,make支持的函数不多。是函数的参数,参数间以逗号“,”分隔,而函数名和参数之间以“空格”分隔。函数调用以“$”开头,以圆括号或花括号把函数名和参数括起。感觉很像一个变量,是不是?函数中的参数可以使用变量,为了风格的统一,函数和变量的括号最好一样,如使用“$(subst
$ x5 |# q5 r2 @a,b,$(x))”这样的形式,而不是“$(subst a,b,${x})”的形式。因为统一会更清楚,也会减少一些不必要的麻烦。
7 [" U& c/ U+ J5 h4 R% ^还是来看一个示例:3 J, o* h5 T+ z% D
comma:= ,3 x% {& w" \5 t8 ?7 V
empty:=
5 s8 w. G' y* `3 j7 j A- t space:= $(empty) $(empty); O/ r' p5 N' ?
foo:= a b c
5 r2 _' Z9 y% i* c# X* a$ L bar:= $(subst $(space),$(comma),$(foo))
* F( u5 R* W8 x+ H0 L& O在这个示例中,$(comma)的值是一个逗号。$(space)使用了$(empty)定义了一个空格,$(foo)的值是“a b c”,$(bar)的定义用,调用了函数“subst”,这是一个替换函数,这个函数有三个参数,第一个参数是被替换字串,第二个参数是替换字串,第三个参数是替换操作作用的字串。这个函数也就是把$(foo)中的空格替换成逗号,所以$(bar)的值是“a,b,c”。 N; ^6 ~6 `( z7 @
二、字符串处理函数
/ j9 D, b9 [% N4 F6 l9 _$(subst1 `. \0 h. F# ^" Z9 y9 Y
,,) 6 z2 n7 R- O e( q
名称:字符串替换函数——subst。; t. W g; a2 z. |" X5 z: G
功能:把字串中的字符串替换成。
& ^/ i: y. P+ S2 ~8 |! ^/ D 返回:函数返回被替换过后的字符串。) `; l/ H4 e' A9 \5 x( V
示例:
6 L- P( q8 h4 N$ v9 N $ Q; f" [5 f( i9 T. A! b
$(subst ee,EE,feet on the street),
% m/ A+ D5 M6 ~# \ 5 I4 |+ C) L' z$ b0 V3 t
把“feet on the street”中的“ee”替换成“EE”,返回结果是“fEEt
2 I8 t! ^* |) Z+ o' Mon the strEEt”。
9 B' ~/ ~9 S' m# i$(patsubst ,,)
7 @( I w2 s0 T7 C4 y; m 名称:模式字符串替换函数——patsubst。! Y1 N/ @2 q$ e$ \, f+ n" P7 E
功能:查找中的单词(单词以“空格”、“Tab”或“回车”“换行”分隔)是否符合模式,如果匹配的话,则以替换。这里,可以包括通配符“%”,表示任意长度的字串。如果中也包含“%”,那么,中的这个“%”将是中的那个“%”所代表的字串。(可以用“\”来转义,以“\%”来表示真实含义的“%”字符)
5 @" J3 U9 I, @$ w, C) b 返回:函数返回被替换过后的字符串。% f! @0 P4 S* p0 J# l4 I
示例:2 g0 I0 q: }8 l
: i! p: F; x& i
$(patsubst %.c,%.o,x.c.c bar.c)
2 a' `2 I6 ]+ e: { 把字串“x.c.c$ d6 U1 R9 H! r" |; L
bar.c”符合模式[%.c]的单词替换成[%.o],返回结果是“x.c.o6 z) q& F( w! c5 b% T2 {2 p
bar.o”
/ Q( P! w. l4 K( c1 j; Y# b0 k# N7 g6 r 备注:+ }/ j5 j7 H; I+ ~: [* K
这和我们前面“变量章节”说过的相关知识有点相似。如:/ q/ p. G# h% ]3 z
“$(var:=)”* D. @/ c8 f; G, B( P" k/ |4 ]
相当于
& }' t: r( g: A& I “$(patsubst
7 p* y8 C2 B$ M+ d! p,,$(var))”," b+ w' y0 J4 ~1 N
而“$(var:
0 e3 F3 K0 X! x$ N/ ^=)”
# \+ i0 Y ?" } 则相当于. L9 b" A! [* o. M# g
“$(patsubst
5 }' V$ j3 V% P) @%,%,$(var))”。) G" Q7 B$ O8 L5 F6 m2 q
例如有:objects = foo.o
' r8 t* y2 W$ B0 b- {9 }bar.o baz.o,6 c$ v# V7 u" [. b+ H2 d7 g
那么,“$(objects:.o=.c)”和“$(patsubst
- T% h0 K! _# a2 U%.o,%.c,$(objects))”是一样的。( f2 B7 z. O; b ^; ]( q
$(strip )
$ t* r. h2 b2 ^+ U Q 名称:去空格函数——strip。6 c9 c. [+ }/ D6 R2 U/ |9 w
功能:去掉字串中开头和结尾的空字符。
+ {! B; ^6 W* g. i/ [ 返回:返回被去掉空格的字符串值。
3 O& }" P( Z [- R2 A } 示例:
7 G) G4 k% L- z
, R2 j$ V2 ~2 z6 } $(strip a b c )
& J2 P* J- F. ] 把字串“a b
/ `) _& h! w: O+ M# R% wc ”去到开头和结尾的空格,结果是“a b c”。
- }! k8 Z1 g! }0 _/ d1 U, ^% ^$(findstring ,)
4 u. g |, F0 y$ Y 名称:查找字符串函数——findstring。
: k( o: S# M9 | s 功能:在字串中查找字串。/ [( A1 ~# Y" C. X( ?' v
返回:如果找到,那么返回,否则返回空字符串。
x/ n; u# O9 ?, b! A 示例:0 \1 j# O7 V% B% M& |! o$ N6 `# y
3 w& s: P8 v5 r% {: S0 }) C$(findstring a,a b c)
6 D8 G8 _3 F' X: c6 C: z# ] $(findstring a,b c)
! P) L$ q s; b& ?7 `2 }/ E 第一个函数返回“a”字符串,第二个返回“”字符串(空字符串)6 q+ P9 Y$ H9 M! m
$(filter& |3 E8 @" @2 l% I- ~( o V, e
,)
7 [ r; X8 O9 z8 d2 U9 W" c 名称:过滤函数——filter。9 x. n6 G( a" ]
功能:以模式过滤字符串中的单词,保留符合模式的单词。可以有多个模式。 F: O- T9 g( F M
返回:返回符合模式的字串。* y& {3 A+ e+ N& S* {
示例:3 q |7 x* \% u. @ O/ L8 q3 @6 T
sources
: P9 }4 h7 X5 E5 s& y ~( T:= foo.c bar.c baz.s ugh.h
! k* W: r0 E* I u foo: $(sources)
. |, U w& T' I2 Z+ y) p
! O0 g: T: i1 g% O, P; vcc $(filter %.c %.s,$(sources)) -o foo
9 k) p' a* |8 D3 U3 F; y& e
' E! X( C' d- u7 X+ g$(filter %.c %.s,$(sources))返回的值是“foo.c bar.c baz.s”。
& y V5 m! D! J' e$(filter-out' [& w: q8 d+ P% M
,)2 E5 Y0 v2 K$ g
名称:反过滤函数——filter-out。2 m' m2 V# Z( \4 D# B+ G
功能:以模式过滤字符串中的单词,去除符合模式的单词。可以有多个模式。
# d4 Y. Y$ Y! G0 C 返回:返回不符合模式的字串。
( [- d: m2 s* t 示例:
1 B2 w k, Y% E# Q7 n9 O 7 P5 _/ k" Q1 X) z+ `
objects=main1.o foo.o main2.o bar.o
/ `5 k8 w! V) C mains=main1.o main2.o$ c8 s5 b9 _6 f# f
5 x' Z% b% p# w* ?
$(filter-out $(mains),$(objects)) 返回值是“foo.o6 A8 }' E! g- r; @: Q3 B" @
bar.o”。
3 V% ?1 }, T z( E' ^% n" A/ w( |
p7 O/ C) B4 a/ t: I& O+ W/ u$(sort )
" q% v7 @5 a& n5 b6 U名称:排序函数——sort。功能:给字符串中的单词排序(升序)。返回:返回排序后的字符串。示例:$(sort foo bar lose)返回“bar foo lose”。备注:sort函数会去掉中相同的单词。0 I. p1 e- S+ v' u6 E
$(word ,)5 v( ]3 h" ^) n# L) A9 L) s
名称:取单词函数——word。功能:取字符串中第个单词。(从一开始)返回:返回字符串中第个单词。如果比中的单词数要大,那么返回空字符串。示例:$(word 2, foo bar baz)返回值是“bar”。( `, r5 N( {3 R" T
$(wordlist; ^: s# C7 {. _
,,)
) U C2 T6 S/ p* |* O% G. k6 I 名称:取单词串函数——wordlist。3 e2 ]+ C; Z. U, }0 R0 c/ X g
功能:从字符串中取从开始到的单词串。和是一个数字。
0 e& j/ ?! D/ p% I 返回:返回字符串中从到的单词字串。如果比中的单词数要大,那么返回空字符串。如果大于的单词数,那么返回从开始,到结束的单词串。) Q2 t1 O3 H. h
示例: $(wordlist 2, 3, foo bar baz)返回值是“bar
6 k m1 s g! N3 w, y/ ubaz”。
6 C3 ^. v# W9 Z6 j$(words )
& D# ?7 _# ~7 O( z I( H 名称:单词个数统计函数——words。/ P# \ v) P) M" r: D2 i( i9 P$ b
功能:统计中字符串中的单词个数。+ }; u* C3 k$ a, o0 i5 A% o
返回:返回中的单词数。
5 _' i. N% S- z- @+ p8 C 示例:$(words, foo bar baz)返回值是“3”。( b1 _% G2 d& Y
备注:如果我们要取中最后的一个单词,我们可以这样:$(word
: B. Z9 E! m) z3 E% a: v$(words ),)。
* p2 F- C' R1 J: b3 r$(firstword ): `4 T4 d5 w& `1 u& t7 V7 k4 L* L
名称:首单词函数——firstword。
* N' L, p! m' p+ f 功能:取字符串中的第一个单词。
6 q" ?: D$ z1 }* x, n 返回:返回字符串的第一个单词。; b O& i1 B* @2 a( T) b- ^) V7 h
示例:$(firstword foo bar)返回值是“foo”。
% p. J P4 L( o& H# k1 O3 G5 h H 备注:这个函数可以用word函数来实现:$(word
" N3 {8 O4 |. ]1 z2 h" [6 W1,)。
0 s8 \- X1 X1 e# a以上,是所有的字符串操作函数,如果搭配混合使用,可以完成比较复杂的功能。这里,举一个现实中应用的例子。我们知道,make使用“VPATH”变量来指定“依赖文件”的搜索路径。于是,我们可以利用这个搜索路径来指定编译器对头文件的搜索路径参数CFLAGS,如:
7 v" |3 d5 G8 m2 a: H' L override CFLAGS += $(patsubst
8 `, b a- G+ J%,-I%,$(subst :, ,$(VPATH)))5 O) l1 E5 A6 L) W; m
如果我们的“$(VPATH)”值是“src:../headers”,那么“$(patsubst2 y" n9 {$ ]& G/ |3 c/ S$ Q3 R C- {
%,-I%,$(subst :, ,$(VPATH)))”将返回“-Isrc -I../headers”,这正是cc或gcc搜索头文件路径的参数。, b2 J+ W" l- p/ A4 q, v% O& {
三、文件名操作函数3 A5 A8 v7 d: U/ a
下面我们要介绍的函数主要是处理文件名的。每个函数的参数字符串都会被当做一个或是一系列的文件名来对待。; q9 z1 @" p! ?$ }$ z8 F! n, l1 u: i
$(wildcard )3 u! O# T$ Z# \$ T v2 x
名称:文件名展开函数——wildcard 。6 S+ }7 `4 B- z8 F
功能:功能是展开成一列所有符合由其参数描述的文件名,文件间以空格间隔。
- r2 P( D( b9 ^6 j% L 返回:函数返回展开后的文件名列表。3 U7 k; j1 c8 b1 H0 {
/ l! a. K: B; |( v8 M; d1 r+ N9 x示例:
2 I: E2 ~0 \' w B* r/ X
; z/ a- e5 g- \9 P; ]. M $(wildcard *.c)3 B% I6 b1 _/ F, |$ J/ ?8 _
, G: ]- @" g4 b& ^ Y
返回结果是一个所有以 '.c' 结尾的文件的列表。 " A$ L" w) Z: {( H# t5 J
$(dir ) 5 p5 \; G) r- X7 r& o* w
名称:取目录函数——dir。$ `; ?) a- h0 o* I- V. x
功能:从文件名序列中取出目录部分。目录部分是指最后一个反斜杠(“/”)之前的部分。如果没有反斜杠,那么返回“./”。" }6 D0 U( @2 G1 Q
返回:返回文件名序列的目录部分。+ g: i6 D* u- U- c+ J1 e/ j- l
示例: $(dir src/foo.c hacks)返回值是“src/
) R) ^+ _& K; B/ t2 S./”。
5 ^/ D3 t, ], z$(notdir )
' I" ^7 ~+ c% F0 H3 s/ B- B 名称:取文件函数——notdir。6 A: q$ I& H( @( Q$ K3 w/ `
功能:从文件名序列中取出非目录部分。非目录部分是指最后一个反斜杠(“/”)之后的部分。' J6 t# L! b! b. f% C
返回:返回文件名序列的非目录部分。( T8 @3 G/ R3 s
示例: $(notdir src/foo.c hacks)返回值是“foo.c
3 O: l% r( }3 s7 N3 N: t$ Ehacks”。0 f+ T$ S7 F3 Y
( r$ @6 z7 ?% [9 S$(suffix ) ) @) @* b7 E. y5 K+ T5 k
4 M. d- I6 n( I) V9 X. J- S 名称:取后缀函数——suffix。/ w4 j2 Y# G; d& a4 d; _
功能:从文件名序列中取出各个文件名的后缀。1 `% m+ f; R: q* U
返回:返回文件名序列的后缀序列,如果文件没有后缀,则返回空字串。$ z- l5 k! U& ~; ]
示例:$(suffix src/foo.c src-1.0/bar.c hacks)返回值是“.c3 l6 _. H( Y. H2 Z. _
.c”。) S. S) y! J" ^1 Q2 f7 h% O
$(basename )
) `! @/ H0 i8 \8 s 名称:取前缀函数——basename。
T% @# Y6 \! ~# \. } 功能:从文件名序列中取出各个文件名的前缀部分。7 E3 ?3 p( d- s' t5 Q7 n; W
返回:返回文件名序列的前缀序列,如果文件没有前缀,则返回空字串。
+ w6 M1 Z/ ?! q; C 示例:$(basename src/foo.c src-1.0/bar.c hacks)返回值是“src/foo& k- R3 @ f0 g5 S
src-1.0/bar hacks”。2 c* X2 c8 ^' i# H* I' y; V
$(addsuffix% v/ [- E' q& v8 _& o' q
,) + B0 p) V' c( {3 e6 [
名称:加后缀函数——addsuffix。- T1 T1 }1 j) C2 h
功能:把后缀加到中的每个单词后面。
6 h4 l# A+ x$ q/ n& @+ {+ K; g 返回:返回加过后缀的文件名序列。5 n3 J& x# B. t) W" d, V
示例:$(addsuffix .c,foo bar)返回值是“foo.c
0 y, K6 {4 t$ u; \, N$ p* t' P6 c- {bar.c”。
6 z. Z/ H4 d: e }; k: d$(addprefix3 r# ?0 ~" |+ f6 B) ]
,) $ s4 r+ A2 N$ d) [4 ~
名称:加前缀函数——addprefix。
5 R: z |3 m+ ^7 r 功能:把前缀加到中的每个单词后面。& P$ N/ N7 V1 c
返回:返回加过前缀的文件名序列。
) {5 f+ o& {2 A4 P8 i K& }4 } 示例:$(addprefix src/,foo bar)返回值是“src/foo- v' Q! a5 Y; s- W1 ^
src/bar”。2 U& Q5 d* _; b
$(join ,)
2 o" r" B+ D+ _! k+ J% Z: ] 名称:连接函数——join。- I: W& c1 ^! Q! W& a; O
功能:把中的单词对应地加到的单词后面。如果的单词个数要比的多,那么,中的多出来的单词将保持原样。如果的单词个数要比多,那么,多出来的单词将被复制到中。
7 O# ^- J* ?# Q9 Y* ]& }$ K2 V 返回:返回连接过后的字符串。5 d+ S7 `1 O+ \9 k
示例:$(join aaa bbb , 111 222 333)返回值是“aaa1113 N' d3 h# ?! a" m5 I; [7 d% F
bbb222 333”。4 i+ R' Z* A- \
& W$ X/ y9 J; ?$ v四、foreach 函数2 U2 ]/ E6 j+ L, O ?7 _$ M& ^" Y
4 J# Y! y+ G; Y% |3 V+ Aforeach函数和别的函数非常的不一样。因为这个函数是用来做循环用的,Makefile中的foreach函数几乎是仿照于Unix标准Shell(/bin/sh)中的for语句,或是C-Shell(/bin/csh)中的foreach语句而构建的。它的语法是:! f J1 o7 R3 _* b' y
' @1 D' j2 t* d f8 r $(foreach+ t4 [4 A5 `) G8 T* @5 g# q' L
,,)8 u" F: T% Z% Z& [# q' p8 F) T% ~# ]
4 h, X- \: [9 D5 D这个函数的意思是,把参数中的单词逐一取出放到参数所指定的变量中,然后再执行所包含的表达式。每一次会返回一个字符串,循环过程中,的所返回的每个字符串会以空格分隔,最后当整个循环结束时,所返回的每个字符串所组成的整个字符串(以空格分隔)将会是foreach函数的返回值。
! d* |7 ?5 y; s, {3 `2 \, Z2 z* p' ~! f6 a
所以,最好是一个变量名,可以是一个表达式,而中一般会使用这个参数来依次枚举中的单词。举个例子:1 ?3 G& u n2 E& L5 v0 W6 R2 w: x
1 b& P- n! B& } names := a b c d" ]7 O7 [+ ]! Q4 K! f3 v
files := $(foreach n,$(names),$(n).o): q' p7 K4 @9 n3 U' B# n
& c2 R M% D q- b! i! p8 Z
上面的例子中,$(name)中的单词会被挨个取出,并存到变量“n”中,“$(n).o”每次根据“$(n)”计算出一个值,这些值以空格分隔,最后作为foreach函数的返回,所以,$(files)的值是“a.o b.o c.o d.o”。
6 g2 e1 t$ d, f$ |/ V
3 N, `# h% Z! X6 n1 G, \- ^8 p注意,foreach中的参数是一个临时的局部变量,foreach函数执行完后,参数的变量将不在作用,其作用域只在foreach函数当中。
% u# [& v& U" P& \ `: D3 z( M
7 T, J" ^& M2 j" B6 J' Y# N0 Y; J4 W3 z; d. F$ e4 ~/ J) A
五、if 函数
* I* S& D( [% F9 B3 p I4 h& R$ I; E# x# ^9 n
if函数很像GNU的make所支持的条件语句——ifeq(参见前面所述的章节),if函数的语法是:& X, `0 s! m# R& g3 q7 n& ^/ E
( c- J: f! R/ J& d
$(if ,)
& }, [6 ?# E2 c7 s# v9 E" u$ ?5 h( W
或是2 G/ {1 d8 X Z; N% s. m
. Q' t; N7 Y0 J+ E" u% k" A
$(if
: ~; m* H, }& e8 y* ]! X3 Y0 U,,)
$ J0 d0 n5 [5 R+ m! \ ~: u5 m7 Z$ y& Y9 M. W) Z
可见,if函数可以包含“else”部分,或是不含。即if函数的参数可以是两个,也可以是三个。参数是if的表达式,如果其返回的为非空字符串,那么这个表达式就相当于返回真,于是,会被计算,否则会被计算。9 `! c, Q( A' Y) a% q7 A4 E; L
* U* \: i5 ^0 x
而if函数的返回值是,如果为真(非空字符串),那个会是整个函数的返回值,如果为假(空字符串),那么会是整个函数的返回值,此时如果没有被定义,那么,整个函数返回空字串。
) g/ e' R: V3 c+ h8 U5 n* K" N( X0 }% j3 ?
所以,和只会有一个被计算。( L) o) @ Q: i; N! {
9 P3 o- W# e* p1 d, D K8 O7 B
/ ]8 X( {6 I: r六、call函数
& O; B5 O& u8 q, {
/ I3 |' S# Z' {7 jcall函数是唯一一个可以用来创建新的参数化的函数。你可以写一个非常复杂的表达式,这个表达式中,你可以定义许多参数,然后你可以用call函数来向这个表达式传递参数。其语法是:: @! t' C7 U1 G5 Z8 s( F4 C
\8 R: t: _. C. `
$(call' |, Q/ s( B2 H4 O& k7 ?
,,,...)5 B: z8 h2 U4 K. Q' S% x
/ n8 Z/ `, R3 n. S' ?
当make执行这个函数时,参数中的变量,如$(1),$(2),$(3)等,会被参数,,依次取代。而的返回值就是call函数的返回值。例如:
: l$ T* d8 I, t( U; E6 @ reverse = $(1) $(2)
& ~; T0 ^3 r9 X- G0 V( i2 u foo = $(call reverse,a,b)( |* ?* A0 C' w' U
那么,foo的值就是“a b”。当然,参数的次序是可以自定义的,不一定是顺序的,如:
* |0 ]1 R- w: Q6 S" S+ R$ m$ d7 B2 }, K! K- y
reverse =
: ~! W. `: o# g8 ]$(2) $(1). g% w9 h) R- K9 j- e% m
foo = $(call reverse,a,b)
! ?+ n6 R, q5 t3 R! T: a此时的foo的值就是“b a”。
: X% {& T9 Q$ J2 K% |, ?% U0 s& m
) L7 u8 `; M& B+ M6 p, J1 X9 Z4 T4 s1 r# `$ k
七、origin函数
& {0 z+ {+ t/ b4 i2 H. m5 Oorigin函数不像其它的函数,他并不操作变量的值,他只是告诉你你的这个变量是哪里来的?其语法是:3 ~! m! M) U$ J/ P6 f2 N
4 I }" Y3 w# |$ p$ d $(origin )
+ H; ~; w. t( _' G$ K5 I A7 p$ C8 E# H0 k
注意,是变量的名字,不应该是引用。所以你最好不要在中使用“$”字符。Origin函数会以其返回值来告诉你这个变量的“出生情况”,下面,是origin函数的返回值:
4 ~) X, U# r8 f
2 x5 ~( N |; |. I“undefined”7 u8 l. B# X6 Q- ?9 T! g0 q
如果从来没有定义过,origin函数返回这个值“undefined”。
) [; ?. M& T$ e1 c% d* J; `
" g" A1 ?8 l' S0 I& i& r' E H“default”
2 K. m0 u: Z5 v! J6 } 如果是一个默认的定义,比如“CC”这个变量,这种变量我们将在后面讲述。
+ S1 L) ]( c( P6 w' Q8 d9 O
: G4 X1 Y( O- a3 O& E6 A“environment”$ B4 Z) B- Y$ n- |( D
如果是一个环境变量,并且当Makefile被执行时,“-e”参数没有被打开。
. |2 }6 F9 L; A4 q& j# X7 {6 E5 |1 o+ i
“file”' W6 U! ~; ~. Y( J) ~4 s
如果这个变量被定义在Makefile中。4 E3 p8 T9 q3 {7 [
# a. h! v2 E$ R3 N
“command* G# g+ w8 i! P( o
line”
& Z& N" V- Y3 m- {* ] 如果这个变量是被命令行定义的。
$ B% i7 g; i6 Y
1 W8 J2 X' x! d7 n0 G4 p8 j9 t“override”0 \/ e, ^# c/ H+ _
如果是被override指示符重新定义的。/ E" H: O% A6 G% b2 k/ g
/ h" e8 F3 N! z, H }2 X) F
“automatic”& D1 b; N- ~) H4 X5 Y
如果是一个命令运行中的自动化变量。关于自动化变量将在后面讲述。
5 k4 ^2 e, P8 R( b- N* Y' ?) u* f* i( W, ]
这些信息对于我们编写Makefile是非常有用的,例如,假设我们有一个Makefile其包了一个定义文件Make.def,在Make.def中定义了一个变量“bletch”,而我们的环境中也有一个环境变量“bletch”,此时,我们想判断一下,如果变量来源于环境,那么我们就把之重定义了,如果来源于Make.def或是命令行等非环境的,那么我们就不重新定义它。于是,在我们的Makefile中,我们可以这样写:
. n" ^ W7 e9 k8 N6 \: i2 t8 E- L( n- E% d# R
ifdef bletch* [6 U6 ^# L% z$ [( G
ifeq "$(origin bletch)"/ h7 T1 H: E# s, o4 ^' l* \
"environment"
3 r. c$ v, q3 {/ R I9 T, o) b bletch = barf, gag, etc.
" {1 h/ m. T( i0 T+ x+ X endif$ ] s) _) [: q0 @3 Z8 ^, o
endif4 P9 g* }3 u: H% [0 N6 J3 Z0 B. d
" ?' n! N( o; a. M& ]
当然,你也许会说,使用override关键字不就可以重新定义环境中的变量了吗?为什么需要使用这样的步骤?是的,我们用override是可以达到这样的效果,可是override过于粗暴,它同时会把从命令行定义的变量也覆盖了,而我们只想重新定义环境传来的,而不想重新定义命令行传来的。
" W6 N$ t; i: R" f+ I1 ~- \4 X1 `; ]/ R: V$ N+ Q
7 K& E. h; ]' u) C0 v/ y
八、shell函数
+ F7 _- m; g4 l+ Q% D6 _2 o
~! E3 i' u" l3 kshell函数也不像其它的函数。顾名思义,它的参数应该就是操作系统Shell的命令。它和反引号“`”是相同的功能。这就是说,shell函数把执行操作系统命令后的输出作为函数返回。于是,我们可以用操作系统命令以及字符串处理命令awk,sed等等命令来生成一个变量,如:
6 w- {9 F" \( { j
/ ^" W/ L- T5 Q- P contents := $(shell cat foo)
& w3 g8 J% X. O& C: v1 L" d1 R! q6 Z" c& b8 C }
files := $(shell echo *.c)" |# D, i+ ]9 d( ]6 V
3 @; k" N! k2 b* |$ |, b
注意,这个函数会新生成一个Shell程序来执行命令,所以你要注意其运行性能,如果你的Makefile中有一些比较复杂的规则,并大量使用了这个函数,那么对于你的系统性能是有害的。特别是Makefile的隐晦的规则可能会让你的shell函数执行的次数比你想像的多得多。
! E1 W2 E7 f+ a. W; l$ k6 |8 }
5 J& `$ s( S" i6 O6 a; @ |
|