欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
make的隱含規則

make的隱含規則


Makefile中重建一類(lèi)目標的標準規則在很多場(chǎng)合需要用到。例如:根據.c源文件創(chuàng )建對應的.o文件,傳統方式是使用GNU C編譯器。

“隱含規則”為make提供了重建一類(lèi)目標文件通用方法,不需要在Makefile中明確地給出重建特定目標文件所需要的細節描述。例如:典型地;makeC文件的編譯過(guò)程是由.c源文件編譯生成.o目標文件。當Makefile中出現一個(gè).o文件目標時(shí),make會(huì )使用這個(gè)通用的方式將后綴為.c的文件編譯稱(chēng)為目標的.o文件。

另外,在make執行時(shí)根據需要也可能是用多個(gè)隱含規則。比如:make將從一個(gè).y文件生成對應的.c文件,最后再生成最終的.o文件。就是說(shuō),只要目標文件名中除后綴以外其它部分相同,make都能夠使用若干個(gè)隱含規則來(lái)最終產(chǎn)生這個(gè)目標文件(當然最原始的那個(gè)文件必須存在)。例如;可以在Makefile中這樣來(lái)實(shí)現一個(gè)規則:“foo : foo.h”,只要在當前目錄下存在“foo.c”這個(gè)文件,就可以生成“foo”可執行文件。本文前邊的很多例子中已經(jīng)使用到了隱含規則。

內嵌的“隱含規則”在其所定義的命令行中,會(huì )使用到一些變量(通常也是內嵌變量)。我們可以通過(guò)改變這些變量的值來(lái)控制隱含規則命令的執行情況。例如:內嵌變量“CFLAGS”代表了gcc編譯器編譯源文件的編譯選項,我們就可以在Makefile中重新定義它,來(lái)改變編譯源文件所要使用的參數。

盡管我們不能改變make內嵌的隱含規則,但是我們可以使用模式規則重新定義自己的隱含規則,也可以使用后追規則來(lái)重新定義隱含規則。后綴規則存在某些限制(目前版本make保存它的原因是為了兼容以前版本)。使用模式規則更加清晰明了。

10.1 隱含規則的使用

使用make內嵌的隱含規則,在Makefile中就不需要明確給出重建某一個(gè)目標的命令,甚至可以不需要規則。make會(huì )自動(dòng)根據已存在(或者可以被創(chuàng )建)的源文件類(lèi)型來(lái)啟動(dòng)相應的隱含規則。例如:

 

foo : foo.o bar.o

cc -o foo foo.o bar.o $(CFLAGS) $(LDFLAGS)

 

這里并沒(méi)有給出重建文件“foo.o”的規則,make執行這條規則時(shí),無(wú)論文件“foo.o”存在與否,都會(huì )試圖根據隱含規則來(lái)重建這個(gè)文件(就是試圖重新編譯文件“foo.c”或者其它類(lèi)型的源文件)。

make執行過(guò)程中找到的隱含規則,提供了此目標的基本依賴(lài)關(guān)系,確定了目標的依賴(lài)文件(通常是源文件,不包含對應的頭文件依賴(lài))和重建目標需要使用的命令行。隱含規則所提供的依賴(lài)文件只是一個(gè)最基本的(通常它們之間的對應關(guān)系為:“EXENAME.o”對應“EXENAME.c”、“EXENAME”對應于“EXENAME.o”)。當需要增加這個(gè)目標的依賴(lài)文件時(shí),要在Makefile中使用沒(méi)有命令行的規則給出。

每一個(gè)內嵌的隱含規則中都存在一個(gè)目標模式和依賴(lài)模式,而且同一個(gè)目標模式可以對應多個(gè)依賴(lài)模式。例如:一個(gè).o文件的目標可以由c編譯器編譯對應的.c源文件得到、Pascal編譯器編譯.p的源文件得到,等等。make會(huì )根據不同的源文件來(lái)使用不同的編譯器。對于“foo.c”就是用c編譯,對于“foo.p”就使用Pascal編譯器編譯。

上邊提到,make會(huì )自動(dòng)根據已存在(或者可以被創(chuàng )建)的源文件類(lèi)型來(lái)啟動(dòng)相應的隱含規則。這里的“可被創(chuàng )建”文件是指:這個(gè)文件在Makefile中被作為目標或者依賴(lài)明確的提及,或者可以根據已存在的文件使用其它的隱含規則來(lái)創(chuàng )建它。當一個(gè)隱含規則的目標是另外一個(gè)隱含規則的依賴(lài)時(shí),我們稱(chēng)它們是一個(gè)隱含規則鏈。

通常,make會(huì )對那些沒(méi)有命令行的規則、雙冒號規則尋找一個(gè)隱含規則來(lái)執行。作為一個(gè)規則的依賴(lài)文件,在沒(méi)有一個(gè)規則明確描述它的依賴(lài)關(guān)系的情況下;make會(huì )將其作為一個(gè)目標并為它搜索一個(gè)隱含規則,試圖重建它。

注意:給目標文件指定明確的依賴(lài)文件并不會(huì )影響隱含規則的搜索。我們來(lái)看一個(gè)例子:

 

foo.o: foo.p

 

這個(gè)規則指定了“foo”的依賴(lài)文件是“foo.p”。但是如果在工作目錄下存在同名.c源文件“foo.c”。執行make的結果就不是用“pc”編譯“foo.p”來(lái)生成“foo”,而是用“cc”編譯“foo.c”來(lái)生成目標文件。這是因為在隱含規則列表中對.c文件的隱含規則處于.p文件隱含規則之前。

當需要給目標指定明確的重建規則時(shí),規則描述中就不能省略命令行,這個(gè)規則必須提供明確的重建命令來(lái)說(shuō)明目標需要重建所需要的動(dòng)作。為了能夠在存在“foo.c”的情況下編譯“foo.p”。規則可以這樣寫(xiě):

 

foo.o: foo.p

pc $< -o $@

 

這一點(diǎn)在多語(yǔ)言實(shí)現的工程編譯中,需要特別注意!否則編譯出來(lái)的可能就不是你想要得程序。

另外:當我們不想讓make為一個(gè)沒(méi)有命令行的規則中的目標搜索隱含規則時(shí),我們需要使用空命令來(lái)實(shí)現。

最后讓我們來(lái)看一個(gè)簡(jiǎn)單的例子,之前在目標指定變量 一節的例子我們就可以簡(jiǎn)化為:

# sample Makefile

 

CUR_DIR = $(shell pwd)

INCS := $(CUR_DIR)/include

CFLAGS := -Wall –I$(INCS)

 

EXEF := foo bar

 

.PHONY : all clean

all : $(EXEF)

 

foo : CFLAGS+=-O2

bar : CFLAGS+=-g

 

clean :

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

 

例子中沒(méi)有出現任何關(guān)于源文件的描述。所有剩余工作全部交給了make去處理,它會(huì )自動(dòng)尋找到相應規則并執行、最終完成目標文件的重建。

隱含規則為我們提供了一個(gè)編譯整個(gè)工程非常高效的手段,一個(gè)大的工程中毫無(wú)例外的會(huì )用到隱含規則。實(shí)際工作中,靈活運用GNU make所提供的隱含規則功能,可以大大提供效率。

10.2      make的隱含規則一覽

本節羅列出了GUN make常見(jiàn)的一些內嵌隱含規則,除非在Makefile有名確定義、或者使用命令行“-r”或者“-R”參數取消隱含規則,否則這些隱含規則將有效。

需要說(shuō)明的是:即使我們沒(méi)有使用命令行參數“-r”,在make中也并不是所有的這些隱含規則都被定義了。其實(shí),很多的這些看似預定義的隱含規則在make執行時(shí),實(shí)際是用后綴規則來(lái)實(shí)現的;因此,它們依賴(lài)于make中的“后綴列表”(也就是目標.SUFFIXES的后綴列表)。make的默認后綴列表為:“.out”、“.a”、“.ln”、“.o”、“.c”、“.cc”、“.C”、“.p”、“.f”、“.F”、“.r”、“.y”、“.l”、“.s”、“.S”、“.mod”、“.sym”、“.def”、“.h”、“.info”、“.dvi”、“.tex”、“.texinfo”、“.texi”、“txinfo”、“.w”、“.ch”、“.web”、“.sh”、“.elc”、“el”。所有我們下邊將提到的隱含規則,如果其依賴(lài)文件中某一個(gè)滿(mǎn)足列表中列出的后綴,則是后綴規則。如果修改了可識別后綴列表,那么可能會(huì )是許多默認預定義的規則無(wú)效(因為一些后綴可能不會(huì )別識別)。以下是常用的一些隱含規則(對于不常見(jiàn)的隱含規則這里沒(méi)有描述):

1.        編譯C程序

N.o”自動(dòng)由“N.c 生成,執行命令為“$(CC) -c $(CPPFLAGS) $(CFLAGS)”。

2.        編譯C++程序

N.o”自動(dòng)由“N.cc”或者“N.C 生成,執行命令為“$(CXX) -c $(CPPFLAGS) $(CFLAGS)”。建議使用“.cc”作為C++源文件的后綴,而不是“.C

3.        編譯Pascal程序

N.o”自動(dòng)由“N.p”創(chuàng )建,執行命令時(shí)“$(PC) -c $(PFLAGS)”。

4.        編譯Fortran/Ratfor程序

N.o”自動(dòng)由“N.r”、“N.F”或者“N.f 生成,根據源文件后綴執行對應的命令:

    .f $(FC) –c  $(FFLAGS)

    .F $(FC) –c  $(FFLAGS) $(CPPFLAGS)

    .r $(FC) –c  $(FFLAGS) $(RFLAGS)

5.        預處理Fortran/Ratfor程序

N.f”自動(dòng)由“N.r”或者“N.F 生成。此規則只是轉換Ratfor或有預處理的Fortran程序到一個(gè)標準的Fortran程序。根據源文件后綴執行對應的命令:

    .F $(FC) –F $(CPPFLAGS) $(FFLAGS)

    .r $(FC) –F $(FFLAGS) $(RFLAGS)

6.        編譯Modula-2程序

N.sym”自動(dòng)由“N.def 生成,執行的命令是:“$(M2C) $(M2FLAGS) $(DEFFLAGS)”。“N.o”自動(dòng)由“N.mod”生成,執行的命令是:“$(M2C) $(M2FLAGS) $(MODFLAGS)”。

7.        匯編和需要預處理的匯編程序

N.s”是不需要預處理的匯編源文件,“N.S”是需要預處理的匯編源文件。匯編器為“as”。

N.o 可自動(dòng)由“N.s”生成,執行命令是:“$(AS) $(ASFLAGS)”。

N.s 可由“N.S”生成,C預編譯器“cpp”,執行命令是:“$(CPP) $(CPPFLAGS)”。

8.        鏈接單一的object文件

N”自動(dòng)由“N.o”生成,通過(guò)C編譯器使用鏈接器(GUN ld),執行命令是:“$(CC) $(LDFLAGS) N.o $(LOADLIBES) $(LDLIBS)”。

此規則僅適用:由一個(gè)源文件直接產(chǎn)生可執行文件的情況。當需要有多個(gè)源文件共同來(lái)創(chuàng )建一個(gè)可執行文件時(shí),需要在Makefile中增加隱含規則的依賴(lài)文件。例如:

x : y.o z.o

當“x.c”、“y.c”和“z.c”都存在時(shí),規則執行如下命令:

cc -c x.c -o x.o

cc -c y.c -o y.o

cc -c z.c -o z.o

cc x.o y.o z.o -o x

rm -f x.o

rm -f y.o

rm -f z.o

在復雜的場(chǎng)合,目標文件和源文件之間不存在向上邊那樣的名字對應關(guān)系時(shí)(“x”和“x.c”對應,因此隱含規則在進(jìn)行鏈接時(shí),自動(dòng)將“x.c”作為其依賴(lài)文件)。這時(shí),需要在Makefile中明確給出描述目標依賴(lài)關(guān)系的規則。

 

通常,gcc在編譯源文件時(shí)(根據源文件的后綴名來(lái)啟動(dòng)相應的編譯器),如果沒(méi)有指定“-c”選項,gcc會(huì )在編譯完成之后調用“ld”連接成為可執行文件。

9.        Yacc C程序

N.c”自動(dòng)由“N.y”,執行的命令:“$(YACC) $(YFALGS)”。(“Yacc”是一個(gè)語(yǔ)法分析工具)

10.   Lex C程序時(shí)的隱含規則。

N.c”自動(dòng)由“N.l”,執行的命令是:“$(LEX) $(LFALGS)”。(關(guān)于“Lex”的細節請查看相關(guān)資料)

 

這里沒(méi)有列出所有的隱含規則,僅列出我個(gè)人在實(shí)際工作中涉及到的。沒(méi)有涉及的很難對英文文檔進(jìn)行深入地說(shuō)明和理解。如果那些沒(méi)有提到的各位有所使用,或者能夠詳細的描述可以添加到這個(gè)文檔中!

 

在隱含規則中,命令行中的實(shí)際命令是使用一個(gè)變量計算得到,諸如:“COMPILE.c”、“LINK.o”(這個(gè)在前面也看到過(guò))和“PREPROCESS.S”等。這些變量被展開(kāi)之后就是對應的命令(包括了命令行選項),例如:變量“COMPILE.c”的定義為 cc -c”(如果Makefile中存在“CFLAGS”的定義,它的值會(huì )存在于這個(gè)變量中)。

make會(huì )根據默認的約定,使用“COMPILE.x”來(lái)編譯一個(gè)“.x”的文件。類(lèi)似地使用“LINK.x”來(lái)連接“.x”文件;使用“PREPROCESS.x”對“.x”文件進(jìn)行預處理。

每一個(gè)隱含規則在創(chuàng )建一個(gè)文件時(shí)都使用了變量“OUTPUT_OPTION”。make執行命令時(shí)根據命令行參數來(lái)決定它的值,當命令行中沒(méi)有包含“-o”選項時(shí),它的值為:“-o $@”,否則為空。建議在規則的命令行中明確使用“-o”選項執行輸出文件路徑。這是因為在編譯一個(gè)多目錄的工程時(shí),如果我們的Makefile中使用了VPATH”指定搜索目錄 時(shí),編譯后的.o文件或者其它文件會(huì )出現在和源文件不同的目錄中。在有些系統的編譯器不接受命令行的“-o”參數,而Makefile中包含“VPAT”的情況時(shí),輸出文件可能會(huì )出現在錯誤的目錄下。解決這個(gè)問(wèn)題的方式就是將“OUTPUT_OPTION”的值賦為“;mv $*.o $@”,其功能是將編譯完成的.o文件改變?yōu)橐巹t中的目標文件。

10.3      隱含變量

內嵌隱含規則的命令中,所使用的變量都是預定義的變量。我們將這些變量稱(chēng)為“隱含變量”。這些變量允許對它進(jìn)行修改:在Makefile中、通過(guò)命令行參數或者設置系統環(huán)境變量的方式來(lái)對它進(jìn)行重定義。無(wú)論是用那種方式,只要make在運行時(shí)它的定義有效,make的隱含規則都會(huì )使用這些變量。當然,也可以使用“-R”或“--nobuiltin-variables”選項來(lái)取消所有的隱含變量(同時(shí)將取消了所有的隱含規則)。

例如,編譯.c源文件的隱含規則為:“$(CC) -c $(CFLAGS) $(CPPFLAGS)”。默認的編譯命令是“cc”,執行的命令是:“cc –c”。我們可以同上述的任何一種方式將變量“CC”定義為“ncc”,那么編譯.c源文件所執行的命令將是“ncc -c”。同樣我們可以對變量“CFLAGS”進(jìn)行重定義。對這些變量重定義后如果需要整個(gè)工程的各個(gè)子目錄有效,同樣需要使用關(guān)鍵字“export”將他們導出;否則目錄間編譯命令可能出現不一致。編譯.c源文件時(shí),隱含規則使用“$(CC)”來(lái)引用編譯器;“$(CFLAGS)”引用編譯選項。

隱含規則中所使用的變量(隱含變量)分為兩類(lèi):1. 代表一個(gè)程序的名字(例如:“CC”代表了編譯器這個(gè)可執行程序)。2. 代表執行這個(gè)程序使用的參數(例如:變量“CFLAGS”),多個(gè)參數使用空格分開(kāi)。當然也允許在程序的名字中包含參數。但是這種方式建議不要使用。

以下是一些作為程序名的隱含變量定義:

10.3.1       代表命令的變量

AR

函數庫打包程序,可創(chuàng )建靜態(tài)庫.a文檔。默認是“ar”。

AS

匯編程序。默認是“as”。

CC

C編譯程序。默認是“cc”。

CXX

C++編譯程序。默認是“g++”。

CO

RCS中提取文件的程序。默認是“co”。

CPP

C程序的預處理器(輸出是標準輸出設備)。默認是“$(CC) -E”。

FC

編譯器和預處理Fortran Ratfor 源文件的編譯器。默認是“f77”。

GET

SCCS中提取文件程序。默認是“get”。

LEX

Lex 語(yǔ)言轉變?yōu)?/span> C Ratfo 的程序。默認是“lex”。

PC

Pascal語(yǔ)言編譯器。默認是“pc”。

YACC

Yacc文法分析器(針對于C程序)。默認命令是“yacc”。

YACCR

Yacc文法分析器(針對于Ratfor程序)。默認是“yacc -r”。

MAKEINFO

轉換Texinfo源文件(.texi)到Info文件程序。默認是“makeinfo”。

TEX

TeX源文件創(chuàng )建TeX DVI文件的程序。默認是“tex”。

TEXI2DVI

Texinfo源文件創(chuàng )建TeX DVI 文件的程序。默認是“texi2dvi”。

WEAVE

轉換WebTeX的程序。默認是“weave”。

CWEAVE

轉換C Web TeX的程序。默認是“cweave”。

TANGLE

轉換WebPascal語(yǔ)言的程序。默認是“tangle”。

CTANGLE

轉換C Web C。默認是“ctangle”。

RM

刪除命令。默認是“rm -f”。

10.3.2       命令參數的變量

下邊的是代表命令執行參數的變量。如果沒(méi)有給出默認值則默認值為空。

ARFLAGS

執行“AR”命令的命令行參數。默認值是“rv”。

ASFLAGS

執行匯編語(yǔ)器“AS”的命令行參數(明確指定“.s”或“.S”文件時(shí))。

CFLAGS

執行“CC”編譯器的命令行參數(編譯.c源文件的選項)。

CXXFLAGS

執行“g++”編譯器的命令行參數(編譯.cc源文件的選項)。

COFLAGS

執行“co”的命令行參數(在RCS中提取文件的選項)。

CPPFLAGS

執行C預處理器“cc -E”的命令行參數(C Fortran 編譯器會(huì )用到)。

FFLAGS

Fortran語(yǔ)言編譯器“f77”執行的命令行參數(編譯Fortran源文件的選項)。

GFLAGS

SCCS get”程序參數。

LDFLAGS

鏈接器(如:“ld”)參數。

LFLAGS

Lex文法分析器參數。

PFLAGS

Pascal語(yǔ)言編譯器參數。

RFLAGS

Ratfor 程序的Fortran 編譯器參數。

YFLAGS

Yacc文法分析器參數。

10.4      make隱含規則鏈

有時(shí),一個(gè)目標文件需要多個(gè)(一系列)隱含規則來(lái)創(chuàng )建。例如:創(chuàng )建文件“N.o”的過(guò)程可能是:首先執行“yacc”由“N.y”生成文件“N.c”,之后由編譯器將“N.c”編譯成為“N.o”。如果一個(gè)目標文件需要一系列隱含規則才能完成它的創(chuàng )建,我們就把這個(gè)系列稱(chēng)為一個(gè)“鏈”。

我們來(lái)看上邊例子的執行過(guò)程。有兩種情況:

1.        如果文件“N.c”存在或者它在Makefile中被提及,那就不需要進(jìn)行其它搜索,make處理的過(guò)程是:首先,make可以確定出“N.o”可由“N.c”創(chuàng )建;之后,make試圖使用隱含規則來(lái)重建“N.c”。它會(huì )尋找“N.y”這個(gè)文件,如果“N.y”存在,則執行隱含規則來(lái)重建“N.c”這個(gè)文件。之后再由“N.c”重建“N.o”;當不存在“N.y”文件時(shí),直接編譯“N.c”生成“N.o”。

2.        文件“N.c”不存在也沒(méi)有在Makefile中提及的情況,只要存在“N.y”這個(gè)文件,那么make也會(huì )經(jīng)過(guò)這兩個(gè)步驟來(lái)重建“N.o”(N.y N.c N.o)。這種情況下,文件“N.c”作為一個(gè)中間過(guò)程文件。Make在執行規則時(shí),如果需要一個(gè)中間文件才能完成目標的重建,那么這個(gè)文件將會(huì )自動(dòng)地加入到依賴(lài)關(guān)系鏈中(和Makefile中明確提及的目標作相同處理),并使用合適的隱含規則對它進(jìn)行重建。

 

make的中間過(guò)程文件和那些明確指定的文件在規則中的地位完全相同。但make在處理時(shí)兩者之間存在一些差異:

第一:中間文件不存在時(shí),make處理兩者的方式不同。對于一個(gè)普通文件來(lái)說(shuō),因為Makefile中有明確的提及,此文件可能是作為一個(gè)目標的依賴(lài),make在執行它所在的規則前會(huì )試圖重建它。但是對于中間文件,因為沒(méi)有明確提及,make不會(huì )去試圖重建它。除非這個(gè)中間文件所依賴(lài)的文件(上例第二種情況中的文件“N.y”;N.c是中間過(guò)程文件)被更新。

第二:如果make在執行時(shí)需要用到一個(gè)中間過(guò)程文件,那么默認的動(dòng)作將是:這個(gè)過(guò)程文件在make執行結束后會(huì )被刪除(make會(huì )在刪除中間過(guò)程文件時(shí)打印出執行的命令以顯示那些文件被刪除了)。因此一個(gè)中間過(guò)程文件在make執行結束后就不再存在了。

Makefile中明確提及的所有文件都不被作為中間過(guò)程文件來(lái)處理,這是缺省地。不過(guò)我們可以在Makefile中使用特殊目標“.INTERMEDIATE”來(lái)指除將那些文件作為中間過(guò)程文件來(lái)處理(這些文件作為目標“.INTERMEDIATE”的依賴(lài)文件羅列),即使它們在Makefile中被明確提及,這些作為特殊目標“.INTERMEDIATE”依賴(lài)的文件在make執行結束之后會(huì )被自動(dòng)刪除。

另一方面,如果我們希望保留某些中間過(guò)程文件(它沒(méi)有在Makefile中被提及),不希望make結束時(shí)自動(dòng)刪除它們??梢栽?/span>Makefile中使用特使目標“.SECONDARY”來(lái)指出這些文件(這些文件將被作為“secondary”文件;需要保留的文件作為特殊目標“.SECONDARY”的依賴(lài)文件羅列)。注意:“secondary”文件也同時(shí)被作為中間過(guò)程文件來(lái)對待。

需要保留中間過(guò)程文件還存在另外一種實(shí)現方式。例如需要保留所有.o的中間過(guò)程文件,我們可以將.o文件的模式(%.o)作為特殊目標“.PRECIOUS”的依賴(lài)。

一個(gè)“鏈”可以包含兩個(gè)以上隱含規則的調用過(guò)程。同一個(gè)隱含規則在一個(gè)“鏈”中只能出現一次。否則就會(huì )出現像“foo”依賴(lài)“foo.o.o”甚至“foo.o.o.o.o…”這樣不合邏輯的情況發(fā)生。因為,如果允許在一個(gè)“鏈”中多次調用同一隱含規則(N : N.o; $(LINK.o) $(LDFLAGS) N.o $(LOADLIBES) $(LDLIBS) ),將會(huì )導致make進(jìn)入到無(wú)限的循環(huán)中去。

隱含規則鏈中的某些隱含規則,在一些情況會(huì )被優(yōu)化處理。例如:從文件“foo.c”創(chuàng )建可執行文件“foo”,這一過(guò)程可以是:使用隱含規則將“foo.c”編譯生成“foo.o”文件,之后再使用另一個(gè)隱含規則來(lái)完成對“foo.o”的鏈接,最后生成執行文件“foo”。這個(gè)過(guò)程中對源文件的編譯和對.o文件的鏈接分別使用了兩個(gè)獨立的規則(它們組成一個(gè)隱含規則鏈)。但是實(shí)際情況是,對源文件的編譯和對.o文件的鏈接是在一個(gè)規則中完成的,規則使用命令“cc foo.c foo”。make的隱含規則表中,所有可用的優(yōu)化規則處于首選地位。

10.5      模式規則

模式規則類(lèi)似于普通規則。只是在模式規則中,目標名中需要包含有模式字符“%”(一個(gè)),包含有模式字符“%”的目標被用來(lái)匹配一個(gè)文件名,“%”可以匹配任何非空字符串。規則的依賴(lài)文件中同樣可以使用“%”,依賴(lài)文件中模式字符“%”的取值情況由目標中的“%”來(lái)決定。例如:對于模式規則“%.o : %.c”,它表示的含義是:所有的.o文件依賴(lài)于對應的.c文件。我們可以使用模式規則來(lái)定義隱含規則。

要注意的是:模式字符“%”的匹配和替換發(fā)生在規則中所有變量和函數引用展開(kāi)之后,變量和函數的展開(kāi)一般發(fā)生在make讀取Makefile時(shí)(變量和函數的展開(kāi)可參考 第五 使用變量  第七章 make的函數 ),而模式規則中的“%”的匹配和替換則發(fā)生在make執行時(shí)。

10.5.1       模式規則介紹

在模式規則中,目標文件是一個(gè)帶有模式字符“%”的文件,使用模式來(lái)匹配目標文件。文件名中的模式字符“%”可以匹配任何非空字符串,除模式字符以外的部分要求一致。例如:“%.c”匹配所有以“.c”結尾的文件(匹配的文件名長(cháng)度最少為3個(gè)字母),“s%.c”匹配所有第一個(gè)字母為“s”,而且必須以“.c”結尾的文件,文件名長(cháng)度最小為5個(gè)字符(模式字符“%”至少匹配一個(gè)字符)。在目標文件名中“%”匹配的部分稱(chēng)為“莖”(前面已經(jīng)提到過(guò),參考 靜態(tài)模式 一節)。使用模式規則時(shí),目標文件匹配之后得到“莖”,依賴(lài)根據“莖”產(chǎn)生對應的依賴(lài)文件,這個(gè)依賴(lài)文件必須是存在的或者可被創(chuàng )建的。

因此,一個(gè)模式規則的格式為:

 

     %.o : %.c ; COMMAND...

 

這個(gè)模式規則指定了如何由文件“N.c”來(lái)創(chuàng )建文件“N.o”,文件“N.c”應該是已存在的或者可被創(chuàng )建的。

模式規則中依賴(lài)文件也可以不包含模式字符“%”。當依賴(lài)文件名中不包含模式字符“%”時(shí),其含義是所有符合目標模式的目標文件都依賴(lài)于一個(gè)指定的文件(例如:%.o : debug.h,表示所有的.o文件都依賴(lài)于頭文件“debug.h”)。這樣的模式規則在很多場(chǎng)合是非常有用的。

同樣一個(gè)模式規則可以存在多個(gè)目標。多目標的模式規則和普通多目標規則有些不同,普通多目標規則的處理是將每一個(gè)目標作為一個(gè)獨立的規則來(lái)處理,所以多個(gè)目標就就對應多個(gè)獨立的規則(這些規則各自有自己的命令行,各個(gè)規則的命令行可能相同)。但對于多目標模式規則來(lái)說(shuō),所有規則的目標共同擁有依賴(lài)文件和規則的命令行,當文件符合多個(gè)目標模式中的任何一個(gè)時(shí),規則定義的命令就有可能將會(huì )執行;因為多個(gè)目標共同擁有規則的命令行,因此一次命令執行之后,規則不會(huì )再去檢查是否需要重建符合其它模式的目標??匆粋€(gè)例子:

#sample Makefile

 

Objects = foo.o bar.o

CFLAGS := -Wall

 

%x : CFLAGS += -g

%.o : CFLAGS += -O2

   

%.o %.x : %.c

       $(CC) $(CFLAGS) $< -o $@

 

當在命令行中執行“make foo.o foo.x”時(shí),會(huì )看到只有一個(gè)文件“foo.o”被創(chuàng )建了,同時(shí)make會(huì )提示“foo.x”文件是最新的(其實(shí)“foo.x”并沒(méi)有被創(chuàng )建)。此過(guò)程表明了多目標的模式規則在make處理時(shí)是被作為一個(gè)整體來(lái)處理的。這是多目標模式規則和多目標的普通規則的區別之處。大家不妨將上邊的例子改為普通多目標規則試試看將會(huì )得到什么樣的結果。

最后需要說(shuō)明的是:

1.        模式規則在Makefile中的順序需要注意,當一個(gè)目標文件同時(shí)符合多個(gè)目標模式時(shí),make將會(huì )把第一個(gè)目標匹配的模式規則作為重建它的規則。

2.        Makefile中明確指定的模式規則會(huì )覆蓋隱含模式規則。就是說(shuō)如果在Makefile中出現了一個(gè)對目標文件合適可用的模式規則,那么make就不會(huì )再為這個(gè)目標文件尋找其它隱含規則,而直接使用在Makefile中出現的這個(gè)規則。在使用時(shí),明確規則永遠優(yōu)先于隱含規則。

3.        另外,依賴(lài)文件存在或者被提及的規則,優(yōu)先于那些需要使用隱含規則來(lái)創(chuàng )建其依賴(lài)文件的規則。

10.5.2       模式規則示例

本小節來(lái)看一些使用模式規則的例子,這些模式規則在GNU make中已經(jīng)被預定義。首先看編譯.c文件到.o文件的隱含模式規則:

 

%.o : %.c

$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@

 

此規則描述了一個(gè).o文件如何由對應的.c文件創(chuàng )建。規則的命令行中使用了自動(dòng)化變量“$<”和“$@”,其中自動(dòng)化變量“$<”代表規則的依賴(lài),“$@”代表規則的目標。此規則在執行時(shí),命令行中的自動(dòng)化變量將根據實(shí)際的目標和依賴(lài)文件取對應值。

make中第二個(gè)內嵌模式規則是:

 

% :: RCS/%,v

$(CO) $(COFLAGS) $<

 

這個(gè)規則的含義是:任何一個(gè)文件“X”都可以由目錄“RCS”下的相應文件“x.v”來(lái)生成。規則的目標為“%”,它匹配任何文件名,因此只要存在相對應的依賴(lài)文件(N.v),目標(N)都可被創(chuàng )建。雙冒號表示該規則是最終規則,意味著(zhù)規則的依賴(lài)文件不是中間過(guò)程文件。

另外,一個(gè)具有多目標的隱含規則是:

 

%.tab.c %.tab.h: %.y

bison -d $<

 

它是一個(gè)多目標模式規則,關(guān)于多目標的特征可參考 模式規則介紹 一小節最后一個(gè)例子。

10.5.3       自動(dòng)化變量

模式規則中,規則的目標和依賴(lài)文件名代表了一類(lèi)文件名;規則的命令是對所有這一類(lèi)文件重建過(guò)程的描述,顯然,在命令中不能出現具體的文件名,否則模式規則失去意義。那么在模式規則的命令行中該如何表示文件,將是本小節的討論的重點(diǎn)。

假如你需要書(shū)寫(xiě)一個(gè)將.c文件編譯到.o文件的模式規則,那么你該如何為gcc書(shū)寫(xiě)正確的源文件名?當然了,不能使用任何具體的文件名,因為在每一次執行模式規則時(shí)源文件名都是不一樣的。為了解決這個(gè)問(wèn)題,就需要使用“自動(dòng)環(huán)變量”,自動(dòng)化變量的取值是根據具體所執行的規則來(lái)決定的,取決于所執行規則的目標和依賴(lài)文件名。

下面對所有的自動(dòng)化變量進(jìn)行說(shuō)明:

$@

表示規則的目標文件名。如果目標是一個(gè)文檔文件(Linux中,一般稱(chēng).a文件為文檔文件,也稱(chēng)為靜態(tài)庫文件),那么它代表這個(gè)文檔的文件名。在多目標模式規則中,它代表的是哪個(gè)觸發(fā)規則被執行的目標文件名。

$%

當規則的目標文件是一個(gè)靜態(tài)庫文件時(shí),代表靜態(tài)庫的一個(gè)成員名。例如,規則的目標是“foo.a(bar.o)”,那么,“$%”的值就為“bar.o”,“$@”的值為“foo.a”。如果目標不是靜態(tài)庫文件,其值為空。

$<

規則的第一個(gè)依賴(lài)文件名。如果是一個(gè)目標文件使用隱含規則來(lái)重建,則它代表由隱含規則加入的第一個(gè)依賴(lài)文件。

$?

所有比目標文件更新的依賴(lài)文件列表,空格分割。如果目標是靜態(tài)庫文件名,代表的是庫成員(.o文件)。

$^

規則的所有依賴(lài)文件列表,使用空格分隔。如果目標是靜態(tài)庫文件,它所代表的只能是所有庫成員(.o文件)名。一個(gè)文件可重復的出現在目標的依賴(lài)中,變量“$^”只記錄它的一次引用情況。就是說(shuō)變量“$^”會(huì )去掉重復的依賴(lài)文件。

$+

類(lèi)似“$^”,但是它保留了依賴(lài)文件中重復出現的文件。主要用在程序鏈接時(shí)庫的交叉引用場(chǎng)合。

$*

在模式規則和靜態(tài)模式規則中,代表“莖”。“莖”是目標模式中“%”所代表的部分(當文件名中存在目錄時(shí),“莖”也包含目錄(斜杠之前)部分)。例如:文件“dir/a.foo.b”,當目標的模式為“a.%.b”時(shí),“$*”的值為“dir/a.foo”。“莖”對于構造相關(guān)文件名非常有用。

自動(dòng)化變量“$*”需要兩點(diǎn)說(shuō)明:

Ø        對于一個(gè)明確指定的規則來(lái)說(shuō)不存在“莖”,這種情況下“$*”的含義發(fā)生改變。此時(shí),如果目標文件名帶有一個(gè)可識別的后綴,那么“$*”表示文件中除后綴以外的部分。例如:“foo.c”則“$*”的值為:“foo”,因為.c是一個(gè)可識別的文件后綴名。GUN make對明確規則的這種奇怪的處理行為是為了和其它版本的make兼容。通常,在除靜態(tài)規則和模式規則以外,明確指定目標文件的規則中應該避免使用這個(gè)變量。

Ø        當明確指定文件名的規則中目標文件名包含不可識別的后綴時(shí),此變量為空。

自動(dòng)化變量“$?”在顯式規則中也是非常有用的,使用它規則可以指定只對更新以后的依賴(lài)文件進(jìn)行操作。例如,靜態(tài)庫文件“libN.a”,它由一些.o文件組成。這個(gè)規則實(shí)現了只將更新后的.o文件加入到庫中:

 

     lib: foo.o bar.o lose.o win.o

             ar r lib $?

 

以上羅列的自動(dòng)量變量中。其中有四個(gè)在規則中代表文件名($@、$<、$%、$*)。而其它三個(gè)的在規則中代表一個(gè)文件名列表。GUN make中,還可以通過(guò)這七個(gè)自動(dòng)化變量來(lái)獲取一個(gè)完整文件名中的目錄部分和具體文件名部分。在這些變量中加入“D”或者“F”字符就形成了一系列變種的自動(dòng)環(huán)變量。這些變量會(huì )出現在以前版本的make中,在當前版本的make中,可以使用“dir”或者“notdir”函數來(lái)實(shí)現同樣的功能。

$(@D)

表示目標文件的目錄部分(不包括斜杠)。如果“$@”是“dir/foo.o”,那么“$(@D)”的值為“dir”。如果“$@”不存在斜杠,其值就是“.”(當前目錄)。注意它和函數“dir的區別!

$(@F)

目標文件的完整文件名中除目錄以外的部分(實(shí)際文件名)。如果“$@”為“dir/foo.o”,那么“$(@F)”只就是“foo.o”。“$(@F)”等價(jià)于函數“$(notdir $@)”。

$(*D)

$(*F)

分別代表目標“莖”中的目錄部分和文件名部分。

$(%D)

$(%F)

當以如“archive(member)”形式靜態(tài)庫為目標時(shí),分別表示庫文件成員“member”名中的目錄部分和文件名部分。它僅對這種形式的規則目標有效。

$(<D)

$(<F)

分別表示規則中第一個(gè)依賴(lài)文件的目錄部分和文件名部分。

$(^D)

$(^F)

分別表示所有依賴(lài)文件的目錄部分和文件部分(不存在同一文件)。

$(+D)

$(+F)

分別表示所有依賴(lài)文件的目錄部分和文件部分(可存在重復文件)。

$(?D)

$(?F)

分別表示被更新的依賴(lài)文件的目錄部分和文件名部分。

 

在討論自動(dòng)化變量時(shí),為了和普通變量(如:“CFLAGS”)區別,我們直接使用了“$<”的形式。這種形式僅僅是為了和普通變量進(jìn)行區別,沒(méi)有別的目的。其實(shí)對于自動(dòng)環(huán)變量和普通變量一樣,代表規則第一個(gè)依賴(lài)文件名的變量名實(shí)際上是“<”,我們完全可以使用“$(<)”來(lái)替代“$<”。但是在引用自動(dòng)化變量時(shí)通常的做法是“$<”,因為自動(dòng)化變量本身是一個(gè)特殊字符。

GUN make同時(shí)支持“Sysv”特性,允許在規則的依賴(lài)列表中使用特殊的變量引用(一般的自動(dòng)化變量只能在規則的命令行中被引用)“$$@”、“$$(@D)”和“$$(@F)”(注意:要使用“$$”),它們分別代表了“目標的完整文件名”、“目標文件名中的目錄部分”和“目標的實(shí)際文件名部分”。這三個(gè)特殊的變量只能用在明確指定目標文件名的規則中或者是靜態(tài)模式規則中,不用于隱含規則中。另外Sysv makeGNU make對規則依賴(lài)的處理也不盡相同。Sysv make對規則的依賴(lài)進(jìn)行兩次替換展開(kāi),而GUN make對依賴(lài)列表的處理只有一次,對其中的變量和函數引用直接進(jìn)行展開(kāi)。

自動(dòng)化變量的這個(gè)古怪的特性完全是為了兼容Sysv 版本的makefile文件。在使用GNU make時(shí)可以不考慮這個(gè),也可以在Makefile中使用偽目標“.POSIX”來(lái)禁止這一特性。

10.5.4       模式的匹配

通常,模式規則中目標模式由前綴、后綴、模式字符“%”組成,這三個(gè)部分允許兩個(gè)同時(shí)為空。實(shí)際文件名應該是以模式指定的前綴開(kāi)始、后綴結束的任何文件名。文件名中除前綴和后綴以外的所有部分稱(chēng)之為“莖”(模式字符“%”可以代表若干字符。因此:模式“%.o”所匹配的文件“test.c”中“test”就是“莖”)。模式規則中依賴(lài)文件名的確定過(guò)程是:首先根據規則定義的目標模式匹配實(shí)際的目標文件,確定“莖”,之后使用 “莖”替代規則依賴(lài)文件名中的模式字符“%”,生成依賴(lài)文件名。這樣就產(chǎn)生了一個(gè)明確指定了目標和依賴(lài)文件的規則。例如模式規則:“%.o : %.c”,當“test.o”需要重建時(shí)將形成規則“test.o : test.c”。

當目標模式中包含斜杠(目錄部分)。在進(jìn)行目標文件匹配時(shí),文件名中包含的目錄字符串在匹配之前被移除,只進(jìn)行基本文件名的匹配;匹配成功后,再將目錄部分加入到匹配之后的字符串之前形成“莖”。來(lái)看一個(gè)例子:例如目標模式為“e%t”,文件“src/eat”匹配這個(gè)模式,那么“莖”就是“src/a”;模式規則中依賴(lài)文件的產(chǎn)生:首先使用“莖”中的非目錄部分(“a”)替代依賴(lài)文件中的模式字符“%”,之后再將目錄部分(“src/”)加入到形成的依賴(lài)文件名之前構成依賴(lài)文件的全路徑名。這里如果模式規則的依賴(lài)模式為“c%r”,則那么目標“src/eat”對應的依賴(lài)文件就為“src/car”。

10.5.5       萬(wàn)用規則

當模式規則的目標只是一個(gè)模式字符“%”(它可以匹配任何文件名)時(shí),我們稱(chēng)這個(gè)規則為萬(wàn)用規則。萬(wàn)用規則在書(shū)寫(xiě)Makefile時(shí)非常有用,但它會(huì )影響make的執行效率,因為make在執行時(shí)將會(huì )使用萬(wàn)用規則來(lái)試圖重建其它規則的目標和依賴(lài)文件。

假如在一個(gè)存在萬(wàn)用規則的Makefile中提及了文件“foo.c”。為了創(chuàng )建這個(gè)目標,make會(huì )試圖使用以下規則來(lái)創(chuàng )建這個(gè)目標:1.對一個(gè).o文件“foo.c.o”進(jìn)行鏈接并產(chǎn)生文件“foo.c”;2.使用c編譯和連接程器由文件“foo.c.c”來(lái)創(chuàng )建這個(gè)文件;3. 編譯并鏈接Pascal程序“foo.c.p”來(lái)創(chuàng )建;等等??傊?/span>make會(huì )試圖使用所有可能的隱含規則來(lái)完成對這個(gè)文件的創(chuàng )建。

當然,我們很清楚以上這樣的過(guò)程是沒(méi)有必要的,我們知道“foo.c”是一個(gè).c原文件,而不是一個(gè)可執行程序。make在執行時(shí)都會(huì )試圖根據可能的隱含規則來(lái)創(chuàng )建這個(gè)文件,但由于其依賴(lài)的文件(“foo.c.o”、“foo.c.c”等)不存在,最終這些可能的隱含規則都會(huì )被否定。但是如果在Makefile中存在一個(gè)萬(wàn)用規則,那么make執行時(shí)所要考慮的情況就比較復雜,也很多(它會(huì )試圖功過(guò)隱含規則來(lái)創(chuàng )建那些依賴(lài)文件,雖然最終這些文件不可能被創(chuàng )建,也無(wú)從創(chuàng )建),從而導致make的執行效率會(huì )很低。

為了避免萬(wàn)用規則帶來(lái)的效率問(wèn)題,我們可以對萬(wàn)用規則的使用加以限制。通常有兩種方式,需要在定義一個(gè)萬(wàn)用規則時(shí)對其進(jìn)行限制。

1.        將萬(wàn)用規則設置為最終規則,定義時(shí)使用雙冒號規則。作為最終規則,此規則只有在它的依賴(lài)文件存在時(shí)才能被應用,即使它的依賴(lài)可以由隱含規則創(chuàng )建也不行。就是說(shuō),最終規則中沒(méi)有進(jìn)一步的“鏈”。

 

例如,從RCSSCCS文件中提取源文件的內嵌隱含規則就是一個(gè)最終規則。因此如果文件“foo.c,v”不存在,make就不會(huì )試圖從一個(gè)中間文件“foo.c,v.o”或“RCS/SCCS/s.foo.c,v”來(lái)創(chuàng )建它。 RCS SCCS 文件一般都是最終的源文件,它不能由其它任何文件重建;make可以記錄它的時(shí)間戳,但不會(huì )尋找重建它們的方式。

如果萬(wàn)用規則沒(méi)有定義為最終規則,那么它就是一個(gè)非最終規則。非最終的萬(wàn)用規則不會(huì )被用來(lái)創(chuàng )建那些符合某一個(gè)明確模式規則的目標和依賴(lài)文件。就是說(shuō)如果在Makefile中存在匹配此文件的模式規則(非萬(wàn)用規則),那么對于這個(gè)文件來(lái)說(shuō)其重建規則只會(huì )是它所匹配的這個(gè)模式,而不是這個(gè)非最終的萬(wàn)用規則。例如,文件“foo.c”,如果在Makefile中同時(shí)存在一個(gè)萬(wàn)用規則和模式規則 %.c : %.y”(該規則運行Yacc)。無(wú)論該規則是否會(huì )被使用(如果存在文件“foo.y”,那么規則將被執行)。那么make試圖重建“foo.c”的規則都是“%.c : %.y”,而不是萬(wàn)用規則。這樣做是為了避免make執行時(shí)試圖使用非最終的萬(wàn)用規則來(lái)重建文件“foo.c”的情況發(fā)生。

2.        定義一個(gè)特殊的內嵌啞模式規則給出如何重建某一類(lèi)文件,避免使用非最終萬(wàn)用規則。啞模式規則沒(méi)有依賴(lài),也沒(méi)有命令行,在make的其它場(chǎng)合被忽略。例如,內嵌的啞模式規則:“%.p :”為Pascal源程序如“foo.p”指定了重建規則(規則不存在依賴(lài)文件、也不存在任何命令),這樣就避免了make試圖“foo.p”而去尋找“foo.p.o”或“foo.p.c”的過(guò)程。

我們可以為所有的make可識別的后綴創(chuàng )建一個(gè)形如“%.p :”的啞模式規則。

10.5.6       重建內嵌隱含規則

一個(gè)隱含規則,我們可以對它進(jìn)行重建。重建一個(gè)隱含規則時(shí),需要使用相同的目標和依賴(lài)模式,命令可以不同(重新指定規則的命令)。這樣就可以替代有相同目標和依賴(lài)的那個(gè)make內嵌規則,替代之后隱含規則可能被使用的順序由它在Makefile中的位置決定。例如通常Makefile中可能會(huì )包含這樣一個(gè)規則:

 

%.o : %.c

$(CC) $(CFLAGS) –D__DEBUG__  $< -o $@

 

它替代了編譯.c文件的內嵌隱含規則。

也可以取消一個(gè)內嵌的隱含規則。同樣需要定義一個(gè)和隱含規則具有相同目標和依賴(lài)的規則,但這個(gè)規則沒(méi)有命令行。例如下邊的這個(gè)規則取消了編譯.s文件的內嵌規則。

    %.o : %.s

 

10.6      缺省規則

有時(shí)make會(huì )需要一個(gè)缺省的規則,在執行過(guò)程中無(wú)法為一個(gè)文件找到合適的重建規則(在Makefile中沒(méi)有給出重建它的明確規則,同時(shí)也沒(méi)有合適可用的隱含規則)。那么make就使用這個(gè)規則來(lái)重建它。就是說(shuō),當所需要的重建的目標文件沒(méi)有可用的命令時(shí)、就執行這個(gè)缺省規則命令。

這樣一個(gè)規則,我們可以使用最終萬(wàn)用規則。例如:調試Makefile時(shí)(可能一些源文件還沒(méi)有完成),我們關(guān)心的是Makefile中所有的規則是否可正確執行,而源文件的具體內容卻不需要關(guān)心?;谶@一點(diǎn)我們就可以使用空文件(和源文件同名的文件),在Makefile中定義這樣一個(gè)規則:

 

%::

touch $@

 

執行make過(guò)程中,對所有不存在的.c文件將會(huì )使用“touch”命令創(chuàng )建這樣一個(gè)空的源文件。

實(shí)現一個(gè)缺省規則的方式也可以不使用萬(wàn)用規則,而使用偽目標“.DEFAULT”。上邊的例子也可以這樣實(shí)現:

 

.DEFAULT :

touch $@

 

需要注意:沒(méi)有指定命令行的偽目標“.DEFAULT”,含義是取消前邊所有使用“.DEFAULT”指定的缺省執行命令。

同樣,也可以讓這個(gè)缺省的規則不執行任何命令(給它定義個(gè)一個(gè)空命令)。

另外缺省規則也可用來(lái)實(shí)現在一個(gè)Makefile中重載另一個(gè)makefile文件。

10.7      后綴規則

后綴規則是一種古老定義隱含規則的方式,在新版本的make中使用模式規則作為對它的替代,模式規則相比后綴規則更加清晰明了。在現在版本中保留它的原因是為了能夠兼容舊的makefile文件。后綴規則有兩種類(lèi)型:“雙后綴”和“單后綴”。

雙后綴規則定義一對后綴:目標文件的后綴和依賴(lài)目標的后綴。它匹配所有后綴為目標后綴的文件。對于一個(gè)匹配的目標文件,它的依賴(lài)文件這樣形成:將匹配的目標文件名中的后綴替換為依賴(lài)文件的后綴得到。如:一個(gè)描述目標和依賴(lài)后綴的“.o”和“.c”的規則就等價(jià)于模式規則“%o : %c”。

單后綴規則只定義一個(gè)后綴:此后綴是源文件名的后綴。它可以匹配任何文件,其依賴(lài)文件這樣形成:將后綴直接追加到目標文件名之后得到。例如:?jiǎn)魏缶Y“.c”就等價(jià)于模式規則“% : %.c”。

判斷一個(gè)后綴規則是單后綴還是雙后綴的過(guò)程:判斷后綴規則的目標,如果其中只存在一個(gè)可被make識別的后綴,則規則是一個(gè)“單后綴”規則;當規則目標中存在兩個(gè)可被make識別的后綴時(shí),這個(gè)規則就是一個(gè)“雙后綴”規則。

例如:“.c”和“.o”都是make可識別的后綴。因此當定義了一個(gè)目標是“.c.o”的規則時(shí)。make會(huì )將它作為一個(gè)雙后綴規則來(lái)處理,它的含義是所有“.o”文件的依賴(lài)文件是對應的“.c”文件。下邊是使用后追規則定義的編譯.c源文件的規則:

 

.c.o:

$(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<

 

注意:一個(gè)后綴規則中不存在任何依賴(lài)文件。否則,此規則將被作為一個(gè)普通規則對待。因此規則:

 

.c.o: foo.h

$(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<

 

就不是一個(gè)后綴規則。它是一個(gè)目標文件為“.c.o”、依賴(lài)文件是“foo.h”的普通規則。它也不等價(jià)于規則:

 

%.o: %.c foo.h

$(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<

 

需要注意的是:沒(méi)有命令行的后綴規則是沒(méi)有任何意義的。它和沒(méi)有命令行的模式規則不同,它也不能取消之前使用后追規則定義的規則。它所實(shí)現的僅僅是將這個(gè)后綴規則作為目標加入到make的數據庫中。

可識別的后綴指的是特殊目標“.SUFFIXES”所有依賴(lài)的名字。通過(guò)給特殊目標“SUFFIXES”添加依賴(lài)來(lái)增加一個(gè)可被識別的后綴。像下邊這樣:

 

.SUFFIXES: .hack .win

 

它所實(shí)現的功能是把后綴“.hack”和“.win”加入到可識別后綴列表的末尾。

如果需要重設默認的可識別后綴,因該這樣來(lái)實(shí)現:

 

.SUFFIXES:          #刪除所有已定義的可識別后綴

.SUFFIXES: .c .o .h   #重新定義

 

首先使用沒(méi)有依賴(lài)的特殊目標“.SUFFIXES”來(lái)刪除所有已定義的可識別后綴;之后再重新定義。

注意:make的“-r”或“-no-builtin-rules”可以清空所有已定義的可識別后綴。

make讀取所有的makefile文件之前,變量“SUFFIXE”被定義為默認的可識別后綴列表。雖然存在這樣一個(gè)變量,但是請不要通過(guò)修改這個(gè)變量值的方式來(lái)改變可識別的后綴列表,應該使用特殊目標“.SUFFIXES”來(lái)實(shí)現。

10.8      隱含規則搜索算法

對于目標“T”,make為它搜索隱含規則的算法如下。此算法適合于:1. 任何沒(méi)有命令行的雙冒號規則;2. 任何沒(méi)有命令行的普通規則;3. 那些不是任何規則的目標、但它是另外某些規則的依賴(lài)文件;4. 在遞歸搜索過(guò)程中,隱含規則鏈中前一個(gè)規則的依賴(lài)文件。

在搜索過(guò)程中沒(méi)有提到后綴規則,因為所有的后綴規則在make讀取Makefile時(shí),都被轉換為對應的模式規則。

對于形式為“ARCHIVE(MEMBER)”的目標,下邊的算法會(huì )執行兩次,第一次的目標是整個(gè)目標名“T”(“ARCHIVE(MEMBER)”),如果搜索失敗,進(jìn)行第二次搜索,第二次以“member”作為目標來(lái)搜索。

搜索過(guò)程如下:

1.        將目標“T”的目錄部分分離,分離后目錄部分稱(chēng)為“D”,其它部分稱(chēng)“N”。例如:“T”為“src/foo.o”時(shí),D就是“src/”,“N”就為“foo.o”。

2.        列出所有和“T”或者“N”匹配的模式規則。如果模式規則的目標中包含斜杠,則認為和“T”相匹配,否則認為此模式規則和“N”相匹配。

3.        只要這個(gè)模式規則列表中包含一個(gè)非萬(wàn)用規則的規則,那么將列表中所有的非最終萬(wàn)用規則刪除。

4.        刪除這個(gè)模式規則列表中的所有沒(méi)有命令行的規則。

5.        對于這個(gè)模式規則列表中的所有規則:

a)       計算出模式規則的“莖”S,S應該是“T”或“N”中匹配“%”的非空的部分。

b)       計算依賴(lài)文件。把依賴(lài)中的“%”用“S”替換。如果目標模式中不包含斜杠,則把“D”加在替換之后的每一個(gè)依賴(lài)文件開(kāi)頭,構成完整的依賴(lài)文件名。

c)        測試規則的所有依賴(lài)文件是否存在或是應該存在(一個(gè)文件,如果在Makefile中它作為一個(gè)明確規則的目標,或者依賴(lài)文件被提及,我們就說(shuō)這個(gè)文件是一個(gè)“應該存在”的文件)。如果所有的依賴(lài)文件都存在、應該存在或是這個(gè)規則沒(méi)有依賴(lài)。退出查找,使用該規則。

6.        截止到第5步,合適的規則還是沒(méi)有被找到,進(jìn)一步搜索。對于這個(gè)模式規則列表中的每一規則:

a)       如果規則是一個(gè)終止規則,則忽略它,繼續下一條模式規則。

b)       計算依賴(lài)文件(同第5步)。

c)        測試此規則的依賴(lài)文件是否存在或是應該存在。

d)       對于此規則中不存在的依賴(lài)文件,遞歸的調用這個(gè)算法查找它是否可由隱含規則來(lái)創(chuàng )建。

e)       如果所有的依賴(lài)文件存在、應該存在、或是它可以由一個(gè)隱含規則來(lái)創(chuàng )建。退出查找,使用該規則。

7.        如果沒(méi)有隱含規則可以創(chuàng )建這個(gè)規則的依賴(lài)文件,則執行特殊目標“.DEFAULT”所指定的命令(可以創(chuàng )建這個(gè)文件,或者給出一個(gè)錯誤提示)。如果在Makefile中沒(méi)有定義特殊目標“DEFAULT”,就沒(méi)有可用的命令來(lái)完成“T”的創(chuàng )建。make退出。

一旦為一類(lèi)目標查找到合適的模式規則。除匹配“T”或者“N”的模式以外,對其它模式規則中的目標模式進(jìn)行配置,使用“莖”S替換其中的模式字符“%”,將得到的文件名保存直到執行命令更新這個(gè)目標文件(“T”)。在命令執行以后,把每一個(gè)儲存的文件名放入數據庫,并且標志為已更新,其時(shí)間戳和文件“T”相同。

在執行更新文件“T”的命令時(shí),使用自動(dòng)化變量表示規則中的依賴(lài)文件和目標文件。


下一章 上一章 目錄

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
GNU make中文手冊-第四章:Makefile的規則
第十一章 : 更新靜態(tài)庫
makefile自動(dòng)變量
如何編寫(xiě)Makefile一份由淺入深的Makefile全攻略(make是如何工作的)
makefile 簡(jiǎn)介
Makefile的使用
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久