天天看點

跟我一起寫 Makefile(三)

Makefile 總述

———————

一、Makefile裡有什麼?

Makefile裡主要包含了五個東西:顯式規則、隐晦規則、變量定義、檔案訓示和注釋。

1、顯式規則。顯式規則說明了,如何生成一個或多的的目标檔案。這是由Makefile的書寫者明顯指出,要生成的檔案,檔案的依賴檔案,生成的指令。

2、隐晦規則。由于我們的make有自動推導的功能,是以隐晦的規則可以讓我們比較粗糙地簡略地書寫Makefile,這是由make所支援的。

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

4、檔案訓示。其包括了三個部分,一個是在一個Makefile中引用另一個Makefile,就像C語言中的include一樣;另一個是指根據某些情況指定Makefile中的有效部分,就像C語言中的預編譯#if一樣;還有就是定義一個多行的指令。有關這一部分的内容,我會在後續的部分中講述。

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

最後,還值得一提的是,在Makefile中的指令,必須要以[Tab]鍵開始。

二、Makefile的檔案名

預設的情況下,make指令會在目前目錄下按順序找尋檔案名為“GNUmakefile”、“makefile”、“Makefile”的檔案,找到了解釋這個檔案。在這三個檔案名中,最好使用“Makefile”這個檔案名,因為,這個檔案名第一個字元為大寫,這樣有一種顯目的感覺。最好不要用“GNUmakefile”,這個檔案是GNU的make識别的。有另外一些make隻對全小寫的“makefile”檔案名敏感,但是基本上來說,大多數的make都支援“makefile”和“Makefile”這兩種預設檔案名。

當然,你可以使用别的檔案名來書寫Makefile,比如:“Make.Linux”,“Make.Solaris”,“Make.AIX”等,如果要指定特定的Makefile,你可以使用make的“-f”和“--file”參數,如:make -f Make.Linux或make --file Make.AIX。

三、引用其它的Makefile

在Makefile使用include關鍵字可以把别的Makefile包含進來,這很像C語言的#include,被包含的檔案會原模原樣的放在目前檔案的包含位置。include的文法是:

    include <filename>

    filename可以是目前作業系統Shell的檔案模式(可以保含路徑和通配符)

在include前面可以有一些空字元,但是絕不能是[Tab]鍵開始。include和<filename>可以用一個或多個空格隔開。舉個例子,你有這樣幾個Makefile:a.mk、b.mk、c.mk,還有一個檔案叫foo.make,以及一個變量$(bar),其包含了e.mk和f.mk,那麼,下面的語句:

    include foo.make *.mk $(bar)

    等價于:

    include foo.make a.mk b.mk c.mk e.mk f.mk

make指令開始時,會把找尋include所指出的其它Makefile,并把其内容安置在目前的位置。就好像C/C++的#include指令一樣。如果檔案都沒有指定絕對路徑或是相對路徑的話,make會在目前目錄下首先尋找,如果目前目錄下沒有找到,那麼,make還會在下面的幾個目錄下找:

    1、如果make執行時,有“-I”或“--include-dir”參數,那麼make就會在這個參數所指定的目錄下去尋找。

    2、如果目錄<prefix>/include(一般是:/usr/local/bin或/usr/include)存在的話,make也會去找。

如果有檔案沒有找到的話,make會生成一條警告資訊,但不會馬上出現緻命錯誤。它會繼續載入其它的檔案,一旦完成makefile的讀取,make會再重試這些沒有找到,或是不能讀取的檔案,如果還是不行,make才會出現一條緻命資訊。如果你想讓make不理那些無法讀取的檔案,而繼續執行,你可以在include前加一個減号“-”。如:

    -include <filename>

    其表示,無論include過程中出現什麼錯誤,都不要報錯繼續執行。和其它版本make相容的相關指令是sinclude,其作用和這一個是一樣的。

四、環境變量 MAKEFILES

如果你的目前環境中定義了環境變量MAKEFILES,那麼,make會把這個變量中的值做一個類似于include的動作。這個變量中的值是其它的Makefile,用空格分隔。隻是,它和include不同的是,從這個環境變中引入的Makefile的“目标”不會起作用,如果環境變量中定義的檔案發現錯誤,make也會不理。

但是在這裡我還是建議不要使用這個環境變量,因為隻要這個變量一被定義,那麼當你使用make時,所有的Makefile都會受到它的影響,這絕不是你想看到的。在這裡提這個事,隻是為了告訴大家,也許有時候你的Makefile出現了怪事,那麼你可以看看目前環境中有沒有定義這個變量。

五、make的工作方式

GNU的make工作時的執行步驟入下:(想來其它的make也是類似)

    1、讀入所有的Makefile。

    2、讀入被include的其它Makefile。

    3、初始化檔案中的變量。

    4、推導隐晦規則,并分析所有規則。

    5、為所有的目标檔案建立依賴關系鍊。

    6、根據依賴關系,決定哪些目标要重新生成。

    7、執行生成指令。

1-5步為第一個階段,6-7為第二個階段。第一個階段中,如果定義的變量被使用了,那麼,make會把其展開在使用的位置。但make并不會完全馬上展開,make使用的是拖延戰術,如果變量出現在依賴關系的規則中,那麼僅當這條依賴被決定要使用了,變量才會在其内部展開。

當然,這個工作方式你不一定要清楚,但是知道這個方式你也會對make更為熟悉。有了這個基礎,後續部分也就容易看懂了.

繼續閱讀