【【小平頭】Linux下Makefile文件的的規(guī)則格式與變量】https://toutiao.com/group/6753030521078415885/?app=explore_article×tamp=1572367321&req_id=20191030004201010014048136068B8D24&group_id=6753030521078415885&tt_from=copy_link&utm_source=copy_link&utm_medium=toutiao_ios&utm_campaign=client_share Makefile 里面是由一系列的規(guī)則組成的,這些規(guī)則格式如下: 目標…... : 依賴文件集合……命令 1命令 2…... 比如下面這條規(guī)則: main : main.o input.o calcu.ogcc -o main main.o input.o calcu.o 這條規(guī)則的目標是 main,main.o、input.o 和 calcu.o 是生成 main 的依賴文件,如果要更新目標 main,就必須要先更新它的所有依賴文,如果依賴文件中的任何一個有更新,那么目標也必須更新,“更新”就是執(zhí)行一遍規(guī)則中的命令列表。 命令列表中的每條命令必須以TAB 鍵開始,不能使用空格!命令列表中的每條命令必須以TAB 鍵開始,不能使用空格 命令列表中的每條命令必須以TAB 鍵開始,不能使用空格! make 命令會為 Makefile 中的每個以TAB 開始的命令創(chuàng)建一個 Shell 進程去執(zhí)行。 了解了 Makefile 的基本運行規(guī)則以后我們再來分析一下 Makefile,代碼如下: main: main.o input.o calcu.o gcc -o main main.o input.o calcu.omain.o: main.c gcc -c main.cinput.o: input.c gcc -c input.ccalcu.o: calcu.c gcc -c calcu.c 9clean: rm *.o rm main 上述代碼中一共有 5 條規(guī)則,1~2 行為第一條規(guī)則,3~4 行為第二條規(guī)則,5~6 行為第三條規(guī)則,7~8 行為第四條規(guī)則,10~12 為第五條規(guī)則,make 命令在執(zhí)行這個 Makefile 的時候其執(zhí)行步驟如下: 首先更新第一條規(guī)則中的main,第一條規(guī)則的目標成為默認目標,只要默認目標更新了那么就認為 Makefile 的工作,完成了整個 Makefile 就是為了完成這個工作。在第一次編譯的時候由于 main 還不存在,因此第一條規(guī)則會執(zhí)行,第一條規(guī)則依賴于文件 main.o、input.o 和 calcu.o這個三個.o 文件,這三個.o 文件目前還都沒有,因此必須先更新這三個文件。make 會查找以這三個.o 文件為目標的規(guī)則并執(zhí)行。以 main.o 為例,發(fā)現(xiàn)更新 main.o 的是第二條規(guī)則,因此會執(zhí)行第二條規(guī)則,第二條規(guī)則里面的命令為“gcc –c main.c”,這行命令很熟悉了吧,就是不鏈接編譯 main.c,生成 main.o,其它兩個.o 文件同理。最后一個規(guī)則目標是 clean,它沒有依賴文件,因此會默認為依賴文件都是最新的,所以其對應的命令不會執(zhí)行,當我們想要執(zhí)行 clean 的話可以直接使用命令“make clean”,執(zhí)行以后就會刪除當前目錄下所有的.o 文件以及 main,因此clean 的功能就是完成工程的清理,“make clean”的執(zhí)行過程如圖所示: make clean執(zhí)行過程 從圖中可以看出,當執(zhí)行“make clean”命令以后,前面編譯出來的.o 和main 可執(zhí)行文件都被刪除掉了,也就是完成了工程清理工作。我們在來總結一下 Make 的執(zhí)行過程: 1、make 命令會在當前目錄下查找以 Makefile(makefile 其實也可以)命名的文件。 2、當找到 Makefile 文件以后就會按照 Makefile 中定義的規(guī)則去編譯生成最終的目標文件。 3、當發(fā)現(xiàn)目標文件不存在,或者目標所依賴的文件比目標文件新(也就是最后修改時間比目標文件晚)的話就會執(zhí)行后面的命令來更新目標。 這就是 make 的執(zhí)行過程,make 工具就是在 Makefile 中一層一層的查找依賴關系,并執(zhí)行相應的命令。編譯出最終的可執(zhí)行文件。Makefile 的好處就是“自動化編譯”,一旦寫好了Makefile文件,以后只需要一個 make 命令即可完成整個工程的編譯,極大的提高了開發(fā)效率。把 make和 Makefile 和做菜類似,目標都是呈現(xiàn)出一場盛宴,它們之間的對比關系如下圖所示: make 和做菜對比 總結一下,Makefile 中規(guī)則用來描述在什么情況下使用什么命令來構建一個特定的文件,這個文件就是規(guī)則的“目標”,為了生成這個“目標”而作為材料的其它文件稱為“目標”的依賴,規(guī)則的命令是用來創(chuàng)建或者更新目標的。 除了 Makefile 的“終極目標”所在的規(guī)則以外,其它規(guī)則的順序在 Makefile 中是沒有意義的,“終極目標”就是指在使用 make 命令的時候沒有指定具體的目標時,make 默認的那個目標,它是 Makefile 文件中第一個規(guī)則的目標,如果 Makefile 中的第一個規(guī)則有多個目標,那么這些目標中的第一個目標就是 make 的“終極目標”。 跟 C 語言一樣 Makefile 也支持變量的,先看一下前面的例子: main: main.o input.o calcu.ogcc -o main main.o input.o calcu.o 上述 Makefile 語句中,main.o input.o 和 calcue.o 這三個依賴文件,我們輸入了兩遍,我們這個 Makefile 比較小,如果 Makefile 復雜的時候這種重復輸入的工作就會非常費時間,而且非常容易輸錯,為了解決這個問題,Makefile 加入了變量支持。不像C 語言中的變量有 int、char等各種類型,Makefile 中的變量都是字符串!類似 C 語言中的宏。使用變量將上面的代碼修改,修改以后如下所示: #Makefile 變量的使用objects = main.o input.o calcu.omain: $(objects)gcc -o main $(objects) 我們來分析一下上面的代碼,第 1 行是注釋,Makefile 中可以寫注釋,注釋開頭要用符號“#”,不能用 C 語言中的“//”或者“/**/”!第 2 行我們定義了一個變量 objects,并且給這個變量進行了賦值,其值為字符串“main.o input.o calcu.o”,第 3 和 4 行使用到了變量objects, Makefile 中變量的引用方法是“$(變量名)”,比如本例中的“$(objects)”就是使用變量 objects。在代碼中我們在定義變量 objects 的時候使用“=”對其進行了賦值,Makefile變量的賦值符還有其它兩個“:=”和“?=”,我們來看一下這三種賦值符的區(qū)別: 1、賦值符“=” 使用“=”在給變量的賦值的時候,不一定要用已經(jīng)定義好的值,也可以使用后面定義的值,比如如下代碼: name = zzk curname = $(name) name = zuozhongkai print: @echo curname: $(curname) 我們來分析一下上述代碼,第 1 行定義了一個變量name,變量值為“zzk”,第 2 行也定義了一個變量curname,curname 的變量值引用了變量name,按照我們C 寫語言的經(jīng)驗此時curname的值就是“zzk”。第 3 行將變量 name 的值改為了“zuozhongkai”,第 5、6 行是輸出變量 curname的值。在 Makefile 要輸出一串字符的話使用“echo”,就和 C 語言中的“printf”一樣,第 6 行中的“echo”前面加了個“@”符號,因為 Make 在執(zhí)行的過程中會自動輸出命令執(zhí)行過程,在命令前面加上“@”的話就不會輸出命令執(zhí)行過程,大家可以測試一下不加“@”的效果。使用命令“make print”來執(zhí)行上述代碼,結果如圖: make執(zhí)行結果 在圖中可以看到curname 的值不是“zzk”,竟然是“zuozhongkai”,也就是變量“name”最后一次賦值的結果,這就是賦值符“=”的神奇之處!借助另外一個變量,可以將變量的真實值推到后面去定義。也就是變量的真實值取決于它所引用的變量的最后一次有效值。 2、賦值符“:=” 在前面代碼上來測試賦值符“:=”,修改第 2 行,將其中的“=”改為“:=”,修改完成以后的代碼如下: name = zzk curname := $(name) name = zuozhongkai print: @echo curname: $(curname) 修改完成以后重新執(zhí)行一下 Makefile,結果如圖所示: make執(zhí)行結果 從圖中可以看到此時的 curname 是 zzk,不是 zuozhongkai 了。這是因為賦值符“:=”不會使用后面定義的變量,只能使用前面已經(jīng)定義好的,這就是“=”和“:=”兩個的區(qū)別。 3、賦值符“?=” “?=”是一個很有用的賦值符,比如下面這行代碼: curname ?= zuozhongkai 上述代碼的意思就是,如果變量 curname 前面沒有被賦值,那么此變量就是“zuozhongkai”,如果前面已經(jīng)賦過值了,那么就使用前面賦的值。 4、變量追加“ =” Makefile 中的變量是字符串,有時候我們需要給前面已經(jīng)定義好的變量添加一些字符串進去,此時就要使用到符號“ =”,比如如下所示代碼: objects = main.o inpiut.o objects = calcu.o 一開始變量 objects 的值為“main.o input.o”,后面我們給他追加了一個“calcu.o”,因此變量 objects 變成了“main.o input.o calcu.o”,這個就是變量的追加。 |
|
來自: 山峰云繞 > 《Linux平臺Shell命令應用》