版主
主题
回帖0
积分10609
阅读权限200
注册时间2008-11-22
最后登录1970-1-1
在线时间 小时
|
在Makefile中可以使用函数来处理变量,从而让我们的命令或是规则更为的灵活和具有智能。make所支持的函数也不算很多,不过已经足够我们的操作了。函数调用后,函数的返回值可以当做变量来使用。1 L* N4 k4 c0 T: h4 G
一、函数的调用语法
- x8 R) {- v% I* B函数调用,很像变量的使用,也是以“$”来标识的,其语法如下:
( j& s6 O9 y) h8 S; ~( {% { $(
7 k o) W4 w3 }9 w! Z# u% q! h)/ H! a2 o# `) f- S+ X& r
或是
& g7 V B$ c4 n" c& X: S2 } ${7 j1 E; H+ o- q$ l& F
}
" P/ d9 F& n6 t) l3 T这里,就是函数名,make支持的函数不多。是函数的参数,参数间以逗号“,”分隔,而函数名和参数之间以“空格”分隔。函数调用以“$”开头,以圆括号或花括号把函数名和参数括起。感觉很像一个变量,是不是?函数中的参数可以使用变量,为了风格的统一,函数和变量的括号最好一样,如使用“$(subst
' R& p2 k6 c3 S v) ua,b,$(x))”这样的形式,而不是“$(subst a,b,${x})”的形式。因为统一会更清楚,也会减少一些不必要的麻烦。
7 J$ ~9 x2 S. r2 q$ I4 r! j还是来看一个示例:8 Q8 Q! d! N1 \1 Y# z5 p
comma:= ,
" q7 F* C9 t3 z- H) C8 @ empty:=
5 \1 ~5 |) W; B9 x- ^5 ]6 e space:= $(empty) $(empty)5 u" o* k: G# R/ |
foo:= a b c: e- w y: G# I t3 S* i r' d
bar:= $(subst $(space),$(comma),$(foo))
0 ^) m7 F* ?- J7 S; j+ X, g在这个示例中,$(comma)的值是一个逗号。$(space)使用了$(empty)定义了一个空格,$(foo)的值是“a b c”,$(bar)的定义用,调用了函数“subst”,这是一个替换函数,这个函数有三个参数,第一个参数是被替换字串,第二个参数是替换字串,第三个参数是替换操作作用的字串。这个函数也就是把$(foo)中的空格替换成逗号,所以$(bar)的值是“a,b,c”。
8 m8 H) O" R- d& k% s5 Z二、字符串处理函数
, u$ A, m1 Q9 h$(subst: P7 S3 j# P: y
,,)
4 y& E- o9 ~5 }4 s5 x4 M1 i 名称:字符串替换函数——subst。
9 L+ W/ l2 i, n* M4 t 功能:把字串中的字符串替换成。
) S5 i/ C3 m7 n2 | 返回:函数返回被替换过后的字符串。9 X8 V! [+ C5 j0 P( u# U' ]1 l! L: I$ I
示例:
& ^3 ?6 t+ R6 F6 O @
0 [& `2 G4 p) K9 M' P* e, @ $(subst ee,EE,feet on the street), `% P9 I. V8 A8 _. H
1 m; O. H7 t: {( H: u! m 把“feet on the street”中的“ee”替换成“EE”,返回结果是“fEEt; D- _" t" `3 w0 C5 x! ~
on the strEEt”。- ~( H: J5 m2 c' {9 B% s ]# n/ F
$(patsubst ,,)
( W3 [6 |- r; R8 n7 U 名称:模式字符串替换函数——patsubst。
: J+ I6 o* E2 Z: V 功能:查找中的单词(单词以“空格”、“Tab”或“回车”“换行”分隔)是否符合模式,如果匹配的话,则以替换。这里,可以包括通配符“%”,表示任意长度的字串。如果中也包含“%”,那么,中的这个“%”将是中的那个“%”所代表的字串。(可以用“\”来转义,以“\%”来表示真实含义的“%”字符)
" d9 \* j4 ]1 a9 b 返回:函数返回被替换过后的字符串。3 e* i8 T3 Z6 p. @+ J7 O/ f
示例:3 W. h' q. K5 d% E, b% Q$ O
( O. L, z3 `5 V- F: a% V9 w$(patsubst %.c,%.o,x.c.c bar.c)
* V9 I z" l! L/ E% V: S 把字串“x.c.c. \/ w5 ^9 R! P2 V- G
bar.c”符合模式[%.c]的单词替换成[%.o],返回结果是“x.c.o
( | I m. ?2 [6 }% \ Hbar.o”
; \$ g u) [& f( f2 g. v; B 备注:
/ L; \! q! d& e. I* t+ L. ] 这和我们前面“变量章节”说过的相关知识有点相似。如:3 ^$ J6 A" v1 V! h
“$(var:=)”' u' x( e/ V( c+ g: H" [
相当于
2 E$ g# U9 O3 R) y7 i “$(patsubst3 |$ S/ q, N1 a7 u6 i( E
,,$(var))”,+ }3 X1 z5 a4 `
而“$(var:
0 ]5 F. i* t6 e2 M( J=)”
9 e, P" K8 ]; m& n 则相当于
: Q! Y1 \, I0 G$ m# S6 A “$(patsubst
5 n4 I) N z" }8 M% P+ f5 H%,%,$(var))”。
' i# C) A2 F8 q; {' e( G' B# q 例如有:objects = foo.o* l4 F5 F% V+ G/ |9 |1 z4 t
bar.o baz.o,+ S$ D7 b+ |) j3 K! u# E$ W( D
那么,“$(objects:.o=.c)”和“$(patsubst. e9 p# F, ^' q$ n% U" N
%.o,%.c,$(objects))”是一样的。) v- |/ X, r5 `6 N. y8 P& ^) S
$(strip )$ N! y( ]# x1 {& D7 B
名称:去空格函数——strip。
1 a3 x" s! D* I 功能:去掉字串中开头和结尾的空字符。
: K9 T8 A o1 n6 ^9 [/ v8 f% u( N8 i 返回:返回被去掉空格的字符串值。; ^7 ]8 J- ]3 U* V
示例:/ {6 {# I( M" d) M
' O: n4 {* f2 [5 x* m
$(strip a b c )% ?. a) n% C6 @- ]1 z" a* p4 j& Y2 {
把字串“a b X/ a: B3 T3 T1 E" l
c ”去到开头和结尾的空格,结果是“a b c”。/ B+ y/ U o3 b, V6 A; G+ P* _+ {
$(findstring ,)
9 m0 Y8 y( O* I" ?2 j* ` 名称:查找字符串函数——findstring。0 _/ t" l3 H6 F- G6 b' N
功能:在字串中查找字串。+ |. N- q; {7 r! G* s9 }
返回:如果找到,那么返回,否则返回空字符串。
: p3 d6 ~! f: N, Q% g, h& Z 示例:- I7 T0 b; _! L( o% d3 ]
+ p8 l9 V- n1 s# b5 r* {, ]/ T$(findstring a,a b c)
- _0 \' k5 N! C$ [! F $(findstring a,b c)
: A- Y8 G7 C7 E$ ?8 m+ P2 ?* D 第一个函数返回“a”字符串,第二个返回“”字符串(空字符串)
e5 Z+ h* w. N6 [4 q$(filter
9 j8 N$ V. d( H1 R5 ?, A0 v' g$ W- L,)
3 B- s+ S: S5 C5 c {- k' _4 E3 N 名称:过滤函数——filter。
* p9 H! y1 w. ?0 J. w 功能:以模式过滤字符串中的单词,保留符合模式的单词。可以有多个模式。
) T" d# p$ Y) l( Z* l+ _* x 返回:返回符合模式的字串。
1 L0 R8 B7 @5 ?$ b* T3 b3 k 示例:7 a4 k9 r5 E2 ]( L9 H ?
sources
# t% W, Q$ m' T$ {" y4 i. n+ U. y:= foo.c bar.c baz.s ugh.h
6 z! D$ u+ N: c0 q1 M; f# a foo: $(sources)1 S5 x( `2 E }
$ f# r9 [- w0 R* ~4 h! O. v9 bcc $(filter %.c %.s,$(sources)) -o foo. e5 s0 R J1 N' C) ^
p; S6 j2 t3 U( r6 e6 [+ l$(filter %.c %.s,$(sources))返回的值是“foo.c bar.c baz.s”。. u4 U) Y( M: X/ E; P2 R! m, p2 } J
$(filter-out W$ h7 s% ]3 Y* J
,)
' d8 m1 l! q1 _( K1 c6 H _( A0 L 名称:反过滤函数——filter-out。
/ k8 b: C2 j9 I- D4 E+ ] 功能:以模式过滤字符串中的单词,去除符合模式的单词。可以有多个模式。
+ F: v8 V5 O1 J: F4 v 返回:返回不符合模式的字串。
) ~: x* p+ b ^ 示例:
8 }/ l. Y; T E1 t
% t0 d1 m( G. K3 v) yobjects=main1.o foo.o main2.o bar.o
7 y, H/ y `' @, r( s1 i mains=main1.o main2.o* W, B0 D4 @- S. _/ P* F- @+ ?
7 Z+ X+ ^# z/ s9 m5 c7 u& z' @ $(filter-out $(mains),$(objects)) 返回值是“foo.o5 u4 `7 r2 }6 F4 G6 R' _
bar.o”。+ E+ l7 X$ i. B
6 a& j- ]2 S" @9 N$(sort )
* \6 _; b. x( c. ^+ P3 r. g名称:排序函数——sort。功能:给字符串中的单词排序(升序)。返回:返回排序后的字符串。示例:$(sort foo bar lose)返回“bar foo lose”。备注:sort函数会去掉中相同的单词。
; \. _# b5 r5 ~( ?4 I6 U/ q- {% j$(word ,)9 s A3 a" Z" k7 {( u
名称:取单词函数——word。功能:取字符串中第个单词。(从一开始)返回:返回字符串中第个单词。如果比中的单词数要大,那么返回空字符串。示例:$(word 2, foo bar baz)返回值是“bar”。
9 a1 K2 E7 r' n8 a$(wordlist
3 G1 D0 c2 D- ~; t$ f; n7 ^,,) : G" n3 G. a: n9 u
名称:取单词串函数——wordlist。
2 v+ ]" K3 M( B" R' d; f* |6 Z$ ] N 功能:从字符串中取从开始到的单词串。和是一个数字。
- A5 g/ }5 m! G7 O( { 返回:返回字符串中从到的单词字串。如果比中的单词数要大,那么返回空字符串。如果大于的单词数,那么返回从开始,到结束的单词串。
8 ]; t( E5 k! C7 b. j$ x' _2 w 示例: $(wordlist 2, 3, foo bar baz)返回值是“bar5 o [, e: J5 f4 Y0 a1 c$ u
baz”。( ^2 a# c2 Z8 u9 h
$(words )4 ^, N5 O) v3 X- B) R
名称:单词个数统计函数——words。
+ g; ^: h5 c3 g, K& H) P3 k 功能:统计中字符串中的单词个数。7 H* x& ]+ c7 o, X6 w8 o& S
返回:返回中的单词数。
* f9 h1 @# r* n% V2 j h6 g7 H 示例:$(words, foo bar baz)返回值是“3”。! Z; J% \- r+ P7 d! b
备注:如果我们要取中最后的一个单词,我们可以这样:$(word& {, L' C( Z/ S% R/ i% A
$(words ),)。, s) f2 W! c! p! g: Z6 u
$(firstword )
$ U3 E; O2 i9 Y8 d' @, d' e; K 名称:首单词函数——firstword。; N, h: G, m* E% |* }6 x
功能:取字符串中的第一个单词。1 x7 c& u \- B0 K U; X
返回:返回字符串的第一个单词。1 Y7 D ^8 m5 V$ V- z4 L, J
示例:$(firstword foo bar)返回值是“foo”。: r0 j9 z. F$ W7 d& ]4 x5 [6 p0 e
备注:这个函数可以用word函数来实现:$(word& R1 I/ z- h6 M8 q
1,)。
3 x1 S) G! ?3 y" |" C; k以上,是所有的字符串操作函数,如果搭配混合使用,可以完成比较复杂的功能。这里,举一个现实中应用的例子。我们知道,make使用“VPATH”变量来指定“依赖文件”的搜索路径。于是,我们可以利用这个搜索路径来指定编译器对头文件的搜索路径参数CFLAGS,如:
) @: N- x$ _; |/ ]/ Z$ o override CFLAGS += $(patsubst
$ p! t" j' Q- A' G* k1 O% J%,-I%,$(subst :, ,$(VPATH))); O/ B" j% B: k" g
如果我们的“$(VPATH)”值是“src:../headers”,那么“$(patsubst
8 @% |) c8 D! g%,-I%,$(subst :, ,$(VPATH)))”将返回“-Isrc -I../headers”,这正是cc或gcc搜索头文件路径的参数。1 y7 ~ f: q- |
三、文件名操作函数- T" W+ t1 w+ h0 y! j
下面我们要介绍的函数主要是处理文件名的。每个函数的参数字符串都会被当做一个或是一系列的文件名来对待。
. B6 p# h4 c$ b. r4 m ?. m$(wildcard )! ?/ D) c5 E! d2 [4 A. S
名称:文件名展开函数——wildcard 。; r1 I) v- d& m, {
功能:功能是展开成一列所有符合由其参数描述的文件名,文件间以空格间隔。* a1 K1 r, B2 `
返回:函数返回展开后的文件名列表。
! U1 d; W- G! `5 ~ 8 r" g' C: m7 @: t. ]; a
示例:3 m( H5 }8 @! z3 q' z* O+ w" ^6 i, `
* T$ T4 M# g3 b* K7 Z2 v $(wildcard *.c)+ `" L4 [6 v. Z- C- n- c
5 e' [4 g, R1 d4 u 返回结果是一个所有以 '.c' 结尾的文件的列表。 / d6 h- V' ]2 A- l* ~0 u
$(dir )
) ?" x' B0 f7 G# F) }+ s 名称:取目录函数——dir。9 n! q; } U. a2 m
功能:从文件名序列中取出目录部分。目录部分是指最后一个反斜杠(“/”)之前的部分。如果没有反斜杠,那么返回“./”。8 k8 S! v2 I. J* }, m- O" [3 }
返回:返回文件名序列的目录部分。+ U% H" S% J4 \+ C
示例: $(dir src/foo.c hacks)返回值是“src/2 w _* _3 E9 g
./”。
6 s6 E+ D1 U. V$(notdir ) $ h% |' E4 T8 O- [- Y) n! Y+ g! A
名称:取文件函数——notdir。5 y9 N( W% h. C( d- v+ G3 X) g
功能:从文件名序列中取出非目录部分。非目录部分是指最后一个反斜杠(“/”)之后的部分。6 A- i- }. m7 H1 M# o
返回:返回文件名序列的非目录部分。
- T _2 k5 m1 s; ]1 ^( K# e/ I5 R8 u 示例: $(notdir src/foo.c hacks)返回值是“foo.c2 @6 z( }3 C( z
hacks”。' ~+ v [' U0 A5 o* Q1 I
6 x' k/ h- y: o1 n* C3 `1 N
$(suffix ) ; G( f% L) Y6 d( L+ w
$ }# I% e7 x$ M% @9 w6 x1 t
名称:取后缀函数——suffix。6 h. H( P% H% {5 t/ b! F6 V
功能:从文件名序列中取出各个文件名的后缀。
" z! t T+ B( J% i, ^8 E 返回:返回文件名序列的后缀序列,如果文件没有后缀,则返回空字串。
, i' Q6 L2 d2 [1 W8 K* L 示例:$(suffix src/foo.c src-1.0/bar.c hacks)返回值是“.c. ~7 X; Z. }' G3 Q5 C, i6 ~
.c”。7 a2 a, Y5 P3 Y9 H" Z! A" M
$(basename )
; I# w0 H3 j7 a4 N! i3 i- z 名称:取前缀函数——basename。
' S7 ~) Y4 r) L: z4 A% R. J 功能:从文件名序列中取出各个文件名的前缀部分。7 n2 P+ N p4 d2 w% B
返回:返回文件名序列的前缀序列,如果文件没有前缀,则返回空字串。$ Z5 ]3 u/ U4 A4 y5 t2 u6 J2 x5 f7 s d* Q
示例:$(basename src/foo.c src-1.0/bar.c hacks)返回值是“src/foo4 [6 U& A$ ~% b; ~ L+ ]# [
src-1.0/bar hacks”。0 o* T! R* ^' s8 \5 [; y9 |: H
$(addsuffix# y( e j- N; Y4 y
,) - ]# P4 m0 g0 N+ v7 i W( |( @
名称:加后缀函数——addsuffix。 a% W; h# X4 ]# ?2 w3 V0 q0 S
功能:把后缀加到中的每个单词后面。2 O( X: M) u. \% A+ ]
返回:返回加过后缀的文件名序列。
6 C$ y/ @: v& n* P" M; [ 示例:$(addsuffix .c,foo bar)返回值是“foo.c
0 E* q/ p% R) w8 e/ k2 ubar.c”。3 @( _, q- e- \# s
$(addprefix. T# ?6 V& _! V6 k3 J, D
,)
& T0 v" Y% a- t3 j 名称:加前缀函数——addprefix。' M7 ^6 z7 K9 z
功能:把前缀加到中的每个单词后面。. x. S8 v ]3 n/ T+ F
返回:返回加过前缀的文件名序列。
3 q7 q. K; l4 }8 v8 D9 J6 J: V' Z 示例:$(addprefix src/,foo bar)返回值是“src/foo4 c. \) r3 h4 Y1 A
src/bar”。, F/ f% A, u5 }/ I
$(join ,)# o0 U2 k: P1 I9 P
名称:连接函数——join。8 D( \- `2 Q& p# ^9 B5 Q# s9 A u
功能:把中的单词对应地加到的单词后面。如果的单词个数要比的多,那么,中的多出来的单词将保持原样。如果的单词个数要比多,那么,多出来的单词将被复制到中。3 V n$ I* y3 o( W1 g6 G7 l& O8 c
返回:返回连接过后的字符串。
2 D+ d5 z8 m( ]+ C6 N" \: Z- y 示例:$(join aaa bbb , 111 222 333)返回值是“aaa111( i4 b% S: z1 q! @, ~# d7 Q7 g. K( w) Q
bbb222 333”。% T/ w6 c2 `0 I5 K4 k* C' Y
1 {4 ?$ ^& O N% X- z& O3 g9 H
四、foreach 函数
: H& P6 ]5 U) E, o3 N5 W
3 w, i+ `8 R/ m! c# W( F3 J" d* h+ {' Rforeach函数和别的函数非常的不一样。因为这个函数是用来做循环用的,Makefile中的foreach函数几乎是仿照于Unix标准Shell(/bin/sh)中的for语句,或是C-Shell(/bin/csh)中的foreach语句而构建的。它的语法是:
: {( j+ j6 M6 m
# T: S! d& R, P' A7 v7 _ $(foreach
) t& n5 |0 v: M J,,)
3 c! Q: t; K0 a5 m$ q8 J" D7 U
$ x; K" C: c* s: w- e+ }2 e' Q这个函数的意思是,把参数中的单词逐一取出放到参数所指定的变量中,然后再执行所包含的表达式。每一次会返回一个字符串,循环过程中,的所返回的每个字符串会以空格分隔,最后当整个循环结束时,所返回的每个字符串所组成的整个字符串(以空格分隔)将会是foreach函数的返回值。/ G8 R+ j- I* g. ?5 g3 P
, p, P! s8 u% Y! g1 v* p1 y
所以,最好是一个变量名,可以是一个表达式,而中一般会使用这个参数来依次枚举中的单词。举个例子: {7 D) |' r# g
/ i4 N p2 ^1 E0 O- ~3 C6 _4 k names := a b c d
: _ s6 C0 s/ Q- T( R& i files := $(foreach n,$(names),$(n).o)2 w$ r8 r: P; n0 A; j6 P. g, u
$ Z+ p) Y$ O; ~/ t: b B" G& K上面的例子中,$(name)中的单词会被挨个取出,并存到变量“n”中,“$(n).o”每次根据“$(n)”计算出一个值,这些值以空格分隔,最后作为foreach函数的返回,所以,$(files)的值是“a.o b.o c.o d.o”。
4 S2 m% F4 ]! D( s0 M
6 z' S$ O0 |0 c2 [" n注意,foreach中的参数是一个临时的局部变量,foreach函数执行完后,参数的变量将不在作用,其作用域只在foreach函数当中。
( M* W+ N* b, P, r: Z& w. a% z; o8 X' ?3 {7 B' J h
4 g A- K& e4 i* e
五、if 函数: y4 I- `/ b- d# L: `( T; W+ M8 Q
" S& c) I) l) M$ _, g/ B
if函数很像GNU的make所支持的条件语句——ifeq(参见前面所述的章节),if函数的语法是:
8 Q& ^. @2 x% I7 e( I7 k8 ?1 U' l9 x) ?4 p
$(if ,)
2 [ _ k8 w# _! [! {0 M+ `# ^7 @! X# I5 k
或是
5 t& N4 N" H4 ]& N) T9 H
8 \ d! x1 e5 g8 g4 p $(if( f/ k; k6 _ p. m: `9 f
,,)
M: g, Y. x+ p" s4 i1 L( f" r) c5 n. g0 E& Y7 i8 D( B$ U
可见,if函数可以包含“else”部分,或是不含。即if函数的参数可以是两个,也可以是三个。参数是if的表达式,如果其返回的为非空字符串,那么这个表达式就相当于返回真,于是,会被计算,否则会被计算。: V5 n! l, N4 G" C
! p) k8 Q' X2 F' T7 B而if函数的返回值是,如果为真(非空字符串),那个会是整个函数的返回值,如果为假(空字符串),那么会是整个函数的返回值,此时如果没有被定义,那么,整个函数返回空字串。2 a) q7 e1 f7 G5 \+ N
! c1 Y# i$ w! D r+ ^
所以,和只会有一个被计算。
1 |3 J( d! `* K, \2 w5 d* D# `% s
9 ]* [! ^ Y \ u8 l; G4 J: Q$ f2 g1 _' U2 |) r( ]
六、call函数
) v6 [ h. B* ~3 D/ Q: L! b3 l, u" W" z+ a
call函数是唯一一个可以用来创建新的参数化的函数。你可以写一个非常复杂的表达式,这个表达式中,你可以定义许多参数,然后你可以用call函数来向这个表达式传递参数。其语法是:' V! o8 m/ T$ a* \* @
1 x, g7 M0 c2 g# X $(call
6 w& H" j# Q. ~+ d$ ~ b, b* Y- k,,,...)
& e2 L7 ^# f: [; ^
! i2 Q+ G% b" a! K9 j当make执行这个函数时,参数中的变量,如$(1),$(2),$(3)等,会被参数,,依次取代。而的返回值就是call函数的返回值。例如:, m) E9 K, n; K; L2 O, F9 u
reverse = $(1) $(2)
2 f4 B' E; A A, P% ~5 Q foo = $(call reverse,a,b)
# I& ^) o" M: B4 C那么,foo的值就是“a b”。当然,参数的次序是可以自定义的,不一定是顺序的,如:
5 k0 f1 F5 A; H7 A+ l- x; Q( _3 j: D5 x) I
reverse = 6 G0 P; z% I% a2 W
$(2) $(1) {4 l2 l$ ~$ `! O Z' J3 A; k: M, Q5 G; U9 g
foo = $(call reverse,a,b)" G }% U7 O/ D& o
此时的foo的值就是“b a”。
) @0 Y% }" n9 a* R
1 Y0 T& I8 A ?; ~" s
) F6 e9 y; t6 R七、origin函数4 @2 h% c% k7 b: @0 F1 w3 n3 S
origin函数不像其它的函数,他并不操作变量的值,他只是告诉你你的这个变量是哪里来的?其语法是:
5 C8 V# b4 v; v* R# r- V8 |( s( B( W" ^1 w5 m5 t! R
$(origin )+ x: a1 S: v5 w* @
* [1 w, t( M1 F; W. H0 Q; A# J
注意,是变量的名字,不应该是引用。所以你最好不要在中使用“$”字符。Origin函数会以其返回值来告诉你这个变量的“出生情况”,下面,是origin函数的返回值:
- U3 I' I" g+ u- u$ t* v
! Z. K( {: Y; O5 L0 k“undefined”5 p4 z& P3 k: |: x0 ~1 m: }/ t
如果从来没有定义过,origin函数返回这个值“undefined”。
: v) b( L$ t$ R0 w7 z: W2 k
9 w# o/ J2 q# u; y' V4 O$ y1 K“default”: w. C1 M6 J! b1 @9 `
如果是一个默认的定义,比如“CC”这个变量,这种变量我们将在后面讲述。( I& x' s2 L" g1 e2 v3 b
( K9 u! f! _. ?$ i. ~/ P! C/ g
“environment”
/ Y1 l; k7 w# g. R9 ?1 o$ a: k 如果是一个环境变量,并且当Makefile被执行时,“-e”参数没有被打开。& Y$ {4 X. |8 S) b. m
, f$ r w \, i0 S8 w: o
“file”% w! }' H: M: [' l% Y/ n
如果这个变量被定义在Makefile中。
9 I( R" I; F. ^$ E& |/ A7 o E" \" e" y& Q3 e. T
“command
0 {0 ]% k- r" n8 s( D+ O6 l3 fline”$ r4 d; Z) u/ ^+ ]% E+ V
如果这个变量是被命令行定义的。
# C" ?1 \% H! G1 E4 m1 z8 G+ R
5 O5 Q# s) i/ a0 E" u“override”# Z3 a2 l1 A$ W! k. e5 p! v( S
如果是被override指示符重新定义的。& b7 A" y7 F( {
" D8 N+ g, p4 U* B w“automatic”
, _; z6 e5 P( k1 ^5 O 如果是一个命令运行中的自动化变量。关于自动化变量将在后面讲述。+ q2 Y7 \0 Y3 \/ D9 j1 F9 V
( O0 D8 ?- [& Z! [+ _这些信息对于我们编写Makefile是非常有用的,例如,假设我们有一个Makefile其包了一个定义文件Make.def,在Make.def中定义了一个变量“bletch”,而我们的环境中也有一个环境变量“bletch”,此时,我们想判断一下,如果变量来源于环境,那么我们就把之重定义了,如果来源于Make.def或是命令行等非环境的,那么我们就不重新定义它。于是,在我们的Makefile中,我们可以这样写:7 {2 ?% n* E2 K7 E: i
) o7 |( j8 k1 v( b) s2 J; C3 k; v ifdef bletch; I4 ?* W1 J* d
ifeq "$(origin bletch)"
7 S" s0 L: p6 M3 G0 u, b"environment"* a- b" D7 P8 l
bletch = barf, gag, etc.3 V4 ^8 p& f( e8 F+ U7 J% s
endif
. O, v3 R7 g9 q' M% i4 V endif$ H; y! t% i8 w5 |+ k( a9 h+ }
( y3 h4 v1 X- M
当然,你也许会说,使用override关键字不就可以重新定义环境中的变量了吗?为什么需要使用这样的步骤?是的,我们用override是可以达到这样的效果,可是override过于粗暴,它同时会把从命令行定义的变量也覆盖了,而我们只想重新定义环境传来的,而不想重新定义命令行传来的。5 o. \* K H3 D! v( W
4 h2 p5 A l. `! S# @' \3 [+ }
( C, s! {6 j. p% D# z. n& V八、shell函数" I# {" \! U- V% _! A- J9 p, w
- B! S! w" h8 W$ ^' s. Y
shell函数也不像其它的函数。顾名思义,它的参数应该就是操作系统Shell的命令。它和反引号“`”是相同的功能。这就是说,shell函数把执行操作系统命令后的输出作为函数返回。于是,我们可以用操作系统命令以及字符串处理命令awk,sed等等命令来生成一个变量,如:
+ U! x+ K- T9 [. m7 u" V6 b4 }4 f$ q( z: Y' {
contents := $(shell cat foo)
$ t C+ s- `" c. W/ h
e* q- f- k2 t% r9 H0 J* v# p files := $(shell echo *.c)) U, R! I) V$ ?* z& ?+ B6 f
0 {( W0 l; y! a# F* A
注意,这个函数会新生成一个Shell程序来执行命令,所以你要注意其运行性能,如果你的Makefile中有一些比较复杂的规则,并大量使用了这个函数,那么对于你的系统性能是有害的。特别是Makefile的隐晦的规则可能会让你的shell函数执行的次数比你想像的多得多。9 E( k+ g" d9 }/ L
# k' s: f; A, }( \% A1 n$ C4 F |
|