1. Makefile 簡介
Makefile 是和 make 命令一起配合使用的.
很多大型項目的編譯都是通過 Makefile 來組織的, 如果沒有 Makefile, 那很多項目中各種庫和代碼之間的依賴關係不知會多複雜.
Makefile的組織流程的能力如此之強, 不僅可以用來編譯項目, 還可以用來組織我們平時的一些日常操作. 這個需要大家發揮自己的想象力.
本篇部落格是基於 {精華} 跟我一起寫 Makefile 而整理的, 有些刪減, 追加了一些樣本.
1.1 Makefile 主要的 5個部分 (顯示規則, 隱晦規則, 變數定義, 檔案指示, 注釋)
Makefile基本格式如下:
target ... : prerequisites ... command ... ...
其中, target - 目標檔案, 可以是 Object File, 也可以是可執行檔 prerequisites - 產生 target 所需要的檔案或者目標 command - make需要執行的命令 (任意的shell命令), Makefile中的命令必須以 [tab] 開頭
顯示規則 :: 說明如何產生一個或多個目標檔案(包括 產生的檔案, 檔案的依賴檔案, 產生的命令) 隱晦規則 :: make的自動推導功能所執行的規則 變數定義 :: Makefile中定義的變數 檔案指示 :: Makefile中引用其他Makefile; 指定Makefile中有效部分; 定義一個多行命令 注釋 :: Makefile只有行注釋 "#", 如果要使用或者輸出"#"字元, 需要進行轉義, "\#"
1.2 GNU make 的工作方式 讀入主Makefile (主Makefile中可以引用其他Makefile) 讀入被include的其他Makefile 初始設定檔案中的變數 推導隱晦規則, 並分析所有規則 為所有的目標檔案建立依賴關係鏈 根據依賴關係, 決定哪些目標要重建 執行產生命令
2. Makefile 初級文法 2.1 Makefile 規則 2.1.1 規則文法
規則主要有2部分: 依賴關係 和 產生目標的方法.
文法有以下2種:
target ... : prerequisites ... command ...
或者
target ... : prerequisites ; command command ...
*注* command太長, 可以用 "\" 作為分行符號
2.1.2 規則中的萬用字元 * :: 表示任意一個或多個字元 ? :: 表示任意一個字元 [...] :: ex. [abcd] 表示a,b,c,d中任意一個字元, [^abcd]表示除a,b,c,d以外的字元, [0-9]表示 0~9中任意一個數字 ~ :: 表示使用者的home目錄
2.1.3 路徑搜尋
當一個Makefile中涉及到大量源檔案時(這些源檔案和Makefile極有可能不在同一個目錄中),
這時, 最好將源檔案的路徑明確在Makefile中, 便於編譯時間尋找. Makefile中有個特殊的變數 VPATH 就是完成這個功能的.
指定了 VPATH 之後, 如果目前的目錄中沒有找到相應檔案或依賴的檔案, Makefile 回到 VPATH 指定的路徑中再去尋找..
VPATH 使用方法: vpath <directories> :: 目前的目錄中找不到檔案時, 就從<directories>中搜尋 vpath <pattern> <directories> :: 符合<pattern>格式的檔案, 就從<directories>中搜尋 vpath <pattern> :: 清除符合<pattern>格式的檔案搜尋路徑 vpath :: 清除所有已經設定好的檔案路徑
# 樣本1 - 目前的目錄中找不到檔案時, 按順序從 src目錄 ../parent-dir目錄中尋找檔案VPATH src:../parent-dir # 樣本2 - .h結尾的檔案都從 ./header 目錄中尋找VPATH %.h ./header# 樣本3 - 清除樣本2中設定的規則VPATH %.h# 樣本4 - 清除所有VPATH的設定VPATH
2.2 Makefile 中的變數 2.2.1 變數定義 ( = or := )
OBJS = programA.o programB.oOBJS-ADD = $(OBJS) programC.o# 或者OBJS := programA.o programB.oOBJS-ADD := $(OBJS) programC.o
其中 = 和 := 的區別在於, := 只能使用前面定義好的變數, = 可以使用後面定義的變數
測試 =
# Makefile內容OBJS2 = $(OBJS1) programC.oOBJS1 = programA.o programB.oall: @echo $(OBJS2)# bash中執行 make, 可以看出雖然 OBJS1 是在 OBJS2 之後定義的, 但在 OBJS2中可以提前使用$ makeprogramA.o programB.o programC.o
測試 :=
# Makefile內容OBJS2 := $(OBJS1) programC.oOBJS1 := programA.o programB.oall: @echo $(OBJS2)# bash中執行 make, 可以看出 OBJS2 中的 $(OBJS1) 為空白$ makeprogramC.o
2.2.2 變數替換
# Makefile內容SRCS := programA.c programB.c programC.cOBJS := $(SRCS:%.c=%.o)all: @echo "SRCS: " $(SRCS) @echo "OBJS: " $(OBJS)# bash中運行make$ makeSRCS: programA.c programB.c programC.cOBJS: programA.o programB.o programC.o
2.2.3 變數追加值 +=
# Makefile內容SRCS := programA.c programB.c programC.cSRCS += programD.call: @echo "SRCS: " $(SRCS)# bash中運行make$ makeSRCS: programA.c programB.c programC.c programD.c
2.2.4 變數覆蓋 override
作用是使 Makefile中定義的變數能夠覆蓋 make 命令參數中指定的變數
文法: override <variable> = <value> override <variable> := <value> override <variable> += <value>
下面通過一個例子體會 override 的作用: