工程專案利用AutoMake生成Makefile實戰
前一段時間突然心血來潮,準備在linux下玩玩介面,就想起把uCGUI移植到linux下,在移植的過程中遇到makefile的編寫,筆者是菜鳥,找了一些資料但還是沒弄清,不能運用自如,參考網上的但大多數是比較簡單的模型,離實際工程還有一段距離,很早就知道有automake這個工具,但一直感覺有點複雜就沒去搞它,這次怕不得已必須搞了,這中間也走了一些曲折的路,筆者摸索了兩天終於撥開雲霧見青天,現分享給大家,希望和我一樣的技術男少走一點彎路,多花時間陪陪女友。
├── uCGUI
│ ├── autom4te.cache
│ ├── Config
│ ├── GUI
│ │ ├── AntiAlias
│ │ ├── ConvertColor
│ │ ├── ConvertMono
│ │ ├── Core
│ │ ├── Font
│ │ ├── JPEG
│ │ │ ├── Doc
│ │ │ └── Image
│ │ ├── LCDDriver
│ │ ├── MemDev
│ │ ├── MultiLayer
│ │ ├── Touch
│ │ ├── VNC
│ │ ├── Widget
│ │ └── WM
│ └── GUIDemo
#######################################################################
/uCGUI/Makefile.am
AUTOMAKE_OPTIONS=foreign
SUBDIRS=GUI GUIDemo
#######################################################################
/uCGUI/GUI/Makefile.am
INCLUDES=-I../Config -IAntiAlias -IConvertColor -IConvertMono -IFont \
-IJPEG -ILCDDriver -IMemDev -IMultiLayer -IWidget -IWM -ICore -I../GUIDemo
noinst_LIBRARIES=libucgui.a
#libucgui_a_LIBADD=-lm -lpthred
libucgui_a_SOURCES=Core/GUI_GetFontSizeY.c \
Core/GUI_DrawBitmapMag.c \
Core/GUI_DrawLine.c \
Core/GUI_RectsIntersect.c \
Core/GUI__GetFontSizeY.c \
Core/GUI__IntersectRect.c \
Core/GUI_TOUCH_StoreState.c \
Core/GUI_CursorPal.c \
Core/GUI_SetDefault.c \
Core/LCD_RotateCCW.c \
Core/GUI__Arabic.c \
Core/GUI_SIF_Prop.c \
Core/GUI_FillPolygon.c \
Core/GUI_FillRect.c \
Core/GUI_DispChar.c \
Core/GUI_WaitKey.c \
Core/GUIColor2Index.c \
Core/GUI__Wrap.c \
Core/GUI_SetTextMode.c \
Core/GUI_CursorCrossMI.c \
Core/GUI_SetTextAlign.c \
Core/GUIPolyM.c \
Core/GUI_ScreenSize.c \
Core/GUI_DispStringInRectWrap.c \
Core/GUI__memset16.c \
Core/LCD_ReadRect.c \
Core/GUICharP.c \
Core/GUI_ALLOC_AllocZero.c \
Core/GUI_ALLOC_AllocInit.c \
Core/LCDRLE4.c \
Core/GUI__SetText.c \
Core/GUI_GetTextMode.c \
Core/LCD_SetAPI.c \
Core/GUI_CursorArrowSPx.c \
Core/GUI_DrawPolygon.c \
Core/GUI_CursorCrossM.c \
Core/GUI_DrawBitmapExp.c \
Core/GUI_DispStringInRect.c \
Core/GUI_GetFontInfo.c \
Core/GUI__HandleEOLine.c \
Core/GUI_CursorArrowLPx.c \
Core/LCD_MixColors256.c \
Core/GUI_GetColor.c \
Core/GUI_SIF.c \
Core/GUI_SetFont.c \
Core/GUI_DispString.c \
Core/GUI_WaitEvent.c \
Core/GUICurs.c \
Core/GUI_Warn.c \
Core/LCD_Index2ColorEx.c \
Core/GUI_TOUCH.c \
Core/GUI_SetPixelIndex.c \
Core/LCD_SetClipRectEx.c \
Core/GUI_CursorCrossLPx.c \
Core/GUI_UC_EncodeUTF8.c \
Core/GUI__memset.c \
Core/GUI_DispHex.c \
Core/GUI_CursorCrossS.c \
Core/GUI__strlen.c \
Core/GUI_DispStringAtCEOL.c \
Core/LCDP565_Index2Color.c \
Core/GUI_DrawPixel.c \
Core/GUI_SetDrawMode.c \
Core/GUI_CalcColorDist.c \
Core/GUI__strcmp.c \
Core/GUI_SetLUTEntry.c \
Core/GUI_OnKey.c \
Core/GUI_DrawPie.c \
Core/LCD_L0_Generic.c \
Core/GUI_CursorHeaderM.c \
Core/GUI_AddHex.c \
Core/GUIRealloc.c \
Core/GUI_AddBin.c \
Core/GUICore.c \
Core/GUI_UC_EncodeNone.c \
Core/LCD.c \
...........................
MultiLayer/LCD_3.c \
MultiLayer/LCD_4.c \
MultiLayer/LCD_2.c
####################################################################
uCGUI/GUIDemo
INCLUDES=-I../Config -I../GUI/AntiAlias -I../GUI/ConvertColor -I../GUI/ConvertMono \
-I../GUI/Font -I../GUI/JPEG -I../GUI/LCDDriver -I../GUI/MemDev -I../GUI/MultiLayer \
-I../GUI/Widget -I../GUI/WM -I../GUI/Core -I../GUIDemo
bin_PROGRAMS=uCDemo
uCDemo_LDADD=../GUI/libucgui.a -lm -lpthread
uCDemo_SOURCES=GUIDEMO_Touch.c \
GUIDEMO_Cursor.c \
GUIDEMO_FrameWin.c \
GUIDEMO_Automotive.c \
GUIDEMO_Polygon.c \
GUIDEMO_WM.c \
GUIDEMO_Dialog.c \
GUIDEMO_Graph.c \
GUIDEMO_LUT.c \
GUIDEMO_Bitmap.c \
GUIDEMO_Messagebox.c \
GUIDEMO.c \
GUIDEMO_Intro.c \
MicriumLogo.c \
GUIDEMO_Speed.c \
GUIDEMO_Circle.c \
GUIDEMO_Bitmap4bpp.c \
GUIDEMO_ColorList.c \
GUIDEMO_Font.c \
MicriumLogoWRed.c \
GUIDEMO_ProgBar.c \
GUIDEMO_ColorBar.c \
GUIDEMO_MemDevB.c \
GUIDEMO_HardwareInfo.c \
GUIDEMO_Navi.c \
DemoTask.c
1:[email protected]:~/NFS/rootfs/uCGUI$ autoscan
修改configure.scan為configure.in
AC_PREREQ([2.68])
AC_INIT(uCDemo, 1.0, - ) #############edit
AM_INIT_AUTOMAKE(uCDemo, 1.0) ##############add
AC_CONFIG_SRCDIR([GUIDemo/DemoTask.c])
#AC_CONFIG_HEADERS([config.h])
# Checks for programs.
AC_PROG_CC
# Checks for libraries.
# Checks for header files.
AC_CHECK_HEADERS([fcntl.h stddef.h stdlib.h string.
h strings.h sys/ioctl.h sys/time.h unistd.h])
# Checks for typedefs, structures, and compiler cha
racteristics.
AC_TYPE_SIZE_T
# Checks for library functions.
AC_FUNC_MALLOC
AC_FUNC_MMAP
AC_CHECK_FUNCS([floor gettimeofday memmove memset s
qrt])
AC_PROG_RANLIB ##################add
AC_CONFIG_FILES([GUI/Makefile
GUIDemo/Makefile
Makefile])
AC_OUTPUT
2[email protected]:~/NFS/rootfs/uCGUI$ aclocal
3[email protected]:~/NFS/rootfs/uCGUI$ autoconf
4[email protected]:~/NFS/rootfs/uCGUI$ automake --add-missing
5[email protected]:~/NFS/rootfs/uCGUI$ ./configure --host=arm-linux
6[email protected]:~/NFS/rootfs/uCGUI$ make
老規矩:上面有不懂的地方自己百度補課。
參考文章:
提綱挈領:使用Autotools其實很簡單
大家不要看到那麼多工具,其實使用起來很簡單,總結起來就是兩部分:
1) 按照順序呼叫各個工具;
2) 修改或者新增3個檔案;
整個操作順序如下圖:
聽到我這麼講,大家是否覺得有信心了?好的,下面我們來看具體如何操作:
1. 原始碼根目錄呼叫autoscan指令碼,生成configure.scan檔案,然後將此檔案重新命名為configure.ac(或configure.in,早期使用.in字尾)
2. 修改【configure.ac】,利用autoconf提供的各種M4巨集,配置專案需要的各種自動化探測專案
3. 編寫【自定義巨集】,建議每個巨集一個單獨的*.m4檔案;
4. 呼叫aclocal收集configure.ac中用到的各種非Autoconf的巨集,包括自定義巨集;
5. 呼叫autoheader,掃描configure.ac(configure.in)、acconfig.h(如果存在),生成config.h.in巨集定義檔案,裡面主要是根據configure.ac中某些特定巨集(如AC_DEFINE)生成的#define和#undefine巨集,configure在將根據實際的探測結果決定這些巨集是否定義(具體見後面例子)。
6. 按照automake規定的規則和專案的目錄結構,編寫一個或多個【Makefile.am】(Makefile.am數目和存放位置和原始碼目錄結構相關),Makefile.am主要寫的就是編譯的目標及其原始碼組成。
7. 呼叫automake,將每個Makefile.am轉化成Makefile.in,同時生成滿足GNU編碼規範的一系列檔案(帶-a選項自動新增缺少的檔案,但有幾個仍需要自己新增,在執行automake前需執行touch NEWS README AUTHORS ChangeLog)。如果configure.ac配置了使用libtool(定義了AC_PROG_LIBTOOL巨集(老版本)或LT_INIT巨集),需要在此步驟前先在專案根目錄執行libtoolize --automake --copy --force,以生成ltmain.sh,供automake和config.status呼叫。
8. 呼叫autoconf,利用M4解析configure.ac,生成shell指令碼configure。以上幾步完成後,開發者的工作就算完成了,後面的定製就由開源軟體的使用者根據需要給configure輸入不同的引數來完成。
9. 使用者呼叫configure,生成Makefile,然後make && make install。
整個過程步驟有9步,但其中有6步你只需要簡單的敲一個命令即可,只有剩下的三步需要你動手寫一些東西,對應上面步驟中的藍色黑體字部分,而本文的重點就是如何在大型專案中完成這三歩。
步步為營:三步完成編譯配置
【第2步:修改configure.ac檔案】
從上面的步驟可以看到,使用autoscan工具掃描後就會生成一個簡單的configure.ac檔案,這已經是一個完整的configure.ac檔案框架了,但還不足以達到我們的要求,因此我們要在框架裡面新增一些東西:
1.1 新增AM_INIT_AUTOMAKE巨集
在AC_INIT 巨集下一行新增AM_INIT_AUTOMAKE([foreign -Wall -Werror]),中括號裡面的選項可以根據需要來修改,具體請看automake手冊關於這個巨集的說明。
1.2 如果需要,新增AC_CONFIG_HEADERS([config.h])巨集
新增這個巨集很簡單,但關鍵是“如果需要”,什麼情況下需要這個巨集呢?
這個巨集的目的是輸出config.h,這是一個C的標頭檔案,裡面主要是包含很多巨集定義#define,說到這裡其實就很明確了,輸出這個檔案的目的就是提供各種相關的巨集,而巨集在程式碼中的作用就是#ifdef,也就是說:如果你的程式碼需要用到巨集開關進行控制,那麼就要輸出這個檔案。具體的使用方法如下:
1) 首先確定程式碼中需要使用什麼巨集來進行開關定製,確定巨集的名稱,編寫和巨集相關的程式碼,且要包含config.h的標頭檔案;
2) 在configure.ac中的各種處理(例如AC_CHECK_***,AC_ARG_***)中使用AC_DEFINE巨集定義C/C++的巨集,名稱和上面的相同;如果是使用AC_CHECK_HEADERS,會自動新增巨集定義;
3) 執行完第7歩後,Autoconf就會自動生成config .h檔案
1.3新增編譯連結需要的程式
編譯連結需要用到的程式需要新增在# Checks for programs.註釋後面。對於C/C++來說,最常見的就是gcc, g++, 靜態庫編譯、動態庫編譯,對應的選項如下:
AC_PROG_CXX
AC_PROG_CC
AC_PROG_RANLIB
如果使用libtool編譯,則選項如下,注意使用了libtool則需要將AC_PROG_RANLIB去掉
LT_INIT
1.4 在configure.ac程式碼中各個部分新增自己的檢測處理
這一步是我們的主要工作,需要根據自己的專案具體情況來編寫,常見操作對應的巨集和樣例請參考本文後面的“【常見操作對應的巨集】”:。至於具體新增在哪個地方,configure.ac中的註釋已經清楚的告訴你了,例如:
# Checks for libraries.
# Checks for library functions.
1.5 在AC_OUTPUT上一行新增AC_CONFIG_FILES巨集
新增這個巨集的目的是制定Autoconf輸出哪些檔案,常見的檔案就是Makefile檔案,config.h在AC_CONFIG_HEADERS巨集裡面指定了,這裡不需要再次指定。例如:
AC_CONFIG_FILES([Makefile tools/Makefile common/Makefile worker/Makefile]) |
【第3步:編寫自定義的Autoconf巨集】
Autoconf雖然提供了很多內建的巨集,但在實際專案中,這些巨集不可能滿足所有的要求,有的處理還是要自己完成。雖然在configure.ac檔案中可以直接編寫各種處理程式碼,但這樣做有幾個缺點:
1) 很不美觀:開啟configure.ac檔案,密密麻麻的一大段花花綠綠的Shell程式碼,看著眼花繚亂;
2) 修改起來很麻煩:要找半天才能找到要修改的位置,一不小心就改錯了;
就像寫C/C++程式碼要進行封裝一樣,Autoconf的處理也需要進行封裝,這個封裝就是自定巨集,定義完成後在configure.ac中呼叫,看起來很清爽,修改也很簡單。
下面我們來看如何自定義巨集:
2.1 新建一個單獨的目錄,用於存放自定義巨集,一般定義為m4
2.2 新建自定義巨集檔案
建議每個巨集一個檔案,檔案必須以.m4結尾,檔名就是巨集名(當然如果你非要不這麼做也可以,檔名隨便取)
2.3 編寫Autoconf巨集
具體的編寫方式請參考Autoconf的手冊第10章節,最好邊看手冊邊對照一個開源軟體的樣例,這樣效果最好了。這裡說明幾個需要注意的地方:
1)m4巨集不是shell,請不要直接在檔案中寫shell程式碼,而要在巨集的各個部分裡面寫程式碼;
最常見的就是if-else判斷,如果要在程式碼中編寫if-else判斷,需要使用AS_IF巨集,或者在其它巨集裡面寫,例如AC_ARG_WITH, AC_CACHE_CHECK;
2)AC_DEFUN是定義autoconf的巨集,AC_DEFINE是定義C/C++的config .h裡面的巨集,不要混淆了;
2.4 執行aclocal工具,生成aclocal.m4
由於自定義巨集是放在我們新建的目錄中的,configure.ac並沒有像C/C++那樣的include語句可用,因此也就找不到這些巨集,這時就需要aclocal工具了:aclocal會將自定義巨集編譯成configure.ac可用的巨集,儲存在和configure.ac同級目錄下的aclocal.m4檔案中,這樣在configure.ac就能夠直接使用了。具體的編譯方法如下(m4就是你的目錄):
aclocal -I m4
同時需要在根目錄下的Makefile.am中新增ACLOCAL_AMFLAGS = -I m4。
還有一種方法是將所有的自定義巨集都放入到一個acinclude.m4檔案中,不過不推薦這種方法,原因是因為這種方法的缺點和直接將所有自定義巨集放入configure.ac中沒有多大差別。
【第6步:編寫Makefile.am檔案】
對於大型專案來說,程式碼一般都是分目錄存放的,而不會像Hello world樣例那樣簡單的就幾個檔案,因此寫Makefile.am就麻煩一些,但其實主要是工作量增加了,原則都是一樣的:
原則1:每個目錄一個Makefile.am檔案;同時在configure.ac的AC_CONFIG_FILES巨集中指定輸出所有的Makefile檔案,例如:
AC_CONFIG_FILES([Makefile tools/Makefile common/Makefile worker/Makefile])
原則2:父目錄需要包含子目錄
在父目錄下的Makefile.am中新增: SUBDIRS = 所有子目錄,例如SUBDIRS=test tools
原則3:Makefile.am中指明當前目錄如何編譯
前兩個原則很簡單,這裡就不多說了,重點說一下如何編寫Makefile.am。
編寫Makefile.am主要是完成3件事情:編譯(make)、安裝(make install)、打包(make dist),下面我們一一來進行講解。
3.1 編譯安裝
編譯和安裝的規則是繫結在一起的,通過同一條語句同時指定了編譯和安裝的處理方式,具體的格式為:安裝目錄_編譯型別=編譯目標
3.1.1【安裝目錄】
例如:bin_PROGRAMS = hello subdir/goodbye,其中安裝目錄是bin,編譯型別是PROGRAMS,編譯目標是兩個程式hello, goodbye.
常用預設的安裝目錄如下
目錄 |
Makefile.am中的變數 |
使用方式 |
prefix |
/usr/local |
安裝目錄,通過--prefix指定 |
exec_prefix |
${prefix} |
同prefix |
bindir |
${exec_prefix}/bin |
bin_編譯型別 |
libdir |
${exec_prefix}/lib |
lib_編譯型別 |
includedir |
${prefix}/include |
include_編譯型別 |
noinstdir |
無 |
noinst_編譯型別,特殊的目錄,表示編譯目標不安裝。 |
除了常用的預設目錄外,有時候我們還需要自定義目錄,例如我們希望安裝完成後安裝目錄下有一個配置檔案目錄config,同時將指定的test.ini拷貝到config目錄,則config目錄需要通過自定義目錄方式定義,然後按照預設目錄的使用方式使用。例如:
在根目錄下的Makefile.am中新增如下內容:
configdir=${prefix}/config => 定義一個自定義的目錄名稱config,注意dir字尾是固定的
config_DATA=config/test.ini => 使用自定義的目錄config,必須要有這句,否則目錄不會建立, =號後面如果有對應的檔案,安裝時會將對應的檔案拷貝到config目錄下。
3.1.2【編譯型別】
常見編譯型別如下,沒有自定義編譯型別
型別 |
說明 |
使用方式 |
PROGRAMS |
可執行程式 |
bin_PROGRAMS |
LIBRARIES |
庫檔案 |
lib_LIBRARIES |
LTLIBRARIES (Libtool libraries) |
libtool庫檔案 |
lib_LTLIBRARIES |
HEADERS |
標頭檔案 |
include_HEADERS |
SCRIPTS |
指令碼檔案,有可執行許可權 |
test_SCRIPTS(需要自定義test目錄) |
DATA |
資料檔案,無可執行許可權 |
conf_DATA(需要自定義conf目錄) |
3.1.3【編譯目標】
編譯目標其實就是編譯型別對應的具體檔案,其中需要make生成的檔案主要有如下幾個:可執行程式_PROGRAMS,普通庫檔案_LIBRARIES,libtool庫檔案_LTLIBRARIES,其它型別對應的編譯目標不需要編譯,原始檔就是目標檔案。
Ø 標準的編譯配置
如果你熟悉gcc的編譯命令寫法,那麼Automake的Makefile.am編譯過程就很好寫了。因為Automake只是將寫在一行gcc命令裡的各個不同部分的資訊分開定義而已。我們來看具體是如何定義的:
_SOURCES:對應gcc命令中的原始碼檔案
_LIBADD:編譯連結庫時需要連結的其它庫,對應gcc命令中的*.a等檔案
_LDADD:編譯連結程式時需要連結的其他庫,對應gcc命令中的*.a等檔案
_LDFLAGS:連結選項,對應gcc命令中的-L, -l, -shared, -fpic等選項
_LIBTOOLFLAGS:libtool編譯時的選項
**FLAGS(例如_CFLAGS/_CXXFLAGS):編譯選項,對應gcc命令中的-O2, -g, -I等選項
舉例如下:
#不同的編譯型別只是第一句不一樣,後面的編譯配置都是一樣的 bin_PROGRAMS= myproject myproject_SOURCES = main.c myproject_LDADD = ./utils/libutils.a ./module1/libmodule1.a ./core1/libcore.a myproject_LDFLAGS = -L/home/test/local -lmemcached myproject_CFLAGS = -I./core1/ -I./module1/ -I./utils/ -O2 -g |
Ø 如何編譯可執行程式
對於大型專案來說,程式碼基本上都是分目錄存放的,如果是直接寫makefile檔案,一般都是將所有原始檔首先編譯成*.o的檔案,再連結成最終的二進位制檔案。但在Automake裡面這樣是行不通的,因為你只要仔細看編譯型別表格就會發現,並沒有一種編譯型別能夠編譯*.o檔案,無法像常規makefile那樣來編寫,所以就需要採取一些技巧。
其實這個技巧也很簡單:將非main函式所在目錄的檔案編譯成靜態連結庫,然後採用連結靜態庫的方式編譯可執行程式。
樣例如下:
=================根目錄Makefile.am======================
#對應Makefile.am原則2 SUBDIRS = tools common worker |
=================tool目錄Makefile.am======================
#只是為了編譯而生成的.a庫檔案,沒有必要安裝, 所以是noinst noinst_LIBRARIES=libtools.a libtools_a_SOURCES=./urlcode.h \ ./stringtools.cpp \ ./stringtools.h \ ./urlcode.c |
===============common目錄Makefile.am======================
#只是為了編譯而生成的.a庫檔案,沒有必要安裝, 所以是noinst noinst_LIBRARIES=libcommon.a libcommon_a_SOURCES=./iniparser.c \ (省略很多檔案, 實際使用時要一一填寫) ./exception.h \ |
==============worker目錄Makefile.am============================
bin_PROGRAMS=worker worker_SOURCES=./workeralgorithm.cpp \ ./worker.cpp \ (省略很多檔案, 實際使用時要一一填寫) ./worker.h #通過_LDADD告訴Automake需要連結哪些庫 worker_LDADD=../tools/libtools.a ../common/libcommon.a |
Ø 如何編譯靜態庫
Automake天然支援編譯靜態庫,只需要將編譯型別指定為_LIBRARIES即可。
Ø 如何編譯動態庫
需要注意的是:_LIBRARIES只支援靜態庫(即*.a檔案),而不支援編譯動態庫(*.so)檔案,要編譯動態連結庫,需要使用_PROGRAMS。除此之外,還需要採用自定義目錄的方式避開Automake的兩個隱含的限制:
1) 如果使用bin_PROGRAMS, 則庫檔案會安裝到bin目錄下,這個不符合我們對動態庫的要求;
2) automake不允許用lib_ PROGRAMS
下面假設將utils編譯成so,採用自定義目錄的方式,修改Makefile.am如下:
mylibdir=$libdir #$libdir其實就是lib目錄,請參考【安裝目錄】表格 mylib_PROGRAMS= libutils.so libutils_so_SOURCES = utils.c utils.h libutils_so_LDFLAGS = -shared –fpic #這個就是gcc編譯動態庫的選項 |
Ø 如何編譯libtool庫
對於跨平臺可移植的庫來說,推薦使用libtool編譯,而且Automake內建了libtool的支援,只需要將編譯型別修改為_LTLIBRARIES即可。
需要注意的是:如果要使用libtool編譯,需要在configure.ac中新增LT_INIT巨集,同時註釋掉AC_PROG_RANLIB,因為使用了LT_INIT後,AC_PROG_RANLIB就沒有作用了。
3.2 打包
Automake預設情況下會自動打包,自動打包包含如下內容:
1) 所有原始檔
2) 所有Makefile.am/Makefile.in檔案
3) configure讀取的檔案
4) Makefile.am’s (using include) 和configure.ac’ (using m4_include)包含的檔案
5) 預設的檔案,例如README, ChangeLog, NEWS, AUTHORS
如果除了這些預設的檔案外,你還想將其它檔案打包(一般包括靜態庫、標頭檔案、配置檔案、幫助檔案),有如下兩種方法:
(1) 粗粒度方式:通過EXTRA_DIST來指定,指定檔案就打包檔案,指定目錄就打包目錄,例如:
EXTRA_DIST=conf/config.ini test tools/initialize.sh
如果test是目錄,那麼會將test目錄下所有的檔案和目錄都打包。
(2) 細粒度方式:在“安裝目錄_編譯型別=編譯目標”前新增dist(表示需要打包), 或者nodist(不需要打包),例如:
#將data_DATA= distribute-this打包 dist_data_DATA = distribute-this #foo_ SOURCES不打包 bin_PROGRAMS = foo nodist_foo_SOURCES = do-not-distribute.c |
【後記】
GNU Autotool工具博大精深,我也是結合專案的實際應用來使用的,並沒有完整的研究所有的工具,因此難免存在瑕疵和紕漏,如果大家發現有疑問或者問題的地方,歡迎大家指正。當然,GNU自己的手冊是最權威的,如果你有疑問的話,參考手冊,以手冊為準。
如果想了解autotools的工作原理和流程以及更高階的技巧,請參考胡華強寫的《autoconf and automake介紹與典型應用.doc》。
【常見操作對應的巨集】
1)給./configure新增--with-package引數,例如:./configure --with-libmemcached
AC_ARG_WITH,具體如何寫請參考autoconf手冊15.2章節,裡面給了一個完整的樣例。
2)給./configure新增 –enable-feature引數,例如:./configure –enable-multithread
AC_ARG_ENABLE,顧名思義,這個巨集的意思就是開啟開關,這個開關可以是編譯開關,也可以是程式碼功能開關,如果是編譯開關,則要配合AM_CONDITIONAL巨集來使用(樣例請看automake手冊20.1章節的AM_CONDITIONAL巨集說明);如果是程式碼功能開關,則要配合AC_DEFINE巨集來使用(請參考autoconf手冊15.2章節的AC_ARG_WITH巨集的樣例)
3)在./configure的時候檢查標頭檔案
AC_CHECK_HEADER: 檢查一個頭檔案
AC_CHECK_HEADERS:檢查一批標頭檔案
4)在./configure時檢查庫檔案
AC_CHECK_LIB:樣例請參考autoconf手冊15.2章節的AC_ARG_WITH巨集的樣例
5)修改make行為
如果你想修改預設的make行為,可以先使用AC_ARG_WITH或者AC_ARG_ENABLE新增./configure引數,再結合如下兩個巨集來