?????????Hello大家好!很高興我們又見面啦!給生活添點passion,開始今天的編程之路!
我的博客:<但凡.
我的專欄:《編程之路》、《數據結構與算法之美》、《C++修煉之路》、《Linux修煉:終端之內 洞悉真理》
感謝你打開這篇博客!希望這篇博客能為你帶來幫助,也歡迎一起交流探討,共同成長。
目錄
1、引入
2、基本概念
? ? ? 理解
?3、推導
4、Makefile語法拓展
1、引入
? ? ? ? 在上一期我們介紹了gcc來編譯源文件,可是大家在未來寫代碼的時候,有可能會有多個源文件需要我們去編譯,那么我們怎么樣才能像在vs那樣,自動化的編譯形成可執行程序呢?
? ? ? ? 我們可以通過這一期介紹的make/Makefile來實現自動化構建。
2、基本概念
? ? ? ? make是Linux系統內置的命令,而Makefile是需要工程師自己建立的文件。
? ? ? ? 那么我們先來簡單看一下怎么操作:
? ? ? ? 現在我們的目錄中已經有了一個寫好的code.c文件。
? ? ? ? 第一步新建一個名為Makefile的文件(或者makefile);
? ? ? ? 第二步,在文件中寫入以下代碼:
????????
? ? ? ? 注意,第二行必須是table而不是空格!
? ? ? ? 第三步,輸入命令 make,我們發現我們當前目錄中生成了code文件:
? ? ? ? 第四步,我們直接執行這個可執行程序code:
? ? ? ? ?接下來,我們在Makefile中寫一下自動清理:
? ? ? ? ?現在,我們執行make clean命令,就能夠自動刪除我們剛才實現的可執行程序了。? ? ? ? ??
? ? ? 理解
????????現在我們來解釋一下我們剛才都寫了什么:
? ? ? ? 文件的第一行,code:code.c 是依賴關系;緊接著第二行叫依賴方法。依賴方法表明了依賴關系。注意第二行開頭必須是TAB鍵,對于縮進有嚴格要求。依賴關系和依賴方法缺一不可。依賴關系中,冒號前面的我們叫目標文件,也就是我們生成的文件。冒號后面的叫依賴文件列表。這個列表可以有多個文件。
? ? ? ? 第三行.PHONY?:clean聲明?clean是一個偽目標,即它不代表實際要生成的文件名。第四行clean:
?定義了一個名為 clean?的目標。當在命令行運行make? clean時,Make 會執行該目標下的命令。偽目標總是被執行的。 什么叫總是被執行的呢?我們多次執行make,會發現他不讓你編譯了,因為他檢測到你的源代碼沒有變化。這就叫總是不被執行,本質上是為了提升效率。如果我們多次執行clean,發現他總是會被執行。因為他被.PHONY修飾了。
? ? ? ? 那么系統是怎么知道我們的源文件有沒有被更改呢?
? ? ? ? 我們看一下code.c的文件屬性:
? ? ? ? 當我們的修改文件內容時,第一二個時間屬性會更改,當訪問時,后兩個時間屬性不會更改,但是第一個可能會更改,根據系統而定。當我們修改屬性但是不修改內容時,只有第三個時間屬性會改變。?系統根據我們code和code.c的Modify時間的新舊來判斷是否需要重修編譯。
? ? ? ? 所以說,系統判斷的并不是你內容是否被更改了,只要你編輯了code.c,就算你去掉一個字母,又加上去了,內容沒有改變,在系統眼里,code.c的Modify時間比code的時間新,那么code.c就允許再次被執行。
? ? ? ? 我們在執行make時,他是從上往下掃描的,默認都是實現遇到的第一個目標。所以說對于這兩個目標的前后順序是不能調換的。
?3、推導
? ? ? ? 我們現在用一幅圖來理解makefile是怎么推導的:
? ? ? ? 我們想要生成code就需要code.o,想生成code.o就需要code.s。以此類推。直到我們想生成code.i需要code.c,我們是有code.c的,所以就能生成了code.i,接著反向執行剛才的每個命令。其實系統在檢測到我們某一個指令沒有前置文件時,先把他入棧。只要沒法生成就入棧,知道可以執行了,就依次出棧執行指令。
?????????但是我們實際上不會這樣寫。往往我們習慣這樣寫:
code:code.o gcc code.o -o code
code.o:code.cgcc -c code.c -o code.o.PHONY:clean
#clean:rm -f code
4、Makefile語法拓展
????????接下來我們適度拓展一下makefile的語法:
? ? ? ? 在寫makefile文件的時候,我們可以不直接把各種命令都寫出來,而是以變量的形式來寫。
BIN=code.exe
CC=gcc
SRC=code.c
OBJ=code.o
CFLAGS=-c
LFLAGS=-o
RM=rm -f$(BIN):$(OBJ)$(CC) $(LFLAGS) $(BIN) $(OBJ) #或者寫成$(CC) $(LFLAGS) $@ $^
$(BOJ):$(SRC)$(CC) $(CFLAGS) $(SRC) #默認生成.o結尾的同名文件.PHONY:clean
clean:$(RM) $(BIN).PHONY:print
print:#打印并關閉回顯#使用@關閉回顯@echo $(BIN)@echo $(CC)@echo $(SRC)@echo $(FLAGS)@echo $(RM)
? ? ? ? 我們定義了一堆變量,我們的命令直接用變量代替就可以了,這類似于C語言中的宏或者全局變量,如果我們想換一些命令,比如把gcc換成g++,就直接切換這個變量就可以了。其中,$@代表上一行中冒號左邊的內容,$^代表冒號右邊所有內容。
? ? ? ? 我們可以把代碼繼續"升級":
BIN=code.exe
CC=gcc
SRC=$(whildcard *.c)
OBJ=$(SRC:.c=.o)
CFLAGS=-c
LFLAGS=-o
RM=rm -f$(BIN):$(OBJ)$(CC) $(LFLAGS) $(BIN) $(OBJ) #或者寫成$(CC) $(LFLAGS) $@ $^
%.o:%.c$(CC) $(CFLAGS) $<.PHONY:clean
clean:$(RM) $(BIN).PHONY:print
print:#打印并關閉回顯#使用@關閉回顯@echo $(BIN)@echo $(CC)@echo $(SRC)@echo $(FLAGS)@echo $(RM)
? ? ? ? whilecard是makefile內置的函數,可以實現查找當前目錄下以.c為結尾的文件。當然我們也可以把.c改成.o或者其他的。第二行代碼就是把SRC的所有文件中都換成同名的.o文件。%.o:%.c代表,冒號左側有一百個文件,分別是code1.o,code2.o......,冒號右側也有一百個文件,分別是code1.c,code2.c......,而$<代表著把以上的文件對應著,一個一個的交給.o文件。而&^代表把冒號右邊的統一交給冒號左邊的。因為最后我們只形成一個可執行程序。
? ? ? ? 當然了我們日常練習也沒必要寫的這么復雜。
? ? ? ? 好了,今天的內容就分享到這,我們下期再見!