一乐电子

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

QQ登录

只需一步,快速开始

微信扫码登录

手机号码,快捷登录

手机号码,快捷登录

搜索
查看: 5665|回复: 1

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

[复制链接]
发表于 2017-5-4 18:32 | 显示全部楼层 |阅读模式
在Makefile中可以使用函数来处理变量,从而让我们的命令或是规则更为的灵活和具有智能。make所支持的函数也不算很多,不过已经足够我们的操作了。函数调用后,函数的返回值可以当做变量来使用。
/ g8 t# I& r/ i: l6 Q9 M5 W一、函数的调用语法
4 n; J7 g! @& o0 a1 x! v& L4 K: f函数调用,很像变量的使用,也是以“$”来标识的,其语法如下:
; w3 f. @3 R9 J( ]' S9 b4 S' |    $(
+ B/ ~/ c0 U' t% })! \# C# _" j; S  B" d% {0 D
或是
. S. i2 k" C& h  T    ${+ T- g6 h; `' l& a) a
}
. K. W1 T' D. a! ^% R  ?' ?& s这里,就是函数名,make支持的函数不多。是函数的参数,参数间以逗号“,”分隔,而函数名和参数之间以“空格”分隔。函数调用以“$”开头,以圆括号或花括号把函数名和参数括起。感觉很像一个变量,是不是?函数中的参数可以使用变量,为了风格的统一,函数和变量的括号最好一样,如使用“$(subst
7 }' B; q9 z7 F2 a8 X; m! @a,b,$(x))”这样的形式,而不是“$(subst a,b,${x})”的形式。因为统一会更清楚,也会减少一些不必要的麻烦。- ?& u' W5 o( M, l. O, r
还是来看一个示例:
; q3 c. e; [1 _% @+ V0 C& v5 Z    comma:= ,
2 ]3 L' F, f. n; k    empty:=
* A9 }* B9 _& p' X& T; o2 k8 ~8 l. y    space:= $(empty) $(empty)" r/ H% E  i4 r! a/ Z. Q/ E2 E
    foo:= a b c! p7 ]$ r6 |7 W5 v: l5 }4 b
    bar:= $(subst $(space),$(comma),$(foo))# U, @  W3 i1 ~% h0 R) m
在这个示例中,$(comma)的值是一个逗号。$(space)使用了$(empty)定义了一个空格,$(foo)的值是“a b c”,$(bar)的定义用,调用了函数“subst”,这是一个替换函数,这个函数有三个参数,第一个参数是被替换字串,第二个参数是替换字串,第三个参数是替换操作作用的字串。这个函数也就是把$(foo)中的空格替换成逗号,所以$(bar)的值是“a,b,c”。6 B6 f; A; C4 K# M) `' @0 P
二、字符串处理函数
/ x( m& Q( B& Z" w" j1 P$(subst
% V) I; h  ^$ f# b% e+ D+ a,,)
0 {( ]" ~% K4 d/ \: V
    名称:字符串替换函数——subst。
, W2 A$ p8 A4 b! O- k    功能:把字串中的字符串替换成。" c2 O$ V& T) h& m, W8 i; I; b
    返回:函数返回被替换过后的字符串。
2 Q# s4 i- A$ C' w  k( T' k    示例:4 X) e8 C! @7 e) y6 t# u
        : g0 d8 v. u9 C6 y! ]  ^
        $(subst ee,EE,feet on the street),. o" }4 l/ d. V- @4 l' s+ y
        
" A4 M. F: F4 n2 Z* k        把“feet on the street”中的“ee”替换成“EE”,返回结果是“fEEt3 r8 ^/ d& b" X/ K' P' K8 k6 P
on the strEEt”。
& c5 T4 y9 d* {! _+ D" o$(patsubst ,,) + h8 S6 ^2 d! d& o* w& i  l
    名称:模式字符串替换函数——patsubst。7 v8 |) Z; Y9 a
    功能:查找中的单词(单词以“空格”、“Tab”或“回车”“换行”分隔)是否符合模式,如果匹配的话,则以替换。这里,可以包括通配符“%”,表示任意长度的字串。如果中也包含“%”,那么,中的这个“%”将是中的那个“%”所代表的字串。(可以用“\”来转义,以“\%”来表示真实含义的“%”字符)  u5 _& W0 V1 u* e) R
    返回:函数返回被替换过后的字符串。
- \3 V6 t3 S+ k1 l) |2 H5 z    示例:
: @9 v* [; a: m+ w0 t0 y      
6 h5 F! o* _2 H$ P! U$(patsubst %.c,%.o,x.c.c bar.c)* n8 n  {0 U( b# s% p
        把字串“x.c.c. s& V' i- I! T3 X  ^+ R+ H' o
bar.c”符合模式[%.c]的单词替换成[%.o],返回结果是“x.c.o0 n0 S0 Z+ W0 c  i1 c
bar.o”/ P/ B' U8 s0 t4 A
    备注:
6 N! J& t& a2 Q1 X% H        这和我们前面“变量章节”说过的相关知识有点相似。如:( }2 q5 [' l% I: t0 E+ B0 y
        “$(var:=)”$ Y3 [, D7 o0 }
         相当于' s5 u/ x! C# ~) y. r3 |; W
        “$(patsubst2 O" o9 {* \3 f' v9 v4 i- z2 l
,,$(var))”,
( w2 l8 }2 J, g$ ^2 x         而“$(var:
. P% Q) U" W: x. T8 \& H: q; e  o=)”( N) S; ]7 G* I* H- a7 C; T; X
         则相当于/ @& w4 `" ^9 S
         “$(patsubst+ }* m4 j! H1 g
%,%,$(var))”。7 a3 H/ ?( a1 ^( O, V
         例如有:objects = foo.o+ d. m' a4 ~) ?* m' H! c4 ], c7 ^
bar.o baz.o,
5 L0 x2 ~$ q0 P, A         那么,“$(objects:.o=.c)”和“$(patsubst
) u4 x1 G6 F) U- L% h%.o,%.c,$(objects))”是一样的。/ q7 o& B& B+ @$ ^* z. w
$(strip )5 w- D7 z! S( q( _
    名称:去空格函数——strip。- J. b, Z- S  [1 T
    功能:去掉字串中开头和结尾的空字符。
9 _8 T0 C" r9 |* S: @- E5 q9 p    返回:返回被去掉空格的字符串值。
  c- G1 K( |& b) k% b    示例:
0 U/ ~. C9 O% r" J% \9 `, H        % |% L+ L! F# j* b- q% z
        $(strip a b c )
; G3 w3 M: W  m6 f! }4 h6 S5 p1 U        把字串“a b: ?1 B: N8 d9 D/ h9 d, }
c ”去到开头和结尾的空格,结果是“a b c”。
# D4 K: f, \* Q  d" j9 f$(findstring ,)
; V; t) T- C9 E4 ]8 _% h0 y    名称:查找字符串函数——findstring。
. L# e$ T) {! |! F9 U% F4 y    功能:在字串中查找字串。4 ^  W$ z- H3 T  R
    返回:如果找到,那么返回,否则返回空字符串。
: E- E0 y, ^/ {5 M" q    示例:8 ~. F# i- v# s" v
      
- Z2 U  M- g( N- J9 d! [9 ]; j9 }$(findstring a,a b c)  s9 s* F0 B$ P5 \- ^) E
        $(findstring a,b c)
' }- i* p5 U5 b8 T1 y  f        第一个函数返回“a”字符串,第二个返回“”字符串(空字符串)9 T4 V  U5 @7 }; F8 S1 H
$(filter' \  C) A0 H: A: {% x0 Z3 ^
,)

; S/ |; g1 q1 f8 i3 ?0 h9 ]( q/ Z    名称:过滤函数——filter。: P0 D/ }) q) k" ^3 n" J. `
    功能:以模式过滤字符串中的单词,保留符合模式的单词。可以有多个模式。
! X$ ^8 a: C- a/ Z' y4 Y    返回:返回符合模式的字串。" W' g1 p) b  e) T# z+ x: @2 F& p+ }5 a
    示例:
* L) ~: P- T! T9 Y6 U% @$ ]        sources
8 R- t4 V6 d9 T" D; C$ d8 t1 ]:= foo.c bar.c baz.s ugh.h7 m5 ?0 \; V  @1 v
        foo: $(sources)7 D' [* K( E9 n8 a9 f& w7 i
               % H- I- I4 P9 {. ?# \
cc $(filter %.c %.s,$(sources)) -o foo
) g5 W7 z) ~5 z' H& D; P. O      
0 X& V- t$ o* @8 m; P* u$(filter %.c %.s,$(sources))返回的值是“foo.c bar.c baz.s”。
/ A. P# C1 R; K* t) w+ ?: X4 G$(filter-out
0 x$ F: ]2 ?* {# Y* ^$ z2 u,)

! L: F) R3 p9 j2 u1 e: C    名称:反过滤函数——filter-out。
5 S2 H5 p7 B4 r- h# w2 ]" ?    功能:以模式过滤字符串中的单词,去除符合模式的单词。可以有多个模式。8 Q7 U7 w# X8 W, P/ V2 N+ Y: o
    返回:返回不符合模式的字串。& _" i, o4 x8 q! ]  R* l
    示例:
: J0 s/ B5 q% u       " [' v% Z( [+ Y7 Z8 Y
objects=main1.o foo.o main2.o bar.o
- G  }* L9 Q" b) ], s        mains=main1.o main2.o: ^/ S; L/ i3 ^$ P
        
* v7 \& R- t5 \/ t' M' Z5 v- g        $(filter-out $(mains),$(objects)) 返回值是“foo.o6 a! ?$ }* Q2 [) U
bar.o”。
7 r. O# u& d( J+ s        
1 V0 t" F2 M3 _. K0 b4 `. E$(sort )' p! |& }$ B: z3 z" j1 b
名称:排序函数——sort功能:给字符串中的单词排序(升序)。返回:返回排序后的字符串。示例:$(sort foo bar lose)返回“bar foo lose备注:sort函数会去掉中相同的单词。
" o0 `: X. U' t2 V& Q% D$(word ,)& I) H: ~( f, z
名称:取单词函数——word功能:取字符串中第个单词。(从一开始)返回:返回字符串中第个单词。如果中的单词数要大,那么返回空字符串。示例:$(word 2, foo bar baz)返回值是“bar”。% f6 D% B# p8 N5 J0 @; J- R
$(wordlist" E0 w2 G: j2 m+ ~& W
,,)
  
: _3 g/ ~: z/ d0 G    名称:取单词串函数——wordlist。
; S. {  H. f0 E3 A1 y; m: R    功能:从字符串中取从开始到的单词串。和是一个数字。6 `  `) s6 |% L0 ~3 A$ K5 @) m
    返回:返回字符串中从到的单词字串。如果比中的单词数要大,那么返回空字符串。如果大于的单词数,那么返回从开始,到结束的单词串。  B( o2 b; H% |$ x0 t! h
    示例: $(wordlist 2, 3, foo bar baz)返回值是“bar
1 Q; K/ O4 Y, @0 bbaz”。
# J2 M! }* \7 A9 X$(words )' z+ y% I6 c# t0 u6 |
    名称:单词个数统计函数——words。# |! [6 }0 ^  r8 C9 E
    功能:统计中字符串中的单词个数。& _2 ?: \* X' n" b) S
    返回:返回中的单词数。
7 {3 h/ E6 v8 U    示例:$(words, foo bar baz)返回值是“3”。1 @5 ]5 h9 S4 @- b& N5 F) J
    备注:如果我们要取中最后的一个单词,我们可以这样:$(word
7 s) q& Y3 D9 f& F$(words ),)。8 B  s  h6 H! h/ X) K
$(firstword )# J1 K2 A8 U0 M8 ?5 h. Z
    名称:首单词函数——firstword。1 M% ^4 T4 W4 j/ n1 i
    功能:取字符串中的第一个单词。/ U3 q- Z, g* H$ e8 y$ W
    返回:返回字符串的第一个单词。
# y1 ]5 Y0 x' z# |  i7 X9 @9 H    示例:$(firstword foo bar)返回值是“foo”。
/ |8 F9 F& h; g' S1 G1 g0 {) W    备注:这个函数可以用word函数来实现:$(word, `% G, P" a  `+ P1 \8 q' V! U
1,)。
' R( a5 m# t% e, b& @7 ^以上,是所有的字符串操作函数,如果搭配混合使用,可以完成比较复杂的功能。这里,举一个现实中应用的例子。我们知道,make使用“VPATH”变量来指定“依赖文件”的搜索路径。于是,我们可以利用这个搜索路径来指定编译器对头文件的搜索路径参数CFLAGS,如:4 E2 g2 }9 y4 a! ~# b; \
    override CFLAGS += $(patsubst
8 O3 F; \# G/ I- {2 J. J1 x%,-I%,$(subst :, ,$(VPATH)))2 v% p$ A2 O! E8 k/ @
    如果我们的“$(VPATH)”值是“src:../headers”,那么“$(patsubst
8 u6 Z. f& Q6 r: w$ Z%,-I%,$(subst :, ,$(VPATH)))”将返回“-Isrc -I../headers”,这正是cc或gcc搜索头文件路径的参数。
' s: j2 P, C( j) K, y( \8 U. x' ?- R三、文件名操作函数
# t1 L+ t: p! g下面我们要介绍的函数主要是处理文件名的。每个函数的参数字符串都会被当做一个或是一系列的文件名来对待。3 L& S% T, ?# a$ x4 H
$(wildcard )
5 T5 @' V- T7 [& Y4 ~名称:文件名展开函数——wildcard 。
" Z4 u8 k5 j! A7 P/ a3 t" ~    功能:功能是展开成一列所有符合由其参数描述的文件名,文件间以空格间隔。
2 Z# t1 W6 q$ \! W    返回:函数返回展开后的文件名列表。- t) a2 d/ w: d
    : y7 Z* z6 Z; {4 D' F8 V* n
示例:
& E3 [; e# C& s1 @9 r% g        ; s, M3 t; _: [! i2 v
        $(wildcard *.c)
  i7 B6 s2 k& B4 Y/ c7 M/ b        
8 A8 Z' G/ K2 ^, R        返回结果是一个所有以 '.c' 结尾的文件的列表。 ' d, y- ~+ {+ Y2 d- c2 g
$(dir )
+ i$ v! ]$ Q; f. S    名称:取目录函数——dir。3 L' h9 X% ?/ m$ G. d8 ^! I# p
    功能:从文件名序列中取出目录部分。目录部分是指最后一个反斜杠(“/”)之前的部分。如果没有反斜杠,那么返回“./”。0 ?  M7 W( m$ g# Y- O1 G& y
    返回:返回文件名序列的目录部分。3 C  u$ t) \$ G8 ?% o. K
    示例: $(dir src/foo.c hacks)返回值是“src/6 _, a0 |! H7 M
./”。+ P+ f9 a8 Z  a7 }$ Y
$(notdir )
( S% _  Q6 t' J; d9 F    名称:取文件函数——notdir。/ F. y( c# R& _: D6 V
    功能:从文件名序列中取出非目录部分。非目录部分是指最后一个反斜杠(“/”)之后的部分。
) A- p* G7 d) a    返回:返回文件名序列的非目录部分。9 s+ W8 v8 u+ g; f5 Z9 Q4 X' [
    示例: $(notdir src/foo.c hacks)返回值是“foo.c
1 c4 h8 b" e% \4 i$ ahacks”。3 C- o7 c" ^0 w' {7 P" F

0 Z1 m/ |, h6 z+ m6 ~$(suffix )
; k/ a" @# D, v& R! J$ m4 b% r   
: D9 [/ z8 k7 T    名称:取后缀函数——suffix。* S: j. d: M9 l- \
    功能:从文件名序列中取出各个文件名的后缀。
  r# k' d' a5 W% ~    返回:返回文件名序列的后缀序列,如果文件没有后缀,则返回空字串。
, Y8 }# v0 B( ]/ h    示例:$(suffix src/foo.c src-1.0/bar.c hacks)返回值是“.c
, X4 g& P) b- S  W! Q.c”。/ z1 D5 L  [: N% y; U- _' o
$(basename )
% |- l, \- b2 H) ?0 U    名称:取前缀函数——basename。0 p: h6 K. M' G; l' n
    功能:从文件名序列中取出各个文件名的前缀部分。
% S; E( R: ?( I- @8 z    返回:返回文件名序列的前缀序列,如果文件没有前缀,则返回空字串。
# n! Q- S+ C! e) c+ w/ ]/ Q    示例:$(basename src/foo.c src-1.0/bar.c hacks)返回值是“src/foo
% T  U: S0 m( ysrc-1.0/bar hacks”。
6 W3 a2 D7 U( L: B, N$ ?+ t3 r$(addsuffix2 e$ S7 U3 ]+ o& ^% S0 |
,)

* P( D6 E8 O4 e    名称:加后缀函数——addsuffix。3 {4 H  ~- }6 M. V7 h& j
    功能:把后缀加到中的每个单词后面。
# f$ V) M! f- \' x    返回:返回加过后缀的文件名序列。! y0 ^5 g4 b6 D/ g
    示例:$(addsuffix .c,foo bar)返回值是“foo.c
: o6 O, r' E# }, Z" v. X' C$ B9 cbar.c”。
3 h' |: Q6 w- f3 r3 ~$(addprefix6 D* O* y: l2 u. G3 L1 g9 K
,)

7 Q4 l4 l  D. p7 m7 T( W    名称:加前缀函数——addprefix。5 \1 M! e! a  G7 T& y) k
    功能:把前缀加到中的每个单词后面。! ]4 Q0 m4 `* B: c
    返回:返回加过前缀的文件名序列。
' I$ F# b9 i& K& J  w    示例:$(addprefix src/,foo bar)返回值是“src/foo
2 ^: P  y# p5 Q- r. {8 O$ x# Fsrc/bar”。+ o0 |+ t$ d; C; @8 j
$(join ,)
' c: ~) b3 {4 S2 r" ]    名称:连接函数——join。# ?6 O2 ?! I$ g6 _6 X
    功能:把中的单词对应地加到的单词后面。如果的单词个数要比的多,那么,中的多出来的单词将保持原样。如果的单词个数要比多,那么,多出来的单词将被复制到中。
" z3 Q2 d* D5 c' J    返回:返回连接过后的字符串。$ @* F' Q. e5 j) W6 F+ e& {
    示例:$(join aaa bbb , 111 222 333)返回值是“aaa1113 {6 d' J' Y' P2 d" k
bbb222 333”。
" G7 [( ?/ H5 V$ i. O( A# o6 F# L7 `- g
四、foreach 函数! Y6 u% q; [1 K; n/ h2 W

0 ?) |7 o5 a  E' ~foreach函数和别的函数非常的不一样。因为这个函数是用来做循环用的,Makefile中的foreach函数几乎是仿照于Unix标准Shell(/bin/sh)中的for语句,或是C-Shell(/bin/csh)中的foreach语句而构建的。它的语法是:# V( I! Q! O" t9 u! I1 v

5 k$ E) k/ y# C8 z  \" a3 _  F6 ]    $(foreach6 ^+ P1 i8 n: X+ n; o
,,)" A) E/ D4 U' u( ~% ~) @4 M" l

* d; o; f6 m* P这个函数的意思是,把参数中的单词逐一取出放到参数所指定的变量中,然后再执行所包含的表达式。每一次会返回一个字符串,循环过程中,的所返回的每个字符串会以空格分隔,最后当整个循环结束时,所返回的每个字符串所组成的整个字符串(以空格分隔)将会是foreach函数的返回值。
- [% U. J/ C/ Y5 B
0 B6 Z4 O1 `. b* e( V: o所以,最好是一个变量名,可以是一个表达式,而中一般会使用这个参数来依次枚举中的单词。举个例子:1 R8 c5 b' P8 F3 h6 R8 [4 a
! I4 z. b" {% z; Y1 W% Q2 O7 G
    names := a b c d4 B2 O/ ]/ w; e
    files := $(foreach n,$(names),$(n).o)
% ?# F2 c9 u$ R9 k" d4 R, A
9 _' D, W; t4 ^9 q$ [! I上面的例子中,$(name)中的单词会被挨个取出,并存到变量“n”中,“$(n).o”每次根据“$(n)”计算出一个值,这些值以空格分隔,最后作为foreach函数的返回,所以,$(files)的值是“a.o b.o c.o d.o”。
/ ?1 C! {3 E7 J8 j" Q* M
& [+ Z9 Z5 j/ H+ h. Q注意,foreach中的参数是一个临时的局部变量,foreach函数执行完后,参数的变量将不在作用,其作用域只在foreach函数当中。& N  N0 m% @' [: `% J2 o3 H
% J5 M# ?% A* z1 z# f* ^; c
4 J: C! m7 I. \. p7 c" k1 m
五、if 函数
5 O6 L" a# J/ f, J( L5 h7 P6 u+ y% j
if函数很像GNU的make所支持的条件语句——ifeq(参见前面所述的章节),if函数的语法是:
! o" n9 l! n. g' L+ G* t# I! |7 [
+ i9 f. m8 K, X    $(if ,)
( @. F: s0 l/ K+ S2 U  A
$ ]+ `: j9 g7 E+ [5 M或是
2 I  Y9 h3 [5 g: H& M2 F/ T' G( K4 d
    $(if0 d" `3 }% T0 J0 l
,,)
* X; Q* q) Y/ ^7 u' {! T- a7 P9 }6 e
$ u, I2 X3 F9 T3 e3 a可见,if函数可以包含“else”部分,或是不含。即if函数的参数可以是两个,也可以是三个。参数是if的表达式,如果其返回的为非空字符串,那么这个表达式就相当于返回真,于是,会被计算,否则会被计算。
: J& m# I/ z7 F: Y7 j1 D
* a! e! {% C; N% E  K而if函数的返回值是,如果为真(非空字符串),那个会是整个函数的返回值,如果为假(空字符串),那么会是整个函数的返回值,此时如果没有被定义,那么,整个函数返回空字串。7 j: `2 @1 W6 x+ M

8 a; [2 x0 Y  ^- f  b1 M/ {所以,和只会有一个被计算。+ L" n9 m% I) p2 O( L& E" ~1 n$ M1 ^
! A6 Z7 p1 U& F9 I' v

9 T0 {: s6 A  |/ @) v% Q. r六、call函数) e( l7 E# s- m
- \, s; {3 C; V0 G5 [+ X
call函数是唯一一个可以用来创建新的参数化的函数。你可以写一个非常复杂的表达式,这个表达式中,你可以定义许多参数,然后你可以用call函数来向这个表达式传递参数。其语法是:
1 V! K# N8 T3 G. n0 C1 [6 m7 \% N8 y- f% W8 M
    $(call
$ b9 S5 H5 I4 G0 J7 Z,,,...)( E! \8 N3 T$ x/ g* k

+ Y8 h2 g5 L1 x5 k当make执行这个函数时,参数中的变量,如$(1),$(2),$(3)等,会被参数,,依次取代。而的返回值就是call函数的返回值。例如:
2 J) d- t9 S5 `% p* J$ u" A    reverse =  $(1) $(2)# k0 O3 j! c' g  N4 H) V& J* r
    foo = $(call reverse,a,b)# W) P& N% B7 y% v3 M
那么,foo的值就是“a b”。当然,参数的次序是可以自定义的,不一定是顺序的,如:2 x2 T1 o) b+ G3 c4 U. n5 R

! p, E* A$ I, M8 T$ V' ]: ]+ W. L    reverse =
' l4 g0 I5 n; R/ @$ d$(2) $(1)
- y& e- o& w5 P% V) u2 Q: q    foo = $(call reverse,a,b)# y/ @  u8 s" }8 n9 d. d$ n& g
此时的foo的值就是“b a”。
7 E4 U; j* Z$ l7 P. [+ O5 O5 U- }2 w. S' M6 u+ A
: n4 _0 X: ^/ Z3 R  w& i
七、origin函数0 e2 v# r( Q0 \
origin函数不像其它的函数,他并不操作变量的值,他只是告诉你你的这个变量是哪里来的?其语法是:$ ^: k* |6 C/ K# c! M& l
( Z$ }$ k* W! O. n9 f$ z+ `: b
    $(origin )
! b0 E  n5 x: i) O& L* G( x% C
" R; I5 J( g2 i% G: M$ R8 U2 d注意,是变量的名字,不应该是引用。所以你最好不要在中使用“$”字符。Origin函数会以其返回值来告诉你这个变量的“出生情况”,下面,是origin函数的返回值:: \) s8 V' q8 q4 f) Q

5 m! q6 y2 X* h5 p) d“undefined”
; r) j. l5 g: P) ^      如果从来没有定义过,origin函数返回这个值“undefined”。6 u- Q- a5 e  c
& F+ X# Q# b: c; X& k/ C  m. ]
“default”, U. j6 V3 ~( H( E! J1 r- Z. s$ Y( l
      如果是一个默认的定义,比如“CC”这个变量,这种变量我们将在后面讲述。1 e* W8 e' b' u- t( f3 p
8 o! a5 M/ w9 P) M  a
“environment”7 u8 y5 n5 O2 X( Y" @
      如果是一个环境变量,并且当Makefile被执行时,“-e”参数没有被打开。' B8 [4 z* v2 d/ G* H" F) w

/ Y2 u3 w7 l3 {6 m. \“file”
! d4 G) F# a" B+ ]( v' o' M      如果这个变量被定义在Makefile中。
6 Q! U' t+ J( O/ C- J8 h; K0 F) _+ @/ J( A! s  A6 C
“command% \+ W. y4 `, g6 |- P4 @4 B( K
line”8 [# Y/ l# w- Q% ^, C' U, D2 y
      如果这个变量是被命令行定义的。
  q4 N4 E  N; b3 U9 ^
8 S7 p% w5 Q: Q: G- M. Q) b“override”5 [- M/ y. B: |' z; Z4 D0 c
      如果是被override指示符重新定义的。
$ A2 D6 f( w& {3 H$ w, ~; @, `! h& J1 l6 l* L6 G+ C, b0 p
“automatic”% O, B, t3 c- Z- j) r9 d1 I
      如果是一个命令运行中的自动化变量。关于自动化变量将在后面讲述。
% B3 A$ v3 C2 m
; Z; v) D5 ?4 w4 I这些信息对于我们编写Makefile是非常有用的,例如,假设我们有一个Makefile其包了一个定义文件Make.def,在Make.def中定义了一个变量“bletch”,而我们的环境中也有一个环境变量“bletch”,此时,我们想判断一下,如果变量来源于环境,那么我们就把之重定义了,如果来源于Make.def或是命令行等非环境的,那么我们就不重新定义它。于是,在我们的Makefile中,我们可以这样写:
4 i& K3 s5 ]3 x+ L  g
3 [  E+ @& t2 ^# F    ifdef bletch
- ]1 m* _' A# @8 b4 \" f    ifeq "$(origin bletch)"
0 K% o/ P/ L; O2 m"environment"5 B8 l8 y% ]: X
    bletch = barf, gag, etc.8 R7 x( Q& F; b5 [3 a& S0 Z
    endif9 W( x/ _% s! v/ m
    endif9 ]& |3 ~' g& [6 L- X8 T
2 l4 ]) j0 Z* b% I
当然,你也许会说,使用override关键字不就可以重新定义环境中的变量了吗?为什么需要使用这样的步骤?是的,我们用override是可以达到这样的效果,可是override过于粗暴,它同时会把从命令行定义的变量也覆盖了,而我们只想重新定义环境传来的,而不想重新定义命令行传来的。
7 }9 [. t3 d/ w5 t. D0 H
% f" ]3 U4 J* k8 \3 M) O
' c; T8 F5 X6 V! y5 M3 Y  P. ^) {八、shell函数2 U' D7 j; J2 L& F9 B+ T2 v5 [
5 E$ w# \4 T8 a# a
shell函数也不像其它的函数。顾名思义,它的参数应该就是操作系统Shell的命令。它和反引号“`”是相同的功能。这就是说,shell函数把执行操作系统命令后的输出作为函数返回。于是,我们可以用操作系统命令以及字符串处理命令awk,sed等等命令来生成一个变量,如:
" I& j+ s" J( j. n: \' a1 z. c
% G9 D: o; K; b- N: s) N1 ^    contents := $(shell cat foo)
: F5 |  U7 S5 Y9 d+ e3 n% u$ n- S/ `+ N* m/ ~# Q! [
    files := $(shell echo *.c)$ L% [! `8 T# i+ ?% H) H9 p' S, o
# W0 L  ], D: V0 ?
注意,这个函数会新生成一个Shell程序来执行命令,所以你要注意其运行性能,如果你的Makefile中有一些比较复杂的规则,并大量使用了这个函数,那么对于你的系统性能是有害的。特别是Makefile的隐晦的规则可能会让你的shell函数执行的次数比你想像的多得多。
) |( _4 E: S1 c& P' t  j' S                ) u; G& w" g9 O* ]" M
 楼主| 发表于 2017-5-4 18:33 | 显示全部楼层
在linux项目中,使用makefile来规定编译规则。
3 E7 x1 w: N1 g/ smakefile中如何调用到子目录下的makefile呢,有很多中方式。4 C2 a5 g5 B4 b" U1 W4 F, l: q$ |
在这里,我要使用的是 -C
4 R5 L% A# y* m
# \0 }2 E- G9 p) Q$ f7 S! d+ |( } 28458801_1414577793Z2n9.jpg
4 e4 J7 G: E" j! O, w: D 28458801_1414577808K1i9.jpg
/ z# G: ]* x" N  S* \( O0 v/ }+ u2 j

1 g/ ^1 h  Z2 @  V; R( b
点击(此处)折叠或打开
& ]0 N% x% y% C2 ?) O; J, M# 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 `: `' t, x3 n. O& X9 l- L
2 o+ S0 d7 i9 Y) s

$ D* w; _4 \2 \: n
0 b! D) K  Z' B7 o# v& I, [1 S
- }% A' s4 n& a# _& ?5 t; k$ Q4 B7 t0 k. C
, S0 Z' T0 y: G1 p% P7 X* K

, S0 t+ l' `3 D- k8 z7 d* G! g/ m- A) i5 l" ]

0 \0 ]% o1 o% {; z9 |
回复

使用道具 举报

本版积分规则

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

GMT+8, 2026-7-13 06:38 , Processed in 0.031888 second(s), 23 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

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