1 引言
衆所周知,Makefile主要用來組織源碼的編譯,其語法在此不做闡述。經分析可發現,源碼的組織結構通常有以下3種形式:
1) flat:所有文件都處在同一目錄
所有源文件、頭文件以及相關的庫文件都處在當前的目錄中,不存在任何子目錄。
2) shallow:主要源代碼處在頂層目錄,其他各部分處在子目錄
主要源文件在當前目錄中,而其它一些實現各部分功能的源文件位於各自不同的目錄。
3) deep:所有源代碼處在子目錄,頂層目錄存放配置信息
所有源文件及自己寫的頭文件位於當前目錄的一個子目錄中,而當前目錄裏沒有任何源文件。
使用automake對以上3種源碼組織結構的編譯過程在某些細節上存在一些差異,但是大概流程是一致的,如下圖所示:
圖1 生成Makefile的過程
2 創建過程
2.1 FLAT
根據引言中對flat源碼結構的描述“所有源文件、頭文件以及相關的庫文件都處在當前的目錄中,不存在任何子目錄”可知其目錄結構如下圖所示:
圖2 flat源碼結構
(注:將algo.c改爲algo.h)
目錄說明:
add.c:實現加法運算 int my_add(int a, int b) { return (a + b); }
sub.c:實現減法運算 int my_sub(int a, int b) { return (a - b); }
mul.c:實現乘法運算 intmy_mul(int a, int b) { return(a
* b); }
div.c: 實現除法運算 intmy_div(int a, int b) { return(a
/ b); }
algo.h:頭文件聲明源碼中實現的函數
test.c:在主函數中調用以上源文件實現的函數,並展示運算結果
編譯步驟:
1) 執行autoscan
在目錄中執行autoscan命令,會生成文件configure.scan,再將其重命名爲configure.in,最後還需要做如下修改。
#autoscan
#mv configure.scan configure.in
#vim configure.in
修改過程:
①、將AC_CONFIG_SRCDIR([sub.c])改爲AC_CONFIG_SRCDIR([test.c]) - 注:使用有主函數main()的源文件test.c取代sub.c
②、將AC_CONFIG_HEADER([config.h])改爲AM_CONFIG_HEADER([config.h])
③、新增AM_INIT_AUTOMAKE(math, 1.0):其中math是希望生成的可執行程序的名字,1.0表示版本號
④、將AC_OUTPUT改爲AC_OUTPUT(Makefile):表示要創建的Makefile名
圖3 修改前後對比
2) 配置Makefile.am
在當前目錄中新建Makefile.am文件,生成可執行文件math,因此其配置內容爲:
圖4 Makefile.am
3) 新建文件
在當前目錄下新建文件NEWS、README、ChangeLog、AUTHORS文件,內容爲空;
#touch NEWS
#touch README
#touch ChangeLog
#touch AUTHORS
4) 生成configure
#aclocal —— 該命令將以configure.in爲輸入文件,生成aclocal.m4
#autoconf —— 該命令將以configure.in和aclocal.m4爲輸入文件,生成文件configure
#autoheader
5) 生成Makefile.in
#automake -a (該命令將以configure.in和Makefile.am爲輸入文件,生成文件Makefile.in)
6) 執行./configure
配置安裝程序,並生成Makefile
7) 編譯源碼
經過以上步驟,已經生成了Makefile,此時只需執行make,便可以編譯源碼,並生成可執行程序了;
8) 運行結果
完成以上所有操作之後,在當前目錄下就生成了可執行程序math,其最終的運行結果如下圖所示:
圖5 flat結果
2.2 SHALLOW
根據引言中對shallow源碼結構的描述“主要源文件在當前目錄中,而其它一些實現各部分功能的源文件位於各自不同的目錄”可知其目錄結構如下圖所示:
圖6 shallow源碼結構
目錄說明:
add/add.c:實現加法運算 int my_add(int a, int b) { return (a + b); }
sub/sub.c:實現減法運算 int my_sub(int a, int b) { return (a - b); }
mul/mul.c:實現乘法運算 int my_mul(int a, int b) { return (a * b); }
div/div.c: 實現除法運算 int my_div(int a, int b) { return (a / b); }
incl/algo.h:頭文件聲明源碼中實現的函數
test.c:在主函數中調用以上源文件實現的函數,並展示運算結果
編譯步驟:
1) 執行autoscan
在目錄中執行autoscan命令,會生成文件configure.scan,再將其重命名爲configure.in,最後還需要做如下修改。
#autoscan
#mv configure.scan configure.in
#vim configure.in
修改過程:
①、將AC_CONFIG_HEADER([config.h])改爲AM_CONFIG_HEADER([config.h])
②、新增AM_INIT_AUTOMAKE(math, 2.0):其中math是希望生成的可執行程序的名字,2.0表示版本號
③、將AC_OUTPUT改爲AC_OUTPUT([Makefile
./add/Makeifle
./sub/Makefile
./mul/Makefile
./div/Makefile]):表示要創建的Makefile名
圖7 修改前後對比
2) 配置Makefile.am
現在存在的目錄有頂層目錄math、add、sub、mul、div和incl,因此需要分別在對應新建Makefile.am文件,一共6個。
1) 頂層目錄的Makefile.am
圖8 頂層目錄Makefile.am
配置說明:
①、SUBDIRS:用來指明源文件、庫文件所在目錄
②、CURRENTPATH:獲取當前代碼所在目錄
③、INCLUDES:指明頭文件所在目錄
④、bin_PROGRAMS:指明生成的可執行文件的名稱exec
⑤、exec_SOURCES: 指明可執行程序依賴的源文件
⑥、exec_LDADD:指明鏈接時依賴的文件
⑦、exec_LDFLAGS:指明鏈接時需要的選項
⑧、DEFS:指明編譯選項
⑨、LIBS:指明程序還需要包含的庫
2) 源文件目錄Makefile.am
圖9 子目錄add中的Makefile.am
這裏使用了欺騙手段,欺騙automake需要生成可執行程序add,讓它生成依賴文件add.o和執行命令。所以當運行完automake命令後,需要修改對應目錄下的Makefile.in,刪除其中的LINK語句。
配置說明:
①、noinst_PROGRAMS:指明需要生成的可執行程序的名稱,在此因爲不要安裝,所以使用關鍵字noinst_PROGRAMS;如果需要安裝,則使用bin_PROGRAMS。
②、exec_SOURCES:指明可執行程序依賴的文件名
③、DEFS:指明編譯選項
因sub、mul以及div目錄的作用與add相似,因此,他們的Makefile.am配置是極其相似,只需將其中的add改爲sub、mul或div即可,在此不再迭述。
3) 頭文件Makefile.am
將被源碼使用的頭文件加入到對應的變量include_HEADERS中即可:
圖10 頭文件Makefile.am
3) 新建文件
在當前目錄下新建文件NEWS、README、ChangeLog、AUTHORS文件,內容爲空;
#touch NEWS
#touch README
#touch ChangeLog
#touch AUTHORS
4) 生成configure
#aclocal —— 該命令將以configure.in爲輸入文件,生成aclocal.m4
#autoconf
—— 該命令將以configure.in和aclocal.m4爲輸入文件,生成文件configure
#autoheader
5) 生成Makefile.in
#automake -a —— 該命令將以configure.in和Makefile.am爲輸入文件,生成文件Makefile.in
因生成add.o、sub.o、mul.o和div.o使用了欺騙的手段,所以當運行完automake命令後,需要修改對應目錄下的Makefile.in,刪除其中的LINK語句。
圖11 修改前後對比
因add、sub、mul與div的功能相似,所以其修改過程也是極其一致的,在此不再迭述。
6) 執行./configure
配置安裝程序,並生成Makefile
7) 編譯源碼
#make
#make install
便可完成源碼的編譯和程序的安裝;
8) 運行結果
完成以上所有操作之後,在當前目錄下就生成了可執行程序math,其最終的運行結果如下圖所示:
圖12 shallow編譯結果
2.3 DEEP
根據引言中對deep源碼結構的描述“所有源文件都放在子目錄中,頂層目錄只放配置信息”可知其目錄結構如下圖所示:
圖13 deep源碼結構
目錄說明:
add/add.c:實現加法運算 int my_add(int a, int b) { return (a + b); }
sub/sub.c:實現減法運算 int my_sub(int a, int b) { return (a - b); }
mul/mul.c:實現乘法運算 int my_mul(int a, int b) { return (a * b); }
div/div.c: 實現除法運算 int my_div(int a, int b) { return (a / b); }
incl/algo.h:頭文件聲明源碼中實現的函數
main/test.c:在主函數中調用以上源文件實現的函數,並展示運算結果
編譯步驟:
1) 執行autoscan
在目錄中執行autoscan命令,會生成文件configure.scan,再將其重命名爲configure.in,最後還需要做如下修改。
#autoscan
#mv configure.scan configure.in
#vim configure.in
修改過程:
①、將AC_CONFIG_SRCDIR([mul/mul.c])改爲AC_CONFIG_SRCDIR([main/test.c])
②、將AC_CONFIG_HEADER([config.h])改爲AM_CONFIG_HEADER([config.h])
③、新增AM_INIT_AUTOMAKE(math, 3.0):其中math是希望生成的可執行程序的名字,2.0表示版本號
④、在AC_CONFIG_FILES([add/Makefile ...])中再添加一行main/Makefile
⑤、將AC_OUTPUT改爲AC_OUTPUT([Makefile])
圖14 修改前後對比
2) 配置Makefile.am
現在存在的目錄有頂層目錄math、add、sub、mul、div、main和incl,因此需要分別在對應新建Makefile.am文件,一共7個。
1) 頂層目錄的Makefile.am
圖15 頂層目錄Makefile.am
配置說明:
①、SUBDIRS:用來指明源文件、庫文件所在目錄
②、CURRENTPATH:獲取當前代碼所在目錄
③、INCLUDES:指明頭文件所在目錄
2) 源文件目錄Makefile.am
圖16 子目錄add中的Makefile.am
這裏使用了欺騙手段,欺騙automake需要生成可執行程序add,讓它生成依賴文件add.o和執行命令。所以當運行完automake命令後,需要修改對應目錄下的Makefile.in,刪除其中的LINK語句。
配置說明:
①、noinst_PROGRAMS:指明需要生成的可執行程序的名稱,在此因爲不要安裝,所以使用關鍵字noinst_PROGRAMS;如果需要安裝,則使用bin_PROGRAMS。
②、exec_SOURCES:指明可執行程序依賴的文件名
③、DEFS:指明編譯選項
因sub、mul、div目錄的作用與add相似,因此,他們的Makefile.am配置是極其相似,只需將其中的add改爲sub、mul或div即可,在此不再迭述。
3) 主函數中的Makefile.am
圖17 子目錄main中的Makefile.am
配置說明:
①、bin_PROGRAMS:指明生成的可執行文件的名稱exec
②、exec_SOURCES: 指明可執行程序依賴的源文件
③、exec_LDADD:指明鏈接時依賴的文件
④、exec_LDFLAGS:指明鏈接時需要的選項
⑤、DEFS:指明編譯選項
⑥、LIBS:指明程序還需要包含的庫
4) 頭文件Makefile.am
將被源碼使用的頭文件加入到對應的變量include_HEADERS中即可:
圖18 頭文件Makefile.am
3) 新建文件
在當前目錄下新建文件NEWS、README、ChangeLog、AUTHORS文件,內容爲空;
#touch NEWS
#touch README
#touch ChangeLog
#touch AUTHORS
4) 生成configure
#aclocal —— 該命令將以configure.in爲輸入文件,生成aclocal.m4
#autoconf —— 該命令將以configure.in和aclocal.m4爲輸入文件,生成文件configure
#autoheader
5) 生成Makefile.in
#automake -a —— 該命令將以configure.in和Makefile.am爲輸入文件,生成文件Makefile.in
因生成add.o、sub.o、mul.o和div.o使用了欺騙的手段,所以當運行完automake命令後,需要修改對應目錄下的Makefile.in,刪除其中的LINK語句。
圖19 修改前後對比
因add、sub、mul與div的功能相似,所以其修改過程也是極其一致的,在此不再迭述。[注:main下的不用修改]
6) 執行./configure
完成安裝路徑的配置和Makefile的生成;
7) 編譯源碼
#make
#make install
便可完成源碼的編譯和程序的安裝;
8) 運行結果
完成以上所有操作之後,在當前目錄下就生成了可執行程序math,其最終的運行結果如下圖所示:
圖20 deep編譯結果
在此文中還有很多變量含義和設置爲明確說明,有興趣的可參考:http://www.ibm.com/developerworks/cn/linux/l-makefile/