一乐电子

 找回密码
 请使用微信账号登录和注册会员

QQ登录

只需一步,快速开始

微信扫码登录

手机号码,快捷登录

手机号码,快捷登录

搜索
查看: 5447|回复: 1

Makefile中常用的函数----特别是MAKE -C

[复制链接]
发表于 2017-5-4 18:32 | 显示全部楼层 |阅读模式
在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
 楼主| 发表于 2017-5-4 18:33 | 显示全部楼层
在linux项目中,使用makefile来规定编译规则。
. P" W1 H  M7 K2 k. L! Z  i% l4 _5 cmakefile中如何调用到子目录下的makefile呢,有很多中方式。
8 c$ ?* m% [/ K1 x! ~. _在这里,我要使用的是 -C- a  U2 N) q3 w: C4 k7 e+ s6 w4 G

, G) D6 ]! n( w$ A' e) I$ J# h 28458801_1414577793Z2n9.jpg
- D/ t: f0 X4 Y% `3 v 28458801_1414577808K1i9.jpg ' a) A: b3 ~7 n( H+ M2 x
* n( M8 {& b( v

1 W% G: V! t' i+ \; H" d- a' q* M
点击(此处)折叠或打开

* ?; X6 w  a% k: K7 N  p
  • # ============= lib compile option ===========#
  • LIB_TARGET := libzbar.a
  • EXP_LIB_INC := $(IMP_INC_DIR)/zbar
  • LIB_SRC := $(PWD)/zbar
  • LIB_CFLAGS := $(ARCH_FLAGS) -fstack-protector -Wall -Wno-parentheses -I$(IMP_INC_DIR) -I$(EXP_LIB_INC) -I$(IMP_TARGET_DIR)
  • LIB_CPPFLAGS:=$(LIB_CFLAGS)
  • LIB_LDFLAGS := -lpthread -L$(PWD)/zbar -lrt -fPIC $(EX_LDFLAGS)
  • # ---------------------------------------------#
  • LIB_MAKE_PARAM := -C $(LIB_SRC)
  • TARGET=$(LIB_TARGET)
  • EXPORT_INC_FILE="$(PWD)/zbar/zbar_interface.h"
  • EXPORT_TARGET_DIR=$(EXP_TARGET_DIR)
  • EXPORT_INC_DIR=$(EXP_INC_DIR)
  • CFLAGS="$(LIB_CFLAGS)"
  • CXXFLAGS="$(LIB_CFLAGS)"
  • LDFLAGS="$(LIB_LDFLAGS)"3 n9 H: i6 J( x9 O

1 N5 z! V* `/ [. m" t; K# p" [2 W, q  f+ a" ~$ {. R# K7 w
! i8 [: X" @6 p6 r' o+ c. U/ s
( Y( [5 g! t# k8 D, O  M

! Y+ _5 B7 d( p: X) z* p5 d: B' K
/ U' D; p# J5 y( r- ?

! G! x& Q  P* \! e/ ~0 O: h/ [( O0 S

0 k' O: f  n% T3 S+ O% Z1 |4 q
回复

使用道具 举报

本版积分规则

QQ|一淘宝店|手机版|商店|一乐电子 ( 粤ICP备09076165号 ) 公安备案粤公网安备 44522102000183号

GMT+8, 2026-4-17 16:27 , Processed in 0.041827 second(s), 23 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表