從版本1到版本5如何編寫牛逼的Makefile
- 2019 年 10 月 6 日
- 筆記
1.Makefile三要素

2.工作原理

3.開始編寫
首先編寫我們的程序,以c語言為例。
1)func.h
定義兩個函數,分別為加法與減法:

2) 加法函數實現

3) 減法函數實現

4)main函數

3.1 版本1
最普通的版本:直接寫即可,簡單解釋一下:當我們編譯上述文件的時候,會通過gcc -o main main.c add.c sub.c。
那麼我們將其轉成Makefile,就是按照上述工作原理與規則進行轉換。
比如sub.o就是依賴與sub.c通過gcc -c命令生成,那麼這種依賴可通過:
sub.o: sub.c來實現,第二行寫上實現的命令即可,注意第二行要有嚴格的類似python語法的tab控制。其餘的類似操作。

3.2 版本2
我們發現版本1太長了,如何把他進行優化,可以根據語言的特性,當然Makefile也有,那就是變量來賦值,將上述的所有.o文件賦值給obj變量,main賦值給target變量。
引用這些變量則是:$(target)形式。$(變量)。
最後兩行解釋之前說一下自動變量:
$<: 規則中的第一個依賴 $@: 規則中的目標 $^: 規則中的所有依賴
所以最後一行就變成如下圖所示的情況,而%.o與%.c表示匹配每一個.o與.c文件。對版本1進行修改就變成如下圖所示:

3.3 版本3
引入CC變量,在Makefile中有一些內置變量,比如這裡要使用的CC,我們可以對其進行賦值修改,也可以直接使用,進一步修改版本2,進一步修改版本2,變為版本3。

3.4 版本4
這裡我們引入Makefile中的兩個常用函數:wildcard與patsubst,分別為查找本地中的文件與模式匹配。
src=查找本地的所有.c文件,obj=將本地的所有.c文件替換為所有的.o文件。

3.5 版本5
在使用Makefile的時候我們需要clean掉所有的.o文件跟中間文件,那麼如何在Makefile中實現呢。
就是通過clean,而在clean的過程中,普通的clean寫法為:
clean: rm *.o main
當我們clean連續兩次就會出現問題,如下圖:

這種問題是因為你刪除了一次,本地磁盤沒有相應文件,而報的錯誤,那麼解決這種問題就是加上-f參數,讓他強制喊出。
clean: rm *.o main -f
當我們在本地創建了一個clean文件,再去make clean的時候,一直都顯示最新的,如下圖:

這裡就要引入一個概念,偽目標,因為make clean,會將本地磁盤與make clean後的文件進行對比,而make clean並沒有生成相應的文件,所以根據Makefile特性,每次更新後必定是新的,而本地磁盤就是現成的,那麼肯定和新的,就會出現上述結果。
像make這種可以生成文件,而make clean沒有生成文件,稱之為偽目標,此時需要在Makefile中進行聲明:
.PHONY: clean clean: rm *.o main
最後當我們在clean下面想做其他工作,比如創建文件操作的時候,如果沒有相應的創建文件權限或者其他情況,直接後面的命令不會被執行。
示例如下:/usr/local下創建文件普通用戶沒有權限,所以必然會報錯:
.PHONY: clean clean: mkdir /usr/local/a rm *.o main

會發現直接報錯了,解決這個問題很簡單,在命令行前面加上一個橫杠(-)。
.PHONY: clean clean: -mkdir /usr/local/a rm *.o main

最後完整版Makefile如下:
