当前位置:文档之家› Makefile的隐含规则

Makefile的隐含规则

Makefile的隐含规则
Makefile的隐含规则

Makefile隱含規則

————

在我們使用Makefile時,有一些我們會經常使用,而且使用頻率非常高的東西,比如,我們編譯C/C++的來源程式為中間目的檔案(Unix下是[.o]文件,Windows 下是[.obj]文件)。本章講述的就是一些在Makefile中的―隱含的‖,早先約定了的,不需要我們再寫出來的規則。

―隱含規則‖也就是一種慣例,make會按照這種―慣例‖心照不喧地來運行,那怕我們的Makefile中沒有書寫這樣的規則。例如,把[.c]檔編譯成[.o]檔這一規則,你根本就不用寫出來,make會自動推導出這種規則,並生成我們需要的[.o]文件。―隱含規則‖會使用一些我們系統變數,我們可以改變這些系統變數的值來定制隱含規則的運行時的參數。如系統變數―CFLAGS‖可以控制編譯時的編譯器參數。

我們還可以通過―模式規則‖的方式寫下自己的隱含規則。用―尾碼規則‖來定義隱含規則會有許多的限制。使用―模式規則‖會更回得智慧和清楚,但―尾碼規則‖可以用來保證我們Makefile的相容性。

我們瞭解了―隱含規則‖,可以讓其為我們更好的服務,也會讓我們知道一些―約定俗成‖了的東西,而不至於使得我們在運行Makefile時出現一些我們覺得莫名其妙的東西。當然,任何事物都是矛盾的,水能載舟,亦可覆舟,所以,有時候―隱含規則‖也會給我們造成不小的麻煩。只有瞭解了它,我們才能更好地使用它。

一、使用隱含規則

如果要使用隱含規則生成你需要的目標,你所需要做的就是不要寫出這個目標的規則。那麼,make會詴圖去自動推導產生這個目標的規則和命令,如果make 可以自動推導生成這個目標的規則和命令,那麼這個行為就是隱含規則的自動推導。當然,隱含規則是make事先約定好的一些東西。例如,我們有下面的一個Makefile:

foo : foo.o bar.o

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

我們可以注意到,這個Makefile中並沒有寫下如何生成foo.o和bar.o這兩目標的規則和命令。因為make的―隱含規則‖功能會自動為我們自動去推導這兩個目標的依賴目標和生成命令。

make會在自己的―隱含規則‖庫中尋找可以用的規則,如果找到,那麼就會使用。如果找不到,那麼就會報錯。在上面的那個例子中,make調用的隱含規則是,把[.o]的目標的依賴檔置成[.c],並使用C的編譯命令―cc–c $(CFLAGS) [.c]‖來生成[.o]的目標。也就是說,我們完全沒有必要寫下下面的兩條規則:

foo.o : foo.c

cc –c foo.c $(CFLAGS)

bar.o : bar.c

cc –c bar.c $(CFLAGS)

因為,這已經是―約定‖好了的事了,make和我們約定好了用C編譯器―cc‖生成[.o]檔的規則,這就是隱含規則。

當然,如果我們為[.o]檔書寫了自己的規則,那麼make就不會自動推導並調用隱含規則,它會按照我們寫好的規則忠實地執行。

還有,在make的―隱含規則庫‖中,每一條隱含規則都在庫中有其順序,越靠前的則是越被經常使用的,所以,這會導致我們有些時候即使我們顯示地指定了目標依賴,make也不會管。如下面這條規則(沒有命令):

foo.o : foo.p

依賴檔―foo.p‖(Pascal程式的原始檔案)有可能變得沒有意義。如果目錄下存在了―foo.c‖檔,那麼我們的隱含規則一樣會生效,並會通過―foo.c‖調用C的編譯器生成foo.o文件。因為,在隱含規則中,Pascal的規則出現在C的規則之後,所以,make找到可以生成foo.o的C的規則就不再尋找下一條規則了。如果你確實不希望任何隱含規則推導,那麼,你就不要只寫出―依賴規則‖,而不寫命令。

二、隱含規則一覽

這裡我們將講述所有預先設置(也就是make內建)的隱含規則,如果我們不明確地寫下規則,那麼,make就會在這些規則中尋找所需要規則和命令。當然,我們也可以使用make的參數―-r‖或―--no-builtin-rules‖選項來取消所有的預設置的隱含規則。

當然,即使是我們指定了―-r‖參數,某些隱含規則還是會生效,因為有許多的隱含規則都是使用了―尾碼規則‖來定義的,所以,只要隱含規則中有―尾碼清單‖(也就一系統定義在目標.SUFFIXES的依賴目標),那麼隱含規則就會生效。默認的尾碼列表是:.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。具體的細節,我們會在後面講述。

還是先來看一看常用的隱含規則吧。

1、編譯C程式的隱含規則。

;.o‖的目標的依賴目標會自動推導為―;.c‖,並且其生成命令是―$(CC)–c $(CPPFLAGS) $(CFLAGS)‖

2、編譯C++程式的隱含規則。

;.o‖的目標的依賴目標會自動推導為―;.cc‖或是―;.C‖,並且其生成命令是―$(CXX)–c $(CPPFLAGS) $(CFLAGS)‖。(建議使用―.cc‖作為C++原始檔案

的尾碼,而不是―.C‖)

3、編譯Pascal程式的隱含規則。

;.o‖的目標的依賴目標會自動推導為―;.p‖,並且其生成命令是―$(PC)–c $(PFLAGS)‖。

4、編譯Fortran/Ratfor程式的隱含規則。

;.o‖的目標的依賴目標會自動推導為―;.r‖或―;.F‖或―;.f‖,並且其生成命令是:

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

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

―.f‖―$(FC)–c $(FFLAGS) $(RFLAGS)‖

5、預處理Fortran/Ratfor程式的隱含規則。

;.f‖的目標的依賴目標會自動推導為―;.r‖或―;.F‖。這個規則只是轉換Ratfor或有預處理的Fortran程式到一個標準的Fortran程式。其使用的命令是:―.F‖―$(FC)–F $(CPPFLAGS) $(FFLAGS)‖

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

6、編譯Modula-2程式的隱含規則。

;.sym‖的目標的依賴目標會自動推導為―;.def‖,並且其生成命令是:―$(M2C) $(M2FLAGS) $(DEFFLAGS)‖。―;‖的目標的依賴目標會自動推導為―;.mod‖,並且其生成命令是:―$(M2C) $(M2FLAGS) $(MODFLAGS)‖。7、彙編和彙編預處理的隱含規則。

;.o‖的目標的依賴目標會自動推導為―;.s‖,默認使用編譯品―as‖,並且其生成命令是:―$(AS)$(ASFLAGS)‖。―;.s‖的目標的依賴目標會自動推導為―;.S‖,默認使用C預編譯器―cpp‖,並且其生成命令是:―$(AS)$(ASFLAGS)‖。

8、連結Object檔的隱含規則。

;‖目標依賴於―;.o‖,通過運行C的編譯器來運行連結程式生成(一般是―ld‖),其生成命令是:―$(CC) $(LDFLAGS) ;.o $(LOADLIBES) $(LDLIBS)‖。這個規則對於只有一個原始檔案的工程有效,同時也對多個Object檔(由不同的原始檔案生成)的也有效。例如如下規則:

x : y.o z.o

並且―x.c‖、―y.c‖和―z.c‖都存在時,隱含規則將執行如下命令:

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

如果沒有一個原始檔案(如上例中的x.c)和你的目標名字(如上例中的x)相關聯,那麼,你最好寫出自己的生成規則,不然,隱含規則會報錯的。

9、Yacc C程式時的隱含規則。

;.c‖的依賴檔被自動推導為―n.y‖(Yacc生成的文件),其生成命令是:―$(YACC)$(YFALGS)‖。(―Yacc‖是一個語法分析器,關於其細節請查看相關資料)

10、Lex C程式時的隱含規則。

;.c‖的依賴檔被自動推導為―n.l‖(Lex生成的文件),其生成命令是:―$(LEX)$(LFALGS)‖。(關於―Lex‖的細節請查看相關資料)

11、Lex Ratfor程式時的隱含規則。

;.r‖的依賴檔被自動推導為―n.l‖(Lex生成的文件),其生成命令是:―$(LEX)$(LFALGS)‖。

12、從C程式、Yacc檔或Lex檔創建Lint庫的隱含規則。

;.ln‖(lint生成的檔)的依賴檔被自動推導為―n.c‖,其生成命令是:―$(LINT) $(LINTFALGS) $(CPPFLAGS) -i‖。對於―;.y‖和―;.l‖也是同樣的規則。

三、隱含規則使用的變數

在隱含規則中的命令中,基本上都是使用了一些預先設置的變數。你可以在你的makefile中改變這些變數的值,或是在make的命令列中傳入這些值,或是在你的環境變數中設置這些值,無論怎麼樣,只要設置了這些特定的變數,那麼其就會對隱含規則起作用。當然,你也可以利用make的―-R‖或―--no–builtin-variables‖參數來取消你所定義的變數對隱含規則的作用。

例如,第一條隱含規則——編譯C程式的隱含規則的命令是―$(CC)–c $(CFLAGS) $(CPPFLAGS)‖。Make默認的編譯命令是―cc‖,如果你把變數―$(CC)‖重定義成―gcc‖,把變數―$(CFLAGS)‖重定義成―-g‖,那麼,隱含規則中的命令全部會以―gcc–c -g $(CPPFLAGS)‖的樣子來執行了。

我們可以把隱含規則中使用的變數分成兩種:一種是命令相關的,如―CC‖;一種是參數相的關,如―CFLAGS‖。下面是所有隱含規則中會用到的變數:

1、關於命令的變數。

AR

函式程式庫打包程式。默認命令是―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方法分析器程式(針對於C或Ratfor)。默認命令是―lex‖。

PC

Pascal語言編譯器。默認命令是―pc‖。

YACC

Yacc文法分析器(針對於C程式)。默認命令是―yacc‖。

YACCR

Yacc文法分析器(針對於Ratfor程式)。默認命令是―yacc–r‖。MAKEINFO

轉換Texinfo原始檔案(.texi)到Info檔程式。默認命令是―makeinfo‖。TEX

從TeX原始檔案創建TeX DVI檔的程式。默認命令是―tex‖。

TEXI2DVI

從Texinfo原始檔案創建軍TeX DVI 檔的程式。默認命令是―texi2dvi‖。WEA VE

轉換Web到TeX的程式。默認命令是―weave‖。

CWEA VE

轉換C Web 到 TeX的程式。默認命令是―cweave‖。

TANGLE

轉換Web到Pascal語言的程式。默認命令是―tangle‖。

CTANGLE

轉換C Web 到 C。默認命令是―ctangle‖。

RM

刪除檔命令。默認命令是―rm–f‖。

2、關於命令參數的變數

下面的這些變數都是相關上面的命令的參數。如果沒有指明其預設值,那麼其預設值都是空。

ARFLAGS

函式程式庫打包程式AR命令的參數。預設值是―rv‖。

ASFLAGS

組合語言編譯器參數。(當明顯地調用―.s‖或―.S‖文件時)。

CFLAGS

C語言編譯器參數。

CXXFLAGS

C++語言編譯器參數。

COFLAGS

RCS命令參數。

CPPFLAGS

C前置處理器參數。( C 和 Fortran 編譯器也會用到)。

FFLAGS

Fortran語言編譯器參數。

GFLAGS

SCCS ―get‖程式參數。

LDFLAGS

連結器參數。(如:―ld‖)

LFLAGS

Lex文法分析器參數。

PFLAGS

Pascal語言編譯器參數。

RFLAGS

Ratfor 程式的Fortran 編譯器參數。

YFLAGS

Yacc文法分析器參數。

四、隱含規則鏈

有些時候,一個目標可能被一系列的隱含規則所作用。例如,一個[.o]的檔生成,可能會是先被Yacc的[.y]文件先成[.c],然後再被C的編譯器生成。我們把這一系列的隱含規則叫做―隱含規則鏈‖。

在上面的例子中,如果檔[.c]存在,那麼就直接調用C的編譯器的隱含規則,如果沒有[.c]檔,但有一個[.y]檔,那麼Yacc的隱含規則會被調用,生成[.c]檔,然後,再調用C編譯的隱含規則最終由[.c]生成[.o]檔,達到目標。

我們把這種[.c]的檔(或是目標),叫做中間目標。不管怎麼樣,make會努力自動推導生成目標的一切方法,不管中間目標有多少,其都會執著地把所有的隱含規則和你書寫的規則全部合起來分析,努力達到目標,所以,有些時候,可能會讓你覺得奇怪,怎麼我的目標會這樣生成?怎麼我的makefile發瘋了?

在預設情況下,對於中間目標,它和一般的目標有兩個地方所不同:第一個不同是除非中間的目標不存在,才會引發中間規則。第二個不同的是,只要目標成功產生,那麼,產生最終目標過程中,所產生的中間目的檔案會被以―rm -f‖刪除。通常,一個被makefile指定成目標或是依賴目標的檔不能被當作仲介。然而,你可以明顯地說明一個檔或是目標是仲介目標,你可以使用偽目標―.INTERMEDIATE‖來強制聲明。(如:.INTERMEDIATE : mid )

你也可以阻止make自動刪除中間目標,要做到這一點,你可以使用偽目標―.SECONDARY‖來強制聲明(如:.SECONDARY : sec)。你還可以把你的目標,以模式的方式來指定(如:%.o)成偽目標―.PRECIOUS‖的依賴目標,以保存被隱含規則所生成的中間檔。

在―隱含規則鏈‖中,禁止同一個目標出現兩次或兩次以上,這樣一來,就可防止在make自動推導時出現無限遞迴的情況。

Make會優化一些特殊的隱含規則,而不生成中間文件。如,從文件―foo.c‖生成目的程式―foo‖,按道理,make會編譯生成中間檔―foo.o‖,然後連結成―foo‖,但在實際情況下,這一動作可以被一條―cc‖的命令完成(cc –o foo foo.c),於是優化過的規則就不會生成中間檔。

五、定義模式規則

你可以使用模式規則來定義一個隱含規則。一個模式規則就好像一個一般的規則,只是在規則中,目標的定義需要有"%"字元。"%"的意思是表示一個或多個任意字元。在依賴目標中同樣可以使用"%",只是依賴目標中的"%"的取值,取決於其目標。

有一點需要注意的是,"%"的展開發生在變數和函數的展開之後,變數和函數的展開發生在make載入Makefile時,而模式規則中的"%"則發生在運行時。

1、模式規則介紹

模式規則中,至少在規則的目標定義中要包含"%",否則,就是一般的規則。目標中的"%"定義表示對檔案名的匹配,"%"表示長度任意的非空字串。例如:"%.c"表示以".c"結尾的檔案名(檔案名的長度至少為3),而"s.%.c"則表示以"s."開頭,".c"結尾的檔案名(檔案名的長度至少為5)。

如果"%"定義在目標中,那麼,目標中的"%"的值決定了依賴目標中的"%"的值,也就是說,目標中的模式的"%"決定了依賴目標中"%"的樣子。例如有一個模式規則如下:

%.o : %.c ; ;

其含義是,指出了怎麼從所有的[.c]文件生成相應的[.o]檔的規則。如果要生成的目標是"a.o b.o",那麼"%c"就是"a.c b.c"。

一旦依賴目標中的"%"模式被確定,那麼,make會被要求去匹配目前的目錄下所有的檔案名,一旦找到,make就會規則下的命令,所以,在模式規則中,目標可能會是多個的,如果有模式匹配出多個目標,make就會產生所有的模式目標,此時,make關心的是依賴的檔案名和生成目標的命令這兩件事。

2、模式規則示例

下面這個例子表示了,把所有的[.c]檔都編譯成[.o]文件.

%.o : %.c

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

其中,"$@"表示所有的目標的挨個值,"$<"表示了所有依賴目標的挨個值。這些奇怪的變數我們叫"自動化變數",後面會詳細講述。

下面的這個例子中有兩個目標是模式的:

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

bison -d $<

這條規則告訴make把所有的[.y]文件都以"bison -d ;.y"執行,然後生成";.tab.c"和";.tab.h"文件。(其中,";"表示一個任意字串)。如果我們的執行程式"foo"依賴於檔"parse.tab.o"和"scan.o",並且檔"scan.o"依賴於檔"parse.tab.h",如果"parse.y"檔被更新了,那麼根據上述的規則,"bison -d parse.y"就會被執行一次,於是,"parse.tab.o"和"scan.o"的依賴檔就齊了。(假設,"parse.tab.o"由"parse.tab.c"生成,和"scan.o"由"scan.c"生成,而"foo"由"parse.tab.o"和"scan.o"連結生成,而且foo和其[.o]檔的依賴關係也寫好,那麼,所有的目標都會得到滿足)

3、自動化變數

在上述的模式規則中,目標和依賴檔都是一系例的檔,那麼我們如何書寫一個命令來完成從不同的依賴檔生成相應的目標?因為在每一次的對模式規則的解析時,都會是不同的目標和依賴檔。

自動化變數就是完成這個功能的。在前面,我們已經對自動化變數有所提涉,相信你看到這裡已對它有一個感性認識了。所謂自動化變數,就是這種變數會把模式中所定義的一系列的檔自動地挨個取出,直至所有的符合模式的檔都取完了。這種自動化變數只應出現在規則的命令中。

下面是所有的自動化變數及其說明:

$@

表示規則中的目的檔案集。在模式規則中,如果有多個目標,那麼,"$@"就是匹配於目標中模式定義的集合。

$%

僅當目標是函式程式庫檔中,表示規則中的目標成員名。例如,如果一個目標

是"foo.a(bar.o)",那麼,"$%"就是"bar.o","$@"就是"foo.a"。如果目標不是函式程式庫檔(Unix下是[.a],Windows下是[.lib]),那麼,其值為空。

$<

依賴目標中的第一個目標名字。如果依賴目標是以模式(即"%")定義的,那麼"$<"將是符合模式的一系列的檔集。注意,其是一個一個取出來的。

$?

所有比目標新的依賴目標的集合。以空格分隔。

$^

所有的依賴目標的集合。以空格分隔。如果在依賴目標中有多個重複的,那個這個變數會去除重複的依賴目標,只保留一份。

$+

這個變數很像"$^",也是所有依賴目標的集合。只是它不去除重複的依賴目標。

$*

這個變數表示目標模式中"%"及其之前的部分。如果目標是"dir/a.foo.b",並且目標的模式是"a.%.b",那麼,"$*"的值就是"dir/a.foo"。這個變數對於構造有關聯的檔案名是比較有較。如果目標中沒有模式的定義,那麼"$*"也就不能被推導出,但是,如果目的檔案的尾碼是make所識別的,那麼"$*"就是除了尾碼的那一部分。例如:如果目標是"foo.c",因為".c"是make所能識別的尾碼名,所以,"$*"的值就是"foo"。這個特性是GNU make的,很有可能不相容於其它版本的make,所以,你應該儘量避免使用"$*",除非是在隱含規則或是靜態模式中。如果目標中的尾碼是make所不能識別的,那麼"$*"就是空值。

當你希望只對更新過的依賴檔進行操作時,"$?"在顯式規則中很有用,例如,假設有一個函式程式庫檔叫"lib",其由其它幾個object文件更新。那麼把object檔打包的比較有效率的Makefile規則是:

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

ar r lib $?

在上述所列出來的自動量變數中。四個變數($@、$<、$%、$*)在擴展時只會有一個檔,而另三個的值是一個檔列表。這七個自動化變數還可以取得檔的目錄名或是在目前的目錄下的符合模式的檔案名,只需要搭配上"D"或"F"字樣。這是GNU make中老版本的特性,在新版本中,我們使用函數"dir"或"notdir"就可以做到了。"D"的含義就是Directory,就是目錄,"F"的含義就是File,就是檔。

下面是對於上面的七個變數分別加上"D"或是"F"的含義:

$(@D)

表示"$@"的目錄部分(不以斜杠作為結尾),如果"$@"值是"dir/foo.o",那麼"$(@D)"就是"dir",而如果"$@"中沒有包含斜杠的話,其值就是"."(目前的目錄)。

$(@F)

表示"$@"的檔部分,如果"$@"值是"dir/foo.o",那麼"$(@F)"就是"foo.o","$(@F)"相當於函數"$(notdir $@)"。

"$(*D)"

"$(*F)"

和上面所述的同理,也是取檔的目錄部分和檔部分。對於上面的那個例子,"$(*D)"返回"dir",而"$(*F)"返回"foo"

"$(%D)"

"$(%F)"

分別表示了函數包檔成員的目錄部分和檔部分。這對於形同"archive(member)"形式的目標中的"member"中包含了不同的目錄很有用。

"$(

"$(

分別表示依賴檔的目錄部分和檔部分。

"$(^D)"

"$(^F)"

分別表示所有依賴檔的目錄部分和檔部分。(無相同的)

"$(+D)"

"$(+F)"

分別表示所有依賴檔的目錄部分和檔部分。(可以有相同的)

"$(?D)"

"$(?F)"

分別表示被更新的依賴檔的目錄部分和檔部分。

最後想提醒一下的是,對於"$<",為了避免產生不必要的麻煩,我們最好給$後面的那個特定字元都加上圓括號,比如,"$(<)"就要比"$<"要好一些。

還得要注意的是,這些變數只使用在規則的命令中,而且一般都是"顯式規則"和"靜態模式規則"(參見前面"書寫規則"一章)。其在隱含規則中並沒有意義。

4、模式的匹配

一般來說,一個目標的模式有一個有首碼或是尾碼的"%",或是沒有前尾碼,直接就是一個"%"。因為"%"代表一個或多個字元,所以在定義好了的模式中,我們把"%"所匹配的內容叫做"莖",例如"%.c"所匹配的文件"test.c"中"test"就是"莖"。因為在目標和依賴目標中同時有"%"時,依賴目標的"莖"會傳給目標,當做目標中的"莖"。

當一個模式匹配包含有斜杠(實際也不經常包含)的檔時,那麼在進行模式匹配

時,目錄部分會首先被移開,然後進行匹配,成功後,再把目錄加回去。在進行"莖"的傳遞時,我們需要知道這個步驟。例如有一個模式"e%t",檔"src/eat"匹配於該模式,於是"src/a"就是其"莖",如果這個模式定義在依賴目標中,而被依賴於這個模式的目標中又有個模式"c%r",那麼,目標就是"src/car"。("莖"被傳遞)5、重載內建隱含規則

你可以重載內建的隱含規則(或是定義一個全新的),例如你可以重新構造和內建隱含規則不同的命令,如:

%.o : %.c

$(CC) -c $(CPPFLAGS) $(CFLAGS) -D$(date)

你可以取消內建的隱含規則,只要不在後面寫命令就行。如:

%.o : %.s

同樣,你也可以重新定義一個全新的隱含規則,其在隱含規則中的位置取決於你在哪裡寫下這個規則。朝前的位置就靠前。

六、老式風格的"尾碼規則"

尾碼規則是一個比較老式的定義隱含規則的方法。尾碼規則會被模式規則逐步地取代。因為模式規則更強更清晰。為了和老版本的Makefile相容,GNU make同樣相容於這些東西。尾碼規則有兩種方式:"雙尾碼"和"單尾碼"。

雙尾碼規則定義了一對尾碼:目的檔案的尾碼和依賴目標(原始檔案)的尾碼。如".c.o"相當於"%o : %c"。單尾碼規則只定義一個尾碼,也就是原始檔案的尾碼。如".c"相當於"% : %.c"。

尾碼規則中所定義的尾碼應該是make所認識的,如果一個尾碼是make所認識的,那麼這個規則就是單尾碼規則,而如果兩個連在一起的尾碼都被make所認識,那就是雙尾碼規則。例如:".c"和".o"都是make所知道。因而,如果你定義了一個規則是".c.o"那麼其就是雙尾碼規則,意義就是".c"是原始檔案的尾碼,".o"是目的檔案的尾碼。如下示例:

.c.o:

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

尾碼規則不允許任何的依賴檔,如果有依賴檔的話,那就不是尾碼規則,那些尾碼統統被認為是檔案名,如:

.c.o: foo.h

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

這個例子,就是說,檔".c.o"依賴於檔"foo.h",而不是我們想要的這樣:

%.o: %.c foo.h

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

尾碼規則中,如果沒有命令,那是毫無意義的。因為他也不會移去內建的隱含規則。

而要讓make知道一些特定的尾碼,我們可以使用偽目標".SUFFIXES"來定義或是刪除,如:

.SUFFIXES: .hack .win

把尾碼.hack和.win加入尾碼列表中的末尾。

.SUFFIXES: # 刪除默認的尾碼

.SUFFIXES: .c .o .h # 定義自己的尾碼

先清楚默認尾碼,後定義自己的尾碼列表。

make的參數"-r"或"-no-builtin-rules"也會使用得默認的尾碼列表為空。而變數"SUFFIXE"被用來定義默認的尾碼列表,你可以用".SUFFIXES"來改變尾碼列表,但請不要改變變數"SUFFIXE"的值。

七、隱含規則搜索演算法

比如我們有一個目標叫 T。下面是搜索目標T的規則的演算法。請注意,在下面,我們沒有提到尾碼規則,原因是,所有的尾碼規則在Makefile被載入記憶體時,會被轉換成模式規則。如果目標是"archive(member)"的函式程式庫檔模式,那麼這個演算法會被運行兩次,第一次是找目標T,如果沒有找到的話,那麼進入第二次,第二次會把"member"當作T來搜索。

1、把T的目錄部分分離出來。叫D,而剩餘部分叫N。(如:如果T是"src/foo.o",那麼,D就是"src/",N就是"foo.o")

2、創建所有匹配於T或是N的模式規則清單。

3、如果在模式規則清單中有匹配所有檔的模式,如"%",那麼從列表中移除其它的模式。

4、移除清單中沒有命令的規則。

5、對於第一個在清單中的模式規則:

1)推導其"莖"S,S應該是T或是N匹配於模式中"%"非空的部分。

2)計算依賴檔。把依賴檔中的"%"都替換成"莖"S。如果目標模式中沒有包含斜框字元,而把D加在第一個依賴檔的開頭。

3)測詴是否所有的依賴檔都存在或是理當存在。(如果有一個檔被定義成另外一個規則的目的檔案,或者是一個顯式規則的依賴檔,那麼這個檔就叫"理當存在") 4)如果所有的依賴檔存在或是理當存在,或是就沒有依賴檔。那麼這條規則將被採用,退出該演算法。

6、如果經過第5步,沒有模式規則被找到,那麼就做更進一步的搜索。對於存在於清單中的第一個模式規則:

1)如果規則是終止規則,那就忽略它,繼續下一條模式規則。

2)計算依賴檔。(同第5步)

3)測詴所有的依賴檔是否存在或是理當存在。

4)對於不存在的依賴檔,遞迴呼叫這個演算法查找他是否可以被隱含規則找到。5)如果所有的依賴檔存在或是理當存在,或是就根本沒有依賴檔。那麼這條規則被採用,退出該演算法。

7、如果沒有隱含規則可以使用,查看".DEFAULT"規則,如果有,採用,把".DEFAULT"的命令給T使用。

一旦規則被找到,就會執行其相當的命令,而此時,我們的自動化變數的值才會生成。

Makefile规则

目录 1.简介 3 1.1.准备工作 3 1.2.Makefile介绍 3 1.3.规则简介 4 1.4.make工作原理 4 1.5.使用变量 5 1.6.简化命令 6 1.7.另一种风格 6 1.8.清理 7 2.Makefile 7 2.1.makefile名字 7 2.2.包含 8 2.3.‘MAKEFILE’变量 8 2.4.怎么重新生成makefile 8 2.5.重载makefile 9 3.规则 9 3.1.例子 9 3.2.规则的语法 9 3.3.通配符 10 3.3.1.通配符的缺陷 10 3.3.2.wildcard函数 11 3.4.目录搜索 11 3.4.1.‘VPATH’ 11 3.4.2.选择性搜索 12 3.4.3.使用自动变量 12 3.4.4.目录搜索和隐含规则 12 3.5.PHONY目标 13 3.6.FORCE目标 14 3.7.空目标 14 3.8.内建的特别目标 14 3.9.一个规则多个目标 15 3.10.一个目标多条规则 15 3.11.静态模式规则 16 3.11.1.语法 16 3.11.2.静态模式规则和隐式规则 17 3.12.双冒号规则 17 3.13.自动生成依赖关系 17 4.编写命令 18 4.1.回显 18 4.2.执行 19 4.3.并行执行 19 4.4.错误 19 4.5.中断make 20 4.6.递归使用 20 4.6.1.‘MAKE’变量 20 4.6.2.传递变量到子make 21 5.命令行参数 21 6.参考 25

6.1.指令 25 6.2.函数 26 6.3.自动变量 27 6.4.特别变量 29 GNU Make使用 Make 程式最初设计是为了维护C程式文件防止不必要的重新编译。在使用命令行编译器的时候,修改了一个工程中的头文件,怎么确保包含这个头文件的所有文件都得到编译?目前10机的版本生成是使用批处理程式,编译那些文件依赖于程式的维护者,在模块之间相互引用头文件的情况下,要将所有需要重新编译的文件找出来是一件痛苦的事情;在找到这些文件之后,修改批处理进行编译。实际上这些工作能让make程式来自动完成,make工具对于维护一些具有相互依赖关系的文件特别有用,他对文件和命令的联系(在文件改动时调用来更新其他文件的程式)提供一套编码方法。Make工具的基本概念类似于Proglog语言,你告诉make需要做什么,提供一些规则,make来完成剩下的工作。 1.简介 make工作自动确定工程的哪部分需要重新编译,执行命令去编译他们。虽然make多用于C程式,然而只要提供命令行的编译器,你能将其用于所有语言。实际上,make工具的应用范围不仅于编程,你能描述任和一些文件改动需要自动更新另一些文件的任务来使用他。 1.1.准备工作 如果要使用make,你必须写一个叫做“makefile”的文件,这个文件描述工程中文件之间的关系,提供更新每个文件的命令。典型的工程是这样的:可执行文件靠目标文件来更新,目标文件靠编译源文件来更新。 Makefile写好之后,每次更改了源文件后,只要执行make就足够了,所有必要的重新编译将执行。Make程式利用makefile中的数据库和文件的最后修改时间来确定那个文件需要更新;对于需要更新的文件,make执行数据库中记录的命令。 能提供命令行参数给make来控制那个文件需要重新编译。 1.2.Makefile介绍 Makefile文件告诉make做什么,多数情况是怎样编译和链接一个程式。 这里有一个简单的makefile,描述怎么编译链接由8个C文件和3个头文件组成的一个编辑器: edit : main.o kbd.o command.o display.o insert.o serach.o files.o utils.o cc ?o edit main.o kbd.o command.o display.o insert.o search.o files.o utils.o main.o : main.c defs.h cc ?c main.c kdb.o : kbd.c defs.h command.h cc ?c kbd.c command.o : command.c defs.h command.h cc -c command.c display.o : display.c defs.h buffer.h cc -c display.c insert.o : insert.c defs.hbuffer.h cc -c insert.c search.o : search.c defs.hbuffer.h cc -c search.c files.o : files.c defs.h buffer.h command.h cc -c files.c utils.o : utils.c defs.h cc -c utils.c

跟我一起写Makefile

跟我一起写Makefile 陈皓 1 概述 什么是makefile?或许很多Winodws的程序员都不知道这个东西,因为那些Windows的IDE都为你做了这个工作,但我觉得要作一个好的和professional的程序员,makefile还是要懂。这就好像现在有这么多的HTML的编辑器,但如果你想成为一个专业人士,你还是要了解HTML的标识的含义。特别在Unix下的软件编译,你就不能不自己写makefile了,会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力。 因为,makefile关系到了整个工程的编译规则。一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。 makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可见,makefile都成为了一种在工程方面的编译方法。 现在讲述如何写makefile的文章比较少,这是我想写这篇文章的原因。当然,不同产商的make各不相同,也有不同的语法,但其本质都是在“文件依赖性”上做文章,这里,我仅对GNU的make进行讲述,我的环境是RedHat Linux 8.0,make的版本是3.80。必竟,这个make是应用最为广泛的,也是用得最多的。而且其还是最遵循于IEEE 1003.2-1992 标准的(POSIX.2)。 在这篇文档中,将以C/C++的源码作为我们基础,所以必然涉及一些关于C/C++的编译的知识,相关于这方面的内容,还请各位查看相关的编译器的文档。这里所默认的编译器是UNIX下的GCC和CC。 2 关于程序的编译和链接 在此,我想多说关于程序编译的一些规范和方法,一般来说,无论是C、C++、还是pas,首先要把源文件编译成中间代码文件,在Windows下也就是.obj 文件,UNIX下是.o 文件,即Object File,这个动作叫做编译(compile)。然后再把大量的Object File合成执行文件,这个动作叫作链接(link)。 编译时,编译器需要的是语法的正确,函数与变量的声明的正确。对于后者,通常是你需要告诉编译器头文件的所在位置(头文件中应该只是声明,而定义应该放在C/C++文件中),只要所有的语法正确,编译器就可以编译出中间目标文件。一般来说,每个源文件都应该对应于一个中间目标文件(O文件或是OBJ 文件)。 链接时,主要是链接函数和全局变量,所以,我们可以使用这些中间目标文件(O文件或是OBJ文件)来链接我们的应用程序。链接器并不管函数所在的源文件,只管函数的中间目标文件(Object File),在大多数时候,由于源文件太多,编译生成的中间目标文件太多,而在链接时需要明显地指出中间目标文件名,这对于编译很不方便,所以,我们要给中间目标文件打个包,在Windows下这种包叫“库文件”(Library File),也就是.lib 文件,在UNIX下,是Archive File,也就是.a 文件。 总结一下,源文件首先会生成中间目标文件,再由中间目标文件生成执行文件。在编译时,编译器只检测程序语法,和函数、变量是否被声明。如果函数未被声明,编译器会给出一个警告,但可以生成Object File。而在链接程序时,链接器会在所有的Object File中找寻函数的实现,如果找不到,那到就会报链接错

手动建立makefile简单实例解析

手动建立makefile简单实例解析 假设我们有一个程序由5个文件组成,源代码如下:/*main.c*/ #include "mytool1.h" #include "mytool2.h" int main() { mytool1_print("hello mytool1!"); mytool2_print("hello mytool2!"); return 0; } /*mytool1.c*/ #include "mytool1.h" #include void mytool1_print(char *print_str) { printf("This is mytool1 print : %s ",print_str); } /*mytool1.h*/ #ifndef _MYTOOL_1_H #define _MYTOOL_1_H void mytool1_print(char *print_str); #endif /*mytool2.c*/ #include "mytool2.h" #include void mytool2_print(char *print_str) { printf("This is mytool2 print : %s ",print_str); }

/*mytool2.h*/ #ifndef _MYTOOL_2_H #define _MYTOOL_2_H void mytool2_print(char *print_str); #endif 首先了解一下make和Makefile。GNU make是一个工程管理器,它可以管理较多的文件。我所使用的RedHat 9.0的make版本为GNU Make version 3.79.1。使用make的最大好处就是实现了“自动化编译”。如果有一个上百个文件的代码构成的项目,其中一个或者几个文件进行了修改,make就能够自动识别更新了的文件代码,不需要输入冗长的命令行就可以完成最后的编译工作。make执行时,自动寻找Makefile(makefile)文件,然后执行编译工作。所以我们需要编写Makefile文件,这样可以提高实际项目的工作效率。 在一个Makefile中通常包含下面内容: 1、需要由make工具创建的目标体(target),通常是目标文件或可执行文件。 2、要创建的目标体所依赖的文件(dependency_file)。 3、创建每个目标体时需要运行的命令(command)。 格式如下: target:dependency_files command target:规则的目标。通常是程序中间或者最后需要生成的文件名,可以是.o文件、也可以是最后的可执行程序的文件名。另外,目标也可以是一个make执行的动作的名称,如目标“clean”,这样的目标称为“伪目标”。 dependency_files:规则的依赖。生成规则目标所需要的文件名列表。通常一个目标依赖于一个或者多个文件。 command:规则的命令行。是make程序所有执行的动作(任意的shell命令或者可在shell下执行的程序)。一个规则可以有多个命令行,每一条命令占一行。注意:每一个命令行必须以[Tab]字符开始,[Tab]字符告诉make此行是一个命令行。make按照命令完成相应的动作。这也是书写Makefile中容易产生,而且比较隐蔽的错误。命令就是在任何一个目标的依赖文件发生变化后重建目标的动作描述。一个目标可以没有依赖而只有动作(指定的命令)。比如Makefile中的目标“clean”,此目标没有依赖,只有命令。它所指定的命令用来删除make过程产生的中间文件(清理工作)。 在Makefile中“规则”就是描述在什么情况下、如何重建规则的目标文件,通常规则

Makefile下编写Helloworld的例子

什么是makefile?或许很多Windows的程序员都不知道这个东西,因为那些Windows的IDE都为你做了这个工作,但我觉得 要作一个好的和professional的程序员,makefile还是要懂。这就好像现在有这么多的HTML的编辑器,但如果你想成为一个专 业人士,你还是要了解HTML的标识的含义。特别在Unix下的软件编译,你就不能不自己写makefile了,会不会写makefile, 从一个侧面说明了一个人是否具备完成大型工程的能力。 因为,makefile关系到了整个工程的编译规则。一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中, makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复 杂的功能操作,因为makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。 makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make 命令,整个工程完全自动编译,极大的提高了软件 开发的效率。make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如: Delphi的make,VisualC++的nmake,Linux下GNU的make。可见,makefile都成为了一种在工程方面的编译方法。 更新版本 hello.c程序 #include int main(){printf("Hello,World!\n");

return 0;}=== makefile开始=== Helloworld: hello.o gcc hello.o–o Helloworld Hello.o: hello.c hello.h gcc–MM hello.c gcc–c hello.c–o hello.o .PHONY: clean Clean: rm–rf*.o hellworld === makefile结束===

Excel常用电子表格公式大全【汇总篇】

Excel 常用电子表格公式大全【汇总篇】 篇一:Excel 常用电子表格公式汇总 Excel 常用电子表格公式汇总 1、查找重复内容公式:=IF(COUNTIF(A:A,A2)>1,"重复","")。 2、用出生年月来计算年龄公式: =TRUNC((DAYS360(H6,"2009/8/30",FALSE))/360,0)。 3、从输入的 18 位身份证号的出生年月计算公式: =CONCATENATE(MID(E2,7,4),"/",MID(E2,11,2),"/",MID(E2,13,2))。 4、从输入的身份证号码内让系统自动提取性别,可以输入以下公式: =IF(LEN(C2)=15,IF(MOD(MID(C2,15,1),2)=1," 男 "," 女 "),IF(MOD(MID(C2,17,1),2)=1," 男 "," 女 ")) 公式内的“C2”代表的是输入身份证号码的单元格。 5、求和: =SUM(K2:K56)——对 K2 到 K56 这一区域进行求和; 6、平均数: =AVERAGE(K2:K56)——对 K2 K56 这一区域求平均数; 7、排名: =RANK(K2,K$2:K$56)——对 55 名学生的成绩进行排名; 8、等级: =IF(K2>=85,"优",IF(K2>=74,"良",IF(K2>=60,"及格","不及格"))) 9、 学期总评: =K2*0.3+M2*0.3+N2*0.4 ——假设 K 列、 M 列和 N 列分别存放着学生的“平 时总评”、“期中”、“期末”三项成绩; 10、最高分: =MAX(K2:K56) ——求 K2 到 K56 区域(55 名学生)的最高分; 11、最低分: =MIN(K2:K56) ——求 K2 到 K56 区域(55 名学生)的最低分; 12、分数段人数统计: (1) =COUNTIF(K2:K56,"100") ——求 K2 到 K56 区域 100 分的人数;假设把结果存放于 K57 单元格; (2)=COUNTIF(K2:K56,">=95")-K57 ——求 K2 到 K56 区域 95~99.5 分的人数;假设把结 果存放于 K58 单元格; (3)=COUNTIF(K2:K56,">=90")-SUM(K57:K58)——求 K2 到 K56 区域 90~94.5 分的人数; 假设把结果存放于 K59 单元格; (4) =COUNTIF(K2:K56,">=85")-SUM(K57:K59)——求 K2 到 K56 区域 85~89.5 分的人数; 假设把结果存放于 K60 单元格; (5) =COUNTIF(K2:K56,">=70")-SUM(K57:K60)——求 K2 到 K56 区域 70~84.5 分的人数; 假设把结果存放于 K61 单元格; (6) =COUNTIF(K2:K56,">=60")-SUM(K57:K61)——求 K2 到 K56 区域 60~69.5 分的人数; 假设把结果存放于 K62 单元格; (7) =COUNTIF(K2:K56," 说明:COUNTIF 函数也可计算某一区域男、女生人数。 如:=COUNTIF(C2:C351,"男") ——求 C2 到 C351 区域(共 350 人)男性人数; 1 / 10

编译内核Makefile时 混和的隐含和普通规则。停止

编译时makefile:Makefile:1503: *** 混和的隐含和普通规则。停止。处理 (2012-05-05 16:45:32) 转载▼ 1.makefile #AR=ar #ARCH=arm #CC=arm-linux-gcc obj-m := hello.o #if we need more than one source code to build the module #we should use the variable below: example: modules-objs := file1.o file2.o #KDIR := /lib/modules/$(shell uname -r)/build KDIR := /UP-Magic/kernel/linux-2.6.24.4 PWD := $(shell pwd) default: # $(MAKE) -C $(KDIR) M=$(PWD) modules $(MAKE) -C $(KDIR) M=$(PWD) modules clean: rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers make时出现; [root@hpx driverPractise]# make make -C /UP-Magic/kernel/linux-2.6.24.4 M=/bochuang/driverPractise modules make[1]: 进入目录“/UP-Magic/kernel/linux-2.6.24.4” Makefile:1503: *** 混和的隐含和普通规则。停止。 make[1]: 离开目录“/UP-Magic/kernel/linux-2.6.24.4” make: *** [default] 错误 2 搜索一下,有人解决了,转载过来: 在编译 kernel 时,有机会碰见下面的错误: Makefile: *** 混合的隐含和普通规则。停止。 Makefile: *** mixed implicit and normal rules. Stop. 这个原因可能是Make工具对低版本内核的Makefile一些旧的规则兼容不好,我们只需要修改对应的Makefile。 如一:

3-Makefile书写规则

3 Makefile书写规则 规则包含两个部分,一个是依赖关系,一个是生成目标的方法。 在Makefile中,规则的顺序是很重要的,因为,Makefile中只应该有一个最终目标,其它的目标都是被这个目标所连带出来的,所以一定要让make知道你的最终目标是什么。一般来说,定义在Makefile中的目标可能会有很多,但是第一条规则中的目标将被确立为最终的目标。如果第一条规则中的目标有很多个,那么,第一个目标会成为最终的目标。make所完成的也就是这个目标。 好了,还是让我们来看一看如何书写规则。 3.1 规则举例 foo.o : foo.c defs.h # foo模块 cc -c -g foo.c 看到这个例子,各位应该不是很陌生了,前面也已说过,foo.o是我们的目标,foo.c和defs.h是目标所依赖的源文件,而只有一个命令“cc -c - g foo.c”(以Tab键开头)。这个规则告诉我们两件事: 1. 文件的依赖关系,foo.o依赖于foo.c和defs.h的文件,如果foo.c 和defs.h的文件日期要比foo.o文件日期要新,或是foo.o不存 在,那么依赖关系发生。 2. 如果生成(或更新)foo.o文件。也就是那个cc命令,其说明 了,如何生成foo.o这个文件。(当然foo.c文件include了defs.h 文件) 3.2 规则的语法 targets : prerequisites command

... 或是这样: targets : prerequisites ; command command ... targets是文件名,以空格分开,可以使用通配符。一般来说,我们的目标基本上是一个文件,但也有可能是多个文件。 command是命令行,如果其不与“target:prerequisites”在一行,那么,必须以[Tab键]开头,如果和prerequisites在一行,那么可以用分号做为分隔。(见上) prerequisites也就是目标所依赖的文件(或依赖目标)。如果其中的某个文件要比目标文件要新,那么,目标就被认为是“过时的”,被认为是需要重生成的。这个在前面已经讲过了。 如果命令太长,你可以使用反斜框(‘\’)作为换行符。make对一行上有多少个字符没有限制。规则告诉make两件事,文件的依赖关系和如何成成目标文件。 一般来说,make会以UNIX的标准Shell,也就是/bin/sh来执行命令。3.3 在规则中使用通配符 如果我们想定义一系列比较类似的文件,我们很自然地就想起使用通配符。make支持三各通配符:“*”,“?”和“[...]”。这是和Unix的B-Shell是相同的。 波浪号(“~”)字符在文件名中也有比较特殊的用途。如果是“~/test”,这就表示当前用户的$HOME目录下的test目录。而“~hchen/test”则表示用户hchen的宿主目录下的test目录。(这些都是Unix下的小知识了,make也支持)而在Windows或是MS-DOS下,用户没有宿主目录,那么波浪号所指的目录则根据环境变量“HOME”而定。

Linux如何写makefile文件

Linux如何写makefile文件 关于程序的编译和链接 —————————— 在此,我想多说关于程序编译的一些规范和方法,一般来说,无论是C、C++、还是pas,首先要把源文件编译成中间代码文件,在Windows下也就是 .obj 文件,UNIX下是 .o 文件,即 Object File,这个动作叫做编译(compile)。然后再把大量的Object File合成执行文件,这个动作叫作链接(link)。 编译时,编译器需要的是语法的正确,函数与变量的声明的正确。对于后者,通常是你需要告诉编译器头文件的所在位置(头文件中应该只是声明,而定义应该放在 C/C++文件中),只要所有的语法正确,编译器就可以编译出中间目标文件。一般来说,每个源文件都应该对应于一个中间目标文件(O文件或是OBJ文 件)。 链接时,主要是链接函数和全局变量,所以,我们可以使用这些中间目标文件(O文件或是OBJ文件)来链接我们的应用程序。链接器并不管函数所在的源文件, 只管函数的中间目标文件(Object File),在大多数时候,由于源文件太多,编译生成的中间目标文件太多,而在链接时需要明显地指出中间目标文件名,这对于编译很不方便,所以,我们要给 中间目标文件打个包,在Windows 下这种包叫“库文件”(Library File),也就是 .lib 文件,在UNIX下,是Archive File,也就是 .a 文件。 总结一下,源文件首先会生成中间目标文件,再由中间目标文件生成执行文件。在编译时,编译器只检测程序语法,和函数、变量是否被声明。如果函数未被声明, 编译器会给出一个警告,但可以生成Object File。而在链接程序时,链接器会在所有的Object File中找寻函数的实现,如果找不到,那到就会报链接错误码(Linker Error),在VC下,这种错误一般是:Link 2001错误,意思说是说,链接器未能找到函数的实现。你需要指定函数的Object File. 好,言归正传,GNU的make有许多的内容,闲言少叙,还是让我们开始吧。 Makefile 介绍 ——————— make命令执行时,需要一个 Makefile 文件,以告诉make命令需要怎么样的去编译和链接程序。 首先,我们用一个示例来说明Makefile的书写规则。以便给大家一个感兴认识。这个示例来源于GNU的make使用手册,在这个示例中,我们的工程有 8

Excel常用函数汇总

如果匹配不到内容就直接返回空值: =IFERROR(VLOOKUP($A2,Sheet2!$A$2:$L$99,5,0),"") 如果A2的单元格不为空就进行匹配,如匹配不到内容则直接返回空,如匹配有内容则将匹配到的文本类型的数字转化为数字类型可求和的数字 =IFERROR(IF(A2<>"",VALUE(VLOOKUP($A2,Sheet2!$A$2:$L$99,5,0)),""),"") 注意:Sheet2表格内的数据由于被引用不能直接删除单元格,只能粘贴替换或选择“清除内容”。 如果A1单元格为空,则为空,如果A1单元格不为空,则求和A1到A5的数值: =IF(A1=””,””,SUM(A1:A5)) 截取单元格中指定字符后的所有文本(不包括指定字符): 截取D5单元格中“市”字后面的所有文本: =MID(D5,FIND("市",D5,1)+1,LEN(D5)-FIND("市",D5,1)) 查找“市”字在D5单元格中的位置并往后移一位得到“市”字后面的第一个字的所在位置字符长度的数字: =FIND("市",D5,1)+1 D5单元格的字符总长度数字减去“市”字前的长度数字得到“市”字后面字符长度的数字(不包括“市”字和“市”字之前的字符): =LEN(D5)-FIND("市",D5,1) excel判断两个单元格是否相同 如果只是汉字,用如下公式 =IF(A1=B1,"相同","不同") 如果包含英文且要区分英文大小写,用如下公式 =IF(EXACT(A1,B1),"相同","不同") 将两个不同表单或表格的内容自动查找相应内容合并在一个表格内:=VLOOKUP(I2,A1:D41,4,0) =VLOOKUP(两表中相同的值,其它表单或表格区域,要匹配值所在的列的数目,0) 将截取后的数字转为数字格式显示(利于计算统计)=VALUE(MID(D2,1,10))

makefile 中 $@ $^ % 使用

makefile 中$@ $^ %< 使用 https://www.doczj.com/doc/f210026589.html,/kesaihao862/article/details/7332528 这篇文章介绍在LINUX下进行C语言编程所需要的基础知识。在这篇文章当中,我们将会学到以下内容:源程序编译Makefile的编写程序库的链接程序的调试头文件和系统求助1.源程序的编译在Linux下面,如果要编译一个C语言源程序,我们要使用GNU的gcc编译器。下面我们以一个实例来说明如何使用gcc编译器。假设我们有下面一个非常简单的源程序(hello.c):int main(int argc,char **argv){printf("Hello Linux\n");}要编译这个程序,我们只要在命令行下执行:gcc -o hello hello.cgcc 编译器就会为我们生成一个hello的可执行文件。执行./hello就可以看到程序的输出结果了。命令行中gcc表示我们是用gcc来编译我们的源程序,-o 选项表示我们要求编译器给我们输出的可执行文件名为hello 而hello.c是我们的源程序文件。gcc编译器有许多选项,一般来说我们只要知道其中的几个就够了。-o 选项我们已经知道了,表示我们要求输出的可执行文件名。-c选项表示我们只要求编译器输出目标代码,而不必要输出可执行文件。-g选项表示我们要求编译器在编译的时候提供我们以后对程序进行调试的信息。知道了这三个选项,我

们就可以编译我们自己所写的简单的源程序了,如果你想要知道更多的选项,可以查看gcc的帮助文档,那里有着许多对其它选项的详细说明。2.Makefile的编写假设我们有下面这样的一个程序,源代码如下:/* main.c */#include "mytool1.h"#include "mytool2.h" int main(int argc,char **argv){mytool1_print("hello");mytool2_print("hello");}/* mytool1.h */ #ifndef _MYTOOL_1_H#define _MYTOOL_1_Hvoid mytool1_print(char *print_str);#endif/* mytool1.c */#include "mytool1.h"void mytool1_print(char *print_str){printf("This is mytool1 print %s\n",print_str);}/* mytool2.h */#ifndef _MYTOOL_2_H#define _MYTOOL_2_Hvoid mytool2_print(char *print_str);#endif/* mytool2.c */#include "mytool2.h"void mytool2_print(char *print_str){printf("This is mytool2 print %s\n",print_str);}当然由于这个程序是很短的我们可以这样来编译gcc -c main.cgcc -c mytool1.cgcc -c mytool2.cgcc -o main main.o mytool1.o mytool2.o这样的话我们也可以产生main程序,而且也不时很麻烦。但是如果我们考虑一下如果有一天我们修改了其中的一个文件(比如说mytool1.c)那么我们难道还要重新输入上面的命令?也许你会说,这个很容易解决啊,我写一个SHELL脚本,让她帮我去完成不就可以了。是的对于这个程序来说,是可

C++项目的Makefile编写

一个C++项目的Makefile编写-Tony与Alex的对话系列- - Tony : Hey Alex, How are you doing? Alex : 不怎么样。(显得很消沉的样子) Tony : Oh , Really ? What is the matter? Alex : 事情是这样的。最近有一个Unix下的C++项目要求我独自完成,以前都是跟着别人做,现在让自己独立完成,还真是不知道该怎么办,就连一个最简单的项目的Makefile都搞不定。昨晚看了一晚上资料也没有什么头绪。唉!! Tony : 别急,我曾经有一段时间研究过一些关于Makefile的东西,也许能帮得上忙,来,我们一起来设计这个项目的Makefile。 Alex : So it is a deal。(一言为定) Tony : 我们现在就开始吧,给我拿把椅子过来。 (Tony坐在Alex电脑的旁边) Tony : 把你的项目情况大概给我讲讲吧。 Alex : No Problem ! 这是一个“半成品”项目,也就是说我将提供一个开发框架供应用开发人员使用,一个类似MFC的东西。 Tony : 继续。 Alex : 我现在头脑中的项目目录结构是这样的: APL (Alex's Programming Library) -Make.properties -Makefile(1) -include //存放头文件 -Module1_1.h -Module1_2.h -Module2_1.h -Module2_2.h -src //存放源文件 -Makefile(2) -module1 -Module1_1.cpp -Module1_2.cpp -Makefile(3) -module2 -Module2_1.cpp -Module2_2.cpp -Makefile(3) -... -lib //存放该Project依赖的库文件,型如libxxx.a -dist //存放该Project编译连接后的库文件libapl.a -examples //存放使用该“半成品”搭建的例子应用的源程序 Makefile(4)

怎样使用Makefile

Mak k e f ile 跟我一 我一起起写Ma 陈皓 (CSDN) 概 述 什么是makefile?或许很多Winodws的程序员都不知道这个东西,因为那些Windows 的IDE都为你做了这个工作,但我觉得要作一个好的和professional的程序员,makefile还是要懂。这就好像现在有这么多的HTML的编辑器,但如果你想成为一个专业人士,你还是要了解HTML的标识的含义。特别在Unix下的软件编译,你就不能不自己写makefile了,会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力。 因为,makefile关系到了整个工程的编译规则。一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能 操作,因为makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。 makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。make是一个命令工具,是一个 解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可见,makefile都成为了一种在工程方面的编译方法。 现在讲述如何写makefile的文章比较少,这是我想写这篇文章的原因。当然,不同产商的make各不相同,也有不同的语法,但其本质都是在“文件依赖性”上做文章,这里,我仅对GNU的make进行讲述,我的环境是RedHat Linux 8.0,make的版本是3.80。必竟,这个make是应用最为广泛的,也是用得最多的。而且其还是最遵循于IEEE 1003.2-1992 标准的(POSIX.2)。 在这篇文档中,将以C/C++的源码作为我们基础,所以必然涉及一些关于C/C++的编译的知识,相关于这方面的内容,还请各位查看相关的编译器的文档。这里所默认的编译器是UNIX下的GCC和CC。 关于程序的编译和链接 在此,我想多说关于程序编译的一些规范和方法,一般来说,无论是C、C++、还是pas,首先要把源文件编译成中间代码文件,在Windows下也就是 .obj 文件,UNIX下是 .o 文件,即 Object File,这个动作叫做编译(compile)。然后再把大量的Object File 合成执行文件,这个动作叫作链接(link)。

如何编写Makefile

概述 —— 什么是makefile?或许很多Winodws的程序员都不知道这个东西,因为那些Windows的IDE 都为你做了这个工作,但我觉得要作一个好的和professional的程序员,makefile还是要懂。这就好像现在有这么多的HTML的编辑器,但如果你想成为一个专业人士,你还是要了解HTML的标识的含义。特别在Unix下的软件编译,你就不能不自己写makefile了,会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力。 因为,makefile关系到了整个工程的编译规则。一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。 makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。make是一个命令工具,是一个解释makefile 中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可见,makefile都成为了一种在工程方面的编译方法。 现在讲述如何写makefile的文章比较少,这是我想写这篇文章的原因。当然,不同产商的make各不相同,也有不同的语法,但其本质都是在“文件依赖性”上做文章,这里,我仅对GNU的make进行讲述,我的环境是RedHat Linux 8.0,make的版本是3.80。必竟,这个make 是应用最为广泛的,也是用得最多的。而且其还是最遵循于IEEE 1003.2-1992 标准的(POSIX.2)。 在这篇文档中,将以C/C++的源码作为我们基础,所以必然涉及一些关于C/C++的编译的知识,相关于这方面的内容,还请各位查看相关的编译器的文档。这里所默认的编译器是UNIX 下的GCC和CC。 关于程序的编译和链接 —————————— 在此,我想多说关于程序编译的一些规范和方法,一般来说,无论是C、C++、还是pas,首先要把源文件编译成中间代码文件,在Windows下也就是 .obj 文件,UNIX下是 .o 文件,即 Object File,这个动作叫做编译(compile)。然后再把大量的Object File合成执行文件,这个动作叫作链接(link)。 编译时,编译器需要的是语法的正确,函数与变量的声明的正确。对于后者,通常是你需要告诉编译器头文件的所在位置(头文件中应该只是声明,而定义应该放在C/C++文件中),只要所有的语法正确,编译器就可以编译出中间目标文件。一般来说,每个源文件都应该对应于一个中间目标文件(O文件或是OBJ文件)。

Excel表格常用运算公式及使用方法汇总

Excel表格常用运算公式及使用方法汇总 1、查找重复内容公式:=IF(COUNTIF(A:AA2)>1”重复””")。 2、用出生年月来计算年龄公式:=TRUNC((DAYS360(H6”2009/8/30″FALSE))/3600)。 3、从输入的18位身份证号的出生年月计算公式: =CONCATENATE(MID(E274)”/”MID(E2112)”/”MID(E2132))。 4、从输入的身份证号码内让系统自动提取性别,可以输入以下公式: =IF(LEN(C2)=15IF(MOD(MI D(C2151)2)=1”男””女”)IF(MOD(MID(C2171)2)=1”男””女”))公式内的“C2”代表的是输入身份证号码的单元格。 1、求和: =SUM(K2:K56) ——对K2到K56这一区域进行求和; 2、平均数: =AVERAGE(K2:K56) ——对K2 K56这一区域求平均数; 3、排名: =RANK(K2,K$2:K$56) ——对55名学生的成绩进行排名; 4、等级:=IF(K2>=85”优”IF(K2>=74”良”IF(K2>=60”及格””不及格”))) 5、学期总评: =K2*0.3+M2*0.3+N2*0.4 ——假设K列、M列和N列分别存放着学生的“平时总评”、“期中”、“期末”三项成绩; 6、最高分: =MAX(K2:K56) ——求K2到K56区域(55名学生)的最高分; 7、最低分: =MIN(K2:K56) ——求K2到K56区域(55名学生)的最低分; 8、分数段人数统计: (1) =COUNTIF(K2:K56”100″) ——求K2到K56区域100分的人数;假设把结果存放于K57单元格; (2) =COUNTI F(K2:K56”>=95″)-K57 ——求K2到K56区域95~99.5分的人数;假设把结果存放于K58单元格; (3)=COUNTIF(K2:K56”>=90″)-SUM(K57:K58) ——求K2到K56区域90~94.5分的人数;假设把结果存放于K59单元格; (4)=COUNTIF(K2:K56”>=85″)-SUM(K57:K59) ——求K2到K56区域85~89.5分的人数;假设把结果存放于K60单元格; (5)=COUNTIF(K2:K56”>=70″)-SUM(K57:K60) ——求K2到K56区域70~84.5分的人数;假设把结果存放于K61单元格; (6)=COUNTIF(K2:K56”>=60″)-SUM(K57:K61) ——求K2到K56区域60~69.5分的人数;假设把结果存放于K62单元格; (7) =COUNTIF(K2:K56”<60″) ——求K2到K56区域60分以下的人数;假设把结果存放于K63单元格; 说明:COUNTIF函数也可计算某一区域男、女生人数。 如:=COUNTIF(C2:C351”男”) ——求C2到C351区域(共350人)男性人数;

跟我一起学Makefile

跟我一起写 Makefile 作者:陈皓 整理:祝冬华

第一部分、概述 (6) 第二部分、关于程序的编译和链接 (6) 第三部分、Makefile 介绍 (7) 一、Makefile的规则 (7) 二、一个示例 (8) 三、make是如何工作的 (9) 四、makefile中使用变量 (10) 五、让make自动推导 (11) 六、另类风格的makefile (12) 七、清空目标文件的规则 (13) 第四部分、Makefile 总述 (13) 一、Makefile里有什么? (13) 1、显式规则。 (14) 2、隐晦规则。 (14) 3、变量的定义。 (14) 4、文件指示。 (14) 5、注释。 (14) 二、Makefile的文件名 (15) 三、引用其它的Makefile (15) 四、环境变量 MAKEFILES (16) 五、make的工作方式 (16) 第五部分、书写规则 (17) 一、规则举例 (17) 二、规则的语法 (17) 三、在规则中使用通配符 (18) 四、文件搜寻 (19) 五、伪目标 (20) 六、多目标 (22) 七、静态模式 (22) 八、自动生成依赖性 (24) 第六部分书写命令 (25) 一、显示命令 (26) 二、命令执行 (26) 三、命令出错 (27) 四、嵌套执行make (28) 五、定义命令包 (30) 第七部分使用变量 (30) 一、变量的基础 (31) 二、变量中的变量 (32) 三、变量高级用法 (34) 四、追加变量值 (37) 五、override 指示符 (37) 六、多行变量 (38)

八、目标变量 (39) 九、模式变量 (40) 第八部分使用条件判断 (40) 一、示例 (40) 二、语法 (42) 第九部分使用函数 (43) 一、函数的调用语法 (44) 二、字符串处理函数 (44) 1、subst (44) 2、patsubst (45) 3、strip (45) 4、findstring (46) 5、filter (46) 6、filter-out (46) 7、sort (47) 8、word (47) 9、wordlist (47) 10、words (47) 11、firstword (48) 12、字符串函数实例 (48) 三、文件名操作函数 (48) 1、dir (48) 2、notdir (48) 3、suffix (49) 4、basename (49) 5、addsuffix (49) 6、addprefix (49) 7、join (50) 四、foreach 函数 (50) 五、if 函数 (50) 六、call函数 (51) 七、origin函数 (51) “undefined” (52) “default” (52) “file” (52) “command line” (52) “override” (52) “automatic” (52) 八、shell函数 (53) 九、控制make的函数 (53) 1、error (53) 2、warning (54) 第十部分 make 的运行 (54)

相关主题
文本预览
相关文档 最新文档