天天看點

使用Automake,Autoconf生成Makefile

使用Automake,Autoconf生成Makefile

在Unix 上寫過程式的人尤其是用 C 來開發程式的人一般都遇到過 Makefile,用 make 來開發和編譯程式的确很友善,可是要寫出一個Makefile就不那麼簡單了。GNU Make 那份幾百頁的檔案,讓許多人害怕。當然,現在關于make的文檔比較多,不過寫一個Makefile總是一件很煩人的事情,GNU Autoconf 及 Automake 這兩個軟體就是幫助程式開發者輕松産生Makefile 檔案的。現在的GNU軟體如Apache, MySQL Minigui等都是利Autoconf,Automake實作自動編譯的。使用者隻要使用 “./configure”, “make”, “make install” 就可以把程式安裝到系統中。

簡介

Makefile 基本上就是『目标』(target), 『關聯』(dependencies) 和『動作』三者所組成的一系列規則。而 make 就是根據 Makefile 的規則決定如何編譯 (compile) 和連接配接 (link) 程式或者其它動作。當然,make 可做的不隻是編譯和連接配接程式,例如 FreeBSD 的 port collection 中,Makefile還可以做到自動下載下傳遠端程式,解壓縮 (extract) , 打更新檔 (patch),設定,然後編譯,安裝到系統中。

Makefile 基本結構雖然很簡單,但是妥善運用這些規則就可以變換出許多不同的花樣。卻也因為這樣,許多人剛開始學寫Makefile 時會覺得沒有規範可以遵循,每個人寫出來的Makefile都不大一樣,不知道從哪裡下手,而且常常會受到開發環境的限制,隻要環境參數不同或者路徑更 改,可能 Makefile 就得跟着修改。雖然有GNU Makefile Conventions (GNU Makefile慣例)制訂出一些在進行 GNU 程式設計時寫 Makefile 的一些标準和規範,但是其内容很長而且很複雜,并且經常作一些調整,為了減輕程式開發人員維護Makefile 的負擔,就出現了Automake。

利用Automake,程式設計者隻需要寫一些預先定義好的宏 (macro),送出給Automake處理,就會産生一個可以供 Autoconf 使用的 Makefile.in檔案。再配合使用 Autoconf産生的自動配置檔案 configure 即可産生一份符合 GNU Makefile 慣例的 Makeifle 了。

 

需要的軟體

在開始使用 Automake 之前,首先确認你的系統安裝有如下軟體:

1. GNU Automake

2. GNU Autoconf

3. GNU m4

4. perl

5. GNU Libtool (如果你需要産生 shared library)

最好也使用 GNU C/C++ 編譯器 、GNU Make 以及其它 GNU 的工具程式來作為開發的環境,這些工具都是屬于 Open Source Software 不但免費而且功能強大。如果你是使用 Red Hat Linux 可以找到所有上述軟體的 rpm 檔案。 

一個簡單的例子

Automake 所産生的 Makefile 除了可以做到程式的編譯和連接配接,也可以用來生成文檔(如 manual page, info 檔案等),還可以有把源碼檔案包裝起來以供釋出,是以程式源代碼所存放的目錄結構最好符合GNU 的标準慣例,接下來就用一個hello.c 來做為例子。

在工作目錄下建立一個新的子目錄devel,再在 devel 下建立一個"hello"' 的子目錄,這個目錄将

作為存放 hello這個程式及其相關檔案的地方:

% mkdir devel;cd devel;mkdir hello;cd hello

用編輯器寫一個hello.c檔案,

#include <stdio.h>

int main(int argc, char** argv)

{

printf(“Hello, GNU!/n”);

return 0;

}

接下來就要用 Autoconf 及 Automake 來産生 Makefile 檔案了,

1. 用 autoscan 産生一個 configure.in 的原型,執行autoscan 後會産生一個configure.scan 的檔案,可以用它作為 configure.in檔案的藍本。

 

% autoscan

% ls

configure.scan hello.c

2. 編輯 configure.scan檔案,如下所示,並且改名為configure.in

dnl Process this file with Autoconf to produce a configure script.

AC_INIT(hello.c)

AM_INIT_AUTOMAKE(hello, 1.0)

dnl Checks for programs.

AC_PROG_CC

dnl Checks for libraries.

dnl Checks for header files.

dnl Checks for typedefs, structures, and compiler characteristics.

dnl Checks for library functions.

AC_OUTPUT(Makefile)

3. 執行 aclocal 和 Autoconf ,分別會産生 aclocal.m4 及 configure 兩個檔案

% aclocal

% Autoconf

% ls

aclocal.m4 configure configure.in hello.c

4. 編輯 Makefile.am 檔案,內容如下

AUTOMAKE_OPTIONS= foreign

bin_PROGRAMS= hello

hello_SOURCES= hello.c

5. 執行 Automake --add-missing ,Automake 會根據Makefile.am 檔案産生一些檔案,包含最重要的Makefile.in

% Automake --add-missing

Automake: configure.in: installing `./install-sh'

Automake: configure.in: installing `./mkinstalldirs'

Automake: configure.in: installing `./missing'

6. 最後執行 ./configure:

% ./configure

creating cache ./config.cache

checking for a BSD compatible install... /usr/bin/install -c

checking whether build environment is sane... yes

checking whether make sets ${MAKE}... yes

checking for working aclocal... found

checking for working Autoconf... found

checking for working Automake... found

checking for working autoheader... found

checking for working makeinfo... found

checking for gcc... gcc

checking whether the C compiler (gcc ) works... yes

checking whether the C compiler (gcc ) is a cross-compiler... no

checking whether we are using GNU C... yes

checking whether gcc accepts -g... yes

updating cache ./config.cache

creating ./config.status

creating Makefile

$ ls

Makefile aclocal.m4 config.status hello.c mkinstalldirs

Makefile.am config.cache configure install-sh

Makefile.in config.log configure.in missing

現在你的目錄下已經産生了一個 Makefile 檔案,輸入make指令就可以編譯 hello.c 了!

% make

gcc -DPACKAGE=/"hello/" -DVERSION=/"1.0/" -I. -I. -g -O2 -c hello.c

gcc -g -O2 -o hello hello.o

你還可以試試 “make clean“,”make install“,”make dist“:

[[email protected] hello]# make clean

test -z "hello " || rm -f hello

rm -f *.o core *.core

[[email protected] hello]# make install

gcc -DPACKAGE=/"hello/" -DVERSION=/"1.0/" -I. -I. -g -O2 -c hello.c

gcc -g -O2 -o hello hello.o

make[1]: Entering directory `/home/joe/devel/hello'

/bin/sh ./mkinstalldirs /usr/local/bin

/usr/bin/install -c hello /usr/local/bin/hello

make[1]: Nothing to be done for `install-data-am'.

make[1]: Leaving directory `/home/joe/devel/hello'

[[email protected] hello]# make dist

rm -rf hello-1.0

mkdir hello-1.0

chmod 777 hello-1.0

here=`cd . && pwd`; /

top_distdir=`cd hello-1.0 && pwd`; /

distdir=`cd hello-1.0 && pwd`; /

cd . /

&& Automake --include-deps --build-dir=$here --srcdir-name=. --output-dir=$top_distdir --foreign Makefile

chmod -R a+r hello-1.0

GZIP=--best gtar chozf hello-1.0.tar.gz hello-1.0

rm -rf hello-1.0

一切工作得很好! 當然,在make install時由于需要向系統目錄拷貝檔案,您需要有root權限。

更進一步

上述産生Makefile 的過程和以往自行編寫的方式非常不一樣,使用 Automake 隻需用到一些已經定義好的宏就可以了。我們把宏及目标 (target)寫在Makefile.am 檔案内,Automake 讀入 Makefile.am 檔案後會把這一串已經定義好的宏展開并産生相對應的

Makefile.in 檔案,然後再由configure這個 shell script 根據 Makefile.in 産生合适的Makefile。

具體流程如下所示:

代碼 --> [autoscan*] --> [configure.scan] --> configure.in

configure.in --. .------> Autoconf* -----> configure

+---+

[aclocal.m4] --+ `---.

[acsite.m4] ---' |

+--> [autoheader*] -> [config.h.in]

[acconfig.h] ----. |

+-----'

[config.h.top] --+

[config.h.bot] --'

Makefile.am --à [Autoconf*] -------> Makefile.in

.-------------> config.cache

configure* ------------+-------------> config.log

|

[config.h.in] -. v .-> [config.h] -.

+--> config.status* -+ +--> make*

Makefile.in ---' `-> Makefile ---'

上圖表示在整個過程中要使用的檔案及産生出來的檔案,有星号 (*) 代表可執行檔案。在此示例中可由 Autoconf 及 Automake 工具所産生的額外檔案有 configure.scan、aclocal.m4、configure、Makefile.in,需要加入設定的有configure.in 及 Makefile.am。 開發者要書寫的檔案集中為confiugre.in和Makefile.am,在minigui項目中,我們把一系列的指令集中到一個批處理檔案中: autogen.sh:

#!/bin/sh

aclocal

autoheader

Automake --add-missing

Autoconf

隻要執行該批處理檔案,結合configure.in和Makefile.am,就可以生成需要的Makefile了。

編輯 configure.in 檔案

Autoconf 是用來産生 'configure'檔案的工具。'configure' 是一個 shell script,它可以自動設定一些編譯參數使程式能夠條件編譯以符合各種不同平台的Unix 系統。Autoconf會讀取configure.in 檔案然後産生'configure' 這個 shell script。

configure.in 檔案内容是一系列GNU m4 的宏,這些宏經Autoconf處理後會變成檢查系統特性的shell scripts。 configure.in檔案中宏的順序并沒有特别的規定,但是每一個configure.in 檔案必須在所有其它宏前加入 AC_INIT 宏,然後在所有其它宏的最後加上 AC_OUTPUT宏。一般可先用 autoscan 掃描原始檔案以産生一個 configure.scan 檔案,再對 configure.scan 做些修改成 configure.in 檔案。在例子中所用到的宏如下:

dnl

這個宏後面的内容不會被處理,可以視為注釋

AC_INIT(FILE)

該宏用來檢查源代碼所在路徑,autoscan 會自動産生,一般無須修改它。

AM_INIT_AUTOMAKE(PACKAGE,VERSION)

這個是使用 Automake 所必備的宏,PACKAGE 是所要産生軟體的名稱,VERSION 是版本編号。

AC_PROG_CC

檢查系統可用的C編譯器,若源代碼是用C寫的就需要這個宏。

AC_OUTPUT(FILE)

設定 configure 所要産生的檔案,若是Makefile ,configure 便會把它檢查出來的結果填充到Makefile.in 檔案後産生合适的 Makefile。

實際上,在使用 Automake 時,還需要一些其他的宏,這些額外的宏我們用 aclocal來幫助産生。執行 aclocal會産生aclocal.m4 檔案,如果沒有特别的用途,不需要修改它,用 aclocal 所産生的宏會告訴 Automake如何動作。

有了 configure.in 及 aclocal.m4兩個檔案以後,便可以執行 Autoconf來産生 configure 檔案了。

編輯Makefile.am 檔案

接下來要編輯Makefile.am 檔案,Automake 會根據 configure.in 中的宏并在perl的幫助下把Makefile.am 轉成 Makefile.in 檔案。 Makefile.am 檔案定義所要産生的目标:

AUTOMAKE_OPTIONS

設定 Automake 的選項。Automake 主要是幫助開發 GNU 軟體的人員來維護軟體,是以在執行Automake 時,會檢查目錄下是否存在标準 GNU 軟體中應具備的檔案,例如 'NEWS'、'AUTHOR'、

'ChangeLog' 等檔案。設定為foreign 時,Automake 會改用一般軟體的标準來檢查。

bin_PROGRAMS

定義要産生的執行檔案名。如果要産生多個執行檔案,每個檔案名用空白符隔開。

hello_SOURCES

定義 'hello' 這個執行程式所需要的原始檔案。如果 'hello'這個程式是由多個原始檔案所産生,

必須把它所用到的所有原始檔案都列出來,以空白符隔開。假設 'hello' 還需要 'hello.c'、'main.c'、'hello.h' 三個檔案的話,則定義

hello_SOURCES= hello.c main.c hello.h

如果定義多個執行檔案,則對每個執行程式都要定義相對的filename_SOURCES。

編輯好 Makefile.am 檔案,就可以用 Automake --add-missing來産生 Makefile.in。加上 --add-missing 選項來告訴 Automake順便加入包裝一個軟體所必須的檔案,如果你不使用該選項,Automake可能會抱怨缺少了什麼檔案。Automake産生出來的 Makefile.in 檔案是完全符合 GNU Makefile 慣例的,隻要執行 configure這個shell

script 便可以産生合适的 Makefile 檔案了。

使用 Makefile

利用 configure 所産生的 Makefile檔案有幾個預先設定的目标可供使用,這裡隻用幾個簡述如下:

make all

産生設定的目标,既範例中的可執行檔案。隻敲入make 也可以,此時會開始編譯源代碼,然後連接配接并産生執行檔案。

make clean

清除之前所編譯的可執行檔案及目标檔案(object file, *.o)。

make distclean

除了清除可執行檔案和目标檔案以外,也把 configure 所産生的 Makefile 清除掉。 通常在釋出軟體前執行該指令。

make install

将程式安裝到系統中,若源碼編譯成功,且執行結果正确,便可以把程式安裝到系統預先設定的執行檔案存放路徑中,若用 bin_PROGRAMS 宏的話,程式會被安裝到 /usr/local/bin下。

make dist

将程式和相關的文檔包裝為一個壓縮文檔以供釋出 (distribution) 。執行完在目錄下會産生一個以

PACKAGE-VERSION.tar.gz 為名稱的檔案。PACKAGE 和 VERSION 這兩個參數是根據 configure.in 文中

AM_INIT_AUTOMAKE(PACKAGE, VERSION) 的定義。在我們的例子中會産生 'hello-1.0.tar.gz' 的檔案。

make distcheck

和 make dist 類似,但是加入檢查包裝以後的壓縮檔案是否正常,這個目标除了把程式和相關文檔包裝成 tar.gz 檔案外,還會自動把這個壓縮檔案解開,執行 configure,并執行 make all ,确認編譯無錯誤以後,方顯示這個 tar.gz 檔案已經準備好并可以釋出了。當你看到:

==========================================

hello-1.0.tar.gz is ready for distribution

==========================================

就可以放心地釋出您的軟體了,檢查過關的套件,基本上可以給任何具備 GNU 開發環境的人去重新編譯成功。

要注意的是,利用 Autoconf 及 Automake 所産生出來的軟體套件是可以在沒有安裝 Autoconf 及 Automake 的環境使用的,因為 configure 是一個 shell script,它己被設計為可以在一般 Unix 的 sh 這個 shell 下執行。但是如果要修改 configure.in 及 Makefile.am 檔案再産生新的 configure 及 Makefile.in 檔案時就一定要有 Autoconf 及 Automake 了。

相關資料

通常我們掌握了一些入門知識就可以開始實踐了,在有新的需求時,參照相關的文檔和别人的例子解決問題,在實踐中不斷提高。

Autoconf 和 Automake 功能十分強大,可以從它們附帶的 info 文檔中找到詳細的使用說明。或者您喜歡html,可以從gun站點上下載下傳hmtl版本。你也可以從許多現有的GNU 軟體或 Open Source 軟體如Minigui中找到相關的 configure.in 或 Makefile.am 檔案,他們是學習 Autoconf 及 Automake 更多技巧的最佳範例。

繼續閱讀