autotools

原文地址

http://blog.dccmx.com/2011/page/9/10

Autotools上手指南1——autoconf基本思想

dccmx 於 2011年 一月 7日 發表 | 最後修改於 2011年 一月 10日
要想弄懂Autotools並使用它,必須先要了解一下M4這個怪物。

那麼何爲M4呢,M4的名稱取自Macro(M後面跟4個字母…)。它和C預處理器裏的宏是一個概念(其實,M4和C預處理器都K&R操刀設計的!!),用來處理文本替換。也就是說,M4是bash裏的預處理器。

取自維基的例子:

divert(-1)
This `divert' discards this text. Note that I had to quote the `divert'
in the comment so it wouldn't get undiverted.
This starts the count at ONE as the incr is a preincrement.
define(`H2_COUNT', 0)
The define H2_COUNT is redefined every time the H2 macro is used.
The dnl deletes everything on the line after it in the output (ie this bit) 
define(`H2', `define(`H2_COUNT', incr(H2_COUNT))'dnl
`<h2>H2_COUNT. $1</h2>')
divert(0)dnl diversion to 0 means back to normal dnl removes this line.
H2(First Section)
H2(Second Section)
H2(Conclusion)

這段M4宏用m4處理輸出的結果就是:

<h2>1. First Section</h2>
<h2>2. Second Section</h2> 
<h2>3. Conclusion</h2>

簡單說下:

1.M4的語法跟C裏面宏的語法差不多,都很像函數,名字加括號。

2.M4裏的參數即使聲明瞭也是可以忽略的,如果一個宏一個參數都不加的話,括號都可以忽略。

懂了吧。就當你懂了。

autoconf就是基於M4這個工具來生成configure腳本的。

我們來看一個最簡單的autoconf輸入,將下面代碼存爲configure.ac

AC_INIT([test], [1.0])
AC_CONFIG_FILES([Makefile]) 
AC_OUTPUT

再新建一個文件Makefile.in內容如下:

all: @PACKAGE_NAME@_bin
 
@PACKAGE_NAME@_bin: test.c
    gcc -o @PACKAGE_NAME@_bin test.c 

好,下面執行命令:

$ autoconf
$ ./configure 

看看,是不是生成了Makefile,是不是下面這樣:

all: test_bin
 
test_bin: test.c
    gcc -o test_bin test.c 

中間發生了什麼?停我慢慢道來。

首先,autoconf讀取configure.ac裏的宏,並調用M4處理這些宏,做些檢查,如果你很感興趣,這些宏的實現可以在/usr/share/autoconf/autoconf/*.m4裏找到這些宏的定義(看了不要發瘋)。檢查完會生成兩個文件:configure。執行configure腳本生成config.status和config.log。config.log裏面是執行的記錄,config.status是下一步執行的腳本,用來生成Makefile,configure生成完這個腳本會自動調用的。

那Makefile.in又是什麼呢?那是第二個宏AC_CONFIG_FILES([Makefile])執行時的默認輸入。方括號是用來表示參數的。就像上面的‘`’一樣。Makefile.in就是一個模板,用來生成Makefile。執行configure腳本時(實際上是config.status腳本),裏面的%變量%會被替換成相應的內容。有哪些變量?看看config.log就知道了。

好了,autoconf的基本原理就這樣了,本質上就做了件檢查環境和變量替換的事。其他的事情以後慢慢講。

Autotools上手指南2——autoscan生成configure.ac

dccmx 於 2011年 一月 10日 發表 | 最後修改於 2011年 一月 11日

前面說了autotools的基本原理:將configure.ac裏的宏展開,運行,生成Makefile。其實,對於大多數項目來說,configure.ac裏的內容基本框架都差不多。既然都差不多那麼有沒有什麼工具可以幫我們做這些基本的事情呢?別忘了你在linux下,有!

autoscan就是幹這事的。

下面我們建個test項目吧。目錄如下:

test
├── README
└── src
    ├── client.c 
    └── server.c 

在test目錄下運行autoscan看看。是不是生成了如下的configure.scan呢(autoscan.log被我們無情的忽略了):

#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
 
AC_PREREQ([2.68])
AC_INIT([FULL-PACKAGE-NAME], [VERSION], [BUG-REPORT-ADDRESS])
AC_CONFIG_SRCDIR([src/server.c])
AC_CONFIG_HEADERS([config.h])
 
# Checks for programs.
AC_PROG_CC
 
# Checks for libraries.
 
# Checks for header files.
AC_CHECK_HEADERS([netinet/in.h stdlib.h strings.h sys/socket.h unistd.h]) 
 
# Checks for typedefs, structures, and compiler characteristics.
AC_TYPE_PID_T
 
# Checks for library functions.
AC_FUNC_FORK
AC_FUNC_MALLOC
AC_CHECK_FUNCS([bzero socket])
 
AC_CONFIG_FILES([Makefile])
AC_OUTPUT

我們把這個文件稍微改改,即可用來當做configure.ac了,先將它重命名爲configure.ac吧。

我們解釋一下這個文件裏的一些宏。

首先是,AC_PREREQ([2.68]),這個宏用來檢查你機器上的autoconf版本的。這裏是我機器上的版本號2.68。

然後AC_INIT宏,這裏你要將裏面的內容改改,裏面的提示你懂的。我們改成下面這樣:

AC_INIT([test], [0.1], [[email protected]])

緊跟着是AC_CONFIG_SRCDIR([src/server.c]),這是autoconf用來定位自己的所在目錄的宏,裏面的內容是所在目錄下的任意一個文件就可以了,你可以改成一個更能代表你項目的文件(這樣不會更其他項目衝突),也可以不動。

下面是AC_CONFIG_HEADERS([config.h]) 這個是用來生成標準的config.h頭文件的宏,這個宏的意思是,從將模板裏的@**@變量替換掉生成config.h頭文件。模板是什麼?默認是.in,你記得的(Makefile.in),這裏就是config.h.in。我們稍後還會提到。

下面就是一系列的check了,最後是生成Makefile的文件,我們介紹過。

好了,改完了,autoconf命令看看吧。

autoconf如願生成了configure,運行configure,是不是很標準的輸出呢,但是最後提示錯了,因爲我們還沒有添加config.h.in和Makefile.in

Makefile.in文件還像以前的:

all: @PACKAGE_NAME@_client @PACKAGE_NAME@_server 
@PACKAGE_NAME@_client:
    gcc -o @PACKAGE_NAME@_client src/client.c
@PACKAGE_NAME@_server:
    gcc -o @PACKAGE_NAME@_server src/server.c

config.h.in呢?我們寫一個吧,從上面autoscan生成的configure.ac來看,宏AC_CHECK_HEADERS([netinet/in.h stdlib.h strings.h sys/socket.h unistd.h])告訴我們的程序調用了這些頭文件,那麼我們的config.h.in就這樣寫:

#undef HAVE_NETINET_IN_H 
#undef HAVE_STDINT_H
#undef HAVE_STDIO_H
#undef HAVE_STDLIB_H
#undef HAVE_STRING_H
#undef HAVE_SYS_SOCKET_H 
#undef HAVE_UNISTD_H
#undef HAVE_NONEXIST_H

看到啦,我們先把這些頭文件全都按規則undef掉,我們還加了個系統不存在的頭文件試試,現在在運行configure腳本看看,是不是出現了下面的config.h頭文件呢:

/* config.h.  Generated from config.h.in by configure.  */ 
#define HAVE_NETINET_IN_H 1
#define HAVE_STDINT_H 1
#define HAVE_STDIO_H 1
#define HAVE_STDLIB_H 1
#define HAVE_STRING_H 1
#define HAVE_SYS_SOCKET_H 1
#define HAVE_UNISTD_H 1
/* #undef HAVE_NONEXIST_H */

看,所有存在的頭文件都被define成了1,不存在的被註釋掉。好吧,在你的程序裏盡情的include吧,生活真美好。現在可以make生成可執行文件了。test_client和test_server是不是如願生成了呢?應該是的!

現在我們項目中仍然有兩個.in文件要我們自己寫:config.h.in和Makefile.in,關於這兩個文件的工具,我們後面再談。拉上老婆出去逛逛吧。歇會兒。

Autotools上手指南3——autoheader和automake

dccmx 於 2011年 一月 11日 發表 | 最後修改於 2011年 十二月 14日

前面提到,config.h.in和Makefile.in還要手寫,現在我們就來看看,Autotools裏有那些工具幫助我們完成這些體力活。
首先是config.h.in。這個非常簡單,弄好configure.ac後,直接在項目根目錄運行下面命令

1
autoheader
看看,是不是生成了config.h.in了,看看內容。真輕鬆啊,autoheader工具分析了configure.ac裏面所有要檢查的東西,然後生成了相應的宏,好了,可以用了。

Makefile.in的生成就比較複雜了,畢竟Makefile是個複雜的東東。
我坦白,要自動生成Makefile.in以便讓configure自動生成Makefile你必須再手動寫個Makefile.am文件(這就是靈活的代價和unix的哲學)。
所謂Makefile.am其實就是automake用來生成Makefile.in的模板,裏面就像一般的Makefile,只不過加了一些automake宏。
回顧前面的目錄結構,我們需要在根目錄和所有源碼目錄添加Makefile.am文件,如下:

test
├── README
├── configure.ac
├── Makefile.am
└── src
    ├── Makefile.am 
    ├── client.c
    └── server.c

先來看根目錄下的Makefile.am文件:

SUBDIRS = src 

灰常簡單!
再看src目錄下的Makefile.am文件:

bin_PROGRAMS = client server 
 
client_SOURCES = client.c
 
server_SOURCES = server.c

同樣灰常簡單,這個文件,不解釋,你懂的。現在應該淡定些了。
好,現在我們還需要建一些文件AUTHORS、COPYING、NEWS、ChangeLog和README,這些文件都是gnu項目的標準文件,automake會檢查這些文件的。所以,如果不想要的話先建個空文件搪塞一下吧,如果實在受不了也可以用–foreign參數來禁止這個檢查。
最後一步,在configure.ac裏面加上automake支持的宏

#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
 
AC_PREREQ([2.68])
AC_INIT([test], [1.0], [[email protected]])
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([src/server.c])
AC_CONFIG_HEADERS([config.h])
 
# Checks for programs.
AC_PROG_CC
 
# Checks for libraries.
 
# Checks for header files.
AC_CHECK_HEADERS([netinet/in.h stdlib.h strings.h sys/socket.h unistd.h]) 
 
# Checks for typedefs, structures, and compiler characteristics.
AC_TYPE_PID_T
 
# Checks for library functions.
AC_FUNC_FORK
AC_FUNC_MALLOC
AC_CHECK_FUNCS([bzero socket])
 
AC_CONFIG_FILES([Makefile src/Makefile])
AC_OUTPUT

看到了,我們現在初始化部分加了AM_INIT_AUTOMAKE 來初始化automake,在最後又改了AC_CONFIG_FILES([Makefile src/Makefile]) ,來吧src目錄下的Makefile也加入管理。
好了,都準備好了,開始幹活:

dccmx@~/projects/console/test$ aclocal
 
dccmx@~/projects/console/test$ autoconf
 
dccmx@~/projects/console/test$ autoheader
 
dccmx@~/projects/console/test$ automake –a –c 
 
dccmx@~/projects/console/test$ make

神清氣爽啊。在src目錄裏生成兩個二進制文件了。make distclean看看?一切恢復如初!make dist看看,自動打包發佈。生活真是美好啊。
等等,第一個命令是幹什麼的呢,這個命令是用來生成automake依賴的宏的,供autoconf調用(因爲automake其實不是autoconf的一部分,只相當於插件)。automake後面的兩個參數又是幹什麼的呢?因爲automake生成的Makefile需要一些外部腳本輔助,而項目裏是沒有的,所以-a就是把這些文件自動添加就來,-c就是指定用複製的方式添加,否則是符號鏈接。
好了,基本的autotools的介紹就這些了。更高級的話題,後面有時間再談吧。洗洗睡了。

Autotools上手指南4——深加工

dccmx 於 2011年 一月 17日 發表 | 最後修改於 2011年 一月 20日

有了前面幾篇文章介紹的幾招,基本的構建系統就算完成了。開始離專業水平還有一定距離。我們現在看看一些後續的方法,讓我們的構建腳本更加專業。

  1. 設置庫依賴和預處理宏:
    設置依賴庫和宏的方法很簡單,只要維護gcc的參數就ok了。這些參數在Makefile.am裏面維護。

先在configure.ac裏面加上相關的宏:AM_PROG_CC_C_O。

要添加預處理宏的話(比如_GNU_SOURCE宏)只要在Makefile.am裏面添加xxx_CFLAGS = -D_GNU_SOURCE。好了。重新configure吧。

依賴的庫呢?你猜對了,在Makefile.am裏面添加xxx_LDFLAGS = -lssl -lidn -lz就ok了。生活。。。真美好!

  1. 檢查目標系統上的庫:
    如何檢查目標系統上有沒有我們程序依賴的庫呢。很簡單,在configure.ac裏面加上AC_CHECK_LIB宏。其實autoscan會檢查Makefile.am中的_LDFLAGS而自動在configure.ac裏面添加相關的check宏的。這個宏的原型如下:
AC_CHECK_LIB(library, function, [action-if-found], [action-if-not-found], [other-libraries])

中間的function可以選擇lib裏面最典型的一個函數,用來測試找到的lib是不是你要的lib,你懂的。舉個例子:

AC_CHECK_LIB([ssl], [SSL_get_peer_certificate], [have_ssl=yes]) 

在在下面加入:

if test "x${have_ssl}" = xno; then
AC_MSG_ERROR([
------------------------------------------
Unable to find ssl on this system.
------------------------------------------]) 
fi

好了,找不到libssl,或者libssl不對(裏面沒有SSL_get_peer_certificate),就會提示了。

檢查頭文件呢?你猜對了。

AC_CHECK_HEADER(header-file, [action-if-found], [action-if-not-found], [includes]) 
  1. 部署文件:
    目前爲止,默認make install已經可以將我們的bin文件安裝到/usr/local/bin下了(可以用–prefix改)。如果我們要安裝其他文件呢,比如默認配置文件啊等等。

比如我們在xml目錄下有a.xml b.xml要安裝到默認的@data@/xml目錄下(默認是/usr/local/share)。

第一步,在xml目錄下建Makefile.am。內容如下:

xmldir = $(datadir)/xml 
xml_DATA = a.xml b.xml

第二步,在configure.ac裏面的AC_CONFIG_FILES([Makefile src/Makefile]) 加上這個Makefile,改成AC_CONFIG_FILES([Makefile src/Makefile xml/Makefile])

第三步,重新autoconf,automake。其實只要一個命令autoreconf就行了。這個命令會替你調用autoheader和automake的。

想要make dist的時候包含到壓縮包裏?在xml_DATA前面加上dist變成:dist_xml_DATA就ok了。

好了,make install看看。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章