2012年9月6日 星期四

[參考文章]automake and autoconf



Abstract

在 Unix 底下,automake 和 autoconf 常被用來管理 C/C++ 的專案。 如果您的專案是根據 GNU 的標準建構出來的,那麼它們能夠幫您節省很多 make 以及 configure 的時間。然而,萬事起頭難。希望這篇指南能夠為剛入門的程式設計師提供一些有用的資訊。
我不是 Unix 以及 autoconf, automake 的專家,所以我歡迎有建設性的批評與指教。

make and configure

這個 make tool 能夠用來管理多個檔案的專案。make 會用到您專案裡的 Makefile 這個檔案,這個檔案列出了各式的編譯以及連結步驟,目的,以及一些相依關係。多檔的專案與 GNU 的 make 工具程式是有很大的關係的。
configure 這個 script 被用來協助處理跨平台的編譯工作。一個合適的 configure script 能夠正確的解譯 Makefile.in 然後產生該平台相依的 Makefile。當然。產生 Makefile 之前必須經過很多測試來決定該平台的特性。
所以我們允許使用者執行 './configure' 然後再執行 'make' 來根據自身的平台而編譯這個專案。

aclocal.m4

很明顯的,大部分寫好的 Makefile 和 configure script 看起來都非常的類似。事實上,GNU 提供了一些關於這些檔案的細部描述。因此,GNU 寫出了 automake 以及 autoconf 來簡化處理這些過程,並且確保 Makefile 以及 configure script 能夠遵守 GNU 標準。
這裡是這些工具的簡單的介紹。我這裡也提供了範例供您測試使用。
注意:這些工具使用 m4 程式語言。 aclocal 增加 aclocal.m4 這個檔案到您的專案目錄,因為包含了一些需要用到的 m4 巨集。

autoconf

autoconf 會尋找叫做 configure.in 這個檔案,然後會根據他找到的巨集而生出 configure script。
注意要的是 autoscan 可以用來產生一個可能使用的 configure.in。它會測試你的原始檔案,然後放進一些建議值到一個叫做 configure.scan 的檔案。當然您必須改名成 configure.in。
不管什麼時候,您在 configure.in 加入一個巨集時,然後必須執行 aclocal 和 autoconf,因為 aclocal 會掃描 configure.in 然後找出它必須提供的巨集。
Lines which every configure.in should have
每一個 configure.in 應該有底下這幾行:
AC_INIT(hello.cc)

AM_INIT_AUTOMAKE(hello,0.1)

AC_PROG_CC

AC_PROG_CXX

AC_PROG_INSTALL

AC_OUTPUT(Makefile)
AC_INIT
這個巨集以一個原始檔當作參數。它會檢查該檔是否存在,也會檢查目錄是否存在。
AM_INIT_AUTOMAKE
這行增加了幾個標準的檢查。它是以程式名稱以及版本號碼當作參數。
AC_PROG_CC
指出了該原始檔是用 C 寫成的。假如原始檔是用 C++ 寫成的,那麼應該改成AC_PROG_CXX。
AC_PROG_INSTALL
會產生安裝目的地,好讓使用者打 make install 便能安裝這套軟體。
AC_OUTPUT
指出應該產生的 Makefile 檔案名稱。
Using a Config Header
AM_CONFIG_HEADER(config.h) 這行指出了您將會使用 config.h 檔。autoconf 將會需要 config.h.in ,並將之處理成 config.h。這是你的原始檔案中,透過 #define 定義的標頭檔,好提供一個方式讓人們為它們的平台自訂 configuration。config.h.in 能夠被autoheader 這個工具程式自動產生。
然而,在你的專案中,你需要 stamp-h 這個檔案來確保 automake 從 config.h.in 重新產生 config.h。執行 'touch stamp-h' 讓您的專案新增這個檔案。

automake

automake 會尋找 Makefile.am 這個檔案,然後依據它找到的巨集產生 Makefile.in。當然,這個會在稍後的 configure script 用到。
GNU-style projects, or not
因為預設值 automake 會嘗試產生 GNU-style 的專案,因此如果一些該有的檔案不存在,automake 會向您抱怨。所以您可以用以下指令產生需要的空白文件:
touch NEWS README AUTHORS ChangeLog
如果您不需要 GNU-style 的檔案,您可以在您的 Makefile.am 增加以下這行:
AUTOMAKE_OPTIONS = foreign
Telling automake about your source files
使用下面這兩行來命名您的程式名稱,以及列出它的原始程式:
bin_PROGRAMS = hello

hello_SOURCES = hello.h hello.cc main.cc
注意:第二個變數的前置是依據第一個變數的。

The Whole Process

假設您已經概略的編輯完 Makefile.am 和 configure.in (底下有範例),藉由底下的指令,您應該能夠 build 您專案了:
autoheader

touch NEWS README AUTHORS ChangeLog

touch stamp-h

aclocal

autoconf

automake



./configure

make
當你想完整重新 build 專案,請重複最後五個步驟。
* autoheader - creates config.h.in
* aclocal - adds aclocal.m4 to directory.
* autoconf - creates configure from configure.in
* automake - Creates Makefile.in from Makefile.am
* ./configure - creates Makefile from Makefile.in

Sub Directories

當 然,專案的檔案應該被組織化的放在子目錄裡。理想上來說,原始檔和 makefile,configure scripts,以及 README 等等這些檔案,應該都放在專案的 src 這個子資料匣中。多層式的專案我們把它叫做 Deep 專案。我會列出應該處理的步驟,但是你依然可以看看範例程式。
當使用子目錄的時候,你必須坐下的步驟:
1. 增加 SUBDIRS 這一項到最頂層的 Makefile.am。例如:
SUBDIRS = doc intl po src tests
注意這些資料匣的名稱要以空白區分。
2. 在每一個子目錄中都要新增一個 Makefile.am。但是不需要 configure.in。而且要確定最頂層的 configure.in 中的 AC_OUPUT 巨集要加入檔名以產生 Makefile。
For sub directories containing additional source code
3. 增加 AC_PROG_RANLIB 巨集到您的 configure.in。這允許您在子目錄中 build 的 code 能夠暫時放到某個暫存目錄,以便之後用來和其他 code 作連結之用。
4. 增加一些巨集到 src 下的任何原始檔目錄的 Makefile.am。這將會 build 一個不會安裝的函式庫。你需要給定以 lib 字母為開頭的函式庫名稱,並且指定該函式庫的原始碼以及標頭檔,例如:
noinst_LIBRARIES = libfoo.a

libfoo_a_SOURCES = foo.h foo.cc

INCLUDES = -I@top_srcdir@/src/includes
注意 SOURCES 巨集會使用底線 '_' 來代替函式庫的名稱的點 '.'。而且要使用 top_srcdir 這個變數來參考到專案的最頂端。
5. 在上一層目錄使用 Makefile.am 的 LDADD 這個巨集,來連結任何可能用到這個暫時函式庫的 Code。例如:
LDADD = foofiles/libfoo.a
For sub directories containing non-source files
3. 一個子目錄下的 Makefile.am 應該包含像底下的這行:
EXTRA_DIST = somefile.txt someotherfile.html
這會告訴 automake 您要發布這些檔案,但是它們不需要編譯。

Example Files

底下就是範例檔了。它是一個使用一個標準函式庫的 C++ 專案。
看看 autoconf 和 automake 的手冊來參閱使用到的一些巨集以及變數。我不要這些範例因為註解而變的難以閱讀。
這個 Deep 專案的架構如下:
helloworld_cc
configure.in
Makefile.am
src
Makefile.am
helloworld.h
helloworld.cc
main.cc
foofiles
Makefile.am
foo.h
foo.cc
configure.in
AC_INIT(src/hello.cc)

AM_INIT_AUTOMAKE(hello,0.1)

AM_CONFIG_HEADER(config.h)

AC_PROG_CC

AC_PROG_CXX

AC_PROG_INSTALL

AC_PROG_RANLIB

AC_OUTPUT(Makefile src/Makefile src/foofiles/Makefile)
Makefile.am
SUBDIRS = src
Makefile.am for the src directory
bin_PROGRAMS = hello

INCLUDES = foofiles

hello_SOURCES = hello.h hello.cc main.cc

SUBDIRS = foofiles

LDADD = foofiles/libfoo.a
Makefile.am for foofiles directory under src
noinst_LIBRARIES = libfoo.a

libfoo_a_SOURCES = foo.h foo.cc

INCLUDES = -I@top_srcdir@/

圖解


1.autoscan (autoconf): 掃描源代碼以搜尋普通的可攜性問題,比如檢查編譯器,庫,頭文件等,生成檔configure.scan,它是configure.ac的一個雛形。
2.aclocal (automake):根據已經安裝的巨集,用戶定義巨集和acinclude.m4檔中的宏將configure.ac檔所需要的巨集集中定義到檔 aclocal.m4中。aclocal是一個perl 腳本程式,它的定義是:“aclocal - create aclocal.m4 by scanning configure.ac”

user input files   optional input     process          output files
================   ==============     =======          ============

                    acinclude.m4 - - - - -.
                                          V
                                      .-------,
configure.ac ------------------------>|aclocal|
                 {user macro files} ->|       |------> aclocal.m4
                                      `-------'
3.autoheader(autoconf): 根據configure.ac中的某些巨集,比如cpp巨集定義,運行m4,聲稱config.h.in

user input files    optional input     process          output files
================    ==============     =======          ============

                    aclocal.m4 - - - - - - - .
                                             |
                                             V
                                     .----------,
configure.ac ----------------------->|autoheader|----> autoconfig.h.in
                                     `----------'
4.automake: automake將Makefile.am中定義的結構建立Makefile.in,然後configure腳本將生成的Makefile.in檔轉換為Makefile。如果在configure.ac中定義了一些特殊的宏,比如AC_PROG_LIBTOOL,它會調用libtoolize,否則它會自己產生config.guess和config.sub

user input files   optional input   processes          output files
================   ==============   =========          ============

                                     .--------,
                                     |        | - - -> COPYING
                                     |        | - - -> INSTALL
                                     |        |------> install-sh
                                     |        |------> missing
                                     |automake|------> mkinstalldirs
configure.ac ----------------------->|        |
Makefile.am  ----------------------->|        |------> Makefile.in
                                     |        |------> stamp-h.in
                                 .---+        | - - -> config.guess
                                 |   |        | - - -> config.sub
                                 |   `------+-'
                                 |          | - - - -> config.guess
                                 |libtoolize| - - - -> config.sub
                                 |          |--------> ltmain.sh
                                 |          |--------> ltconfig
                                 `----------'
5.autoconf:將configure.ac中的宏展開,生成configure腳本。這個過程可能要用到aclocal.m4中定義的宏。

user input files   optional input   processes          output files
================   ==============   =========          ============

                   aclocal.m4 - - - - - -.
                                         V
                                     .--------,
configure.ac ----------------------->|autoconf|------> configure ----->autoconfig.h,Makefile


沒有留言:

張貼留言

文章分類