Autoconf 能夠產生一份 Shell 腳本。對於大部分類 Unix 系統,這份 Shell 腳本可以自動配置軟件源碼包的構建環境。這份 Shell 腳本就是 Linux 系統中大名鼎鼎的 configure 腳本。segmentfault
在 Linux 系統中,只要你打算以編譯源碼的方式安裝軟件包,一般要藉助 configure 腳本構建軟件源碼包的編譯環境,除非是某個基於 CMake 或 SCons 構建的軟件源碼包。迄今爲止 Autoconf 所屬的 GNU Autotools 依然是類 Unix 系統中主流的項目構建工具,而且也是 Linux 系統中軟件源碼構建工具的事實標準。bash
與同類相比,GNU Autotools 最大的特色是不從新發明輪子,它徹底基於 GNU M4 與 Bash Shell 語言(實際上還有 Perl)開發而成。此外,基於 GNU Autotools 發佈的軟件,它的構建環境配置以及構建過程再也不依賴 GNU Autotools,這一點是 CMake 與 SCons 們沒法作到的。工具
要知道 Autoconf 如何生成 Shell 腳本,你至少要具有一丁點 Shell 腳本與 M4 的知識。在此,Shell 腳本指的是 Bash Shell 腳本,有關它的一些知識能夠閱讀『用幾分鐘學習 Bash』;M4 指的是 GNU M4,它的一些知識能夠閱讀『讓這世界再多一份 GNU m4 教程』。學習
如今假設你已經具有了這些基礎知識。下面是我寫的一段很簡單的 Shell 代碼,它能夠檢測系統中是否安裝了 foo 程序:code
if [ $(which foo) ] then echo "checking foo ... yes!" else echo "You should install foo!" exit -1 fi
如今,我用 M4 給上述 Bash 代碼製做一個『界面』:教程
define(`檢測系統中是否已安裝 foo', ` if [ $(which foo) ] then echo "checking foo ... yes!" else echo "You should install foo!" exit -1 fi ')
所謂的『界面』,就是宏 檢測系統中是否已安裝 foo
。當 GNU m4 讀到這個宏時,它就會自動將其展開爲它所封裝的 Bash 代碼。爲了說明這一點,請將上述 M4 代碼放到一份名爲 check-foo.m4 的文件中,而後在一份名爲 configure.ac 的文件中寫出如下代碼:開發
include(check-foo.m4) 檢測系統中是否已安裝 foo
而後用 GNU m4 讀入這個 configure.ac 文件,並將展開結果寫入到一份名爲 configure 的 Bash 腳本中:get
$ m4 configure.ac > configure
結果就在 configure 文件中得到了 檢測系統中是否已安裝 foo
這個宏的展開結果:源碼
if [ $(which foo) ] then echo "checking foo ... yes!" else echo "You should install foo!" exit -1 fi
若是你得不到上述結果,是由於我欺騙了你。雖然 m4 容許使用中文宏名,可是它不認爲這是真的宏名。你能夠將 檢測系統中是否已安裝 foo
改成 check-foo
,這樣 m4 就認爲它是真正的宏了。也可使用 GNU M4 提供的間接宏調用功能,這樣就能夠迂迴的使得 m4 支持中文宏名了,即:it
indir(`檢測系統中是否已安裝 foo')
如今,我認爲我已經回答了『autoconf 是如何生成 Shell 腳本的』這個問題,你只須要將上述的 m4
命令視爲 autoconf
便可。也就是說,autoconf 本質上就是 m4——穿了外套的 m4。
當 autoconf 將 configure.ac 文件中的宏展開爲 Bash 代碼並將其存儲於 configure 腳本以後,之後執行 configure 腳本時,就與 autoconf 無關了。並且,我將 configure 腳本傳給他人使用,他們也不須要 autoconf。
這就是 autoconf 運做的基本原理。然而不少人被這個基本原理嚇走了,由於他們看見 M4 與 Shell 語言就頭大!
若是看到這裏你依然不以爲懼怕,那麼我就能夠放心的將上文中的那個 Bash 代碼片斷作成一個真正的 Autoconf 宏了。所謂的 Autoconf 宏,它本質上就是 M4 宏——穿了外套的 M4 宏。
下面,我要建立一個目錄,叫 m4,在這個目錄中放置 check-foo.m4 文件,而後將 check-foo.m4 文件的內容修改成:
AC_DEFUN([CHECK_FOO], [if [[ $(which foo) ]] then echo "checking foo ... yes!" else echo "You should install foo!" exit -1 fi])
這裏的 CHECK_FOO
是一個 Autoconf 宏,它與前文中的那個 M4 宏 檢測系統中是否已安裝 foo
本質上是同樣的。兩者的定義有區別的地方就在於:
AC_DEFINE
取代了 define
;[
取代了 M4 的左引號,]
取代了 M4 的右引號;CHECK_FOO
取代了 檢測系統中是否已安裝 foo
;[[ $(which foo) ]]
取代了 [ $(which foo) ]
,這一點須要瞭解 M4 的工做原理。這些『取代』,是 M4 所容許的,也就是說,這一切只用 M4 就可以作到。
接下來,再將 configure.ac 文件修改成:
AC_INIT CHECK_FOO
而後,在 configure.ac 文件所在的目錄執行如下命令:
$ aclocal -I m4 $ autoconf $ ./configure
若是你的系統中沒有 foo 程序,就能夠獲得這樣的結果:
which: no foo in (/bin:/usr/bin:/usr/local/bin) You should install foo!
上述過程,只有兩點須要略作說明。首先,configure.ac 文件中出現的 AC_INIT
宏會被 autoconf 展開爲很長的一段 Bash 代碼,用於初始化軟件源碼構建環境;其次,aclocal
命令負責收集 M4 文件的路徑信息並將其存儲於 aclocal.m4 文件中。
在執行 autoconf
命令時,它會自動讀取 configure.ac 文件,而後根據 aclocal.m4 文件中記錄的 M4 文件,去尋找 configure.ac 中出現的宏的定義而後進行展開,展開結果就是 configure 腳本。執行 configure 腳本,除了會執行 AC_INIT
所展開的 Bash 代碼,還執行了 CHECK_FOO
所展開的:
if [ $(which foo) ] then echo "checking foo ... yes!" else echo "You should install foo!" exit -1 fi