做糕點哪個網站鄂州網站seo
目錄
一、前言
?二、make / Makefile背景介紹
?🥝Makefile是干什么的?
?🍇make又是什么?
三、demo實現(xiàn)【見見豬跑🐖】?
?四、依賴關系與依賴方法
1、概念理清?
2、感性理解【父與子👨】
3、深層理解【程序的翻譯環(huán)境 + 棧的原理】?
?五、多學一招:項目清理
?1、演示與原理講解
?2、.PHONY偽目標的作用
?3、.PHONY偽目標的原理?
?六、make的工作原理分析
?1、再談make與Makefile
?2、探究make的判斷機制🔍
?七、Makefile小知識📚
?八、總結與提煉
?九、共勉
一、前言
? ? ? ? 在之前的博客中,講解了 Linux的基本指令:指令詳解? ,但是呢,在我們常見的項目編譯中肯定會包含很多代碼文件,只會運用 指令 是不夠滴,所以本次博客我們來介紹一下如何使用 make/Makefile 實現(xiàn)項目的自動化構建。
- 大部分老鐵都應該知道如何在Linux上編譯C語言代碼,而且清楚了可執(zhí)行文件
a.out
的由來,是從test.c
經過預編譯到test.i
test.i
經過編譯到test.s
test.s
經過匯編到test.o
test.o
經過鏈接到a.out
- 如果有老鐵還不清楚的可看看這篇?編譯+鏈接?的過程,是不是覺得很冗余復雜,我們平常做做練習還好,但若是到了那些大型工程中,可是具有上千、上萬條代碼,若是一次編譯完成之后又修改了源代碼,接著又想進行編譯,此時便需要重新敲入指令,那會使得工作量變得很大。可是在VS中,我們可以無限地修改自己的代碼,然后隨時編譯運行,不需要考慮這些復雜的原理
- 那Linux中有沒有這樣的一站式操作呢,那就是【make/Makefile】👈
?二、make / Makefile背景介紹
首先我們來介紹一下什么是make/Makefile,以及它們之間的關系?
?🥝Makefile是干什么的?
- Makefile 是一個
文件
。它是一個工程文件的編譯規(guī)則,它記錄了原始碼如何編譯的詳細信息、描述了整個工程的編譯鏈接等規(guī)則。
- Makefile 帶來的好處就是——“自動化編譯"。一旦寫好,只需要一個make命令,整個工程完全自動編譯,極大的提高了軟件開發(fā)的效率🚀
🎯先來看一下Makefile的【語法】:?
target(目標文件):文件1 文件2(依賴文件列表) //依賴關系<Tab>gcc -o 欲建立的執(zhí)行文件 目標文件1 目標文件2 ///依賴方法command......
- target就是我們想要建立的信息,一般稱作
目標文件
。而后面的依賴文件列表
就是具有相關性的 object files,也就是目標文件所依賴的文件(可以是一個或多個,也可以沒有)
?🎯然后看一下Makefile的【規(guī)則】:
- ?目標文件與依賴文件列表文件之間要使用冒號隔開
目標文件:依賴文件列表
- ?target可以是一個目標文件、執(zhí)行文件,甚至可以是一個標簽【后面會提到的偽目標】
- ?依賴方法前面必須加Tab空格鍵
- ?依賴方法以gcc為例,也可以是其他的shell指令【command】
💪會不會寫Makefile ,從一個側面說明了一個人是否具備完成大型工程的能力💪?
?🍇make又是什么?
- make是一個
命令工具
,是一個解釋makefile中指令的命令工具,一般來說,大多數(shù)的IDE都有這個命令,比如:Delphi 的 make,Visual C++的nmake,Linux下GNU的make??梢?#xff0c;Makefile都成為了一種在工程方面的編譯方法
【總結一下】:make?一條命令,makefile 是一個文件,兩個搭配使用,完成項目自動化構建👈?
三、demo實現(xiàn)【見見豬跑🐖】?
了解可什么是make/Makefile之后,我們就來用一用它們?
- 剛才說到make命令是用來解釋 Makefile 中指令的,所以我們需要創(chuàng)建一個。我喜歡用大寫的Makefile,當然你寫成 makefile 也是可以的
- ?這里直接
vim Makefile
即可,進入編輯界面,如果有不懂vim的,可以看看我的文章---------- - Vim 的超詳細使用
- 此時我們可以再創(chuàng)建一個
test.c
,作為源文件,然后開始往里面寫內容 - 現(xiàn)在我要通過gcc去編譯這個test.c的文件,然后生成一個我自己命名的【mytest】這個可執(zhí)行文件,此時我們只需要在Makefile寫上這兩行即可
mytest:test.cgcc -o mytest test.c
- 然后回到命令行,我們來執(zhí)行一下這個
make
指令,它就是自動在當前源文件的所在路徑下搜尋Makefile,并解釋里面命令。之后若是我們需要去編譯任何文件,只需要在Makefile里面做一個添加即可,怎么樣,是不是很方便
看到了 make / Makefile 的基本實現(xiàn)過程,我們再來說一下 它的原理吧!!!
?四、依賴關系與依賴方法
通過小小的demo,想必你已經感受到了【自動化構建工具】的強大,我們來仔細看看Makefile中的指令為何要如此書寫??
1、概念理清?
- 對于?
mytest:test.c
,冒號左側是目標文件,右側是它的依賴文件,所以就可以說它們之間存在一種【依賴關系】,只有test.c存在才可以有mytest
- 那要如何通過test.c去生成mytest呢? 此時就需要使用到下面的這句gcc指令
gcc -o mytest test.c
?👉它叫做【依賴方法】
?2、感性理解【父與子👨】
?就這么說還是不太好理解,我們舉個父與子的生活小案例來幫助理解
今天呢,是這個月的12號的了,家里面在月初給你的2000塊錢差不多也花完了,于是這兩天只能吃土,此時你打開微信后看到和老爸的聊天框,于是就想著和老爸要點錢【畢竟兒子向父親要錢天經地義😀】
- ?這里的老爸和兒子指的就是
[依賴關系]
- ?兒子向老爸要錢指的就是
[依賴方法]
下面辨析幾種依賴關系與依賴方法?
?錯誤的依賴方法?
- 此時你打電話和你老爸說:“我是你兒子,你幫我寫作業(yè)?!?/li>
- 以上這句話就是依賴關系正確,但是依賴方法不正確。老爸幫兒子寫作業(yè)無法執(zhí)行
所以只有依賴關系不行,還得有正確的依賴方法?
?錯誤的依賴關系?
- 此時你拿起室友的手機和他爸爸打電話說:“我是你兒子,你給我點零花錢?!?/li>
- 以上這句話就是依賴方法正確,但是依賴關系不正確。因為別人的老爸沒義務給你錢
依賴方法對了,但是依賴關系不對也不行?
????正確的依賴關系與依賴方法
- 經歷了種種挫折后,你重新拿起手機說:“老爸,我是你兒子,可以給我點零花錢嗎?”
- 上面這種說法就是完全正確的依賴關系與依賴方法
完成一件事,必須得有正確的依賴關系 + 正確的依賴方法?
3、深層理解【程序的翻譯環(huán)境 + 棧的原理】?
?看完了【依賴關系】與【依賴方法】的感性理解,相信你對它們有了一定程度的認識,接下去深入地來了解一下它們之間的關系
1 mytest:test.o2 gcc test.o -o mytest
- 開頭提到過源程序是如何經過一步步的編譯來形成可執(zhí)行文件的嗎,因為可執(zhí)行文件
mytest
是依賴于匯編后的目標文件test.o
的,但是現(xiàn)在我們沒有這個文件,因此就要去倒推一下如何獲取這個test.o
- ??對于
test.o
來說,它依賴于test.s
這個經過編譯之后文件,可是【test.s】不存在,所以跳轉到下一條依賴關系
3 test.o:test.s4 gcc -c test.s -o test.o
- 對于
test.s
來說,它依賴于test.i
這個經過預編譯之后的文件,可是【test.i】不存在,所以跳轉到下一條依賴關系?
5 test.s:test.i6 gcc -S test.i -o test.s
- ?對于
test.i
來說,它依賴于test.c
這個源文件,查找后發(fā)現(xiàn)源文件存在,于是開始執(zhí)行gcc命令
7 test.i:test.c8 gcc -E test.c -o test.i
?以下就是我們需要在Makefile中修改的【依賴關系】與【依賴方法】
- 最后來到命令行中執(zhí)行一下【make】命令,便完成了所有的編譯,對于之前一步步地寫這個編譯的過程,真的是來得方便很多
- 因為只有當執(zhí)行完了最后一條命令后生成了【test.i】的文件之后才可以一一往上繼續(xù)執(zhí)行,這種反著來的執(zhí)行邏輯就相當于是我們在數(shù)據(jù)結構中學過的棧,有一個先進后出的邏輯
?那這個Makefile這么牛,我們將?gcc編譯 的順序修改一下,會發(fā)生什么呢?
- 可是呢,當我再去
make
的時候,卻發(fā)現(xiàn)這個執(zhí)行的順序還是按照沒打亂之前的位置,這說明了一點:make會自動推導Makefile中的依賴關系形成棧式結構
【總結一下】:在 [依賴關系] 中,若是目標文件所依賴的文件不存在,就將這個依賴方法入棧,轉到下一組[依賴關系],依次循環(huán)往復,直到當前目標文件所依賴的文件存在時,就進行出棧,開始執(zhí)行依賴方法。最后獲取的便是那個我們最初想要的目標文件,即使Makefile中的編譯順序發(fā)生了變化,make也會去做一個自動推導的工作
?五、多學一招:項目清理
?1、演示與原理講解
平時我們在進行各種操作之后目錄中都會出現(xiàn)很多文件,此時當我們不想要這些文件的時候,就得去一一刪除,顯得尤為麻煩,如果編譯可以使用Makefile來自動化構建,那清理項目中的文件可不可以呢,我們來看看?
- 此時我們在
Makefile
中增加一個【清理】功能
- 來看一下是否可以達到清理的目的
- 當我想使用清理功能的時候,并沒有像自動化編譯那樣直接
make
,而是在make后面加上了一個clean
,這是為什么呢? - 新加上的
.PHONY
是什么?它對clean而言意味著什么?
?我們帶著這些問題一起進入【偽目標】------ .PHONY 的學習📖
?2、.PHONY偽目標的作用
-
.PHONY是一個偽目標,Makefile中將 .PHONY 放在一個目標前就是指明這個目標是偽文件目標。其作用就是防止在Makefile中定義的執(zhí)行命令的目標和工作目錄下的實際文件出現(xiàn)名字沖突
-
也就是下面這句,此時的clean被
.PHONY
修飾了,那么它就可以反復執(zhí)行它的依賴方法
.PHONY:clean
- 可以看到對于目標文件
clean
來說,它的依賴文件列表為空,上面我們也有提到過它可以為空
11 clean:12 rm -f mytest test.i test.s test.o
- 所以只要你一直使用【make clean】,它便會反復地執(zhí)行
rm -f mytest test.i test.s test.o
- .PHONY?配置項的目標clean并不是其他文件生成的實際文件,使make命令會自動繞過隱含規(guī)則搜索過程,也就是說執(zhí)行命令
make clean
會自動忽略名為"clean"文件的存在,因此聲明.PHONY配置項會改善性能,并且不需要擔心實際同名文件存在與否😮 - 【通俗一點說】:.PHONY修飾的目標clean并不是某個依賴項生成的實際文件,因此make命令不再去搜尋當前文件夾下是否有clean文件,這樣少去做一些事,自然會改善性能,并且不用擔心當前文件夾下是否有同名的文件
?我們到命令行中來驗證一下??
- 可以看到,我進行了三次make clean,不過其實在第一次執(zhí)行的時候,就已經達成了我們清理的目的,可是后面還可以繼續(xù)執(zhí)行,這其實就是.PHONY修飾起的作用
- 其實對于【clean】來說,不加修飾其實也是可以辺反復執(zhí)行的,這點我們在本模塊開頭的時候有說到過。我現(xiàn)在將這個修飾去掉,來試試看
- 可以看到,即使是去掉了
.PHONY
做修飾之后一樣是可以反復執(zhí)行
?那就有同學問:這是為什么呢?為何clean不加
.PHONY
修飾也可以多次執(zhí)行
- 原因就在于它的依賴對象為空,當我們需要生成這個【clean】目標文件的時候就不需一些文件必須要存在,因此就可以一直
[clean]
?3、.PHONY偽目標的原理?
- 可是呢,對于其他的指令就不行了,例如我們上面說到過的gcc去編譯一個文件的過程
- 我們試著在【mytest】前面加上一個
.PHONY
的修飾試試
- 然后再去試試能不能進行反復使用【這里給讀者詳細解釋一下
.PHONY
修飾的原理】
我們來詳細分析一下,首先可以清楚的是加上
.PHONY
修飾之后便可以多次make,但是可以看到在編譯的過程中進行make的時候所執(zhí)行的指令不太相同,只有gcc test.o -o mytest
這一句,卻少了如何產生【test.o】的過程,這是為何呢
- 因為在經過一次make之后,gcc對【test.c】進行了預編譯、編譯、匯編,最后生成了【test.o】,那它就已經在那里了,在此中間我們沒有再對源文件進行再度修改,在編譯的時候,其實會去查看目標對象和依賴對象的生成時間,若是依賴對象的生成時間要早于目標對象,說明它還沒有被重新修改過,所以無需再度去重新編譯生成(這一塊在后面make的工作原理中細講)
- ?因此我們再去make的話gcc是不會重新編譯的,可以當我去修改了一下【test.c】這個源文件之后,再度去make一下的話gcc又會對這個源文件進行一個重新的全過程編譯。?
?編譯這一塊比較復雜,需要重點理解??
- 不過其實可以看出,每次去修改一下就重新編譯全部的文件,也是挺繁瑣的。所以我們在開發(fā)的時候一般不給編譯生成的目標文件帶
.PHONY
的修飾,就防止其被多次重復編譯
【總結一下】:
📚?
.PHONY
修飾的是偽目標,對于偽目標來說,它可以被反復執(zhí)行📚?
.PHONY
修飾的一定能被反復執(zhí)行,但是能被反復執(zhí)行的不一定被.PHONY
修飾
?六、make的工作原理分析
?1、再談make與Makefile
- 通過【ldd】去查看
make
指令的動態(tài)依賴關系,我們可以發(fā)現(xiàn) make指令 也是依賴于標準的C庫,而我們在Makefile中寫得也都是一些指令,因此使用make指令才可以對Makefile中的內容做一個識別
?因此我們可以得出一個結論
👉
make
是專門給【Makefile】寫的一個命令,在執(zhí)行make的時候,就會自動在你當前目錄下去搜索Makefile
這個文件,搜索之后打開,然后對它里面的內容做分析?
那 make 是如何進行分析 Makefile 的呢,有什么規(guī)則嗎?
- make掃描Makefile文件時會默認執(zhí)行第一組依賴關系和依賴方法?
- 還記得我們
- 在獲取
mytest
這個目標對象的時候都是直接使用的【make】嗎; - 而在獲取
clean
這個目標對象時卻用的是【make clean】
- 在獲取
- 那你是否會感到疑惑為何不使用【make mytest】就可以獲取到嗎,就是因為默認執(zhí)行的就是第一組的依賴關系和依賴方法
- 我們可以試著把【clean】和【mytest】調個位置
- 可以看到,在調換了位置之后我們直接【make】的話獲取的就是clean對象了,想要去使用gcc編譯源文件生成可執(zhí)行文件就需要用到【make mytest】。
- 不過也并不是第一組依賴關系和依賴方法就一定要直接【make】,我們使用【make clean】也是可以用的
?2、探究make的判斷機制🔍
?好,我們來深入探討一下剛才遺留下的問題:make究竟是如何知道我們的可執(zhí)行文件是否需要重新編譯呢?
- 再來回顧一下,當我們執(zhí)行完一次【make】獲取
mytest
這個目標文件后,第二次再去執(zhí)行【make】指令就不會其效果了,這是為何呢?
- 我們可以將源文件和可執(zhí)行文件當做是一條時間軸。對于
可執(zhí)行文件
來收,它生成的時間一定是晚于源文件
的【因為中間要經過一系列編譯 + 鏈接的過程】
- 我們可以通過【stat】這個指令來查看源文件和可執(zhí)行文件的所有屬性,不過要觀察的還是其中一個叫做ACM時間
- Access: 最后一次訪問該文件的時間
- Change:最后一次改變該文件屬性或狀態(tài)的時間
- Modify:最近一次修改文件內容的時間【比較的是這個時間】
- 可以很清晰地看出10
:30:14
是要早于11:20:57
的。所以【make】指令才會不起作用。所以它就是通過這個 Modify 時間來進行對比才能判斷出是否需要重新編譯
?七、Makefile小知識📚
?本模塊來拓展一下有關make/Mailefile里的一些小知識
1. Makefile文件保存了編譯器和鏈接器的參數(shù)選項,并且描述了所有源文件之間的關系。make程序會讀取makefile文件中的數(shù)據(jù),然后根據(jù)規(guī)則調用編譯器,匯編器,鏈接器產生最后的輸出
2. Makefile里主要包含了五個東西:顯式規(guī)則、隱晦規(guī)則、變量定義、文件指示和注釋
- 【顯式規(guī)則】:如何生成一個或多個目標文件;
- 【隱晦規(guī)則】:make有自動推導的功能,所以隱晦的規(guī)則可以讓我們比較粗糙地簡略地書寫?makefile,比如源文件與目標文件之間的時間關系判斷之類;
- 【變量定義】:在makefile中可以定義變量,當makefile被執(zhí)行時,其中的變量都會被擴展到相應的引用位置上,通常使用 $(var) 表示引用變量;
- 【文件指示】:包含在一個makefile中引用另一個makefile,類似C語言中的include;
3. 默認的情況下,make命令會在當前目錄下按順序找尋文件名為“GNUmakefile”
、“makefile”
、“Makefile”
的文件
4. 我們可以在Makefile中添加一些特殊符號,就可以起到一些特殊的功能?
- 即這個
$@
和$^
,前者表示:
左側被編譯的所有內容,即【目標文件】,后者表示:
之后所有內容,即【依賴文件】
- 此時,當我們再去
make
的時候,就可以發(fā)現(xiàn)這個特殊符號自動替換成了:
兩側的【目標文件】和【依賴文件】
?接下去我再來介紹一種 Makefile 中的特殊文件
- 寫了這么多【make】,你是否感覺每次都會出現(xiàn)回顯很麻煩呢?能不能像我們在敲普通指令的時候一樣,直接給出結果呢?
- 這里我們就可以在執(zhí)行的命令行前加上這個
@
- 此時當我們在【make】和【make clean】的時候就不會產生任何回顯了,可以達到一樣的效果
?八、總結與提煉
?最后我們來總結一下本文所學習的內容📖
本文我們學習了Linux下的項目自動化構建工具 -?make/Makefile
?
- 首先清楚了【Makefile】它是一個文件,我們可以在里面寫入一些編譯的規(guī)則。而【make】則是一個命令,它可以用來解析Makefile中的內容
- 接著,在通過初次寫一個小案例去接觸make/Makefile的時候我們了解到了【依賴關系】和【依賴方法】,不僅感性地去理解了它們,而且深入地清楚了它們的底層實現(xiàn)邏輯是基于數(shù)據(jù)結構中的棧
- 然后,不僅僅局限于一個目標文件,我們又學了一招,知道了如何去清理項目中的文件,知道了.PHONY修飾的文件叫做【偽目標文件】
- 最后,我們通過再度觸及make/Makefile,真正搞清楚了它們之間的關系,也了解到make在判斷一個文件是否需要重新編譯的時候是基于比較源文件與目標文件的【Modify時間】
?九、共勉
? ? ? ?以下就是我對【Linux】makefile自動化編譯 的理解,如果有不懂和發(fā)現(xiàn)問題的小伙伴,請在評論區(qū)說出來哦,同時我還會繼續(xù)更新對? Linux--進程?的理解,請持續(xù)關注我哦!!!!!????
?