利用make工具能夠自動完成編譯工做,這些工做包括:html
利用這種自動編譯能夠大大簡化開發工做,避免沒必要要的從新編譯。make工具經過一個稱爲Makefile的文件來完成並自動維護編譯工做,Makefile文件描述了整個工程的編譯、鏈接規則。shell
Makefile描述了整個工程的編譯鏈接規則。Makefile的基本規則爲:函數
TARGET...: DEPENDENCIES... COMMAND ...
$ touch add.c add.h sub.c sub.h main.c
如今有這5個文件add.h 、sub.h中包含了函數聲明,add.c、sub.c中包含了函數實現,main.c調用了函數。Makefile的文件:工具
main:main.o add.o sub.o 【目標文件是main,它依賴於main.o,add.o,sub.o這三個文件】 gcc -Wall -g main.o add.o sub.o -o main 【由依賴文件生成目標文件應該執行的命令】 main.o:main.c gcc -Wall -g -c main.c -o main.o add.o:add.c add.h gcc -Wall -g -c add.c -o add.o sub.o:sub.c sub.h gcc -Wall -g -c sub.c -o sub.o
保存Makefile文件後執行make命令:spa
$ make gcc -Wall -g -c main.c -o main.o gcc -Wall -g -c add.c -o add.o gcc -Wall -g -c sub.c -o sub.o gcc -Wall -g main.o add.o sub.o -o main
能夠看到執行了make以後,因爲 目標文件main依賴於 main.o add.o sub.o ,因此是須要先 生成 這三個.o文件,最後才生成main。
若是此時再次輸入make,會看到:命令行
$ make make: 'main' is up to date.
make的編譯規則是根據時間來進行判斷,一旦依賴列表中某個文件的更新時間比目標文件晚,則會從新生成目標,不然會出現以上提示。
默認狀況下敲擊make將生成第一個目標,也就是main。也能夠生成指定的目標:code
$ make add.o 【指定只生成add.o文件】
Makefile文件的名字不必定得命名爲「Makefile」或"makefile",使用其餘名字也是能夠的。例如咱們由一個文件叫myMakefile,一樣可使用它:htm
make -f myMakefile 【-f 選項的做用是把名字"myMakefile"做爲makefile來對待。】
TARGET...: DEPENDENCIES... COMMAND 【注意COMMAND以前是一個TAB,不是空格】 ...
前面說過,TARGET除了能夠是目標文件以外,還能夠是僞目標。執行僞目標的效果等於執行了某一個動做, 並不產生目標文件。例如添加一個僞目標:blog
main:main.o add.o sub.o gcc -Wall -g main.o add.o sub.o -o main main.o:main.c gcc -Wall -g -c main.c -o main.o add.o:add.c add.h gcc -Wall -g -c add.c -o add.o sub.o:sub.c sub.h gcc -Wall -g -c sub.c -o sub.o clean : 【這是一個僞目標】 rm -f $(OBJECTS) main
使用make來執行僞目標:開發
$ make clean rm -f main.o add.o sub.o main
能夠看到make將執行僞目標下面的命令。
從上面的Makefile文件咱們發現一些問題:有時候目標文件的依賴列表過長,或者命令重複書寫。利用Makefile自動化變量能夠解決這個問題。
選項名 | 做用 |
---|---|
\(@|規則的目標文件名| |\)< | 規則的第一個依賴文件名 |
$^ | 規則的全部依賴文件列表 |
剛纔的Makefile文件,咱們能夠改寫爲:
main:main.o add.o sub.o gcc -Wall -g $^ -o $@ 【等價於 gcc -Wall -g main.o add.o sub.o -o main】 main.o:main.c gcc -Wall -g -c $< -o $@ add.o:add.c add.h gcc -Wall -g -c $< -o $@ sub.o:sub.c sub.h gcc -Wall -g -c $< -o $@
執行make,能夠看到效果和以前是同樣的:
$ make gcc -Wall -g -c main.c -o main.o gcc -Wall -g -c add.c -o add.o gcc -Wall -g -c sub.c -o sub.o gcc -Wall -g main.o add.o sub.o -o main
還能夠自定義變量:
OBJECTS = main.o add .o sub.o 【OBJECTS是自定義的變量名】 main:$(OBJECTS) 【能夠在須要的地方使用變量名進行替換,替換規則爲$(變量名)】 gcc -Wall -g $^ -o $@ main.o:main.c gcc -Wall -g -c $< -o $@ add.o:add.c add.h gcc -Wall -g -c $< -o $@ sub.o:sub.c sub.h gcc -Wall -g -c $< -o $@
假設如今不僅是想生成可執行main,還想生成可執行文件main2,能夠這樣寫
BIN = main main2 【自定義變量BIN】 OBJECTS= main.o add.o sub.o all : $(BIN) 【關注重點】 main : $(OBJECTS) gcc -Wall -g $< -o $@ main2: $(OBJECTS) gcc -Wall -g $< -o $@ main.o : main.c gcc -Wall -g -c $< -o $@ main2.o :msin2.c gcc -Wall -g -c $< -o $@ add.o:add.c add.h gcc -Wall -g -c $< -o $@ sub.o:sub.c sub.h gcc -Wall -g -c $< -o $@ clean : rm -f $(OBJECTS) $(BIN)
爲了生成目標文件all,須要先生成BIN,也便是 main main2。這樣就能夠生成兩個可執行文件了。利用自定義變量能夠再簡化這段Makefile文件:
BIN = main main2 OBJECTS= main.o add.o sub.o CC = gcc CFALGS = -Wall -g all : $(BIN) main : $(OBJECTS) $(CC) $(CFALGS) $< -o $@ main2: $(OBJECTS) $(CC) $(CFALGS) $< -o $@ main.o : main.c $(CC) $(CFALGS) -c $< -o $@ main2.o :msin2.c $(CC) $(CFALGS) -c $< -o $@ add.o:add.c add.h $(CC) $(CFALGS) -c $< -o $@ sub.o:sub.c sub.h $(CC) $(CFALGS) -c $< -o $@ clean : rm -f $(OBJECTS) $(BIN)
可是這樣看起來,重複的內容仍是比較多,可使用下面的方法來繼續簡化:
BIN = main main2 OBJECTS= main.o add.o sub.o CC = gcc CFALGS = -Wall -g all : $(BIN) main : $(OBJECTS) $(CC) $(CFALGS) $< -o $@ main2: $(OBJECTS) $(CC) $(CFALGS) $< -o $@ .o .c : 【關注重點在這裏】 $(CC) $(CFALGS) -c $< -o $@ clean : rm -f $(OBJECTS) $(BIN)
利用 .o.c :,能夠自動地把全部的.c文件到.o文件的生成都使用同一條命令來完成,簡化的重複的工做。
首先看make中函數調用的形式:
//函數調用 $(function arguments) 【function是函數名稱,arguments是參數,使用$來調用】
值得注意的是,函數名稱與參數之間是空格。
來看三個經常使用make內嵌函數。
src = $(wildcard *.c) 【在當前目錄下搜索全部.c文件,文件名稱列表保存到src中】
$(patsubst %.c,%.o,$src) 【把src中的.c文件列表中的文件從.c替換爲.o】 等價於: $(src:.c =.o) 【這種方式更經常使用】
shell函數能夠執行shell下的命令,一樣是使用$來引用,例如
$(shell ls -d */) 【將當前目錄下的全部文件夾都列出來】
下面經過一個多級目錄的例子來使用這些函數。場景是這樣的,當前目錄下有main.c文件,同時還有若干個目錄,每一個目錄中都有各自的.c文件。利用全部的.c文件編譯生成最後的main文件:
CC = gcc CFLAGS = -Wall -g BIN = main SUBDIR = $(shell ls -d */) 【SUBDIR變量保存了子目錄的列表】 ROOTSRC = $(wildcard *.c) 【ROOTSRC保存了當前目錄下的.c文件列表】 ROOTOBJ = $(ROOTSRC:%.c = %.o) 【ROOTBOJ 保存了當前目錄下.c文件同名的.o列表】 SUBSRC = $(shell find $(SUBDIR) -name '*.c') 【SUBSRC 保存了全部子目錄下的的.c文件】 SUBOBJ = $(SUBSRC:%.c = %.o) 【SUBOBJ保存了全部子目錄下的.c文件同名的.o文件列表】 $(BIN):$(ROOTOBJ) $(SUBOBJ) 【main的生成依賴與當前目錄及全部子目錄下的.o文件】 $(CC) $(CFLAGS) -o $(BIN) $(ROOTOBJ) $(SUBOBJ) .o .c: $(CC) $(CFLAGS) -c $< -o $@ clean: rm -f $(BIN) $(ROOTOBJ) $(SUBOBJ)
文章連接:http://www.cnblogs.com/QG-whz/p/5461110.html