1. 程式人生 > >GNU Make讀書筆記 :(一)規則

GNU Make讀書筆記 :(一)規則

前言

規則主要是分為三種:模式規則 隱含規則 靜態模式規則

具體規則:就是指定需要更新的工作目標,如果存在的依賴的時間戳在目標的後面就是對目標進行更新。這是最常見的規則型別。

模式規則:使用的是萬用字元(wildcard)不是明確的檔名

隱含規則:可以是模式規則也可以是內置於make的字尾規則,這會使得makefile編寫的更加容易

具體規則

需要寫好目標和它們所需要的依賴,如果兩個目標的依賴是一樣的,那麼在依賴被修改之後,兩個目標要分別生成

vpath.o variable.o : make.h getopt.h

//輸出
vpath.o: make.h getopt.h
variable.o : make.h getopt.h

萬用字元

  • ~  後面接的如果是使用者名稱就代表當前使用者的主目錄,否則就代表是當前目錄的使用者
  • *   代表這全部符合某一特點的項
  • ? 代表著單一字元
  • […] 代表一個字符集 比如[abcd] 可以和 "apple"裡面的a匹配
  • [^...] 字符集的補集    比如[^asd] 可以和"call" 裡面的c匹配

注意使用萬用字元可能導致的一些錯誤,如果在執行某一個目標之前,這個目標用萬用字元查詢之後發現不存在,就會造成錯誤。

所以在使用萬用字元查詢當前應該生成的各項檔案的資訊之前,首先要做的就是生成你所需的.o目標檔案

注意一點:在使用萬用字元進行模式匹配的時候,如果模式匹配出現在目標檔案裡面,則是make來展開,如果出現在命令裡面則是subshell來展開。make會在讀取makefile之後直接展開匹配結果,但是subshell只有在執行的時候才會展開,在編寫大工程的時候會造成影響。

假想工作目標 (phony target)

假想工作目標的含義:

在makefile裡面你會發現有一些目標不代表檔案,而是代表一些指令的執行。比如說clean是用來清理工程,那麼clean就是一個比較典型的假想工作目標。

clean:
    rm -f *.o [email protected]

make不會區分假想工作目標和工作目標的區別,所以如果同一檔案內部有同名的檔案,就會出現一些錯誤.

所以make裡面提供了一個特殊的目標.PHONY用來告訴make這不是一個真正的目標。

假想目標總是尚未更新的,所以每次都可以被執行。並且還會告訴makefile不要生成相應的檔案。

並且假想目標可以用來改善使用者介面,比如列印一些除錯資訊等。

變數

如果你想定義一個變數和應用變數,大致的用法如下

TARGET = main

OBJ = main.o public.o

SRC = main.cpp public.c

INCLUDE = public.h

CC = g++

${TARGET} :  $(OBJ) 
    $(CC) $(OBJ) -o ${TARGET} 
public.o: public.cpp
    $(CC) -c public.cpp 

自動變數

記住七個核心的就可以了

  1. [email protected]   代表的是工作目標的檔名
  2. $^   所有需要生成目標檔案的必要條件的檔名
  3. $?  代表的是時間戳在當前目標檔案之後的所有檔案,並且以空格分割
  4. $<  第一個必要條件的檔名,一般就是下面需要生成的.o檔名
  5. $% 檔案檔案成員內部的變數
  6. $*  工作目標的主檔名
  7. $+  功能和$^差不多,但是可能會包含重複的檔名

使用VPATH以及Vpath來查詢檔案

在使用makefile進行程式設計的時候我們通常會將我們的一些檔案分別村犯這樣是為了整個專案更加好管理,如果不分開目錄寫一旦工程量大了就會造成麻煩。

在程式設計的時候我們一般將makefile放在上層,之後將標頭檔案放在include資料夾裡面,原始碼就放在src資料夾裡面。

但是在編譯的時候Make會找不到相應的檔案,因為它們被放在了下一級的資料夾裡面。

我們使用Vpath和VPATH來指定檔案的目錄進行查詢。

#指定路徑給VPATH搜尋
VPATH = src
main: main.o public.o 
    g++ $^ -o [email protected]
main.o: main.cpp include/public.h
    g++ -c $< -o [email protected]
public.o: public.cpp include/public.h
    g++ -c $< -o [email protected]


編譯結果,自動包含.cpp檔案的路徑src,並且在makefile裡面做出了調整使得輸出更加明確。

如果出現找不到標頭檔案的錯誤那就需要指定標頭檔案的資料夾

CPPFLAGS = -I include
#使用的時候 g++ $(CPPFLAGS) -c $< -o [email protected]  

But VPATH有一個特性就是如果在不同的目錄裡面有重名的選項的話就只會找到第一個檔案就不會再去找了。

所以,可以使用vpath來指定什麼資料夾裡面找什麼檔案。

vpath %.c src
vpath %.h include

模式規則

使用匹配來簡化Makefile的書寫量

採用假設的方式,如果依賴是.o檔案的話那麼c編譯器預設是將從c檔案裡面編譯生成新的.o檔案,簡化成以下

#指定路徑給VPATH搜尋
VPATH = src include
main: main.o public.o 
main.o: main.cpp public.h
public.o: public.cpp public.h

模式

模式規則裡面的百分比符號(%)等效於Unix shell裡面的*號的作用,可以代表任意多個字元。

百分比以外的文字將會被按照字面進行匹配,一個模式裡面可以包含一個字首或者一個字尾,或者都包含。

在字首和字尾之間的部分是詞幹(stem),匹配的時候就是在提取詞幹。

#字首
lib*
#字尾
*.cpp *.h
#前後綴
lib*.a stl_*.h 

靜態模式規則

只可以用在特定的工作目標上面,開頭多了一個object,表示指定了相應的目標

$(OBJECT): %.0:%.c
    $(CC) -c $(CPPFLAGS) $< -o [email protected]