Linux学习:makefile介绍
一、為什么使用 makefile?
makefile 帶來(lái)的好處就是“自動(dòng)化編譯”,一旦寫(xiě)好,只需要一個(gè) make 命令, 整個(gè)工程完全自動(dòng)編譯, 極大的提高了軟件開(kāi)發(fā)的效率。
同時(shí),makefile 文件中可以定義一系列的規(guī)則來(lái)指定,哪些文件需要先編譯,哪些文件需要后編譯,哪些文件需要重新編譯,甚至于進(jìn)行更復(fù)雜的功能操作,因?yàn)?makefile 就像一個(gè) Shell 腳本一樣,其中也可以執(zhí)行操作系統(tǒng)的命令。
二、makefile 的命名規(guī)則
(1)規(guī)則:
目標(biāo)...: 依賴(lài)... // 注意:一個(gè) makefile 中可以有多個(gè)規(guī)則 (tab)命令 // 注意:tab 縮進(jìn)不能是 4 個(gè)空格.....(2)三要素:
目標(biāo):要生成的目標(biāo)文件。
依賴(lài):目標(biāo)文件由哪些文件生成。
命令:如何通過(guò)執(zhí)行該命令使依賴(lài)文件生成目標(biāo)文件。
三、makefile 的設(shè)計(jì)思路
(1) 需求:
1)含有頭文件、加減乘除的實(shí)現(xiàn)文件、測(cè)試 main 文件。
(include 目錄包含 head.h 、add.c div.c mul.c sub.c 、main.c) 。
2)將這 3 類(lèi)文件制作成 makefile 文件,實(shí)現(xiàn)自動(dòng)編譯,生成 app 可執(zhí)行文件。
1、第一版本:最簡(jiǎn)單
app: add.c div.c mul.c sub.c main.cgcc add.c div.c mul.c sub.c main.c -o app -I include(1)說(shuō)明:
目標(biāo):app 文件
依賴(lài):用于生成目標(biāo)(add.c div.c mul.c sub.c main.c)
命令:gcc 編譯(-o 指定名稱(chēng) app 因?yàn)橛蓄^文件,所以要有 –I)
(2) 缺陷:
改變一個(gè)依賴(lài)文件(例:只 touch add.c 甚至不改變其內(nèi)容),所有依賴(lài)文件都要重新更新編譯
2、第二版本:依賴(lài)于.o 文件
app: main.o add.o div.o mul.o sub.ogcc main.o add.o div.o mul.o sub.o -o app(1) 相較于第一個(gè)版本,依賴(lài)于.o 文件。
(2) 命令依然是 gcc,區(qū)別是由.o 生成 app。
(3)第一個(gè)目標(biāo)(app)稱(chēng)為終極目標(biāo)。因?yàn)榻K極目標(biāo)依賴(lài)于.o 文件,所以需要依賴(lài)于“.c 文件”生成“.o 目標(biāo)”,因此,有以下內(nèi)容:
(4)相較于第一版的好處是改變一個(gè)依賴(lài)文件,只有 改變的依賴(lài)文件和終極目標(biāo)需要重新生成,其他不動(dòng)。
(5) 缺陷:
相似代碼體太多
(6)鋪墊知識(shí):
1)makefile 中的變量:
makefile 中的變量有點(diǎn)類(lèi)似于 C 語(yǔ)言中的宏定義,使用該變量相當(dāng)于內(nèi)容替換,使用變量可以使 makefile 易于維護(hù),修改起來(lái)變得簡(jiǎn)單。
2)變量的分類(lèi):普通變量、自動(dòng)變量
普通變量 (嚴(yán)格區(qū)分大小寫(xiě)),定義 key = val 引用 val $(key)。舉例 foo = a.o b.o c.o $(foo) 就相當(dāng)于 a.o b.o c.o
自動(dòng)變量:特別注意:自動(dòng)變量只能在規(guī)則的命令中使用.
$@ 表示規(guī)則中的目標(biāo)
$< 表示規(guī)則中的第一個(gè)依賴(lài)條件
$^ 表示規(guī)則中的所有的依賴(lài)條件
3、第三版本: “模式規(guī)則”(利用 makefile 變量 和 占位符% 實(shí)現(xiàn))
app: main.o add.o div.o mul.o sub.o gcc $^ -o $@ // $^ 指所有的.o文件 //$@ 指app ,編譯所有的.o文件生成目標(biāo),并指定為app %.o:%.c // % 是占位符 gcc -c $< -o $@ -I include // $< 第一個(gè)的.c 文件 ,編譯一個(gè).c 文件($<)生成.o 文件($@)(1)缺陷:
終極目標(biāo) app 的依賴(lài)是完全定死的,扔到另一個(gè)項(xiàng)目中就不能用了,可移植性差。
(2)鋪墊知識(shí):makefile 函數(shù)(所有的函數(shù)都有返回值,我們基本都是需要它的返回值)
1)wildcard :查找指定目錄下的指定類(lèi)型的文件
2)patsubst :匹配替換
obj = $(patsubst %.c , %.o , $(src) ) //把 src 變量里所有后綴為.c 的文件替換成.o ,$(src) == *.c4、第四版本:利用 makefile 函數(shù)
// makefile 函數(shù) src = $(wildcard *.c) // 當(dāng)前目錄下,所有 .c 文件 obj = $(patsubst %.c , %.o , $(src) ) // 當(dāng)前目錄下,所有 以.c 文件生成的.o 文件 // makefile 普通變量 target = app // 如果主體多次使用 app,想修改終極目標(biāo),只需要在這里改一次就行了 cc = gcc // makefile 自動(dòng)變量(模式規(guī)則) $( target): $(obj) $(cc) $^ -o $@ %.o:%.c $(cc) -c $< -o $@ -I include(1)缺陷:每次重新編譯都需要手工清理中間.o 文件和最終目標(biāo)文件
(2)鋪墊知識(shí): clean / make clean
用途:清除編譯生成的中間.o 文件和最終目標(biāo)文件
1)出現(xiàn)的問(wèn)題:make clean 如果當(dāng)前目錄下有同名 clean 文件,則不執(zhí)行用于清除的 clean 命令,這時(shí)解決方法為:.PHONY:clean(偽目標(biāo)聲明)。
效果:聲明偽目標(biāo)之后, makefile 將不會(huì)檢查該目標(biāo)是否存在或者該目標(biāo)是否需要更新。
2) clean 命令中的特殊符號(hào):
– 此條命令出錯(cuò),make 也會(huì)繼續(xù)執(zhí)行后續(xù)的命令。如:-rm main.o。
rm –f :強(qiáng)制執(zhí)行,主要解決:如果要?jiǎng)h除的文件不存在使用 –f 不會(huì)報(bào)錯(cuò)。
3)@不顯示命令本身,只顯示結(jié)果。如:@echo clean done
(3)其他:
1)make 默認(rèn)執(zhí)行終極目標(biāo),可通過(guò)“make 目標(biāo)名”指定要執(zhí)行的目標(biāo),例如 make clean。
2)make –f:例如,有 makefile、makefile1,使用 make 命令,默認(rèn)執(zhí)行 makefile,若想指定運(yùn)行makefile1,則 make –f makefile1
5、第五版本:最終版本
// makefile 函數(shù) src = $(wildcard *.c) obj = $(patsubst %.c , %.o , $(src) ) // makefile 普通變量 target = app cc = gcc // makefile 自動(dòng)變量(模式規(guī)則) $( target): $(obj)$(cc) $^ -o $@ %.o:%.c $(cc) $< -c -I include -o $@ // 清理工作 .PHONY: clean //添加偽目標(biāo),防止歧義 // 注意以 “." 開(kāi)頭 clean:rm -f $(target) rm -f $(obj)四、 makefile 的工作原理
1、目標(biāo)的生成
若想生成目標(biāo),首先檢查規(guī)則中的所有的依賴(lài)文件是否都存在:
如果有的依賴(lài)文件不存在, 則向下搜索規(guī)則,看是否有生成該依賴(lài)文件的規(guī)則:
(1)如果有規(guī)則用來(lái)生成該依賴(lài)文件,則執(zhí)行規(guī)則中的命令生成依賴(lài)文件,再生成終極目標(biāo)。
(2)如果沒(méi)有規(guī)則用來(lái)生成該依賴(lài)文件,則報(bào)錯(cuò)
例如:
第一版本:依賴(lài)文件.c 都存在,直接生成目標(biāo)。
第二版本:依賴(lài)文件.o 不存在,向下搜索。
有生成該依賴(lài)文件的規(guī)則(依賴(lài).c 生成目標(biāo).o)則也可以生成目標(biāo)。
2、目標(biāo)的更新:
如果所有依賴(lài)都存在,想要檢查規(guī)則中的目標(biāo)是否需要更新,必須先檢查它的所有依賴(lài),依賴(lài)中有任何一個(gè)被更新,則有關(guān)目標(biāo)必須更新。
(1)說(shuō)明:
第一版本中,一個(gè)依賴(lài)被更新,所有依賴(lài)都更新,然后更新終極目標(biāo)。
第二版本中,一個(gè)依賴(lài)被更新,只有該依賴(lài)對(duì)應(yīng)的目標(biāo)更新,然后再更新終極目標(biāo)。
(2)是否更新的判斷方法:看“依賴(lài)的最后訪(fǎng)問(wèn)時(shí)間”是否晚于“目標(biāo)的最后訪(fǎng)問(wèn)時(shí)間”。
依賴(lài)的最后訪(fǎng)問(wèn)時(shí)間 < 目標(biāo)的最后生成時(shí)間 早于 不更新。
依賴(lài)的最后訪(fǎng)問(wèn)時(shí)間 > 目標(biāo)的最后生成時(shí)間 晚于 更新。
總結(jié)
以上是生活随笔為你收集整理的Linux学习:makefile介绍的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Linux学习:静态库和动态库
- 下一篇: Linux学习:文件描述符表