autoconf/automake を使ってみる

先日 autoconf/automake を使ってみたのだが、ドキュメントもろくに読まずにやったら当然ながらうまくいかなくてかなり試行錯誤するはめになった。復習を兼ねてその時の作業をメモしてみる。あ、今もちゃんと理解してる訳ではないので「こうやったらうまくいった(っぽい)」というだけで、間違ってることを言ってる可能性は大です。そのあたりはご注意を。

まずは作業前の状態。

% ls
CVS/  ChangeLog  README.bhl  xmessage+.c

ソース xmessage+.c から xmessage+ というバイナリを作ってみます。ソースの中身は先日のポップアップウィンドウそのままですが、諸般の事情で名前を変えてみてます。ヘッダファイルもないし GTK+ を使っていること以外は "Hello world!!" と大して変わりません。README.bhl は xmessage+ の説明を BHL で書いたもの。最終的にはこいつを変換して README を作りますが、とりあえずは気にしなくていいです。

Makefile.am を作る

さて、まず最初に Makefile.am を作ります。内容はこんなん。

bin_PROGRAMS=xmessage+
xmessage__SOURCES=xmessage+.c
INCLUDES=$(XMESSAGE__CFLAGS)
xmessage__LDADD=$(XMESSAGE__LIBS)

一行目で「xmessage+ というバイナリを作る」ことを宣言します。二行目がその元となるソースファイル (xmessage+.c) の指定。素直にやると

xmessage+_SOURCES=xmessage+.c

とするところなんですが、変数名に使える記号はアンダースコアだけなので xmessage__SOURCES= にしてやります。更に GTK+ が必要とするフラグやライブラリを三行目と四行目で参照しています。このあたりの話はこちらが参考になります。

configure.in を作る

Makefile.am ができたら autoscan を実行して configure.in の雛形となる configure.scan を作ります。

% autoscan
autom4te: configure.ac: no such file or directory
autoscan: /usr/bin/autom4te failed with exit status: 1
zsh: exit 1     autoscan

なんかエラーが出ちゃいますが

% ls
CVS/       Makefile.am  autoscan.log    xmessage+.c
ChangeLog  README.bhl   configure.scan

configure.scan は無事できているのでこいつを編集していきます。いきなり最終形と diff るとこんなん。

% diff configure.scan configure.in
--- configure.scan      2006-02-19 10:20:10.263352824 +0900
+++ configure.in        2006-02-19 10:27:03.575519824 +0900
@@ -2,14 +2,18 @@
 # Process this file with autoconf to produce a configure script.

 AC_PREREQ(2.59)
-AC_INIT(FULL-PACKAGE-NAME, VERSION, BUG-REPORT-ADDRESS)
+AC_INIT(xmessage+, 0.1, foo@example.com)
+AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION)
 AC_CONFIG_SRCDIR([xmessage+.c])
-AC_CONFIG_HEADER([config.h])
+AM_CONFIG_HEADER(config.h)

 # Checks for programs.
 AC_PROG_CC

 # Checks for libraries.
+PKG_CHECK_MODULES(XMESSAGE_, gtk+-2.0)
+AC_SUBST(XMESSAGE__CFLAGS)
+AC_SUBST(XMESSAGE__LIBS)

 # Checks for header files.
 AC_HEADER_STDC
zsh: exit 1     diff -u configure.scan configure.in

AC_INIT() の行はそのまま FULL-PACKAGE-NAME, VERSION, BUG-REPORT-ADDRESS を書き直し、AC_CONFIG_HEADER() を AM_CONFIG_HEADER() に変更します。それと AM_INIT_AUTOMAKE() の行を追加。ここいらはこうするもんのようです。

更に GTK+ 絡みは先のページを参考に PKG_CHECK_MODULES(), AC_SUBST() を追加します。PKG_CHECK_MODULES マクロはライブラリの依存関係を指定します。今回の場合は gtk+-2.0 を指定しています。AC_SUBST は必要となるフラグやライブラリを収集してくれます。これは先程作った Makefile.am の中で参照しています。

これでほぼ準備は整いましたが、automake は NEWS, README, AUTHORS, ChangeLog の有無をチェックするので空ファイルでいいのでとりあえずこれらを作っときます。

% touch NEWS README AUTHORS ChangeLog
% ls
AUTHORS  ChangeLog    NEWS    README.bhl    configure.in
CVS/     Makefile.am  README  autoscan.log  xmessage+.c

automake する

最後に下記コマンドで configure や Makefile.in を生成します。

% aclocal && autoheader && autoconf && automake --add-missing
automake: configure.in: installing `./install-sh'
automake: configure.in: installing `./mkinstalldirs'
automake: configure.in: installing `./missing'
automake: configure.in: installing `./config.guess'
automake: configure.in: installing `./config.sub'
automake: Makefile.am: installing `./INSTALL'
automake: Makefile.am: installing `./COPYING'
% ls
AUTHORS    Makefile.am  aclocal.m4       config.sub@   mkinstalldirs@
COPYING@   Makefile.in  autom4te.cache/  configure*    stamp-h.in
CVS/       NEWS         autoscan.log     configure.in  xmessage+.c
ChangeLog  README       config.guess@    install-sh@
INSTALL@   README.bhl   config.h.in      missing@

これで ./configure && make できる状態になりました。

% ./configure && make
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking whether make sets $(MAKE)... yes
(中略)
gcc -DHAVE_CONFIG_H -I. -I. -I. -DXTHREADS -I/usr/include/gtk-2.0 -I/usr/lib/gtk-2.0/include -I/usr/X11R6/include -I/usr/include/atk-1.0 -I/usr/include/pango-1.0 -I/usr/include/freetype2 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include      -g -O2 -c xmessage+.c
gcc  -g -O2  -o xmessage+  xmessage+.o -Wl,--export-dynamic -lgtk-x11-2.0 -lgdk-x11-2.0 -latk-1.0 -lgdk_pixbuf-2.0 -lm -lpangoxft-1.0 -lpangox-1.0 -lpango-1.0 -lgobject-2.0 -lgmodule-2.0 -ldl -lglib-2.0
% ls xmessage+
xmessage+*

ちゃんとバイナリ xmessage+ が出来てました。ふぅ。

この automake で作った Makefile には distcheck ってターゲットがあって、make distcheck すると tar ball でパッケージを作ったうえでいろいろテストをやってくれます。便利。

% make distcheck
rm -rf xmessage+-0.1
mkdir xmessage+-0.1
chmod 777 xmessage+-0.1
(中略)
rm -rf xmessage+-0.1
==============================================
xmessage+-0.1.tar.gz is ready for distribution
==============================================
% ls *.tar.gz
xmessage+-0.1.tar.gz

おまけ

実はこの時点で README は touch で作っただけなので内容が空です。tar ball にまとめる際に README.bhl -> README に変換してやる必要があります。このようなパッケージ作成時に追加したい処理には dist-hook ターゲットを使います。今回の場合は Makefile.am に以下を追加。

dist-hook:
	-test -e $(srcdir)/README.bhl \
	  && bhl2txt -f $(srcdir)/README.bhl -o $(srcdir)/README
	test -e $(distdir)/README || cp $(srcdir)/README $(distdir)

パッケージには README.bhl は含まずに、生成した README だけを同梱したいのでちょっと小細工してますが、まぁこんなかんじです。

それと、コンパイラgcc の時には -Wall オプションを追加したい、といった場合には

% diff configure.in.old configure.in
--- configure.in.old    2006-02-19 10:59:24.007791000 +0900
+++ configure.in        2006-02-19 12:35:32.712815048 +0900
@@ -9,6 +9,9 @@

 # Checks for programs.
 AC_PROG_CC
+if test "$GCC" = "yes"; then
+  CFLAGS="$CFLAGS -Wall"
+fi

 # Checks for libraries.
 PKG_CHECK_MODULES(XMESSAGE_, gtk+-2.0)
zsh: exit 1     diff -u configure.in.old configure.in

こんなんを configure.in に加えとくといいようです。


いろいろ書いてみたけど合ってるのかなあ。なんか嘘いっぱいな予感がしないでもなかったり。