Makefile 學習筆記

  make是一個解釋makefile中指令的命令工具。Make工具最主要也是最基本的功能就是通過makefile文件來描述源程序之間的相互關係並自動維護編譯工作。而makefile
文件需要按照某種語法進行編寫,文件中需要說明如何編譯各個源文件並連接生成可執行文件,並要求定義源文件之間的依賴關係。 Makefile
裏主要包含了五種類型的語句/行:顯式規則、隱式規則、變量定義、文件指示和註釋。 make命令格式:make [-f Makefile] [option] [target]

  1. 編譯和鏈接規則
    1)如果這個工程沒有編譯過,那麼我們的所有C文件都要編譯並被鏈接。
    2)如果這個工程的某幾個C文件被修改,那麼我們只編譯被修改的C文件,並鏈接目標程序。
    3)如果這個工程的頭文件被改變了,那麼我們需要編譯引用了這幾個頭文件的C文件,並鏈接目標程序。

    • makefile的構成
      (1)需要由make工具創建的目標體(target),通常是目標文件或可執行文件。
      (2)要創建的目標體所依賴的文件(dependency_file)。
      (3)創建每個目標體時需要運行的命令(command)。
      格式如下: target:dependency_files command 在這裏面,變量一般都是字符串,他有點像c語言的宏。
      makefile中的文件指示,包含3部分,一個是在一個Makefie中引用另一個Makefile,就像c語言的include一樣;另一個是根據某些情況指定Makefile中的有效部分,就像C語言中的預編譯#if一樣;還有就是定義一個多行的命令。
      註釋:註釋符用 “#”,可以用反斜框進行轉義,如輸入註釋,“\#”。
  2. makefile的書寫
    1)所有文件都在一個目錄中
    示例

st_work : main.o st_work.o fun.o
gcc main.o st_work.o fun.o -o
st_work main (命令以Tab開頭) st_work.o : st_work.c
gcc -c st_work.c -o st_work
main.o : main.c st_work.h
gcc -c main.c -o main.o
fun.o : fun.c fun.h
gcc -c fun.c -o fun.o
clean:
rm -f st_work *.o

2)多目錄的寫法
我們這裏,在工作目錄下有4個文件夾 分別是 sources(源文件) obj (中間文件)headers(頭文件) bin(目標文件)
sources裏面有 main.c st_work.c fun.c
obj 裏面最初沒有文件
headers 裏面有 fun.h st_work.h
最終目標取名爲 st_work,它應存放到bin裏面
預備知識:
gcc 的3個參數:
- -o 指定目標文件
gcc sources/main.c -o bin/main
- -c 編譯的時候只生產目標文件不鏈接
gcc -c sources/main.c -o obj/main.o
- -I 主要指定頭文件的搜索路徑
gcc -I headers -c main.c -o main.o
- -l 指定靜態庫
gcc -lpthread …
示例

bin/st_work : obj/main.o obj/st_work.o obj/fun.o
gcc obj/main.o obj/st_work.o obj/fun.o -o bin/st_work (命令以Tab開頭)
obj/st_work.o : sources/st_work.c
gcc -I headers -c sources/st_work.c -o obj/st_work.o
obj/main.o : sources/main.c
gcc -I headers -c sources/main.c -o obj/main.o
obj/fun.o : sources/fun.c
gcc -I headers -c sources/fun.c -o obj/fun.o
clean:
  rm -f bin/st_work obj/*.o

3)隱式規則的引入
3個預定義變量介紹:
- $@ 表示要生成的目標
- $^ 表示全部的依賴文件
- $< 表示第一個依賴文件

bin/st_work : obj/main.o obj/st_work.o obj/fun.o
gcc $^ -o $@ (命令一定要用以Tab開頭)
obj/st_work.o : sources/st_work.c
gcc -I headers -c$< -o $@
gcc -I headers -c $< -o $@
gcc -I headers -c $< -o $@
clean:
  rm -f bin/st_work obj/*.o

4)變量的引入
變量的引入和應用:

CC=gcc
HD=-I headers
SC=-c $<
OBJ=-o $@ bin/st_work : obj/main.o obj/st_work.o obj/fun.o
gcc $^ -o $@ (命令一定要用以Tab開頭)
obj/st_work.o : sources/st_work.c
$(CC) $(HD) $(SC) $(OBJ)
obj/main.o : sources/main.c
$(CC) $(HD) $(SC) $(OBJ)
obj/fun.o :sources/fun.c
$(CC) $(HD) $(SC) $(OBJ)
clean:
  rm -f bin/st_workfile_o/*.o

可以看到,依賴關係由上到下。
More:
(1)如此定義變量後,
objects = main.o,
foo = $(bar)
使用$(object)來代替變量的值,用“$$”來表示$
(2)變量替換
其格式是“$(var:a=b)”或是“${var:a=b}”,其意思是,把變量“var”中所有以“a”字串“結尾”的“a”替換成“b”字串。這裏的“結尾”意思是“空格”或是“結束符”。
foo := a.o b.o c.o
bar := $(foo:.o=.c)
(3)變量可以嵌套
 $($(x))
(4)可以使用“+=”操作符給變量追加值。
(5)當make嵌套調用時,上層Makefile中定義的變量會以系統環境變量的方式傳遞到下層的Makefile中。這裏的系統環境變量與本makefile中定義的變量的關係有點類似於全局變量與局部變量的關係。默認情況下,只有通過命令行設置的變量會被傳遞。而定義在文件中的變量,如果要向下層Makefile傳遞,則需要使用exprot關鍵字來聲明。
5)信息顯示
在執行make時,會把所有這些信息都輸出來。
在命令前面加個@,就不會把相關信息輸出屏幕了。
6)函數的使用
函數調用後,函數的返回值可以當做變量來使用。
調用格式如下所示: $( ;)
函數調用以“$”開頭,以圓括號或花括號把函數名和參數括起。參數間以逗號“,”分隔,而函數名和參數之間以“空格”分隔。參數可以使用變量。
bar:= $(subst $(space),$(comma),$(foo))
上面的函數subst是把第三個參數中包含第一個參數中的字串替換成第二個參數中的字串。
7)語句的使用
$(if ;,;)
$(if ;,;,;)
make支持三各通配符:“*”,“?”和“[…]”。波浪號“~”字符在文件名中也有比較特殊的用途。如果是“~/test”,這就表示當前用戶的$HOME目錄下的test目錄。而“~hchen/test”則表示用戶hchen的宿主目錄下的test目錄
5、其他注意點
1)在大多數時候,由於源文件太多,編譯生成的中間目標文件太多,而在鏈接時需要明顯地指出中間目標文件名,這對於編譯很不方便,所以,通常要給中間目標文件打個包,在Windows 下這種包叫“庫文件”(Library File),也就是 .lib 文件,在UNIX 下,是Archive File,也就是 .a 文件。
編譯階段,主要解決語法問題,如函數,變量等聲明是否正確,而鏈接階段,因爲要生成可執行文件了,要明確具體的地址關係,及尋找真實的定義等。
2)將長行用 “\” 分開便於閱讀。
3)和目標沒有依賴關係的規則不會被處理,除非指定make 處理(如make clean)。
4)將源文件分門別類地放置時,編譯時要進行尋找。通過VPATH實現。
如果沒有指明這個變量,make 只會在當前的目錄中去找尋依賴文件和目標文件。如果定義了這個變量,那麼,make就會在噹噹前目錄找不到的情況下,到所指定的目錄中去找尋文件了。
VPATH = src:../headers
多個目錄使用:分開。
另外一個vpath,不是變量,使用方法如下:
它可以指定不同的文件在不同的搜索目錄中。使用方法有三種:
(1)vpath 。爲符合模式的文件指定搜索目錄。
(2)vpath 。清除符合模式的文件的搜索目錄。
(3)vpath。清除所有已被設置好了的文件搜索目錄。
需要包含“%”字符。“%”的意思是匹配零或若干字符,例如,“%.h”表示所有以“.h”結尾的文件。指定了要搜索的文件集,而則指定了的文件集的搜索的目錄。例如:
vpath %.h ../headers
該語句表示,要求make 在“../headers”目錄下搜索所有以“.h”結尾的文件。
5)有些情況下,則規則失效,沒有依賴文件,文件clean命令永遠不會執行;爲避免這個問題,可使用”.PHONY”指明該目標。如:
.PHONY : clean
這樣,在make clean是會無視clean是否存在,直接執行其命令。
與上面等效的另外一個表達:
clean: FORCE
rm $(objects)
FORCE:
6)此外,還有很少使用的雙冒號規則。
7)使用include關鍵字可以把別的Makefile包含進來。

8)objects = *.o
通配符同樣可以用在變量中。並不是說[*.o]會展開,objects的值就是“*.o”。Makefile 中的變量其實就是 C/C++中的宏。如果你要讓通配符在變量中展開,也就是讓 objects 的值是所有[.o]的文件名的集合,那麼,你可以這樣:objects := $(wildcard *.o),這種用法由關鍵字“wildcard”指出。
9)通過makefile編譯,自動推導,如果發現當前的文件沒有做過更新,則不會編譯,只編譯更新過了的。

預定義變量選項

預定義變量 含義
$* 不包含擴展名的目標文件名稱。
$+ 所有的依賴文件,以空格分開,並以出現的先後爲序,可能包含重複的依賴文件。
$< 第一個依賴文件的名稱。
$? 所有的依賴文件,以空格分開,這些依賴文件的修改日期比目標的創建日期晚。
$@ 目標的完整名稱。
$^ 所有的依賴文件,以空格分開,不包含重複的依賴文件。
$% 如果目標是歸檔成員,則該變量表示目標的歸檔成員名稱。例如,如果目標名稱爲 mytarget.so(image.o),則 $@ 爲 mytarget.so,而 $% 爲 image.o。
CC C 編譯器的名稱,默認值爲 cc。
CCFLAGS C 編譯器的選項。
CPP C 預編譯器的名稱,默認值爲 $(CC) -E。
CPPFLAGS C 預編譯的選項。
CXX C++ 編譯器的名稱,默認值爲 g++。
CXXFLAGS C++ 編譯器的選項。
AR 歸檔維護程序的名稱,默認值爲 ar。
ARFLAGS 歸檔維護程序的選項。
AS 彙編程序的名稱,默認值爲 as。
ASFLAGS 彙編程序的選項。

make選項

命令行選項 含義
-C DIR 在讀取 makefile 之前改變到指定的目錄 DIR。
-f FILE 以指定的 FILE 文件作爲 makefile。
-h 顯示所有的 make 選項。
-i 忽略所有的命令執行錯誤。
-I DIR 當包含其他 makefile 文件時,可利用該選項指定搜索目錄。
-n 只打印要執行的命令,但不執行這些命令。
-p 顯示 make 變量數據庫和隱含規則。
-s 在執行命令時不顯示命令。
-w 在處理 makefile 之前和之後,顯示工作目錄。
-W FILE 假定文件 FILE 已經被修改。

示例代碼:

CC=gcc
CXX=g++
CFLAGS= -g -Wall
INC=./***
LIB=./***.a
CFLAGS+= -DSNACC_DEEP_COPY-
DHAVE_VARIABLE_SIZED_AUTOMATIC_ARRAYS -Wno-deprecated -lpthread -lssl
TARGET=***
OBJ = **.o \
./**.o\
$(TARGET): $(OBJ)
  $(CXX) $(CFLAGS) -o $@ $^ $(LIB)
如下代碼,把所有的cpp文件編譯成.o文件
%.o: %.cpp
  $(CXX) $(CFLAGS) $(INC) -c -o $@ $<
clean:
  rm -f *.o
  rm -f $(TARGET)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章