版主
  
主题
帖子
积分10609
阅读权限200
注册时间2008-11-22
最后登录1970-1-1
在线时间 小时
|
在Makefile中可以使用函数来处理变量,从而让我们的命令或是规则更为的灵活和具有智能。make所支持的函数也不算很多,不过已经足够我们的操作了。函数调用后,函数的返回值可以当做变量来使用。: d% K2 v2 j! r& @
一、函数的调用语法7 z% V/ X% V9 T4 t* ?- e6 P
函数调用,很像变量的使用,也是以“$”来标识的,其语法如下:
6 ?0 F8 ?5 J$ ^ j $(# H4 _( W: L' k$ x
); ^+ t9 G# |& u; L5 F1 }
或是
/ s0 {7 F* f8 D, ]9 Z# M5 H ${
4 F! ^' i8 Y* _0 k7 J" A}
' ^2 v7 h: H( S1 C. L1 c: w这里,就是函数名,make支持的函数不多。是函数的参数,参数间以逗号“,”分隔,而函数名和参数之间以“空格”分隔。函数调用以“$”开头,以圆括号或花括号把函数名和参数括起。感觉很像一个变量,是不是?函数中的参数可以使用变量,为了风格的统一,函数和变量的括号最好一样,如使用“$(subst" R" z8 k5 |$ j6 ?
a,b,$(x))”这样的形式,而不是“$(subst a,b,${x})”的形式。因为统一会更清楚,也会减少一些不必要的麻烦。7 u9 T& d2 P K6 `
还是来看一个示例: {5 R, _+ m4 S3 c' K X
comma:= ,
5 z2 b9 Y8 r) P- y# U% n2 P' B9 I+ G empty:=
- a4 @: F5 p. |6 `# Z5 t space:= $(empty) $(empty)3 n& b: X J3 q4 U
foo:= a b c
. ~5 V& Q# ?+ B/ \- w bar:= $(subst $(space),$(comma),$(foo))2 w# Y# s1 \' m7 R! s8 x' J
在这个示例中,$(comma)的值是一个逗号。$(space)使用了$(empty)定义了一个空格,$(foo)的值是“a b c”,$(bar)的定义用,调用了函数“subst”,这是一个替换函数,这个函数有三个参数,第一个参数是被替换字串,第二个参数是替换字串,第三个参数是替换操作作用的字串。这个函数也就是把$(foo)中的空格替换成逗号,所以$(bar)的值是“a,b,c”。/ `9 P7 ]: |, ^& w" C
二、字符串处理函数
- j) G: X3 p9 J- t- w$(subst
4 \2 u! c2 J1 V5 l& e" P,,) , }4 B1 L% H/ H: Q
名称:字符串替换函数——subst。 k! N- v) b; \( g# P( O$ H
功能:把字串中的字符串替换成。) J' D1 J) F' F
返回:函数返回被替换过后的字符串。
; T# o" { I- Q( v- w4 K/ w 示例:8 v& `7 { f6 _7 b# P
9 s) i! b) k, _3 P5 \/ y$ I
$(subst ee,EE,feet on the street),4 t6 a* K: q r
3 U( v2 ^) B+ Y% B% }& \+ r
把“feet on the street”中的“ee”替换成“EE”,返回结果是“fEEt p2 p, M. @5 j
on the strEEt”。, Z# f$ t6 P# D2 P$ k( R
$(patsubst ,,) ) w) B: M: L% b( G. d, G0 L$ y& u9 y
名称:模式字符串替换函数——patsubst。
1 a# v* Q% u5 S( X0 z2 p" L 功能:查找中的单词(单词以“空格”、“Tab”或“回车”“换行”分隔)是否符合模式,如果匹配的话,则以替换。这里,可以包括通配符“%”,表示任意长度的字串。如果中也包含“%”,那么,中的这个“%”将是中的那个“%”所代表的字串。(可以用“\”来转义,以“\%”来表示真实含义的“%”字符)
) h" v5 x1 ?& {5 M6 X. O' d 返回:函数返回被替换过后的字符串。4 F2 m5 M8 g4 k( M2 @
示例:
) ]7 u: c F: l& n
' E9 N: T8 ^7 p( b3 c7 N3 J! C' Y$(patsubst %.c,%.o,x.c.c bar.c): S1 U3 p: J- |5 D4 t7 U2 i# y
把字串“x.c.c1 E! Q1 m1 k7 {) n$ {- ?
bar.c”符合模式[%.c]的单词替换成[%.o],返回结果是“x.c.o
7 ?- |. u6 w8 u% K2 kbar.o”* l, ^1 P# E! t, b
备注:
3 K' b8 w- ?1 \8 ~8 x, { 这和我们前面“变量章节”说过的相关知识有点相似。如:+ y& b9 h+ J1 j. I
“$(var:=)”) x( g' d2 j2 I& [$ M. _
相当于
J& s o: H# _4 U3 ^1 K “$(patsubst+ ~5 t2 g) \) f8 m6 u
,,$(var))”,
^ R# x0 J* a 而“$(var:0 I" o. c# ]2 O4 c
=)” ]+ N# L5 a. E5 s
则相当于' B. v$ r3 h0 z- q) g8 q5 W! A
“$(patsubst
) N( a! J; l: R1 j" C4 F%,%,$(var))”。
" `, E+ R1 e' k; A- B 例如有:objects = foo.o2 L9 t+ ^" O4 Z9 U8 ~, W
bar.o baz.o," a0 P4 M) I( G- `
那么,“$(objects:.o=.c)”和“$(patsubst
+ d" U: W1 t, H, H3 {%.o,%.c,$(objects))”是一样的。- G8 ?# r$ D0 M9 q2 h
$(strip )
5 e! k H3 |8 R( P0 C% z 名称:去空格函数——strip。( u7 L8 W; X" @/ ?
功能:去掉字串中开头和结尾的空字符。/ b5 W; b2 v" H( C
返回:返回被去掉空格的字符串值。
8 `2 n* T. j: |+ F) z3 j, C 示例:2 n) D2 T+ i. ?' j
! I/ x& q8 m" b: M* J5 w
$(strip a b c )
" u$ ?" J* b$ {) [( d 把字串“a b
+ [1 ]; O$ i4 \* ?1 H) mc ”去到开头和结尾的空格,结果是“a b c”。
1 i s8 U$ s: l% h, t9 a$(findstring ,)
$ u& f( _7 S/ s! X6 m1 S$ D t) r 名称:查找字符串函数——findstring。
+ q$ Z' N0 s* v" I3 V 功能:在字串中查找字串。
9 i- f: U9 L/ d! c/ e 返回:如果找到,那么返回,否则返回空字符串。
$ }- ~ a) o3 j; X# ~2 K% f! k 示例:
# Q6 a9 A. E2 w* L q . ]" ]3 n; M, `! v4 I2 j
$(findstring a,a b c)
1 p. _% Z6 ?- Z9 C $(findstring a,b c)
. `3 y& y5 b) i, P: [" h 第一个函数返回“a”字符串,第二个返回“”字符串(空字符串) @; i: }5 k: J/ m* `
$(filter' U8 D$ P9 J9 f1 `0 G
,)
* ]2 Q/ w; [7 r8 D9 B 名称:过滤函数——filter。
& t: |! m4 E/ l. c* E 功能:以模式过滤字符串中的单词,保留符合模式的单词。可以有多个模式。' C( K$ d! r( H$ A* P: M/ h2 o
返回:返回符合模式的字串。
1 s+ W9 {5 b8 ~ 示例:
* P& H# Z b( _3 O) i sources7 l, r; v3 z/ [4 h9 Y1 H9 A& t
:= foo.c bar.c baz.s ugh.h" m+ w* V- c" o/ w8 D* ?/ Z
foo: $(sources)
& p$ _7 U: L' L# J# u9 g 0 j: B6 \) b% L" s( W# R
cc $(filter %.c %.s,$(sources)) -o foo
1 S: `: d* ^4 N- O
+ r; t$ o6 F" j$ v" c4 ?6 X8 U$(filter %.c %.s,$(sources))返回的值是“foo.c bar.c baz.s”。% }6 [6 t* E, q" Y" ?) m
$(filter-out W% s7 L h6 c& h8 N
,)' V7 f8 G: {9 \* a" O
名称:反过滤函数——filter-out。# M: Q* f: D8 u7 e; J
功能:以模式过滤字符串中的单词,去除符合模式的单词。可以有多个模式。& Q4 ?7 k( J/ G
返回:返回不符合模式的字串。; {1 x% n9 @6 V& {# G' B6 F
示例:( D% C* c7 Q8 j( v
T7 k- Y* q+ v$ Y/ F! l; G8 Lobjects=main1.o foo.o main2.o bar.o
9 L& ]4 Q$ M9 v T: O mains=main1.o main2.o' |; y6 ^: z* t: R2 J
% k2 E5 H+ t0 K* A. U. W+ w
$(filter-out $(mains),$(objects)) 返回值是“foo.o
3 G5 m. y" Z, w! X8 X) O2 `bar.o”。
! l C' t9 \+ X5 `* l7 m
{! N. B2 e% S, U$(sort )
% C7 S6 ]/ }0 t+ S( |名称:排序函数——sort。功能:给字符串中的单词排序(升序)。返回:返回排序后的字符串。示例:$(sort foo bar lose)返回“bar foo lose”。备注:sort函数会去掉中相同的单词。: ^( ]3 R8 ?; }* B' A" ~6 A0 `( j% n
$(word ,)/ j/ x- D% S7 K4 O
名称:取单词函数——word。功能:取字符串中第个单词。(从一开始)返回:返回字符串中第个单词。如果比中的单词数要大,那么返回空字符串。示例:$(word 2, foo bar baz)返回值是“bar”。, |& U% v2 L1 J7 q
$(wordlist
, b R8 U2 Y+ b2 {- ^,,) & h; Y! \' z1 `
名称:取单词串函数——wordlist。( G2 g8 x+ }5 w# _7 H/ d- J
功能:从字符串中取从开始到的单词串。和是一个数字。8 W4 c3 F# D8 n7 N
返回:返回字符串中从到的单词字串。如果比中的单词数要大,那么返回空字符串。如果大于的单词数,那么返回从开始,到结束的单词串。: F, r1 J9 |/ G$ Q2 }
示例: $(wordlist 2, 3, foo bar baz)返回值是“bar
0 z/ \/ s' w2 j1 Ubaz”。
/ C# X* |# x2 g; R+ J$(words )4 \; w" B: }, w( {. A
名称:单词个数统计函数——words。
6 A, ^# _$ H$ a. U5 q 功能:统计中字符串中的单词个数。4 B' `* c8 H% n1 @6 Q5 E- x) c8 [
返回:返回中的单词数。( T3 b; ]8 i) X. ?7 T; G
示例:$(words, foo bar baz)返回值是“3”。
- L( l- ?6 I- M ~3 @! g* J" M/ `; T 备注:如果我们要取中最后的一个单词,我们可以这样:$(word, u6 g% B. I: z
$(words ),)。
& w6 o" h, r: k2 x8 @2 R' q* l6 J( r$(firstword )
" D+ A3 q4 N; i2 |; M 名称:首单词函数——firstword。+ K, T2 w! g& A: ~7 ` |( X d( Q
功能:取字符串中的第一个单词。* V4 |9 M7 Q' l; e; S
返回:返回字符串的第一个单词。
, J9 H" s# r# B g3 S" `- D 示例:$(firstword foo bar)返回值是“foo”。, ?. [( f4 n2 P7 m! ]
备注:这个函数可以用word函数来实现:$(word, t1 O: B: d; H( A( A; Z9 r; @" x
1,)。. c9 S# R P" q' v& S9 K4 `
以上,是所有的字符串操作函数,如果搭配混合使用,可以完成比较复杂的功能。这里,举一个现实中应用的例子。我们知道,make使用“VPATH”变量来指定“依赖文件”的搜索路径。于是,我们可以利用这个搜索路径来指定编译器对头文件的搜索路径参数CFLAGS,如:
2 e& g3 y) c! J3 m& L6 P override CFLAGS += $(patsubst
9 n* G9 Z+ U6 J: L' M9 [& s' w1 |# t%,-I%,$(subst :, ,$(VPATH)))
o% L' [8 t. X 如果我们的“$(VPATH)”值是“src:../headers”,那么“$(patsubst
( x& Q. [1 ?0 b. u%,-I%,$(subst :, ,$(VPATH)))”将返回“-Isrc -I../headers”,这正是cc或gcc搜索头文件路径的参数。
1 U; B5 K: I0 F% _% m% a1 d三、文件名操作函数
- J: X9 w% I& c' p' f! g下面我们要介绍的函数主要是处理文件名的。每个函数的参数字符串都会被当做一个或是一系列的文件名来对待。+ p# f. Z1 w( s; j
$(wildcard )
6 M: n2 H4 i/ S2 j名称:文件名展开函数——wildcard 。
3 z7 C3 s/ v3 ?/ x0 M 功能:功能是展开成一列所有符合由其参数描述的文件名,文件间以空格间隔。% n+ `: O, `3 ^$ n
返回:函数返回展开后的文件名列表。% b: n5 r# d. i9 A" r/ n$ e- W
% M5 @0 }; `% N7 Y
示例:3 O, [' B& b' p4 K& f, i3 k
$ Q) Z/ a4 c4 B/ Q
$(wildcard *.c)
5 z) I5 b$ s* }9 w* j 5 Z Z- u% z, K! `- H9 H1 p
返回结果是一个所有以 '.c' 结尾的文件的列表。 1 `* R3 a/ t7 N; I, E X
$(dir )
9 M8 ~* H) ?! p* |$ Q3 x 名称:取目录函数——dir。
' ^/ E; U s" o7 h* s" Y) C9 G 功能:从文件名序列中取出目录部分。目录部分是指最后一个反斜杠(“/”)之前的部分。如果没有反斜杠,那么返回“./”。4 Q; I! e, l* }
返回:返回文件名序列的目录部分。+ x/ U+ W0 {1 E, s" ?
示例: $(dir src/foo.c hacks)返回值是“src/
, [; q7 k1 q$ A8 R$ x" @, G./”。
/ V4 e+ R5 v; w: C$(notdir )
x# H. U. f1 q 名称:取文件函数——notdir。
3 g8 {; I- E$ [- S# l$ N7 \+ ?9 \ 功能:从文件名序列中取出非目录部分。非目录部分是指最后一个反斜杠(“/”)之后的部分。& l' N5 z f [6 y: n
返回:返回文件名序列的非目录部分。 P4 e7 G* s+ Q! \; D# _ P
示例: $(notdir src/foo.c hacks)返回值是“foo.c
/ r3 W1 s+ ~! P% P( {/ q5 l! C: hhacks”。
: ?. | S0 X0 Z( X) E9 r$ I+ E
" W& q/ l, R$ F- Y$(suffix )
, Z4 c# R" v8 N' v4 \' V0 g * D' N( A1 }) k. x0 k# r
名称:取后缀函数——suffix。
5 ~# f! w1 i: B" x9 B3 d3 G 功能:从文件名序列中取出各个文件名的后缀。0 }6 L; j$ [5 r7 ]. H: `3 k
返回:返回文件名序列的后缀序列,如果文件没有后缀,则返回空字串。
1 W, S/ R7 u. ` 示例:$(suffix src/foo.c src-1.0/bar.c hacks)返回值是“.c
. P- ~, R5 L4 E! U' E ?.c”。
/ G) @) D+ `/ w6 x i$(basename )
! a! \# E+ r- r$ Z0 b7 ~* k, [4 m 名称:取前缀函数——basename。7 l! G( X& @5 D$ ]9 x! d
功能:从文件名序列中取出各个文件名的前缀部分。: B$ q5 {$ C8 e: y
返回:返回文件名序列的前缀序列,如果文件没有前缀,则返回空字串。) F! |) D( a* k
示例:$(basename src/foo.c src-1.0/bar.c hacks)返回值是“src/foo- o- m. h2 D% o/ F4 i4 j" l
src-1.0/bar hacks”。
) h \ F" c, U; T$(addsuffix3 \+ t/ [: Z2 w* d A! V* ^" X
,) : \4 t3 N6 `2 H# l- G' ~
名称:加后缀函数——addsuffix。
1 J" Q. a+ g( I: c 功能:把后缀加到中的每个单词后面。- D/ y5 X8 e4 }! G3 \
返回:返回加过后缀的文件名序列。
3 P6 a" O1 @: R 示例:$(addsuffix .c,foo bar)返回值是“foo.c
1 i8 G, B) z" pbar.c”。
. L# y+ d! W) h9 r9 X8 R! }9 Y+ Q$(addprefix5 ?' ]# k* [6 P4 Z: U' d, V
,)
3 A: c3 z6 f! Q ?7 U4 q' u, i 名称:加前缀函数——addprefix。4 y$ i2 a a# H% E' [8 m8 O6 h
功能:把前缀加到中的每个单词后面。
. ^3 ^0 ]4 |# j 返回:返回加过前缀的文件名序列。6 ~9 z& U6 Y c' y: [
示例:$(addprefix src/,foo bar)返回值是“src/foo0 a9 a' b G5 ^; O
src/bar”。" ~ Q/ Z* [& m1 G! v; F+ P @+ F8 ?
$(join ,)6 S5 K2 f: m0 m6 W4 Q
名称:连接函数——join。5 X/ k& U/ @# @
功能:把中的单词对应地加到的单词后面。如果的单词个数要比的多,那么,中的多出来的单词将保持原样。如果的单词个数要比多,那么,多出来的单词将被复制到中。
0 }( T- \9 }( R 返回:返回连接过后的字符串。
$ v4 |1 B L- s E3 d+ C u* W 示例:$(join aaa bbb , 111 222 333)返回值是“aaa111
# `( |3 M |: T/ y4 ?2 obbb222 333”。
; i% e6 I0 l4 P5 S& W8 F. @6 d3 S8 f- W5 M. i2 H p9 V. \
四、foreach 函数7 V* W, b( Q& ^# S1 ]4 l( T
5 i) M- x; z" u$ p; t( l# G0 O
foreach函数和别的函数非常的不一样。因为这个函数是用来做循环用的,Makefile中的foreach函数几乎是仿照于Unix标准Shell(/bin/sh)中的for语句,或是C-Shell(/bin/csh)中的foreach语句而构建的。它的语法是:
# j; D- z! R6 m; e3 R+ U9 r1 [( C# R) C
$(foreach4 V d' H6 Z' d2 n
,,)2 w3 G# r) P! K" I3 @4 ]
7 P6 t$ I" x4 d# l这个函数的意思是,把参数中的单词逐一取出放到参数所指定的变量中,然后再执行所包含的表达式。每一次会返回一个字符串,循环过程中,的所返回的每个字符串会以空格分隔,最后当整个循环结束时,所返回的每个字符串所组成的整个字符串(以空格分隔)将会是foreach函数的返回值。* `* p2 S2 g1 K2 L: O$ T2 `
: e& n# ~4 ~8 {所以,最好是一个变量名,可以是一个表达式,而中一般会使用这个参数来依次枚举中的单词。举个例子:
# k, u2 {7 f7 e, X$ T
7 i3 _" ^# N F( O. I& |$ S names := a b c d
3 o% r3 T0 R8 Z) f2 F1 ]$ E files := $(foreach n,$(names),$(n).o)9 z1 l4 v' W7 A8 T4 r9 j! i- R
9 T3 l$ w8 R6 ~' v9 e3 t+ E4 F上面的例子中,$(name)中的单词会被挨个取出,并存到变量“n”中,“$(n).o”每次根据“$(n)”计算出一个值,这些值以空格分隔,最后作为foreach函数的返回,所以,$(files)的值是“a.o b.o c.o d.o”。
/ D, I% w+ X( \, c0 A9 @# y- c
7 q( H% c5 P6 x5 k注意,foreach中的参数是一个临时的局部变量,foreach函数执行完后,参数的变量将不在作用,其作用域只在foreach函数当中。. O7 h/ |9 b/ G# j- \# o
0 s7 ?, K/ U- Z( e
4 g3 _8 c' C e7 b五、if 函数& E# I2 a/ r! o# R& l. H# F
* d) x& Z( b5 Z
if函数很像GNU的make所支持的条件语句——ifeq(参见前面所述的章节),if函数的语法是:4 y. Y/ l5 H3 a. t/ m( Y) e Y
: m3 H+ A& O( E, I; m1 n4 _8 D
$(if ,) : P2 x. G2 c0 A& K$ `
8 C2 ^$ N# a1 f4 g& m0 {或是7 P5 y3 G& r+ ]' r' \" I
- p! z: _* h) V $(if
3 i/ w5 s6 S, _' m0 Z,,)
' P" A, y R3 e; t1 l: |% G
' | }7 z9 z" n0 [0 \4 m7 h可见,if函数可以包含“else”部分,或是不含。即if函数的参数可以是两个,也可以是三个。参数是if的表达式,如果其返回的为非空字符串,那么这个表达式就相当于返回真,于是,会被计算,否则会被计算。" z& g, a% m% v' t. j3 M4 `
- {# |6 J3 i* k; p q8 l$ W) G
而if函数的返回值是,如果为真(非空字符串),那个会是整个函数的返回值,如果为假(空字符串),那么会是整个函数的返回值,此时如果没有被定义,那么,整个函数返回空字串。
& S5 C/ m; l. C. D) N5 Y* _2 M) \1 H- u5 }4 K. \! d+ `9 \4 R2 `
所以,和只会有一个被计算。
4 T8 v0 N9 B# ~; C
1 @) j3 M( _4 e) @, y& U7 F) d2 ~: F8 r0 @
六、call函数9 U3 O+ D3 R4 l1 A. B7 q
8 S! P! l$ a" Y# s+ Y8 D. v8 mcall函数是唯一一个可以用来创建新的参数化的函数。你可以写一个非常复杂的表达式,这个表达式中,你可以定义许多参数,然后你可以用call函数来向这个表达式传递参数。其语法是:! X* b* n! G! Q- p" t3 i
4 a9 S+ m7 s) A8 f7 V
$(call
- p0 c1 F/ X) t,,,...)! d6 \, U" y* P, x. b
; h U( W* K+ `: N8 |当make执行这个函数时,参数中的变量,如$(1),$(2),$(3)等,会被参数,,依次取代。而的返回值就是call函数的返回值。例如:
, W% z# [) \3 W& R6 D, w reverse = $(1) $(2)
7 J* J/ r4 u' ~% W; \* \ foo = $(call reverse,a,b)" H. H0 f5 u0 C: Q0 @# y
那么,foo的值就是“a b”。当然,参数的次序是可以自定义的,不一定是顺序的,如:
/ }8 H7 n: w6 k# D/ |, H1 K5 b
, g d4 m; |# Y9 I/ ~ reverse = 3 ], ~% }3 E. _# [( F! R9 w; P
$(2) $(1) i1 w4 N5 c; F5 Z) E
foo = $(call reverse,a,b)% f7 R6 s5 Q0 _5 K% C9 ~; L% p
此时的foo的值就是“b a”。; J0 \2 k ]$ Q1 K+ y# @
H4 i" c9 W' n0 a9 ?
5 M3 J" I! o" ]七、origin函数& S9 F4 m( U: Q( m# c: ]9 p ~5 Q8 z
origin函数不像其它的函数,他并不操作变量的值,他只是告诉你你的这个变量是哪里来的?其语法是:2 a" Y# z) q( n& a- z2 r6 J
% Y* |& h* S. N" V) H $(origin )1 b$ \+ O( |+ j0 x( L+ j5 i: K
, S3 q% `( Z* A: d9 ~注意,是变量的名字,不应该是引用。所以你最好不要在中使用“$”字符。Origin函数会以其返回值来告诉你这个变量的“出生情况”,下面,是origin函数的返回值:
- N' V2 G; Z& j; o" B
% S4 w( s3 p5 b/ D" r" d“undefined”
1 Y: D M) H$ k" A& z1 ?6 H6 h 如果从来没有定义过,origin函数返回这个值“undefined”。
; x% U! U) j. y! n+ N- h- K* ]& m3 _# ~2 |# N: _* U' U
“default”
. e2 @, g. J) L' [1 J' m 如果是一个默认的定义,比如“CC”这个变量,这种变量我们将在后面讲述。
3 r9 @! ?4 w2 Y; @; O! ]7 M U$ |
" w2 p6 t A L! J% R$ Z/ ?“environment”* W# W. @! y0 B- g! N1 ^( s
如果是一个环境变量,并且当Makefile被执行时,“-e”参数没有被打开。; k% h: }; u9 v" U. R6 L7 q/ m
' \5 s9 ~ x# ?' L
“file”1 I; J+ G! Q& m. h6 \: Q2 `
如果这个变量被定义在Makefile中。
; w2 m- j$ Z+ v/ J+ H6 _
- B# J& Y, I0 P1 u. b“command
" Y) A7 A1 m4 Hline”
7 k- C" q ?# x( }! J 如果这个变量是被命令行定义的。
) b# ^; {8 C* V( x$ M2 ]# h
3 u2 f8 [9 g4 B$ F* L/ c/ }“override”
4 R, f: p8 D! L. } 如果是被override指示符重新定义的。. ~# m. {6 i& H* q! q" Q8 `
% a" n5 H8 K* J4 i; m, b) {2 Z“automatic”
1 l; s( \6 C5 N7 P& i$ |7 o 如果是一个命令运行中的自动化变量。关于自动化变量将在后面讲述。7 U; g6 x3 u1 Z
m7 X# ]5 K# T! H: K
这些信息对于我们编写Makefile是非常有用的,例如,假设我们有一个Makefile其包了一个定义文件Make.def,在Make.def中定义了一个变量“bletch”,而我们的环境中也有一个环境变量“bletch”,此时,我们想判断一下,如果变量来源于环境,那么我们就把之重定义了,如果来源于Make.def或是命令行等非环境的,那么我们就不重新定义它。于是,在我们的Makefile中,我们可以这样写:3 c9 C7 d: q0 y% Y
( y% {1 [+ w+ i; }0 U
ifdef bletch% Q2 f: U9 p& H
ifeq "$(origin bletch)"
3 u, ]/ w* ^7 \8 ^6 s" u, P& Y/ T"environment"
6 X2 ~* T# L6 c8 T" c bletch = barf, gag, etc.
: N2 H# y. J8 o endif) p t: q# O7 u- E7 ]
endif
! ~; N. b5 D- p9 T# c# g( X. }* |/ D7 b/ C5 |* N. J
当然,你也许会说,使用override关键字不就可以重新定义环境中的变量了吗?为什么需要使用这样的步骤?是的,我们用override是可以达到这样的效果,可是override过于粗暴,它同时会把从命令行定义的变量也覆盖了,而我们只想重新定义环境传来的,而不想重新定义命令行传来的。
" k9 }" g, `( P4 v3 U4 V( {% C5 d, `& t W# s9 D Z
% A7 W" y5 h$ G$ e% c; x& t A% a# T八、shell函数9 m" T6 X6 \" A* Z0 M4 h2 W
9 T- |7 u4 |- N h; f6 \$ pshell函数也不像其它的函数。顾名思义,它的参数应该就是操作系统Shell的命令。它和反引号“`”是相同的功能。这就是说,shell函数把执行操作系统命令后的输出作为函数返回。于是,我们可以用操作系统命令以及字符串处理命令awk,sed等等命令来生成一个变量,如:
8 y N7 I. _( t" X. f o$ p. J5 W; d
contents := $(shell cat foo)
' x# v5 t9 _/ a+ f$ k5 M
3 G7 x \% c6 N7 H) `/ m files := $(shell echo *.c)
* ?( K: {/ W7 y" A1 c
' e4 S* _; `! A2 |- T注意,这个函数会新生成一个Shell程序来执行命令,所以你要注意其运行性能,如果你的Makefile中有一些比较复杂的规则,并大量使用了这个函数,那么对于你的系统性能是有害的。特别是Makefile的隐晦的规则可能会让你的shell函数执行的次数比你想像的多得多。
* \6 b0 K' I Q8 S; p% l; K1 M n
Y3 R" C9 a2 _* |6 H* R) F, @ |
|