電腦怎樣做病毒網(wǎng)站成都十大營(yíng)銷策劃公司
什么是 make
make
是一個(gè)命令,他會(huì)在源文件的當(dāng)前目錄下尋找 makefile
或者 Makefile
文件執(zhí)行這個(gè)文件中的代碼。
makefile 文件的編寫
我們先來見見豬跑,看看 make
怎么用的:
下面是 makefile
文件的內(nèi)容:
這是 test.c
中的內(nèi)容:
#include<stdio.h>
int main()
{printf("hello make\n");return 0;
}
之前我們想要使用 gcc
編譯 test.c
生成 test
可執(zhí)行文件,你是不是要這樣寫命令:
gcc -o test test.c
在我們寫了上面的 makefile
文件之后,我們就能使用 make
命令來代替啦!
我們可以看到使用 make
命令之后順利編譯出來了可執(zhí)行文件,并且能夠順利執(zhí)行!
makefile 文件的編寫
我們?cè)賮砜?makefile
文件中的代碼:
其中這個(gè)冒號(hào)前面的部分叫做依賴關(guān)系(綠色框框的那個(gè)),后面的部分叫做依賴方法(紅色框框的那個(gè))。聽上去十分高大尚,翻譯成白話文就是:依賴關(guān)系的形成需要依賴方法中的所有文件。
make
命令會(huì)自動(dòng)掃描makefile
文件,查看當(dāng)前目錄下是否存在依賴方法中的所有文件,如果已經(jīng)存在,那么就會(huì)執(zhí)行下一行Tab
縮進(jìn)的代碼(只能是Tab
縮進(jìn))。那么如果不存在怎么辦呢?
我們?cè)谥v C 語言編譯鏈接的時(shí)候知道:從 C 語言的源文件到生成功可執(zhí)行文件是分成很多步驟的:
gcc -E
gcc -S
gcc -C
根據(jù)這個(gè)原理我們就在 makefile
文件中將那一行編譯生成可執(zhí)行文件的代碼分成一步一步來執(zhí)行。
test:test.ogcc test.o -o test
test.o:test.sgcc -c test.s -o test.o
test.s:test.igcc -S test.i -o test.s
test.i:test.cgcc -E test.c -o test.i
make
命令掃描 makefile
文件時(shí):
- 發(fā)現(xiàn)依賴關(guān)系
test
的依賴文件test.o
在源文件的當(dāng)前目錄不存在,繼續(xù)向下掃描。 - 發(fā)現(xiàn)依賴關(guān)系
test.o
的依賴文件test.s
在源文件的當(dāng)前目錄不存在,繼續(xù)向下掃描。 - 發(fā)現(xiàn)依賴關(guān)系
test.s
的依賴文件test.i
在源文件的當(dāng)前目錄不存在,繼續(xù)向下掃描。 - 發(fā)現(xiàn)依賴關(guān)系
test.i
的依賴文件test.c
在源文件的當(dāng)前目錄已經(jīng)存在,就會(huì)執(zhí)行Tab
縮進(jìn)的代碼:gcc -E test.c -o test.i
生成test.i
。 test.i
依賴文件已經(jīng)存在啦,就會(huì)執(zhí)行:gcc -S test.i -o test.s
生成test.s
文件。test.s
依賴文件已經(jīng)存在啦,就會(huì)執(zhí)行:gcc -c test.s -o test.o
生成test.o
文件。test.o
依賴文件已經(jīng)存在啦,就會(huì)執(zhí)行:gcc test.o -o test
生成test
可執(zhí)行文件。
在上述過程執(zhí)行完成之后(使用 make
命令之后),源文件的當(dāng)前目錄下就會(huì)生成:test.i test.s test.o test
文件。
我們可以看到顯示出來命令的執(zhí)行順序與我們推導(dǎo)的順序是一樣的哈!
綜上所述:掃描 makefile
文件的時(shí)候,如果源文件的當(dāng)前目錄不存在依賴文件,就會(huì)遞歸似的向下執(zhí)行,這種行為叫做 make
的自動(dòng)化推導(dǎo)。
清理可執(zhí)行文件
我們?cè)诟牧嗽次募拇a之后,需要清除可執(zhí)行文件后重新編譯。那么清除可執(zhí)行文件能否使用 make
命令呢?那肯定是可以的撒!
clean:rm -f test
其中,clean
是依賴關(guān)系,冒號(hào)右側(cè)為空說明表明沒有依賴的文件。那么我們應(yīng)該如何使用這個(gè)依賴關(guān)系呢?
執(zhí)行命令:make clean
即可。
make clean
我們看到順利運(yùn)行了呢!
將 clean
放在 makefile
文件的最開頭
如果我們像這樣寫 makefile
文件會(huì)發(fā)生什么呢?
clean:rm -f test
test:test.cgcc -o test test.c
可以看到我們想要編譯文件就需要使用命令:make test
,而 make
命令變成了執(zhí)行:rm -f test
。
由此可見:make
命令會(huì)從上到下掃描 makefile
文件,將掃描到的第一個(gè)依賴關(guān)系作為 make
命令的默認(rèn)行為。
不推薦將依賴關(guān)系 clean
放在 makefile
文件的開頭。
make
命令編譯多個(gè)文件
多個(gè)源文件生成一個(gè)可執(zhí)行程序
我們寫一個(gè)代碼:在 function.h
中聲明一個(gè) Add
函數(shù),在 function.c
中實(shí)現(xiàn) Add
函數(shù),然后在 test.c
中調(diào)用 Add
函數(shù)。
function.h
:
#pragma once
int Add(int a, int b);
function.c
:
int Add(int a, int b)
{return a + b;
}
test.c
:
#include<stdio.h>
#include "function.h"
int main()
{int a, b;scanf("%d %d", &a, &b);printf("a + b 的結(jié)果:%d\n", Add(a, b));return 0;
}
我們想要編譯 function.h function.c test.c
應(yīng)該怎么做呢?其實(shí)很簡(jiǎn)單哈!
test:function.c test.cgcc -o test test.c function.c
clean:rm -f test
如果是多個(gè)源文件生成一個(gè)可執(zhí)行程序,只需要在依賴文件中以空格隔開多個(gè)源文件即可。如果 .h
文件在源文件的當(dāng)前目錄,依賴文件中是不需要寫 .h
文件的!
多個(gè)源文件生成多個(gè)可執(zhí)行程序
如果在 makefile
文件的目錄下有多個(gè)源文件,并且想要將這些個(gè)源文件分別編譯成可執(zhí)行文件應(yīng)該怎么做呢?你可以先想一想🤔,你應(yīng)該是有能力寫出來的。
我們來寫這樣兩個(gè)源文件:test1.c
和 test2.c
test1.c
:
#include<stdio.h>int main()
{printf("i am test1.c\n");return 0;
}
test2.c
:
#include<stdio.h>int main()
{printf("i am test2.c\n");return 0;
}
我們要使用 make
命令講他們分別編譯成:test1
和 test2
兩個(gè)可執(zhí)行文件。makefile
文件可以這樣寫:
All:test1 test2
test1:test1.cgcc -o test1 test1.c
test2:test2.cgcc -o test2 test2.c
clean:rm -f test1 test2
依賴關(guān)系:All
依賴于 test1 和 test2
,make
命令掃描 makefile
文件,發(fā)現(xiàn)源文件當(dāng)前目錄不存在 test1 和 test2
那么就會(huì)繼續(xù)向下掃描。當(dāng)掃描到 test1 和 test2
這兩個(gè)依賴關(guān)系,他們的依賴文件都在源文件的當(dāng)前目錄??梢灾苯訄?zhí)行他們 Tab
縮進(jìn)的代碼,生成 test1 和 test2
,最后完成兩個(gè)源文件的編譯生成兩個(gè)可執(zhí)行文件。
我們可以看到執(zhí)行 make
命令之后也是順利生成了 test1
和 test2
兩個(gè)可執(zhí)行文件了呢!
make
可以重復(fù)編譯嗎?為什么?
我們還是回到最開始的那個(gè)代碼:
test.c
:
#include<stdio.h>
int main()
{printf("hello make!\n");return 0;
}
makefile
:
test:test.cgcc -o test test.c
clean:rm -f test
我們發(fā)現(xiàn)在不修改代碼的情況下,是不允許二次編譯的:
這是為什么呢?
顯然是因?yàn)闆]有這個(gè)必要哈,既然你的源文件沒有被修改為什么要為你重新編譯呢?
那這個(gè)是怎么做到的呢?
- 一般來說,我們都是先有源文件,再有可執(zhí)行程序。這就意味著源文件的最近修改時(shí)間比可執(zhí)行程序的最近修改時(shí)間要早。
- 因此,我們只需要比較可執(zhí)行程序的最近修改時(shí)間和源文件的最近修改時(shí)間,就可以判斷源文件是否需要重新被編譯啦!
🤔思考:源文件的最近修改時(shí)間會(huì)和可執(zhí)行程序的最近修改時(shí)間想等嗎?這個(gè)一般是不會(huì)的!😊
那么,這個(gè)用來比較的時(shí)間哪里來呢?
我們先來學(xué)習(xí)一個(gè)命令吧:這個(gè)命令可以查看一個(gè)文件的時(shí)間狀態(tài)。
stat 文件
Access Modify Change
這三個(gè)時(shí)間稱為文件的 ACM
時(shí)間。
- Access:最近訪問時(shí)間,幾乎文件的任何操作之后,這個(gè)時(shí)間都會(huì)發(fā)生改變。
- Modify:當(dāng)對(duì)文件的內(nèi)容做出修改之后,這個(gè)時(shí)間就會(huì)更新。
- Change:當(dāng)對(duì)文件的屬性做出修改之后,這個(gè)時(shí)間就會(huì)更新。
這就意味著,一旦對(duì)文件的內(nèi)容做出修改,Access Modify Change
時(shí)間都會(huì)被更新。
因?yàn)?
Access
時(shí)間要被頻繁被修改,在實(shí)際的實(shí)現(xiàn)中Access
時(shí)間的更新是有一定的更新策略(例如:當(dāng)Modiify
或者Change
時(shí)間到達(dá)一定的次數(shù)之后再更新Access
時(shí)間),而不是根據(jù)Access
時(shí)間的定義那樣,操作一次文件都要更新這個(gè)時(shí)間。
原因:文件是被存放在磁盤中的,將數(shù)據(jù)刷新到磁盤的速度是比較慢的,頻繁地修改Access
時(shí)間勢(shì)必會(huì)影響操作系統(tǒng)的效率的。
在判斷源文件是否需要重新編譯,就是根據(jù)源文件和可執(zhí)行程序 Modify
時(shí)間的比較結(jié)果來判定的!
如何驗(yàn)證呢?
再來學(xué)習(xí)一個(gè)命令吧:
touch 文件名
這個(gè) touch
命令除了能夠創(chuàng)建一個(gè)普通文件,還有一個(gè)功能就是:當(dāng)這個(gè)文件已經(jīng)存在時(shí),能更新一個(gè)文件的 ACM
時(shí)間到當(dāng)前的最新時(shí)間。
因此,我們可以更新源文件的 ACM
時(shí)間到最新,使得 make
命令可以反復(fù)編譯一個(gè)相同的源文件。
我們看到,第一次可以順利編譯,這很正常。第二次使用
make
編譯的時(shí)候就不能了!我們?cè)诟略次募?ACM
時(shí)間之后又能使用 make
編譯了!由此可以驗(yàn)證就是通過比較源文件與可執(zhí)行文件的時(shí)間來判斷是否能使用 make
再次編譯的!
如何讓一個(gè)依賴關(guān)系一直被執(zhí)行
我們上面講了通過 touch
命令可以使用 make
一直編譯。但是,還是不建議這么做,沒有修改源文件就不要重復(fù)編譯,這很好,不是嗎!
但是清理可執(zhí)行文件的依賴關(guān)系,我們就有這個(gè)需求,讓他總是被執(zhí)行。那么 makefile
文件應(yīng)該怎么寫呢?
test:test.cgcc -o test test.c
.PHONY:clean
clean:rm -f test
makefile
文件中被 .PHONY
修飾的依賴關(guān)系就可以被一直執(zhí)行啦!
你若不信,就可以給可執(zhí)行文件 test
這個(gè)依賴關(guān)系加上 .PHONY
修飾,看能不能 make
重復(fù)編譯(不建議這么做!!!)。
特殊符號(hào)
- $@:表示:
依賴關(guān)系:依賴方法
中冒號(hào)前面的一坨! - @^:表示:
依賴關(guān)系:依賴方法
中冒號(hào)后面的一坨!
那么,我們寫 makefile
文件就可以這么寫啦:
test:test.cgcc -o $@ $^
.PHONY:clean
clean:rm -f test
在這個(gè) makefile
文件中:$@
就是 test
,$^
就是 test.c
。
==這才是我們?cè)谄綍r(shí)用的最多的 makefile
文件的編寫方法啦!==😊
取消回顯
我們?cè)谑褂?make
的時(shí)候是不是能看到 make
推導(dǎo)出來的要執(zhí)行的指令的內(nèi)容!像這樣:
如果你不想回顯命令,只需要在指令前面加上 @
符號(hào)就可以啦!
test:test.c@gcc -o $@ $^
.PHONY:clean
clean:@rm -f test