makefile(二):普通規則
一.普通規則
規則是makefile的主要內容,它決定了編譯系統何時,如何來編譯指定的目標。規則的語法如下:
目標:依賴
指令
請特別注意,指令前面有一個tab空格。
同時指令可以直接寫在依賴後面,即同一行上,並且這種情況下指令前可以不用tab鍵,但各個指令以分號分隔,這種寫法常常用來寫一個空命令,如下,
target:;
普通命令請不要這樣書寫,因為這樣並不便於閱讀
另外,在GNU make手冊中提到,我們也可以更改.RECIPEPREFIX變數的值來指定指令前面的字元。例子如下:
.RECIPEPREFIX := >
all:
>@echo wanbiao
不過在我目前使用的GNU make 3.81下進行測試,並不能正確執行,這個可以作為一個擴充套件功能。(也或許是我自己的書寫錯誤,沒有繼續深究)
同時依賴也可以當成其他的規則的目標,如下例子:
all:a.o b.o
gcc –o all a.o b.o
a.o:a.c
gcc –c a.c
b.o:b.c
gcc –c b.c
那麼當我們直接執行make命令的時候,它的執行順序如下:
1.首先掃描到all目標,然後把它當作終極目標,即整個make的執行都是為了建立一個all目標出來,
2.檢視當前目錄下是否有all檔案,如果沒有,那麼就根據依賴進行生成,此時檢測依賴,a.o和b.o,發現在當前目錄下沒有這兩個檔案。那麼就將這兩個依賴作為目標,查詢規則。
3.此時查詢到a.o的規則,和b.o的規則,發現他們分別依賴a.c和b.c,然後繼續檢測a.c和b.c,看看當前目錄下面有沒有,發現有a.c和b.c,
4.那麼就開始生成目標a.o和b.o即,執行gcc –c a.c 和 gcc –c b.c命令生成a.o 和b.o此時有了a.o和b.o那麼就可以生成終極目標all了,
5.此時執行gcc –o all a.o b.o生成終極目標。整個makefile執行完畢。
對上面的一些補充說明:
make在沒有指定目標的時候,makefile遇到的第一個有效目標作為終極目標,因此終極目標應該寫在前面,而其他的目標順序則沒有要求。如果一個規則有多個目標,那麼將其第一目標作為終極目標。
另外,有效的目標指:1.不是以點號開頭的目標(當然如果點號後面是一個路徑,那麼這個目標也可以作為終極目標);2。也不能是模式目標,關於模式目標後面會詳細敘述。
當多個目標出現在同一條規則時,稱為:多目標規則
當一個目標出現在多條規則中時,稱為:多規則目標。這些規則中只能有一條規則有命令列,如果其他規則也有,那麼會報錯。make在執行時,會將所有規則的依賴合併在一起形成一個依賴列表,最終形成一個規則。
二.靜態模式規則
存在如下這種情況,某一類的目標,具有相類似的依賴。此時如果用普通規則,那麼需要為每個都這麼寫,因此,為了減少工作量,引入了靜態模式規則,這個和後面的模式規則有一定的區別,後面敘述模式規則。
他的語法規則如下:
目標列表:目標模式:依賴模式
命令列
目標列表包含了這個規則的全部目標,注意不能包含不適用此條規則的其他目標。
目標模式:是一個包含%的模式字串。%匹配任意的字元。
依賴模式:也是一個包含%的模式字串。依賴中的%的具體值等於目標中的%的值。
因為這裡用到了模式字串,因此,在命令列中就不能將一些命令寫死,需要用到自動化變數,自動化變數的詳細說明,可以參考後面的敘述。
舉例如下:
objects := foo.o bar.o
all:$(objects)
$(objects):%.o:%.c
$(CC) –c $(CFLAGS) $< -o [email protected]
對於foo.o來說,%的值為foo,那麼他的依賴中的%的值也為foo,那麼依賴為foo.c
如果需要使用%的值可以使用$*,$*在這種模式下代表%的值。
注意:
$(objects)不能包含不匹配%.o:%.c規則的檔案,如下。
objects := foo.o bar.o test.fle
all:$(objects)
$(objects):%.o:%.c
$(CC) –c $(CFLAGS) $< -o [email protected]
這個會得到一個錯誤的提示。改進版如下:
objects := foo.o bar.o test.fle
all:$(objects)
$(filter %.o,$(objects)):%.o:%.c
$(CC) –c $(CFLAGS) $< -o [email protected]
這裡使用了filter函式,他的作用是:從$(objects)過濾出.o結尾的檔案。
三.雙冒號規則
雙冒號規則,就是用::代替:的規則。這種規則和普通的規則的處理不太一樣。當同一個目標出現在多個規則中時,普通規則只允許一條規則有命令列,而雙冒號規則允許所有的規則都有命令列。make不會將這些規則進行合併,當不同的雙冒號規則需要更新的時候,可以執行不同的命令,舉例如下:
ob::foo.c
$(CC) $(CFLAGS) $^ -o [email protected]
ob::bar.c
$(CC) $(CFLAGS) -g $^ -o [email protected]
當foo.c比ob新時,則執行$(CC) $(CFLAGS) $^ -o $@命令,當bar.c比ob新時,執行$(CC) $(CFLAGS) -g $^ -o $@命令
那麼當這兩條規則為普通規則的時候,make將會提示錯誤資訊
優勢:
雙冒號規則給我們提供了:根據不同的依賴來執行不同命令的機制。
四:模式規則
考慮上面的靜態模式規則,如果我們能將目標列表增加到,所有makefile檔案裡面定義的目標,那麼寫出來的目標列表會變得非常冗餘。此時可以去掉這個目標列表只剩下,目標模式和依賴模式。如下:
目標模式字串:依賴模式字串
命令列
這種規則稱為:模式規則。
其使用跟靜態模式規則一模一樣,並且它沒有了目標列表這部分,也就沒有了目標列表不能包含不符合此規則的限制。
模式規則也可以用來覆蓋makefile的隱含規則,詳細細節可參考隱含規則一節。
五.自動化變數
當時用了靜態模式規則,和模式規則的時候,如果命令列不能依據目標的%進行相應的變化,那麼模式規則和靜態模式規則毫無意義。因此這裡需要使用自動化變數。
常見自動化變數的說明如下:
$@ 代表目標的依賴檔案。
$% 當規則的目標是一個靜態庫檔案的時候,代表靜態庫的一個成員
$< 代表第一個依賴檔案
$? 所有比目標更新的依賴檔案
$^ 代表所有依賴檔案,當依賴檔案重複時,去掉重複檔案
$+ 與$^相同,但是保留重複的依賴檔案
$* 在模式規則和靜態模式規則中,代表%的值。
在老版本的makefile中,還可以通過組合D或者F來,表示目錄和檔名,如下:
$(@D) 代表依賴檔案的目錄部分
$(@F) 代表依賴檔案的檔名(除去目錄部分)
對於其他的自動化變數有相同的用法,具體細節可參考GNU make官方文件。網址如下:
http://www.gnu.org/software/make/manual/make.html
六.偽目標
偽目標不代表一個真正的檔案。系統不會主動執行偽目標,只有手動指定偽目標之後,才進行相應的操作。如下:
clean:
rm -rf *.o
考慮如下情況,當工作目錄下剛好有一個clean檔案,沒有依賴,此時目標clean被認為了最新,不去執行相應的操作,因此不符合我們的需求,因此,可以強制將clean定義為偽目標,使用.PHONY特殊目標,如下:
.PHONY : clean
clean:
rm -rf *.o
這樣就避免了衝突。
七.依賴的型別
在上面介紹的所有規則中,依賴可以分為兩種,一種是:一旦依賴比目標新則更新目標,另外一類是:當依賴比目標新,不更新目標,只有當目標沒有的時候,才去更新目標。第一種依賴就是前面介紹的普通依賴,後面這種依賴稱為,命令依賴,即當目標沒有的時候,給命令更新目標的時候用。
命令依賴以|開頭,舉例如下:
libs := bar.a
test:foo.o | $(libs)
$(CC) $(CFLAGS) $< -o [email protected] $(libs)
當foo.o比test新,那麼命令就會執行,反之當bar.o比test新,並不會執行命令。
七.其他的使用技巧
一.萬用字元的使用
我們可以在目標和依賴中使用%來進行相應的模式匹配,同樣我們也可以使用萬用字元在目標和依賴中進行更加靈活的匹配,如下
print:*.c
lpr -p $?
touch print
該規則指定了依賴當前目錄下的所有c檔案
可以使用的萬用字元有三種:*,?,[]
這三種可以使用在規則的目標和依賴中,也可以使用在規則的命令中,謹記不能使用在其他地方,比如變數的定義,如下:
objects := *.o
objects的值為*.o,並不是所有的.o檔案。
foo:$(objects)
$(cc) -o foo $(CFLAGS) $(objects)
當工作目錄下沒有.o檔案的時候,則會提示:沒有建立*.o檔案的規則。改進方法如下:
objects := $(patsubst %.c,%.o,$(wildcard *.c))
wildcard函式表示在工作目錄下,使用萬用字元進行查詢相應的檔案,並返回。patsubst函式進行相應的替換並返回。
objects的值,則根據下面的步驟進行產生:
1.取得工作目錄下所有的.c檔案
2.將對應的.c檔案替換成.o,並返回給objects變數。
二.VPATH,vpath,GPATH的使用
VPATH = src:../headers
表示的是:當在工作目錄下沒有找到相應的檔案的時候,可以在VPATH裡面指定的目錄下進行查詢,上例中指定了兩個目錄,一個為src,一個為headers,多個目錄使用冒號分割。
vpath 模式字串 directory
表示的是:可以將符合模式字串的檔案,在directory資料夾中進行尋找,例子如下:
vpath %.h ../headers
表示的是:當在工作目錄中沒有找到某個.h檔案的時候,可以在../headers資料夾下進行查詢
vpath 模式字串
表示:清楚之前為模式字串進行的相應的資料夾設定。
vpath
表示清楚所有已被設定的檔案搜尋路徑。
當一個目標沒有在工作目錄下,但是在vapth,或者VPATH進行目錄搜尋之後被找到,當需要更新目標的時候,此時,更新的目標會被放置在工作目錄下,如果想要放置在以前找到的目錄下,需要使用GPATH變數,讓其值指定該目錄。
三.庫檔案通過目錄搜尋得到
程式連線使用的靜態庫,動態庫,同樣可以使用目錄搜尋進行找到。這個需要在依賴列表中,進行如下的寫法。-lname,name為庫的名字,而這個庫的名字,不包括前面的lib和後面的字尾。
舉例如下:
foo:foo.c -lcurses
$(cc) $^ -o [email protected]
詳細過程如下:
1.make會在當前目錄下尋找libcurses.so,如果沒有,
2.搜尋vpath,VPATH路徑下,還是沒有,
3.搜尋系統預設的庫檔案存放目錄,順序為:/lib,/usr/lib,/usr/local/lib
4.如果還是沒有找到,則按上面的步驟搜尋libcurses.a庫檔案。
四.合理使用偽目標,提高編譯效率
SUBDIRS := foo bar baz
subdirs :
for dir in $(SUBDIRS) ;do \
$(MAKE) -C $$dir;\
done
當執行subdirs目標時,會依次進行子目錄然後執行make,當我們使用-j引數之後,這個還是呈現一個單執行緒的執行。我們可以進行如下修改
SUBDIRS = foo bar baz
.PHONY: subdirs $(SUBDIRS)
subdirs: $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C [email protected]
foo: baz
最後一條規則,表示baz比foo先生成。用來限制子目錄的make順序。
此時,當執行subdirs目標的時候,會去檢測foo bar baz,發現都沒有的時候,會使用
$(SUBDIRS):
$(MAKE) -C [email protected]
規則進行相應的生成,此時可以發揮了make的多執行緒功能了,因為這三個檔案,可以放在不同的執行緒中進行生成,從而避免了shell命令列下,for的單執行緒操作,可以更好的發揮電腦效能。
相關推薦
makefile(二):普通規則
一.普通規則 規則是makefile的主要內容,它決定了編譯系統何時,如何來編譯指定的目標。規則的語法如下: 目標:依賴 指令 請特別注意,指令前面有一個tab空格。 同時指令可以直接寫在依賴後面,即同一行上,並且這種情況下指令前可以
從頭開始寫專案Makefile(一):基本規則
【版權宣告:轉載請保留出處:blog.csdn.net/gentleliu。Mail:shallnew at 163 dot com】 一般一個稍大的linux專案會有很多個原始檔組成,最終的可執行程式也是由這許多個原始檔編譯連結而成的。編譯是把一個.c或.cpp檔案編譯成
javascript資料結構與演算法筆記(二):普通佇列
javascript資料結構與演算法筆記(二):普通佇列 一:簡介 二:ES6版Queue類 一:簡介 佇列是遵循FIFO( First In First Out, 先進先出,也稱為先來先服務)原則的一組有序的項。 佇
從頭開始寫專案Makefile(八):模式規則
【版權宣告:轉載請保留出處:blog.csdn.net/gentleliu。Mail:shallnew at 163 dot com】 上一節講到目錄建立成功,目標檔案沒有生產到對應目錄下,這裡我們先給目標檔案加上對應目錄,這樣的話產生對應的目標檔案會直接生成到對應
移動推薦演算法(二):基於簡單規則的預測
本文為轉載文章,來源為: https://blog.csdn.net/Snoopy_Yuan/article/details/72850601 一直在探索資料探勘、資料建模的案例,百度搜到這篇文章,收穫頗豐,轉載以作記錄。 前言:移動推薦演算法是阿里天池賽2015年賽題之
makefile(四):makefile規則中的命令
規則中的命令被傳遞給shell進行解析執行。除跟在依賴後面的第一條命令以外,其他命令必須與tab鍵開頭。如下: 目標:依賴;命令1 命令2 通常情況下也並不推薦這種寫法,推薦的寫法還是將命令1,另起一行,並以tab鍵開頭,這樣做的好處,就是便於觀
Spring-Cloud-Ribbon學習筆記(二):自定義負載均衡規則
lan cse 重新啟動 ping for obi .config 流行 prope Ribbon自定義負載均衡策略有兩種方式,一是JavaConfig,一是通過配置文件(yml或properties文件)。 需求 假設我有包含A和B服務在內的多個微服務,它們均註冊在一個E
Javascript面向對象編程(二):構造函數的繼承
沒有 cal type 這一 今天 nts 實現繼承 刪除 函數綁定 今天要介紹的是,對象之間的"繼承"的五種方法。 比如,現在有一個"動物"對象的構造函數。 function Animal(){ this.species = "動物"; } 還有一個
虛擬化(二):虛擬化及vmware workstation產品使用
應該 server esxi aof 手機 text 產品 窗體 pass 虛擬化(一):虛擬化及vmware產品介紹 vmware workstation的最新版本號是10.0.2。相信大家也都使用過,當中的簡單的虛擬機的創建。刪除等,都非常easy
CSS3動畫(二):波浪效果
col -1 loading ack css代碼 code load width ase 實現效果 如圖所示: 首先得準備三張圖,一張是淺黃色的背景圖loading_bg.png,一張是深紅色的圖loading.png,最後一張為bolang.png。 css代碼
設計模式(二): 工廠模式
dem blank hibernate 執行 oid code 做出 void actor 工廠模式 工廠模式(Factory Pattern)是 Java 中最常用的設計模式之一。這種類型的設計模式屬於創建型模式,它提供了一種創建對象的最佳方式。 在工廠模式中,我們在創建
iptables實用教程(二):管理鏈和策略
否則 命令顯示 accept 目的 number cep 存在 當前 末尾 概念和原理請參考上一篇文章“iptables實用教程(一)”。 本文講解如果管理iptables中的鏈和策略。 下面的代碼格式中,下劃線表示是一個占位符,需要根據實際情況輸入參數,不帶下劃線的表示是
javascript學習筆記(二):定義函數、調用函數、參數、返回值、局部和全局變量
兩個 cnblogs bsp 結果 value ava ase com 調用 定義函數、調用函數、參數、返回值 關鍵字function定義函數,格式如下: function 函數名(){ 函數體 } 調用函數、參數、返回值的規則和c語言規則類似。 1 <!DOC
Nginx實用教程(二):配置文件入門
affinity type 服務 源碼編譯 設置時間 shutdown ber 可用 控制指令 Nginx配置文件結構 nginx配置文件由指令(directive)組成,指令分為兩種形式,簡單指令和區塊指令。 一條簡單指令由指令名、參數和結尾的分號(;)組成,例如:
Python和C|C++的混編(二):利用Cython進行混編
cde uil 有時 當前 class def 將在 python 混編 還能夠使用Cython來實現混編 1 下載Cython。用python setup.py install進行安裝 2 一個實例 ① 創建helloworld文件夾創建hellowor
RabbitMQ消息隊列(二):”Hello, World“
復雜 article ins don title apple lar github publish 本文將使用Python(pika 0.9.8)實現從Producer到Consumer傳遞數據”Hello, World“。 首先復習一下上篇所學:RabbitM
ASP.NET MVC5(二):控制器、視圖與模型
script pcr 靜態 簡單 err ice message blog 控制器 前言 本篇博文主要介紹ASP.NET MVC中的三個核心元素:控制器、視圖與模型,以下思維導圖描述了本文的主要內容。 控制器 控制器簡介 在介紹控制器之前,簡單的介紹一下MVC工
CSS學習筆記(二):特性
code 背景色 左移 line tex lin 安裝 其中 cas 一、顏色特性 1. 前景色:color 用種方式指定前景色,3種方式分別是rgb顏色,#16進制編碼,顏色名稱: color: rgb(100,100,100); color: #ee3e80; col
python中關於操作時間的方法(二):使用datetime模塊
log time模塊 bsp lib .py nth mon target ear 使用datetime模塊來獲取當前的日期和時間 1 import datetime 2 i=datetime.datetime.now() 3 print ("當前的日期和時間是%
JS筆記(二):隱式轉換
-1 筆記 總結 img 轉換 隱式轉換 基礎 blog com 最近剛開始復習JS的基礎知識,看到隱式轉換這一塊,發現它的規則很多,紅寶書上列出的框框又有些冗雜,所以這裏我借一個式子總結一下其中的規律以及一些有趣的現象。 JS筆記(二):隱式轉換