【Linux筆記】make工程管理工具(二)

  • 2019 年 11 月 28 日
  • 筆記

1、前言

上一篇筆記分享了使用make工具編譯C程式的方法(【Linux筆記】make工程管理工具(一)),但是還未分享make工具是什麼,本篇筆記就來看一下make工具是什麼吧。

make和Makefile(或者makefile)文件提供了一種簡單有效的工程管理方式。Makefile文件是一個決定著如何編譯工程的文本,有一定的書寫規則。make是一個GNU命令工具,用來解釋Makefile文件中的命令來編譯我們的工程。

2、make工具

make 是一個命令工具,是一個解釋 Makefile 中指令的命令工具,一般來說,大多數的 IDE(集成開發環境) 都有這個命令,比如:Delphi 的 make,Visual C++的 nmake。但是在Linux 下一般不具有IDE,所以我們需要學會如何使用make工具來編譯。

3、Makefile文件的書寫規範

Makefile文件中最重要的是規則。規則的格式如下:

target:prerequisites      command

其中,target 為目標,prerequisites 為依賴。command 為make需要執行的命令。

  • 目標:往往是程式的中間或者最終生成的文件名,比如目標文件、可執行文件等。
  • 依賴:是指用來產生目標文件的輸入文件名,一個目標往往依賴於一個或多個文件。
  • 命令:是指任何一個文件發生改動之後,需要重新生成目標文件需要執行的命令,這裡可以有多條命令,但是每個命令必須單獨佔一行,且需要注意的是,每個命令的前面必須有一個<tab鍵>,因為make是用過來識別命令行的,進而完成相應的動作。

例如,上一篇我們的筆記中為編譯hello.c書寫的Makefile文件如下:

其中,第1、2行為一條規則,第4、5行為一條規則,第7、8行為一條規則,第10、11行為一條規則,第13、14行為一條規則。

拿第1、2行這一條規則來舉例說明, hello 為目標文件, hello.o 為依賴文件, gcc hello.o -o hello 為命令。除此之外,這個文件中, #符號後面是注釋, clean 是一個特殊的目標,它沒有依賴,稱為偽目標。

規則是Makefile文件中的最基本的、也是最核心的部分。Makefile中還有其他內容。

Makefile文件主要包含5個方面內容:顯示規則、隱式規則、變數、文件指示、注釋、實目標與偽目標等。

(1)顯式規則。顯式規則說明了,如何生成一個或多的的目標文件。這是由 Makefile 的書寫者明顯指出,要生成的文件,文件的依賴文件,生成的命令。如

hello:hello.o      gcc hello.o -o hello

這就是一條顯示規則。

(2)隱式規則。隱含規則是系統或用戶預先定義好的一些特殊規則,主要是一些常用的依賴關係和更新命令。一般規則使用文件的全名,而隱含規則中出現的目標文件和依賴文件都只使用文件的擴展名。

如果Makefile 文件裡面沒有顯式給出文件的依賴關係的時候,make 就會根據文件的擴展名找到相應的隱含規則,然後按照隱含規則來更新目標。隱式規則的例子是:

hello:hello.o      $(CC) $^ -o $@

(3)變數定義。在 Makefile 中我們要定義一系列的變數,變數一般都是字元串,這個有點像 C 語言中的宏,當 Makefile 被執行時,其中的變數都會被擴展到相應的引用位置上。如:

其中 CC 為變數的定義, $(CC) 為變數的調用。 $^、 $@也是變數的調用,這兩個變數是Makefile文件中最常用的變數(不需要自己定義),$^ 代表當前規則中所有的依賴文件, $@ 代表當前規則的目標文件。

(4)文件指示。其包括了三個部分,一個是在一個 Makefile 中引用另一個 Makefile,就像 C 語言中的 include 一樣;另一個是指根據某些情況指定 Makefile 中的有效部分,就像 C 語言中的預編譯#if 一樣;還有就是定義一個多行的命令。

(5)注釋。Makefile 中只有行注釋,和 UNIX 的 Shell 腳本一樣,其注釋是用 # 字元,這個就像C/C++中的//一樣。如果你要在你的Makefile 中使用#字元,可以用反斜框進行轉義,如:#。

(6)實目標與偽目標。Makefile 文件中的目標分為兩類:實目標和偽目標。

實目標是真正要生成的以文件形式存放在磁碟上的目標。如:

hello:hello.o      $(CC) $^ -o $@ # 鏈接

其中,hello 文件就是實目標;

而偽目標不要求生成實際的文件,它主要是用於完成一些輔助操作。如:

clean:      rm -rf hello.i hello.s hello.o hello # 刪除編譯生成文件

其中的 clean 就是一個偽目標。我們在命令裡面輸入命令: make clean 就可以執行刪除操作: rm -rf hello.i hello.s hello.o hello 。

但是這種書寫形式不是很嚴謹,因為可能在當前目錄下面存在文件名為 clean 的文件,因為這時候, 後面沒有依賴文件,所以make 就認為這個文件是最新的,所以就不會執行 rm -rf hello.i hello.s hello.o hello 。所以為了避免這種情況的發生,所以建議使用這種寫法:

.PHONY:clean  clean:      rm -rf hello.i hello.s hello.o hello # 刪除編譯生成文件

使用 .PHONY 說明clean是一個偽目標。

4、make是如何工作的?

當我們只輸入make 命令。那麼:

(1)make 會在當前目錄下找名字叫Makefile或makefile的文件。

(2)如果找到,它會找文件中的第一個目標文件(target),在上面的例子中,它會找到hello這個文件,並把這個文件作為最終的目標文件 。

(3)如果 hello文件不存在,或是hello 所依賴的後面的 .o文件,的文件修改時間要比 hello 這個文件新,那麼,他就會執行後面所定義的命令來生成 hello 這個文件。 (4)如果hello所依賴的 .o 文件也存在,那麼make會在當前文件中找目標為.o文件的依賴性,如果找到則再根據那一個規則生成.o文件。(這有點像一個堆棧的過程) (5)當然,我們的c文件和h 文件是存在的啦,於是 make 會生成 .o文件,然後再用 .o 文件生命make 的終極任務,也就是執行文件 hello了。

這就是整個make 的依賴性,make 會一層又一層地去找文件的依賴關係,直到最終編譯出第一個目標文件。在找尋的過程中,如果出現錯誤,比如最後被依賴的文件找不到,那麼 make 就會直接退出,並報錯,而對於所定義的命令的錯誤,或是編譯不成功,make 根本不理。

像clean 這種偽目標,沒有被第一個目標文件直接或間接關聯,那麼它後面所定義的命令將不會被自動執行。

以上就是本次的筆記分享,主要介紹make工具、Makefile文件大概有哪些內容、make是如何工作的。如有錯誤,歡迎指出!

參考資料:

《嵌入式Linux上的C語言編程實踐》、  https://segmentfault.com/a/1190000003756084#articleHeader4、  https://blog.csdn.net/haoel/article/details/2886

如果你覺得對你有用的話,麻煩幫忙點個贊。如果你覺得對你的同學與朋友也有用的話,歡迎轉發。

Tags: