剛開始用make的時候,以為makefile中名字叫做main的target就是make默認執行的target(中文翻譯叫做標的(di,四聲),下面統一稱呼為標的),然后曾經很天真地犯過這樣的錯誤,就一個.c文件(名字叫做main.c),功能是打印helloworld,然后我寫了這樣的makefile來編譯:
main: gcc -o main main.c
結果第一次make命令能編譯,后面如果還想再用make命令編譯的話,就會出現這樣的錯誤:
即使更改了main.c中的代碼,也會出現這樣的錯誤。當時我一直想不通,為什么第一次能編譯,后面編譯就會報錯呢,后來學習了一下makefile的語法,才知道makefile是這樣定義的。
target ...: PRerequisites command command
target代表的是一個 標的,prerequisites代表的是這個標的所依賴的標的,下面那個command就是生成這個標的的命令。
那么那個標的代表的是什么呢?其實它就是代表了一個與他同名的文件,編譯之后生成的.o文件,編譯鏈接之后生成的可執行文件或者其他任何類型的文件,例如main這個標的代表的就是main這個可執行文件。
可能這樣將有點晦澀,就拿我上面那個錯誤來舉例,在上面那個例子中,執行make之后,它做的工作是這樣的:
1.查找makefile,默認執行第一個標的(即main)。
2.檢查main這個文件存不存在或者需不需要更新。
3.如果main文件不存在,則執行下面那個gcc命令來生成這個文件。
4.如果main文件已經存在,且它的修改時間要早于依賴文件的修改時間(即這個main文件過期了),那么執行下面的gcc命令來生成這個文件。
看了上面那個步驟,大家應該就能理解為什么我上面會報錯了吧,就是由于我那個main標的所依賴的文件為空,所以那個main文件永遠不會過期,所以,每回執行make命令都會提示main is up to date.(意思是這個文件是最新的,不需要更新了)
那么該怎么做才是對的呢,我們可以改成這種形式:
main: main.c gcc -o main main.c
這里給main這個標的添加了一個依賴,依賴于main.c這個文件,如果main.c這個文件的修改時間晚于main這個文件的修改時間,那么就執行下面的gcc命令來生成main這個文件。
OK,分析完了這個,我們再來分析一下另一個經典的標的,clean,還是上面的栗子,我添加上clean的標的,就是刪除生成的main這個可執行文件,如下所示:
main: main.c gcc -o main main.cclean: rm main
此時如果我運行了make clean命令,那么就會刪除main這個可執行文件,那么這個標的的原理是什么呢?其實當我們運行了make clean命令之后,它的執行步驟是這樣的:
由于clean標的沒有依賴的文件,所以它就是檢查clean這個文件是否存在,如果不存在,那么執行clean標的下面的命令來生成clean文件。但是下面的rm命令又不會生成clean文件,所以導致的結果就是每回我們運行make clean命令,都會執行下面的rm命令。如下圖所示:
那么如果我們在當前目錄下添加上一個clean文件會怎么樣呢,就會出現下面的效果了:
這次,clean標的下面的命令都不會被執行了。
為了解決這種沖突,我們可以把clean定義成一個偽目標文件。具體如下:
這樣,即使當前目錄下面存在clean這個文件,make clean命令也會照常執行,如下圖所示:
還有一點需要注意的是,clean標的的命令中,rm前面那個-號表示如果中途出錯,則會忽略錯誤,繼續執行。例如如果main.o,不存在,make clean會報錯,但不會停止,如下圖所示:
OK,我想聊的makefile的內容就是這些,最后來總結一下吧。
1.makefile中的每個標的都代表了一個文件。
2.如果只運行make命令,那么默認執行第一個標的。
3.執行一個標的時,會做兩件事情:
3.1.查看與這個標的同名的文件是否存在,如果不存在,那么就運行這個標的下面的命令。
3.2.如果與這個標的同名的文件已經存在,那么就檢查與這個標的同名的文件是否需要更新(即標的文件的修改時間是否早于依賴文件的修改時間),如果需要更新,那么就運行這個標的下面的命令。
新聞熱點
疑難解答