本博文是在學習了《GNU Make中文手冊》後記錄下來的本身的關於自動產生makefile依賴的語句的理解,向你們分享。linux
《GNU make中文手冊》中的相關章節見一下連接:正則表達式
http://blog.csdn.net/gmpy_tiger/article/details/51849257
shell
========================================================================================編程
爲了理解自動產生依賴的代碼,必須先掌握這兩個基礎又有點偏的知識點:數組
一、Makefile 中,一個文件能夠做爲多個規則的目標(多個規則中只能有一個規則定義命令)。這種狀況時,以這個文件爲目標的規則的全部依賴文件將會被合併成此目標一個依賴文件列表,當其中任何一個依賴文件比目標更新(比較目標文件和依賴文件的時間戳)時,make 將會執行特定的命令來重建這個目標。編輯器
舉個例子:學習
有以下的makefile:this
foo.o : defs.h等效於:spa
foo.o : defs.h config.h.net
bar.o : defs.h test.h
就是把相同foo.o目標的規則(最多隻容許一個規則有命令,其餘規則只能有依賴)合併全部的依賴。
二、在linux 的命令sed中,有這麼一個規則(模式替換單獨的單詞,見《Linux命令行與shell腳本編程大全》):
sed編輯器用圓括號來定義替代模式的子字符串,替代字符由反斜槓和數組組成。
很難理解是吧,舉個例子你就懂了。
echo "maybe this is a test" | sed 's/\ (this\ ) is a \ (test\ )/Is \1 really \2 /g'
輸出:
maybe Is this really test
關於腳本的echo,管道,sed的替換命令s等基礎我就不講了,本身百度學習。這裏我要講的是,用「()」小括號括起來的被替換內容,能夠在替換內容上用「\數字」代替,直接動態引用,省去重複輸入的麻煩。例如上面的例子,\1表明this,\2表明test,整個sed命令的意思是把
this is a test
替換爲
Is this really test
ps:由於小括號在正則表達式中有意義,所以須要轉義,所以是\ (...\ )而不是(...)
========================================================================================
廢話很少說,先直接上我本身寫得自動產生依賴的代碼(與《GNU Make中文手冊》有些許出入,會寫linux腳本的就會發現,修改的部分無傷大雅):
%.d : %.c
gcc -MM $< > $@.$ $ $ $; \ (1)
sed 's/\ ($*\ )\.o/\1.o $@/g' < $@.$ $ $ $ > $@; \ (2)
rm -f $@.$ $ $ $ (3)
ps:網頁的排版問題,爲了看的直觀作了修改,使用時請把四個$以及\ (和\ )之間的空格去掉,下同
繼續以例子講解:
源代碼以下(helloworld.c):
#include <stdio.h>
#include "test.h" //test.h爲空文件,只用於實驗講解
int main(int argc, char *argv){
printf("hello world!\n");
}
(1):
用gcc -MM helloworld.c的輸出結果是:
helloworld.o: helloworld.c test.h
所以(1)行代碼
gcc -MM $< > $@.$ $ $ $; \ (1)
的做用,就是生成helloworld.o.xxxx的臨時文件,文件內寫得是"helloworld.o: helloworld.c test.h"
ps:在第一行的代碼裏涉及到makefile的自動化變量$<、$@和linux腳本的重定向,自行百度,再也不講解。
(2):
第二行的代碼
sed 's/\ ($*\ )\.o/\1.o $@/g' < $@.$ $ $ $ > $@; \ (2)
參考本博文上文的基礎知識2,其中,$*是自動化變量,在這裏指的是:helloworld。$@也是自動化變量,在這裏指的是helloworld.d。
這行代碼能夠理解爲:
sed 's/helloworld.o/helloworld.o helloworld.d/g' < $@.$ $ $ $ >$@
ps:其中的兩個< 、>爲linux腳本的重定向,本身百度學習。
所以,實際的處理結果是把第(1)行代碼的結果
helloworld.o: helloworld.c test.h
轉換爲:
helloworld.o helloworld.d: helloworld.c test.h
並把轉換的結果保存到helloworld.d文件中。
(3):
第二行代碼其實就已經完成任務了,第三行代碼僅僅是刪除第一行代碼建立的臨時文件$@.$$$$。在此再也不詳述。
=======================================================================================
自動產生依賴的代碼就這樣理解,那怎麼使用呢?
先看看上面代碼生成的結果:
helloworld.o helloworld.d: helloworld.c test.h 保存在helloworld.d文件中
要使用,除了上面的代碼以外,只須要加一句
include helloworld.d
其實就至關於把代碼自動生成的 helloworld.o helloworld.d: helloworld.c test.h包含在makefile中。
包含上了helloworld.d的做用有兩條
一、由於要包含helloworld.d,當搜索不到有helloworld.d文件時,就會自動匹配上文產生依賴的代碼,自行生成helloworld.d,固然,當helloworld.c或者test.h修改後,因爲helloworld.d已通過時,也會從新生成helloworld.d
二、helloworld.o的依賴會合並上helloworld.c test.h(參考本博文上文的基礎知識1),從而實現了自動產生依賴
=======================================================================================
總結起來,我對上面helloworld源碼寫的makefile以下:
CC = gcc
TARGET = helloworld
$(TARGET) :
include $(TARGET).d
%.d : %.c
gcc -MM $^ > $@.$ $ $ $; \
sed 's/\ ($*.o\ )/\1 $@/g' < $@.$ $ $ $ > $@; \
rm $@.$ $ $ $
.PHONY: clean
clean:
$(RM) $(TARGET) $(TARGET).d $(TARGET).o
helloworld.d以下:
helloworld.o helloworld.d: helloworld.c test.h