一乐电子

一乐电子百科

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

QQ登录

只需一步,快速开始

快捷登录

手机号码,快捷登录

搜索
查看: 2706|回复: 1
收起左侧

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

[复制链接]
发表于 2017-5-4 18:32 | 显示全部楼层 |阅读模式
在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; @
 楼主| 发表于 2017-5-4 18:33 | 显示全部楼层
在linux项目中,使用makefile来规定编译规则。
- ?% G' M5 c7 `  \- t- Tmakefile中如何调用到子目录下的makefile呢,有很多中方式。9 \+ a6 o( f. m- I  C
在这里,我要使用的是 -C/ T* ?4 }2 x8 b- U: u$ G

: ~7 \4 K1 {. w" Z: a, L 28458801_1414577793Z2n9.jpg
  n( f2 n/ U( n0 m 28458801_1414577808K1i9.jpg % l, ]! W- B. M5 p1 N1 p
5 [3 o8 ~  V( L. Q; `0 t! @
2 W! t( x9 ^# Z+ r9 m7 M
点击(此处)折叠或打开
7 H! L' G+ F2 Z' s5 r5 T
  • # ============= 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)". V# P; {+ l0 S0 ~
+ {+ V& O- v( t9 I( R/ S
7 y' x5 q  ^$ e
3 `& t0 T6 j8 g7 v% {7 ?7 N

8 V2 j' c! ]) @# ~3 W% @/ Q& ~* c! P  I

6 O0 I1 m8 v9 t- F! X
( x% x$ K) `- \5 z& ?
- y0 j6 O. E: S+ S5 E+ V) F$ H+ z+ S! @% D- L! i% [

本版积分规则

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

GMT+8, 2024-4-26 07:52 , Processed in 0.056557 second(s), 27 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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