Makefile 系統說明

要理解本文的內容,你需要以下的知識:




無遞歸 Make


Make 是所有系統開發平台的項目編譯、連接以及組件依存管理等工作的管理工具,不同的平台有不同的Make 版本,譬如Linux 下常見的GNU Make, FreeBSD 下的 BSD Make 等。


(!) 很多人以為Make 是Unix/Linux 下專有的。其實並不是這樣, Windows 下的項目管理用的是 NMake只不過是大部分人在Windows 下開發都用的是“好用” Visual Studio, NMake 被包裝和隱藏起來了,但是當項目複雜的時候,那套“好用的” IDE 機制就變得不再適用了。 記得早些年,我為我開發的汽車防爆膜開膜機編寫上位機CAD時, 很多編譯連接、以及組件依存關係就很難控制。


同樣,為一個複雜的項目編寫一個好的Makefile 也不是一件容易的事,編寫Makefile 通常有兩種方式:



  • Recursive Make (遞歸 make)
  • Non-recursive Make (無遞歸 make)

Recursive Make 就是make 跳轉到項目的各個組件目錄中進行編譯連接, GNU automake/autoconfig 生成的makefile 就是採用的這樣的機制, 但是這種方式對於手工寫makefile 來說似乎會帶來很多的麻煩,請參看著名文檔 Recursive Make Considered Harmful


LanDog 的 Makefile 採用 Non-recursive Make 的方式,這種方式的大體思想是將項目的所有組件控制變量都用Make 的偽指令“include”, 包含到頂層Makefile 中,而有頂層Makefile 統一進行規則處理。 Linux 內核的Makefile 也基本是這一管理思想的體現。



項目佈局



 landog/
|
+- Makefile # 頂層 Makefile 文件
+- README # 自述文件
|
+- include/ # 各個組件的頭文件根目錄
| |
| +- sniff/ # 網絡監控頭文件
| +- cgic/ # lib CGIC 第三方庫頭文件目錄
|
+- lib/ # 各個庫組件的實現源文件跟目錄
| |
| +- sniff/ # 網絡監控庫目錄
| +- cgic/ # lib CGIC 第三方庫源碼目錄
|
+- app/ # 應用程序跟目
| |
| +- sniff/ # 網絡監控程序目錄
| +- sniffweb/ # CGI Web 應用程序目錄
|
+- doc/ # 文檔目錄
|
+- db/ # 數據庫目錄





文件名稱及make變量命名約定



Makefile的基本變量


LanDog Top-level Makefile 的開頭定義了 LanDog 項目管理的基本變量:


modules := $(subst /module.mk,,$(shell find . -type f -name module.mk))

sources :=
objects :=
libraries :=
programs :=

cgi_bins :=

dependencies = $(subst .c,.d,$(sources))

include_dirs := ./include
CPPFLAGS += -Wall -g $(addprefix -I,$(include_dirs))
vpath %.h $(include_dirs)


利用 gcc -MM 選項生成 make 規則


以下代碼片段實現如何由*c 文件生成make 依賴規則文件*.d,並對這段代碼進行詳細的分析。


%.d: %.c
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -MM $< | \
$(SED) 's,\($(notdir $*)\.o\) *:,$(dir $@)\1 $@: ,' > $@.tmp
$(MV) $@.tmp $@


說明:




  • $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH -MM $< | \



這裡是利用gcc -M 選項生成編譯%.c 文件時的make 依賴規則, 並通過輸出管道"|" 輸出到流編輯器sed, 再由sed 來進一步編輯依賴關係。 -M 選項是gcc 的重要特性, 該選項使gcc 自動分析並輸出編譯生成*.o 文件的依賴關係以便make 調用, 詳情請參閱gcc 和make 的文檔。 例如:


$ cat foo.c
#include "foo.h"

int main(void)
{
printf("foo say hello\n");
return 0;
}

$ gcc -I../include -M foo.c
foo.o: foo.c ../include/foo.h



  • $(SED) 's,\($(notdir $*)\.o\) *:,$(dir $@)\1 $@: ,' > $@.tmp



這裡是用流編輯器sed 對通過管道由"gcc -M" 傳遞過來的make 依賴規則進行進一步的編輯, (!) 注意這裡採用了逗號"," 作為sed 的匹配替換模板分隔符, 和常見的sed 匹配替換模板分隔符"/" 和":" 是等效的,因此,這個語句和下面的語句是等效的:


$(SED) 's/\($(notdir $*)\.o\) *:/$(dir $@)\1 $@: /' > $@.tmp


 


 


http://cky0612.blog.163.com/blog/static/2747891620077163541642/

arrow
arrow
    全站熱搜

    立你斯 發表在 痞客邦 留言(0) 人氣()