乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      GNU make中文手冊-第六章:Makefile中的變量

       todaytomo 2006-12-30
      GNU make中文手冊-第六章:Makefile中的變量 作者: hew  發(fā)布日期: 2006-3-21    查看數(shù): 162   出自: http://www.
      第六章:Makefile中的變量

      --------------------------------------------------------------------------------

      在Makefile中,變量就是一個(gè)名字(像是C語言中的宏),代表一個(gè)文本字符串(變量的值)。在Makefile的目標(biāo)、依賴、命令中引用一個(gè)變量的 地方,變量會(huì)被它的值所取代(與C語言中宏引用的方式相同,因此其他版本的make也把變量稱之為“宏”)。在Makefile中變量的特征有以下幾點(diǎn):

      1. Makefile中變量和函數(shù)的展開(除規(guī)則的命令行以外),是在make讀取makefile文件時(shí)進(jìn)行的,這里的變量包括了使用“=”定義和使用指示符“define”定義的。

      2. 變量可以用來代表一個(gè)文件名列表、編譯選項(xiàng)列表、程序運(yùn)行的選項(xiàng)參數(shù)列表、搜索源文件的目錄列表、編譯輸出的目錄列表和所有我們能夠想到的事物。

      3. 變量名是不包括“:”、“#”、“=”、前置空白和尾空白的任何字符串。需要注意的是,盡管在GNU make中沒有對變量的命名有其它的限制,但定義一個(gè)包含除字母、數(shù)字和下劃線以外的變量的做法也是不可取的,因?yàn)槌帜浮?shù)字和下劃線以外的其它字符可 能會(huì)在以后的make版本中被賦予特殊含義,并且這樣命名的變量對于一些shell來說不能作為環(huán)境變量使用。

      4. 變量名是大小寫敏感的。變量“foo”、“Foo”和“FOO”指的是三個(gè)不同的變量。Makefile傳統(tǒng)做法是變量名是全采用大寫的方式。推薦的做法 是在對于內(nèi)部定義定義的一般變量(例如:目標(biāo)文件列表objects)使用小寫方式,而對于一些參數(shù)列表(例如:編譯選項(xiàng)CFLAGS)采用大寫方式,這 并不是要求的。但需要強(qiáng)調(diào)一點(diǎn):對于一個(gè)工程,所有Makefile中的變量命名應(yīng)保持一種風(fēng)格,否則會(huì)顯得你是一個(gè)蹩腳的程序員(就像代碼的變量命名風(fēng) 格一樣)。

      5. 另外有一些變量名只包含了一個(gè)或者很少的幾個(gè)特殊的字符(符號(hào))。稱它們?yōu)樽詣?dòng)化變量。像“$<”、“$@”、“$?”、“$*”等。

      6.1 變量的引用
      當(dāng)我們定義了一個(gè)變量之后,就可以在Makefile的很多地方使用這個(gè)變量。變量的引用方式是:使用“$(VARIABLE_NAME)”或者“${ VARIABLE_NAME }”來引用一個(gè)變量的定義。例如:“$(foo) ”或者“${foo}”就是取變量“foo”的值。美元符號(hào)“$”在Makefile中有特殊的含義,所有在命令或者文件名中使用“$”時(shí)需要用兩個(gè)美元 符號(hào)“$$”來表示。對一個(gè)變量的引用可以在Makefile的任何上下文中,目標(biāo)、依賴、命令、絕大多數(shù)指示符和新變量的賦值中。這里有一個(gè)例子,其中 變量保存了所有.o文件的列表:



      objects = program.o foo.o utils.o

      program : $(objects)

      cc -o program $(objects)



      $(objects) : defs.h



      變量引用的展開過程是嚴(yán)格的文本替換過程,就是說變量值的字符串被精確的展開在此變量被引用的地方。因此規(guī)則:



      foo = c

      prog.o : prog.$(foo)

      $(foo) $(foo) -$(foo) prog.$(foo)



      被展開后就是:



      prog.c : prog.c

      cc -c prog.c



      通過這個(gè)例子我們可以看到變量的展開過程完全和c語言中的宏展開的過程一樣,是一個(gè)嚴(yán)格的文本替換過程。上例中在變量“foo”被展開過程中,其值中的前 導(dǎo)空格會(huì)被忽略。這里舉這個(gè)例子的目的是為了讓我們更清楚地了解變量的展開方式,而不是建議大家按照這樣的方式來書寫Makefile。在實(shí)際書寫時(shí),千 萬不要使用這種方式。否則將會(huì)給你帶來很多不必要的麻煩。

      注意:Makefile中在對一些簡單變量的應(yīng)用,我們也可以不使用“()”和“{}”來標(biāo)記變量名,而直接使用“$x”的格式來實(shí)現(xiàn),此種用法僅限于變 量名為單字符的情況。另外自動(dòng)化變量也使用這種格式。對于一般多字符變量的引用必須使用括號(hào)了標(biāo)記,否則make將把變量名的首字母作為作為引用(“$ PATH”在Makefile中實(shí)際上是“$(P)ATH”)。這一點(diǎn)和shell中變量的引用方式不同。shell中變量的引用可以是“${xx}”或 者“$xx”格式。但在Makefile中多字符變量名的引用只能是“$(xx)”或者“${xx}”格式。



      一般在我們書寫Makefile時(shí),各部分變量引用的格式我們建議如下:

      1. make變量(Makefile中定義的或者是make的環(huán)境變量)的引用使用“$(VAR)”格式,無論“VAR”是單字符變量名還是多字符變量名。

      2. 出現(xiàn)在規(guī)則命令行中shell變量(一般為執(zhí)行命令過程中的臨時(shí)變量,它不屬于Makefile變量,而是一個(gè)shell變量)引用使用shell的“$tmp”格式。

      3. 對出現(xiàn)在命令行中的make變量我們同樣使用“$(CMDVAR)” 格式來引用。



      例如:

      # sample Makefile

      ……

      SUBDIRS := src foo



      .PHONY : subdir

      Subdir :

      @for dir in $(SUBDIRS); do \

      $(MAKE) –C $$dir || exit 1; \

      done



      ……

      6.2 兩種變量定義(賦值)
      GNU make中,一個(gè)變量的定義有兩種方式(或者稱為風(fēng)格)。我們把這兩種方式定義的變量可以看作變量的兩種不同風(fēng)格。變量的這兩種不同的風(fēng)格的區(qū)別在于:1. 定義方式;2. 展開時(shí)機(jī)。下邊我們分別對這兩種不同的風(fēng)格進(jìn)行詳細(xì)地討論。

      6.2.1 遞歸展開式變量
      第一種風(fēng)格的變量就是遞歸方式擴(kuò)展的變量。這一類型的變量的定義是通過“=”或者使用指示符“define”定義的變量。對這種變量的引用,在引用的地方 是嚴(yán)格的文本替換過程,此變量值的字符串原模原樣的出現(xiàn)在引用它的地方。如果此變量定義中存在對其他變量的引用,這些被引用的變量會(huì)在它被展開的同時(shí)被展 開。就是說在變量定義時(shí),變量值中對其他變量的引用不會(huì)被替換展開。而是,變量在引用它的地方進(jìn)行替換展開的同時(shí),它所引用的其它變量才會(huì)被替換展開。語 言的描述可能比較晦澀,讓我們來看一個(gè)例子:



      foo = $(bar)

      bar = $(ugh)

      ugh = Huh?



      all:;echo $(foo)



      執(zhí)行“make”將會(huì)打印出“Huh?”。整個(gè)變量的替換過程時(shí)這樣的:首先“$(foo)”被替換為“$(bar)”,接下來“$(bar)”被替換為 “$(ugh)”,最后“$(ugh)”被替換為“Hug?”。整個(gè)替換的過程是在執(zhí)行“echo $(foo)”是進(jìn)行的。

      這種類型的變量是其它版本的make所支持的類型。我們可以把這種類型的變量稱為“遞歸展開”式變量。此類型的變量存有它的優(yōu)點(diǎn)同時(shí)也存在其缺點(diǎn)。其優(yōu)點(diǎn)是:

      這種類型變量的定義時(shí),可以引用其它的之前沒有定義的變量(可能在后續(xù)部分定義,或者是通過make的命令行選項(xiàng)傳遞的變量)。看一個(gè)這樣的例子:



      CFLAGS = $(include_dirs) -O

      include_dirs = -Ifoo -Ibar



      “CFLAGS”會(huì)在命令中被展開為“-Ifoo -Ibar -O”。我們可以看到在“CFLAGS”定義中使用到了之后定義的變量“include_dirs”。

      其缺點(diǎn)是:

      1. 使用此風(fēng)格的變量定義,可能會(huì)由于出現(xiàn)變量的遞歸定義而導(dǎo)致make陷入到無限的變量展開過程中,最終使make執(zhí)行失敗。例如,接上邊的例子,我們給這個(gè)變量追加值:



      CFLAGS = $(CFLAGS) –O



      它將會(huì)導(dǎo)致make進(jìn)入對變量“CFLAGS”的無限展過程中去(這種定義就是變量的遞歸定義)。因?yàn)橐坏┖罄m(xù)同樣存在對“CLFAGS”定義的追加,展 開過程將是套嵌的、不能終止的(在發(fā)生這種情況時(shí),make會(huì)提示錯(cuò)誤信息并結(jié)束)。一般在書寫Makefile時(shí),使用這種追加變量值的方法也很少使用 (也不是我們推薦的方式)。我們可以來看另外一個(gè)例子:



      x = $(y)

      y = $(x) $(z)



      這種情況下同樣會(huì)導(dǎo)致make陷入到無限的變量展開過程中。因此我們在使用這種風(fēng)格的變量,當(dāng)一個(gè)變量定義需要引用其它的變量時(shí)需要特別的注意,防止變量 的展開進(jìn)入無限的循環(huán)。當(dāng)出現(xiàn)這樣的錯(cuò)誤時(shí),首先檢查你的Makefile中變量是否出現(xiàn)了遞歸定義。這是它的一個(gè)缺點(diǎn)。

      2. 第二個(gè)缺點(diǎn):這種風(fēng)格變量的定義中如果使引用了某一個(gè)函數(shù),那么函數(shù)總會(huì)在其被引用的地方被執(zhí)行。

      這是因?yàn)檫@種風(fēng)格變量的定義中,對函數(shù)引用的替換展開發(fā)生在展開它自身的時(shí)候,而不是在定義它的時(shí)候。這樣所帶來的問題是,可能可能會(huì)使make的執(zhí)行效 率降低,同時(shí)對某些變量和函數(shù)的引用出現(xiàn)問題。特別是當(dāng)變量定義中引用了“shell”和“wildcard”函數(shù)的情況,可能出現(xiàn)不可控制或者難以預(yù)料 的錯(cuò)誤,因?yàn)槲覀儫o法確定它在何時(shí)會(huì)被展開。

      6.2.2 直接展開式變量
      為了避免“遞歸展開式”變量存在的問題和不方便。在GNU make中可以使用另外一種風(fēng)格的變量,我們將它稱為“直接展開”式。這種風(fēng)格的變量使用“:=”來定義變量。在使用“:=”定義變量時(shí),變量值中對另外 變量的引用或者函數(shù)的引用在定義時(shí)被展開(對變量進(jìn)行替換)。所以在變量被定義以后就是一個(gè)實(shí)際所需要定義的文本串,其中不再包含任何對其它變量的引用。 因此



      x := foo

      y := $(x) bar

      x := later



      就等價(jià)于:



      y := foo bar

      x := later



      需要注意的是:此風(fēng)格變量在定義時(shí)就完成了對所引用的變量的展開,因此它不能實(shí)現(xiàn)對其后定義變量的引用。例如:



      CFLAGS := $(include_dirs) -O

      include_dirs := -Ifoo -Ibar



      由于在變量“include_dirs”的定義出現(xiàn)在“CFLAGS”定義之后。因此在“CFLAGS”的定義中,“include_dirs”的值為 空。“CFLAGS”的值為“-O”而不是“-Ifoo -Ibar -O”。這一點(diǎn)也是直接展開式和遞歸展開式變量的不同點(diǎn)。注意這里的兩個(gè)變量都是“直接展開”式的。大家不妨試試將其中某一個(gè)變量使用遞歸展開式定義后看 一下又會(huì)出現(xiàn)什么樣的結(jié)果。

      下邊讓我們來看一個(gè)復(fù)雜一點(diǎn)的例子。分析一下直接展開式變量定義(:=)的用法,這里也用到了make的shell函數(shù)和變量“MAKELEVEL”(此變量在make的遞歸調(diào)用時(shí)代表make的調(diào)用深度)。

      其中包括了make的函數(shù)、條件表達(dá)式和一個(gè)系統(tǒng)變量“MAKELEVEL”的使用:



      ifeq (0,${MAKELEVEL})

      cur-dir := $(shell pwd)

      whoami := $(shell whoami)

      host-type := $(shell arch)

      MAKE := ${MAKE} host-type=${host-type} whoami=${whoami}

      endif



      第一行是一個(gè)條件判斷,說明如果是頂層Makefile,就定義下列變量。否則不定義任何變量。第二、三、四、五行分別定義了一個(gè)變量,在進(jìn)行變量定義時(shí)對引用到的其它變量和函數(shù)展開。最后結(jié)束定義。由于直接展開式的這個(gè)優(yōu)點(diǎn)我們就可以書寫這樣一個(gè)規(guī)則:



      ${subdirs}:

      ${MAKE} cur-dir=${cur-dir}/$@ -C $@ all



      它實(shí)現(xiàn)了在不同子目錄下變量“cur_dir”使用不同的值(為當(dāng)前工作目錄)。

      在復(fù)雜的Makefile中,推薦使用直接展開式變量。因?yàn)檫@種風(fēng)格變量的使用方式和大多數(shù)編程語言中的變量使用方式基本上相同。它可以使一個(gè)比較復(fù)雜的 Makefile在一定程度上具有可預(yù)測性。而且這種變量允許我們利用之前所定義的值來重新定義它(比如使用某一個(gè)函數(shù)來對它以前的值進(jìn)行處理并重新賦 值),此方式在Makefile中經(jīng)常用到。盡量避免和減少遞歸方式的變量的使用。

      6.2.3 如何定義一個(gè)空格
      使用直接擴(kuò)展式變量定義我們可以實(shí)現(xiàn)將一個(gè)前導(dǎo)空格定義在變量值中。一般變量值中的前導(dǎo)空格字符在變量引用和函數(shù)調(diào)用時(shí)被丟棄。直接展開式變量在定義時(shí)對 引用的其它變量或函數(shù)進(jìn)行展開的特點(diǎn),使我們可以實(shí)現(xiàn)在一個(gè)變量中包含前導(dǎo)空格并在引用此變量時(shí)對空格加以保護(hù)。像這樣:



      nullstring :=

      space := $(nullstring) # end of the line



      這里,變量“space”就正好表示一個(gè)一個(gè)空格。“space”定義的行中的注釋在這里使得我們的目的更清晰(明確地描述一個(gè)空格字符比較困難),明確 的指定我們需要的是一個(gè)空格。這是一個(gè)很好地實(shí)現(xiàn)方式。使用變量“nullstring”標(biāo)明變量值的開始,采用“#”注釋來結(jié)束,中間是一個(gè)空格字符。

      make對變量進(jìn)行處理時(shí)變量值中尾空格是不被忽略的,因此定義一個(gè)包含一個(gè)或者多個(gè)空格的變量定義時(shí),上邊的實(shí)現(xiàn)就是一個(gè)簡單并且非常直觀的方式。但是 需要注意的是對于不包含尾空格的變量的定義,就不能隨便使用幾個(gè)空格之后,在同行中放置它的注釋內(nèi)容。這是千萬需要注意的。例如下邊的做法就是不正確的:



      dir := /foo/bar # directory to put the frobs in



      變量“dir”的值是“/foo/bar ”(后面有4個(gè)空格),這可能并不是你想要實(shí)現(xiàn)的。假如一個(gè)特定的文件以它作為路徑來表示“$(dir)/file”,那么大錯(cuò)特錯(cuò)了。

      這里順便提醒大家,在書寫Makefile時(shí)。注釋內(nèi)容推薦書寫在獨(dú)立的一行或者多行,這樣就可以防止出現(xiàn)這種意外情況的發(fā)生,而且注釋行獨(dú)立的行書寫時(shí) 也使得你的Makefile更加清晰,便于別人的預(yù)讀。對于特殊的定義,比如定義包含一個(gè)或者多個(gè)空格空格的變量時(shí)進(jìn)行詳細(xì)地說明和注釋。

      6.2.4 “?=”操作符
      GNU make中,還有一個(gè)被稱為條件賦值的賦值操作符“?=”。被稱為條件賦值是因?yàn)椋褐挥写俗兞吭谥皼]有賦值的情況下才會(huì)對這個(gè)變量進(jìn)行賦值。例如:



      FOO ?= bar



      其等價(jià)于:



      ifeq ($(origin FOO), undefined)

      FOO = bar

      endif



      含義是:如果變量“FOO”在沒有定義過,就給它賦值“bar”。否則不改變它的值。

      6.3 變量的高級(jí)用法
      本節(jié)討論一些變量的高級(jí)用法,這些高級(jí)的用法使我們可以更靈活的使用變量。

      6.3.1 變量的替換引用
      對于一個(gè)已經(jīng)定義的變量,可以使用“替換引用”將其值使用指定的字符(字符串)進(jìn)行替換。格式為“$(VAR:A=B)”(或者“${VAR:A= B}”),意思是,替換變量“VAR”中所有“A”字符結(jié)尾的字為“B”結(jié)尾的字。“結(jié)尾”的含義是空格之前(變量值的多個(gè)字以空格分開)。而對于變量其 它部分的“A”字符不進(jìn)行替換。例如:



      foo := a.o b.o c.o

      bar := $(foo:.o=.c)



      在這個(gè)定義中,變量“bar”的值就為“a.c b.c c.c”。使用變量的替換引用將變量“foo”以空格分開的值中的所有的字的尾字符“o”替換為“c”,其他部分不變。而且如果在變量“foo”中如果存 在“o.o”時(shí),那么變量“bar”的值為“a.c b.c c.c o.c”而不是“a.c b.c c.c c.c”。這一點(diǎn)需要明確。

      變量的替換引用其實(shí)是函數(shù)“patsubst”(參考文本處理函數(shù)一節(jié))的一個(gè)簡化實(shí)現(xiàn)。在GNU make中同時(shí)提供了這兩種方式來實(shí)現(xiàn)同樣的目的,以兼容其它版本make。

      另外一種引用替換的技術(shù)使用功能更強(qiáng)大的“patsubst”函數(shù)的所有功能。它的格式和上面“$(VAR:A=B)”的格式相類似,不過需要在這里的 “A”和“B”中需要包含模式字符“%”。只是它就和“$(patsubst A,B $(VAR))”所實(shí)現(xiàn)功能相同。例如:





      foo := a.o b.o c.o

      bar := $(foo:%.o=%.c)



      這個(gè)例子同樣使變量“bar”的值為“a.c b.c c.c”。這種格式的替換引用方式比第一種方式更為通用。

      6.3.2 變量的套嵌引用
      計(jì)算的變量名是一個(gè)比較復(fù)雜的概念,僅用在那些復(fù)雜的Makefile中。通常我們不需要對它的計(jì)算過程有深入地了解,只要知道當(dāng)一個(gè)被引用的變量名之中 含有“$”時(shí),可以得到另外一個(gè)值。你如果是一個(gè)比較喜歡追根問底的人,或者你想弄清楚make計(jì)算變量的過程。就可以參考本節(jié)的內(nèi)容。

      一個(gè)變量名(文本串)之中可以包含對其它變量的引用。這種情況我們稱之為“變量的套嵌引用”或者“計(jì)算的變量名”。例如:

      先看一個(gè)例子:



      x = y

      y = z

      a := $($(x))



      這個(gè)例子中,最終定義了“a”的值為“z”。來看一下變量的引用過程:首先最里邊的變量引用“$(x)”被替換為變量名“y”(就是“$($(x))”被 替換為了“$(y)”),之后“$(y)”被替換為“z”(就是a := z)。這個(gè)例子中(a:=$($(x)))所引用的變量名不是明確聲明的,而是由$(x)擴(kuò)展得到。這里“$(x)”相對于外層的引用就是套嵌的變量引 用。

      上個(gè)例子我們可以看到是一個(gè)兩層的套嵌引用,具有多層的套嵌引用在Makefile中也是允許的。下邊我們在來看一個(gè)三層套嵌引用的例子:



      x = y

      y = z

      z = u

      a := $($($(x)))



      這個(gè)例子的最終是定義了“a”的值為“u”。它的擴(kuò)展過程和上邊第一個(gè)例子的過程相同。首先“$(x)”被替換為“y”,則“$($(x))”就是“$(y)”,“$(y)”在北替換為“z”,所有就是“a:=$(z)”;“$(z)”最后被替換為“u”。

      以上兩個(gè)套嵌引用的例子中沒有使用到遞歸展開式變量。遞歸展開式變量的變量名的計(jì)算過程,也是按照相同的方式被擴(kuò)展的。我們看一個(gè)這樣一個(gè)例子:



      x = $(y)

      y = z

      z = Hello

      a := $($(x))



      此例最終實(shí)現(xiàn)了“a:=Hello”這么一個(gè)定義。其中“$($(x))”被替換成了“$($(y))”,“$($(y)) ”在被替換為“$(z)”,最終就是“a:=Hello”。

      這里的$($(x))被替換成了$($(y)),因?yàn)?(y)值是“z”,所以,最終結(jié)果是:a:=$(z),也就是“Hello”。

      遞歸變量的套嵌引用過程,也可以包含變量的修改引用和函數(shù)調(diào)用??聪逻叺睦?,使用了make的文本處理函數(shù):



      x = variable1

      variable2 := Hello

      y = $(subst 1,2,$(x))

      z = y

      a := $($($(z)))



      此例同樣的實(shí)現(xiàn)“a:=Hello”。“$($($(z)))”替換為“$($(y))”,之后再次被替換為“$($(subst 1,2,$(x)))”(“$(x)”的值是“variable1”,所以有“$($(subst 1,2,$(variable1)))”)。函數(shù)處理之后為“$(variable2)”

      之后對它在進(jìn)行替換展開。最終,變量“a”的值就是“Hello”。從上邊的例子中我們看到,計(jì)算的變量名的引用過程存在多層套嵌過程,也是用了文本處理 函數(shù)。這個(gè)復(fù)雜的計(jì)算變量的過程,會(huì)使很多人感到混亂甚至迷惑。上例中所要實(shí)現(xiàn)的目的沒有直接使用“a:=Hello”來的直觀明了。我們在書寫 Makefile時(shí),應(yīng)盡量避免使用套嵌的變量引用方式。在一些必需的地方,也最好不要使用高于兩級(jí)的套嵌引用。使用套嵌的變量引用時(shí),如果涉及到遞歸展 開式的變量引用時(shí)需要特別注意。如果處理不當(dāng)可能會(huì)導(dǎo)致遞歸展開錯(cuò)誤,或者出現(xiàn)一些那一預(yù)料的現(xiàn)象。

      一個(gè)計(jì)算的變量名可以不是對一個(gè)完整、單一的其它變量的引用。其中可以包含多個(gè)變量的引用,也可以包含一些文本字符串。就是說,計(jì)算變量的名字可以由一個(gè)或者多個(gè)變量引用同時(shí)加上字符串混合組成。例如:





      a_dirs := dira dirb

      1_dirs := dir1 dir2



      a_files := filea fileb

      1_files := file1 file2



      ifeq "$(use_a)" "yes"

      a1 := a

      else

      a1 := 1

      endif



      ifeq "$(use_dirs)" "yes"

      df := dirs

      else

      df := files

      endif



      dirs := $($(a1)_$(df))



      這個(gè)例子實(shí)現(xiàn)對變量“dirs”的定義,它的可能取值為“a_dirs”、“1_dirs”、“a_files”或者“a_files”四個(gè)值其中之一,具體依賴于“use_a”和“use_dirs”的定義。

      計(jì)算的變量名也可以使用上一小節(jié)我們討論過的“變量的替換引用”。例如:



      a_objects := a.o b.o c.o

      1_objects := 1.o 2.o 3.o



      sources := $($(a1)_objects:.o=.c)



      這個(gè)例子實(shí)現(xiàn)對變量“sources”的定義,它的可能取值為“a.c b.c c.c”和“1.c 2.c 3.c”,具體依賴于“a1”的定義。大家自己分析一下計(jì)算變量名的過程。

      使用嵌套的變量引用的唯一限制是,不能通過指定部分需要調(diào)用的函數(shù)名稱(調(diào)用的函數(shù)包括了函數(shù)名本身和執(zhí)行的參數(shù))來實(shí)現(xiàn)對這個(gè)函數(shù)的調(diào)用。這是因?yàn)樘浊? 引用在展開之前已經(jīng)完成了對函數(shù)名的識(shí)別測試。語言的描述可能比較難理解。我們來看一個(gè)例子,此例子試圖將函數(shù)執(zhí)行的結(jié)果賦值給一個(gè)變量:

      ifdef do_sort

      func := sort

      else

      func := strip

      endif



      bar := a d b g q c

      foo := $($(func) $(bar))



      此例的本意是將“sort”或者“strip”(依賴于是否定義了變量“do_sort”)以“a d b g q c”的執(zhí)行結(jié)果賦值變量“foo”。在這里使用了套嵌引用方式來實(shí)現(xiàn),這個(gè)實(shí)現(xiàn)的結(jié)果是:變量“foo”的值為字符串“sort a d b g q c”或者“strip a d g q c”。這是目前版本的make在處理套嵌變量引用時(shí)的限制。

      計(jì)算的變量名可以用在:1. 一個(gè)使用賦值操作符定義的變量的左值部分;2. 使用“define”定義的變量名中。例如:



      dir = foo

      $(dir)_sources := $(wildcard $(dir)/*.c)

      define $(dir)_print

      lpr $($(dir)_sources)

      endef



      在這個(gè)例子中我們定義了三個(gè)變量:“dir”,“foo_sources”和“foo_print”。

      計(jì)算的變量名在進(jìn)行替換時(shí)的順序是:從最里層的變量引用開始,逐步向外進(jìn)行替換。一層層展開直到最后計(jì)算出需要應(yīng)用的具體的變量,之后進(jìn)行替換展開得到實(shí)際的引用值。

      變量的套嵌引用(計(jì)算的變量名)在我們的Makefile中應(yīng)該盡量避免使用。在必需的場合使用時(shí)掌握的原則是:套嵌使用的層數(shù)越少越好,使用多個(gè)兩層套 嵌引用代替一個(gè)多層的套嵌引用。如果在你的Makefile中存在一個(gè)層次很深的套嵌引用。會(huì)給其他人閱讀造成很大的困難。而且變量的多級(jí)套嵌引用在某些 時(shí)候會(huì)使簡單問題復(fù)雜化。

      作為一個(gè)優(yōu)秀的程序員,在面對一個(gè)復(fù)雜問題時(shí),應(yīng)該是尋求一種盡可能簡單、直接并且高效的處理方式來解決,而不是將一個(gè)簡單問題在實(shí)現(xiàn)上復(fù)雜化。如果想在簡單問題上突出自己使用某種語言的熟練程度,是一種非常愚蠢、且不成熟的行為。

      注意:

      套嵌引用的變量和遞歸展開的變量在本質(zhì)上存在區(qū)別。套嵌的引用就是使用一個(gè)變量表示另外一個(gè)變量,或者更多的層次;而遞歸展開的變量表示當(dāng)一個(gè)變量存在對 其它變量的引用時(shí),對這變量替換的方式。遞歸展開在另外一個(gè)角度描述了這個(gè)變量在定義是賦予它的一個(gè)屬性或者風(fēng)格。并且我們可以在定義個(gè)一個(gè)遞歸展開式的 變量時(shí)使用套嵌引用的方式,但是建議你的實(shí)際編寫Makefile時(shí)要盡量避免這種復(fù)雜的用法。

      6.4 變量取值
      一個(gè)變量可以通過以下幾種方式來獲得值:

      ² 在運(yùn)行make時(shí)通過命令行選項(xiàng)來取代一個(gè)已定義的變量值。

      ² 在makefile文件中通過賦值的方式(參考如何設(shè)置變量一節(jié))或者使用“define”來為一個(gè)變量賦值。

      ² 將變量設(shè)置為系統(tǒng)環(huán)境變量。所有系統(tǒng)環(huán)境變量都可以被make使用。

      ² 自動(dòng)化變量,在不同的規(guī)則中自動(dòng)化變量會(huì)被賦予不同的值。它們每一個(gè)都有單一的習(xí)慣性用法。

      ² 一些變量具有固定的值。

      6.5 如何設(shè)置變量
      Makefile中變量的設(shè)置(也可以稱之為定義)是通過“=”(遞歸方式)或者“:=”(靜態(tài)方式)來實(shí)現(xiàn)的。“=”和“:=”左邊的是變量名,右邊是變量的值。下邊就是一個(gè)變量的定義語句:



      objects = main.o foo.o bar.o utils.o



      這個(gè)語句定義了一個(gè)變量“objects”,其值為一個(gè).o文件的列表。變量名兩邊的空格和“=”之后的空格在make處理時(shí)被忽略。

      使用“=”定義的變量稱之為“遞歸展開”式變量;使用“:=”定義的變量稱為“直接展開”式變量,“直接展開”式的變量如果其值中存在對其變量或者函數(shù)的引用,在定義時(shí)這些引用將會(huì)被進(jìn)行替換展開。

      定義一個(gè)變量時(shí)需要明確以下幾點(diǎn):

      1. 變量名之中可以包含函數(shù)或者其它變量的引用,make在讀入此行時(shí)根據(jù)已定義情況進(jìn)行替換展開而產(chǎn)生實(shí)際的變量名。

      2. 變量的定義值在長度上沒有限制。不過還是需要考慮你的實(shí)際情況,保證你的機(jī)器上有足夠的可用的交換空間來處理一個(gè)超常的變量值。變量定義較長時(shí),一個(gè)好的 做法就是將比較長的行分多個(gè)行來書寫,除最后一行外行與行之間使用反斜杠(\)連接,表示一個(gè)完整的行。這樣的書寫方式對make的處理不會(huì)造成任何影 響,便于后期修改維護(hù)而且使得你的Makefile更清晰。例如上邊的例子就可以這樣寫:

      ojects = main.o foo.o \

      bar.o utils.o

      3. 當(dāng)引用一個(gè)沒有定義的變量時(shí),make默認(rèn)它的值為空。

      4. 一些特殊的變量在make中有內(nèi)嵌固定的值(可參考 9.3 隱含變量 一節(jié)),不過這些變量允許我們在Makefile中顯式得重新給它賦值。

      5. 還存在一些由兩個(gè)符號(hào)組成的特殊變量,稱之為自動(dòng)環(huán)變量。它們的值不能在Makefile中進(jìn)行顯式的修改。這些變量使用在規(guī)則中時(shí),不同的規(guī)則中它們會(huì)被賦予不同的值。

      6. 如果你希望實(shí)現(xiàn)這樣一個(gè)操作,僅對一個(gè)之前沒有定義過的變量進(jìn)行賦值。那么可以使用速記符“?=”(條件方式)來代替“=”或者“:=”來實(shí)現(xiàn)(可參考 5.2.4 “?=”操作符 一小節(jié))。

      6.6 追加變量值
      通常對于一個(gè)通用變量在定義之后的其他一個(gè)地方,需要給它的值進(jìn)行追加。這也是非常有用的。我們可以在開始給它定義一個(gè)基本的值,后續(xù)可以不斷地根據(jù)需要給它增加一些必要值。在Makefile中使用“+=”(追加方式)來實(shí)現(xiàn)對一個(gè)變量值的追加操作。像下邊那樣:



      objects += another.o



      這個(gè)操作把字符串“another.o”添加到變量“objects”原有值的末尾,使用空格將其分開。因此我們可以看到:



      objects = main.o foo.o bar.o utils.o

      objects += another.o



      上邊的兩個(gè)操作之后變量“objects”的值成:“main.o foo.o bar.o utils.o another.o”。使用“+=”操作符,就相當(dāng)于:

      objects = main.o foo.o bar.o utils.o

      objects := $(objects) another.o



      但是,這兩種方式可能在簡單一些的Makefile有相同的效果,復(fù)雜的Makefile中它們之間的差異就會(huì)導(dǎo)致一些問題。為了方便我們調(diào)試,了解這兩種實(shí)現(xiàn)的差異還是很有必要的。

      1. 如果被追加值的變量之前沒有定義,那么,“+=”會(huì)自動(dòng)變成“=”,此變量就被定義為一個(gè)遞歸展開式的變量。如果之前存在這個(gè)變量定義,那么“+=”就繼承之前定義時(shí)的變量風(fēng)格。

      2. 直接展開式變量的追加過程:變量使用“:=”定義,之后“+=”操作將會(huì)首先替換展開之前此變量的值,爾后在末尾添加需要追加的值,并使用“:=”重新給此變量賦值。實(shí)際的過程像下邊那樣:



      variable := value

      variable += more



      就是:



      variable := value

      variable := $(variable) more



      3. 遞歸展開式變量的追加過程:一個(gè)變量使用“=”定義,之后“+=”操作時(shí)不對之前此變量值中的任何引用進(jìn)行替換展開,而是按照文本的擴(kuò)展方式(之前等號(hào)右 邊的文本未發(fā)生變化)替換,爾后在末尾添加需要追加的值,并使用“=”給此變量重新賦值。實(shí)際的過程和上邊的相類似:



      variable = value

      variable += more



      相當(dāng)于:



      temp = value

      variable = $(temp) more



      當(dāng)然了,上邊的過程并不會(huì)存在中間變量:“temp”,這里只是使用它來描述得更形象。這種情況時(shí)如果“value”中存在某種引用,情況就有些不同了??次覀兺ǔR粋€(gè)會(huì)用到的例子:



      CFLAGS = $(includes) -O

      ...

      CFLAGS += -pg # enable profiling



      第一行定義了變量“CFLAGS”,它是一個(gè)遞歸展開式的變量。因此make在處理它的定義時(shí)不會(huì)對其值中的引用“$(includes)”進(jìn)行展開,它 的替換展開是在變量“CFLAGS”被引用的規(guī)則中。因此,變量“include”可以在“CFLAGS”之前沒有定義,只要它在實(shí)際引用 “CFLAGS”之前定義就可以了。如果給“CFLAGS”追加值使用“:=”操作符,我們按照下邊那樣實(shí)現(xiàn):



      CFLAGS := $(CFLAGS) -pg # enable profiling



      這樣似乎好像很正確,但是實(shí)際上它在有些情況時(shí)卻不是你所要實(shí)現(xiàn)的。我們來看看,因?yàn)?#8220;:=”操作符定義的是直接展開式變量,因此變量值中對其它變量或者 函數(shù)的引用會(huì)在定義時(shí)進(jìn)行展開。在這種情況下,如果變量“includes”在之前沒有進(jìn)行定義的話,變量“CFLAGS”的值為“-O -pg”($(includes)被替換展開為空字符)。而其后出現(xiàn)的“includes”的定義對“CFLAGS”將不產(chǎn)生影響。相反的情況,如果我們 在這里使用“+=”實(shí)現(xiàn):



      CFLAGS += -pg # enable profiling



      那么變量“CFLAGS”的值就是文本串“$(includes) –O -pg”,因?yàn)橹?#8220;CFLAGS”定義為遞歸展開式,所以追加值時(shí)不會(huì)對其值的引用進(jìn)行替換展開。因此變量“includes”只要出現(xiàn)在規(guī)則對 “CFLAGS”的引用之前定義,它都可以對“CFLAGS”的值起作用。對于遞歸展開式變量的追加,make程序會(huì)同樣會(huì)按照遞歸展開式的定義來實(shí)現(xiàn)對 變量的重新賦值,不會(huì)發(fā)生遞歸展開式變量展開過程的無限循環(huán)。



      6.7 override 指示符
      通常在執(zhí)行make時(shí),如果通過命令行定義了一個(gè)變量,那么它將替代在Makefile中出現(xiàn)的同名變量的定義。就是說,對于一個(gè)在Makefile中使 用常規(guī)方式(使用“=”、“:=”或者“define”)定義的變量,我們可以在執(zhí)行make時(shí)通過命令行方式重新指定這個(gè)變量的值,命令行指定的值將替 代出現(xiàn)在Makefile中此變量的值。為了防止命令行變量定義的值替代Makefile中變量定義的值。需要在Makefile中使用指示符 “override”來聲明這個(gè)變量,像下邊那樣:



      override VARIABLE = VALUE



      或者:



      override VARIABLE := VALUE



      也可以對變量使用追加方式:



      override VARIABLE += MORE TEXT



      對于追加方式需要說明的是:變量在定義時(shí)使用了“override”,則后續(xù)對它值進(jìn)行追加時(shí),也需要使用帶有“override”指示符的追加方式。否則對此變量值的追加不會(huì)生效。

      指示符“override”并不是用來調(diào)整Makefile和執(zhí)行時(shí)命令參數(shù)的沖突,其存在的目的是為了使用戶可以改變或者追加那些使用make的命令行 指定的變量的定義。從另外一個(gè)角度來說,就是實(shí)現(xiàn)了在Makefile中增加或者修改命令行參數(shù)的一種機(jī)制。我們可能會(huì)有這樣的需求;可以通過命令行來指 定一些附加的編譯參數(shù),對一些通用的參數(shù)或者必需的編譯參數(shù)我們可以在Makefile中指定,而在命令行中可以指定一些特殊的參數(shù)。對待這種需求,我們 可以使用指示符“override”來實(shí)現(xiàn)。

      例如無論命令行指定那些編譯參數(shù),必須打開調(diào)試開關(guān)“-g”,我們的Makefile對“CFLAGS”應(yīng)該這樣寫:



      override CFLAGS += -g



      無論通過命令行指定那些編譯選項(xiàng),“-g”參數(shù)始終存在。

      對于使用“define”定義的變量我們同樣也可以使用“override”進(jìn)行聲明。例如:



      override define foo

      bar

      endef







      最后我們來看一個(gè)例子:



      # sample Makefile



      EXEF = foo



      override CFLAGS += -Wall –g



      .PHONY : all debug test

      all : $(EXEF)



      foo : foo.c

      ………..

      ………..



      $(EXEF) : debug.h

      $(CC) $(CFLAGS) $(addsuffix .c,$@) –o $@



      debug :

      @echo ”CFLAGS = $(CFLAGS)”



      執(zhí)行:make CFLAGS=-O2 將顯式結(jié)果為編譯“foo”的過程是“cc –O2 –Wall –g foo.c –o foo”。執(zhí)行“make CFLAGS=-O2 debug”可以查看到變量“CFLAGS”的值為“–O2 –Wall –g”。另外,這個(gè)例子中,如果把變量“CFLAGS”之前的指示符“override”去掉以后使用相同的命令將得到不同的結(jié)果。大家試試看!



      6.8 多行定義
      定義變量的另外一種方式是使用“define”指示符。它定義一個(gè)包含多行字符串的變量,我們就是利用它的這個(gè)特點(diǎn)實(shí)現(xiàn)一個(gè)完整命令包的定義。使用“define”定義的命令包可以作為“eval”函數(shù)的參數(shù)來使用。

      本文的前些章節(jié)已經(jīng)不止一次的提到并使用了“define”。相信大家已經(jīng)有所了解。本節(jié)就“define”定義變量從以下幾個(gè)方面來討論:

      1. “define”定義變量的語法格式:以指示符“define”開始,“endif”結(jié)束,之間的所有內(nèi)容就是所定義變量的值。所要定義的變量名字指示符 “define”的同一行之后;指示符所在行的下一行開始一直到“end”所在行的上一行之間的若干行,是變量的值定義。

      define two-lines

      echo foo

      echo $(bar)

      endef



      如果將變量“two-lines”作為命令包執(zhí)行時(shí),其相當(dāng)于:

      two-lines = echo foo; echo $(bar)



      我想大家對這個(gè)命令的執(zhí)行應(yīng)該是比較熟悉的。它把變量“two-lines”的值作為一個(gè)完整的shell命令行來處理(是使用分號(hào)“;”分開的在同一行 中的兩個(gè)命令而不是作為兩個(gè)命令行來處理),保證了變量完整。(關(guān)于完整命令行的執(zhí)行可參考 5.2 命令的執(zhí)行 一節(jié))

      2. 變量的風(fēng)格:使用“define”定義的變量和使用“=”定義的變量一樣,屬于“遞歸展開”式的變量,兩者只是在語法上不同。因此“define”所定義 的變量值中,對其它變量或者函數(shù)引用不會(huì)在定義時(shí)替換展開,其展開是在“define”定義的變量被引用時(shí)進(jìn)行的。

      3. 可以套嵌引用。因?yàn)槭沁f歸展開式變量,所以在存在嵌套引用時(shí)“$(x)”將是變量的值的一部分。

      4. 變量值中可以包含:換行符、空格等特殊符號(hào)(注意如果定義中某一行是以[Tab]字符開始時(shí),當(dāng)引用此變量時(shí)這一行會(huì)被作為命令行來處理)。

      5. 可以使用“override”在定義時(shí)聲明變量:這樣可以防止變量的值被命令行指定的值替代。例如:

      override define two-lines

      foo

      $(bar)

      endef





      6.9 系統(tǒng)環(huán)境變量
      make在運(yùn)行時(shí),系統(tǒng)的所有環(huán)境變量對它都是可見的。在Makefile中,可以引用任何已定義的系統(tǒng)環(huán)境變量。(這里我們區(qū)分系統(tǒng)環(huán)境變量和make 的環(huán)境變量,系統(tǒng)環(huán)境變量是這個(gè)系統(tǒng)所有用戶所擁有的,而make的環(huán)境變量只是對于make的一次執(zhí)行過程有效,以下正文中出現(xiàn)沒有限制的“環(huán)境變量” 時(shí)默認(rèn)指的是“系統(tǒng)環(huán)境變量”,在特殊的場合我們會(huì)區(qū)分兩者)正因?yàn)槿绱?,我們就可以設(shè)置一個(gè)命名為“CFLAGS”的環(huán)境變量,用它來指定一個(gè)默認(rèn)的編 譯選項(xiàng)。我們就可以在所有的Makefile中直接使用這個(gè)變量來對c源代碼就行編譯。通常這種方式是比較安全的,但是它的前提是大家都明白這個(gè)變量所代 表的含義,沒有人在Makefile中把它作其他的用途。當(dāng)然了,你也可以在你的Makefile中根據(jù)你的需要對它進(jìn)行重新定義。

      使用環(huán)境變量我們需要注意以下幾點(diǎn):

      1. 在Makefile中對一個(gè)變量的定義或者以make命令行形式對一個(gè)變量的定義,都將覆蓋同名的環(huán)境變量(注意:它并不改變系統(tǒng)環(huán)境變量定義,被修改的 環(huán)境變量只在make執(zhí)行過程有效)。而make使用“-e”參數(shù)時(shí),Makefile和命令行定義的變量不會(huì)覆蓋同名的環(huán)境變量,make將使用系統(tǒng)環(huán) 境變量中這些變量的定義值。

      2. make的遞歸調(diào)用中,所有的系統(tǒng)環(huán)境變量會(huì)被傳遞給下一級(jí)make。默認(rèn)情況下,只有環(huán)境變量和通過命令行方式定義的變量才會(huì)被傳遞給子make進(jìn)程。 在Makefile中定義的普通變量需要傳遞給子make時(shí)需要使用“export”指示符來對它聲明。

      3. 一個(gè)比較特殊的是環(huán)將變量“SHELL”。在系統(tǒng)中這個(gè)環(huán)境變量的用途是用來指定用戶和系統(tǒng)的交互接口,顯然對于make是不合適的。因此在make的執(zhí) 行環(huán)境變量“SHELL”的取值不使用同名的環(huán)境變量定義,而默認(rèn)使用“/bin/sh”作為它的命令行解釋程序(make執(zhí)行之前設(shè)置它為 “/bin/sh”)。



      這里不推薦使用環(huán)境變量來完成普通變量的工作,特別是在make的遞歸調(diào)用中。任何一個(gè)環(huán)境變量的錯(cuò)誤定義都對系統(tǒng)上的所有make產(chǎn)生影響,甚至是毀壞 性的。因?yàn)榄h(huán)境變量具有全局的特征。所以盡量不要污染環(huán)境變量,造成環(huán)境變量名字污染。我想大多數(shù)系統(tǒng)管理員都明白環(huán)境變量對系統(tǒng)是多么的重要。





      我們來看一個(gè)例子,結(jié)束本節(jié)。假如我們的機(jī)器名為“server-cc”;我們的Makefile內(nèi)容如下:



      # sample Makefile

      HOSTNAME = server-http

      …………

      …………

      .PHONY : debug

      debug :

      @echo “hostname is : $( HOSTNAME)”

      @echo “shell is $(SHELL)”



      1. 執(zhí)行“make debug”將顯示:

      hostname is : server-http

      shell is /bin/sh

      2. 執(zhí)行“make –e debug”;將顯示:

      hostname is : server-cc

      shell is /bin/sh

      3. 執(zhí)行“make –e HOSTNAEM=server-ftp”;將顯示:

      hostname is : server-ftp

      shell is /bin/sh



      記住:除非必須,否則在你的Makefile中不要重置環(huán)境變量“SHELL”的值。因?yàn)橐粋€(gè)不正確的命令行解釋程序可能會(huì)導(dǎo)致規(guī)則定義的命令執(zhí)行失敗,甚至是無法執(zhí)行!當(dāng)需要重置它時(shí),必須有充分的理由和配套的規(guī)則命令來適應(yīng)這個(gè)新指定的命令行解釋程序。



      6.10目標(biāo)指定變量
      在Makefile中定義一個(gè)變量,這個(gè)變量對此Makefile的所有規(guī)則都是有效的。它就像是一個(gè)“全局的”變量(僅限于定義它的那個(gè) Makefile中的所有規(guī)則,如果需要對其它的Makefile中的規(guī)則有效,就需要使用“export”對它進(jìn)行聲明)。當(dāng)然“自動(dòng)化變量”除外。

      另外一個(gè)特殊的變量就是所謂的“目標(biāo)指定變量(Target-specific Variable)”。此特性允許對于相同變量根據(jù)目標(biāo)指定不同的值,有點(diǎn)類似于自動(dòng)化變量。目標(biāo)指定的變量值只在指定它的目標(biāo)的上下文中有效,對于其他 的目標(biāo)不產(chǎn)生影響。就是說目標(biāo)指定的變量具有“局部性”。

      設(shè)置一個(gè)目標(biāo)指定變量的語法為:



      TARGET ... : VARIABLE-ASSIGNMENT



      或者:



      TARGET ... : override VARIABLE-ASSIGNMENT



      一個(gè)多目標(biāo)指定的變量的作用域是所有這些目標(biāo)的上下文,它包括了和這個(gè)目標(biāo)相關(guān)的所有執(zhí)行過程。

      目標(biāo)指定變量的一些特點(diǎn):

      1. “VARIABLE-ASSIGNMENT”可以使用任何一個(gè)有效的賦值方式,“=”(遞歸)、“:=”(靜態(tài))、“+=”(追加)或者“?=”(條件)。

      2. 使用目標(biāo)指定變量值時(shí),目標(biāo)指定的變量值不會(huì)影響同名的那個(gè)全局變量的值。就是說目標(biāo)指定一個(gè)變量值時(shí),如果在Makefile中之前已經(jīng)存在此變量的定 義(非目標(biāo)指定的),那么對于其它目標(biāo)全局變量的值沒有變化。變量值的改變只對指定的這些目標(biāo)可見。

      3. 目標(biāo)指定變量和普通變量具有相同的優(yōu)先級(jí)。就是說,當(dāng)我們使用make命令行的方式定義變量時(shí),命令行中的定義將替代目標(biāo)指定的同名變量定義(和普通的變 量一樣會(huì)被覆蓋)。另外當(dāng)使用make的“-e”選項(xiàng)時(shí),同名的環(huán)境變量也將覆蓋目標(biāo)指定的變量定義。因此為了防止目標(biāo)指定的變量定義被覆蓋,可以使用第 二種格式,使用指示符“override”對目標(biāo)指定的變量進(jìn)行聲明。

      4. 目標(biāo)指定的變量和同名的全局變量屬于兩個(gè)不同的變量,它們在定義的風(fēng)格(遞歸展開式和直接展開式)上可以不同。

      5. 目標(biāo)指定的變量變量會(huì)作用到由這個(gè)目標(biāo)所引發(fā)的所有的規(guī)則中去。例如:



      prog : CFLAGS = -g

      prog : prog.o foo.o bar.o



      這個(gè)例子中,無論Makefile中的全局變量“CFLAGS”的定義是什么。對于目標(biāo)“prog”以及其所引發(fā)的所有(包含目標(biāo)為“prog.o”、“foo.o”和“bar.o”的所有規(guī)則)規(guī)則,變量“CFLAGS”值都是“-g”。

      使用目標(biāo)指定變量我們可以在Makefile實(shí)現(xiàn),對于不同的目標(biāo)文件使用不同的編譯參數(shù)??匆粋€(gè)例子:

      # sample Makefile



      CUR_DIR = $(shell pwd)

      INCS := $(CUR_DIR)/include

      CFLAGS := -Wall –I$(INCS)



      EXEF := foo bar



      .PHONY : all clean

      all : $(EXEF)



      foo : foo.c

      foo : CFLAGS+=-O2

      bar : bar.c

      bar : CFLAGS+=-g

      ………..

      ………..



      $(EXEF) : debug.h

      $(CC) $(CFLAGS) $(addsuffix .c,$@) –o $@



      clean :

      $(RM) *.o *.d $(EXES)



      這個(gè)Makefile文件實(shí)現(xiàn)了在編譯程序“foo”使用優(yōu)化選項(xiàng)“-O2”但不使用調(diào)試選項(xiàng)“-g”,而在編譯“bar”時(shí)采用了“-g”但沒有“-O2”。這就是目標(biāo)指定變量的靈活之處。目標(biāo)指定變量的其它特性大家可以修改這個(gè)簡單的Makefile來進(jìn)行驗(yàn)證!

      6.11模式指定變量
      GNU make中,除了支持上一節(jié)所討論的模式指定變量之外(參考上一節(jié)),還支持另外一種方式:模式指定變量(Pattern-specific Variable)。使用目標(biāo)定變量定義時(shí),此變量被定義在某個(gè)具體目標(biāo)和由它所引發(fā)的規(guī)則的目標(biāo)上。而模式指定變量定義是將一個(gè)變量值指定到所有符合特 定模式的目標(biāo)上去。對于同一個(gè)變量如果使用追加方式,通常一個(gè)目標(biāo)的局部變量值的順序是:(為所有規(guī)則定義的全局值)+(引發(fā)它所在規(guī)則被執(zhí)行的目標(biāo)所指 定值)+(它所符合的模式指定值)+(此目標(biāo)所指定的值)。這個(gè)大家也不需要深入了解。

      設(shè)置一個(gè)模式指定變量的語法和設(shè)置目標(biāo)變量的語法相似:



      PATTERN ... : VARIABLE-ASSIGNMENT



      或者:



      PATTERN ... : override VARIABLE-ASSIGNMENT



      和目標(biāo)指定變量語法的唯一區(qū)別就是:這里的目標(biāo)是一個(gè)或者多個(gè)“模式”目標(biāo)(包含模式字符“%”)。例如我們可以為所有的.o文件指定變量“CFLAGS”的值:



      %.o : CFLAGS += -O



      它指定了所有.o文件的編譯選項(xiàng)包含“-O”選項(xiàng),不改變對其它類型文件的編譯選項(xiàng)。

      需要說明的是:在使用模式指定的變量定義時(shí)。目標(biāo)文件一般除了模式字符(%)以外需要包含某種文件名的特征字符(例如:“a%”、“%.o”、“%.a”等)。當(dāng)單獨(dú)使用“%”作為目標(biāo)時(shí),指定的變量會(huì)對任何類型的目標(biāo)文件都有效

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請遵守用戶 評(píng)論公約

        類似文章 更多