初心者への GNU autoconf のススメ
Lynx Optimized Pages!
This page is written in Japanese.

145585 accesses since 2001/07/27.
17 accesses per day.

[ TOP ]

©1997-99 Kazuya 'Sharl' Masuda <sharl @ hauN.org>

目次:
  1. はじめに
    1. なぜ autoconf?
    2. インストール
  2. 実際に使ってみる
    1. ひとまずプログラムを書く
    2. configure.in を作る
    3. Makefile.in を修正する
    4. configure.in を見ながらいろいろ修正する
    5. config.h を作ってみる
  3. 終わりに
  4. 謝辞
  5. 変更履歴

はじめに

このドキュメントは、初心者とはいえ C プログラミングができて Makefile を記述することが 可能な人を対象にしています。

「使ってみたいけど、とっかかりがわからない」という人に読んでほしいです。


なぜ autoconf?

GNU の autoconf の使い方を知らなくても、GNU のツールを インストールするときに

% ./configure
% make
% su
$ make install

とするのがほとんどでしょう。この簡便さをすべてのソフトウエアのコンパイルでも享受したい とは思いませんか。そんなあなたのために「どのようにすれば ./configure; make 一発でコンパイルが 終わるパッケージを書けるようになるか」を書いていきます。導入ガイドみたいなもんです。


インストール

次のアーカイブを用意します。

ほとんどが perl スクリプトなので perl が必須です。また、一部のスクリプトで awk を使っているので awk も必須です。

dejagnu-1.3 は入れても入れなくてもいいです。厳密な動作チェックをしたい人は入れましょう。

各プログラムのインストールは通常の GNU パッケージをインストールするときと同じです。


実際に使ってみる


ひとまずプログラムを書く

まずは試しに、こんなソースを書いてみました。

#include <stdio.h>
#include <stdlib.h>

int
main(int argc, char *argv[])
{
  char pathname[1024], *envname;

  getwd(pathname);
  if (argc == 1) {
    if ((envname = getenv("HOME")) != NULL) {
      if (strncmp(pathname, envname, strlen(envname)) == 0) {
	*pathname = '~';
	strcpy(pathname + 1, (char *)(pathname + strlen(envname)));
      }
    }
  } else if ((argc != 2)
	     || (*argv[1] != '-')
	     || (*(argv[1] + 1) != 'l')
	     || (*(argv[1] + 2) != '\0')) {
    puts("usage: pwd [-l]");
    return 1;
  }
  puts(pathname);
  return 0;
}

C 入門のようなソースですが、このままではコンパイルできない OS がまだまだ世の中にはあります。 このソースをいじりながら configure を作成するためのテンプレート configure.in と Makefile のテンプレート Makefile.in を作っていきます。


configure.in を作る

ひとまずこのソースのあるディレクトリで Makefile.in を作成しておきます。

% touch Makefile.in

今はこれでじゅうぶんです。そして autoscan を実行すると、configure.scan が作成されます。これが configure.in の雛型になります。 あくまでも雛型なので、さまざまな条件が足りません。

configure.scanconfigure.in にコピーして configure.in をいじります。

% cp configure.scan configure.in

C でプログラムを組むので、Checks for programs. のところに AC_PROG_CC を付け加えて (dnl は m4 マクロのコメントです)

dnl Checks for programs.
AC_PROG_CC

autoconf を実行すると、configure が作成されます。さっそく実行してみましょう。

% ./configure

Makefile.in を修正する

Makefile はできたけど空です。このままでは始まらないので、Makefile を書くように Makefile.in を 書いてみましょう。

#
# Makefile for autoconf tutorial
#

CC = @CC@
DEFS = @DEFS@
LIBS = @LIBS@

SRCS = pwd.c
OBJS = $(SRCS:.c=.o)
PROG = pwd

all: $(PROG)

$(PROG): $(OBJS)
	$(CC) -o $@ $(OBJS) $(LIBS)

.c.o:
	$(CC) $(DEFS) -c -o $@ $<

clean:
	rm -f $(OBJS)

@CC@ とか @DEFS@ などとなっているところがミソです。さっき configure.in に付け加えた AC_PROG_CC で検出された C コンパイラが @CC@ と置き換わります。@DEFS@ はあとで述べるシンボルに、@LIBS@ は検出されたライブラリに置換されます。


configure.in を見ながらいろいろ修正する

できあがった Makefile を使って make してみると、うまくいくシステムと warning を吐いたりして うまくいかないシステムがあると思います。

configure.in を改めて見ると AC_ で始まるマクロがいくつか定義されています。 AC_CHECK_FUNCS に羅列されている関数を持っていないシステムでは、このままではコンパイル できないので修正する必要があります。カレントディレクトリを取得する関数が getcwd() しかないシステムのために、getcwd() も使って書き直します。

dnl Checks for library functions.
AC_CHECK_FUNCS(getcwd getwd)

このとき、どの関数を持っているかを判別するためのシンボルが HAVE_関数名 というように定義されるので、それを利用します。関数名はすべて大文字に変換されて定義されます。 Makefile を見てみると、@DEFS@ が置き換わっているのでわかるでしょう。

#ifdef HAVE_GETCWD
    getcwd(pathname, sizeof(pathname));
#else
#  ifdef HAVE_GETWD
    getwd(pathname);
#  endif
#endif

デフォルトでリンクされる libc.a 以外のライブラリに含まれている関数を使っている場合には AC_CHECK_LIB を使います。第一引数がライブラリ名、第二引数が関数名です。

たとえば socket() が libsocket.a に含まれている OS では AC_CHECK_FUNCS(socket) で失敗し、LIBS に -lsocket が追加されないのでリンク時にエラーになって しまいます。これを避けるには configure.in に

dnl Checks for libraries.
AC_CHECK_LIB(socket, socket)

と書きます。

中級者向け:
ネットワーク周りのライブラリのチェックには AC_PATH_XTRA を使って @X_EXTRA_LIBS@ を追加すると いう手もありますが、X 使わないのに…という向きには CF_NETLIBS というものがあります。これを aclocal.m4 に書いておいて AC_FOOBAR と同じ感じで CF_NETLIBS と書いておけばチェックしてくれます。

(Lynx current の aclocal.m4 からのパクり。 AC_HAVE_LIBRARY で warning が出るけど無視してかまいません)

configure.in を修正したら autoconf の実行からやり直しです。


config.h を作ってみる

GNU のソースを見ると、@DEFS@ が -DHAVE_CONFIG_H になっていて、-D... の羅列になっていたものが config.h にまとめて定義されているものがあります。Make 時のだらだらと長いコマンド行が嫌いな人、 ファイルの依存関係をきちんと記述する人にはこちらのほうが向いていると思います。

config.h を作るためには configure.in に AC_CONFIG_HEADER(config.h) を追加(AC_INIT の直後がいいかも)して、autoheader を実行して config.h.in を作る必要があります。 AC_CONFIG_HEADER(conf.h) にすると、conf.h.in が生成されます。

ここで注意。

#ifdef HAVE_CONFIG_H
#  include "config.h"
#endif

とソースに書くのを忘れると、かなりマヌケです。

また、AC_CONFIG_HEADER で指定したヘッダももちろん configure.in に依存しているので、依存関係を 反映させるために Makefile.in も修正しましょう。

config.h.in: configure.in
	autoheader

終わりに

以上のループの繰り返しで autoconf を利用したプログラミングが終わります。だいたいの感じは つかめたでしょうか?

実際にはいろいろな OS の上でコンパイルしてみるのが一番ですが、なかなかそうもいきません。 autoconf を使うのだから、いろんなところにばらまいて試してもらって feedback をもらうのが楽です :-) 経験を積むうちに、だんだんとコツがつかめてくるので、がんばりましょう。

とかいうわたしも附属の info をまったく読まないで GNU パッケージについてくるソースを読んで 使い方を覚えたので、まだまだ修行中です。ツッコミや使ってみて詰まったところなどがありましたらメイルください


謝辞

このページを作るきっかけを与えてくださり、autoconf ぼくらの約束もっと使おう autoconf: tips 集を 開示してやる気を出させてくれた いとぢゅんさん。 これらのページが表に出なかったら、まだまだできてませんでした。本当にありがとうございます。


変更履歴

(1998/04/06)
config.h を作ってみる」を追加。 「configure.in を見ながらいろいろ修正する」に AC_CHECK_LIB の使い方を追加。
(1998/03/17)
ひとまずプログラムを書く」のサンプルが間違ってた(汗;)。浦栃さんありがとう。
(1997/10/09)
autoconf をインストールする説明を追加。
(1997/09/20)
例を増やしてみた。
(1997/09/16)
とりあえず完成。公開してみる。
(1997/04/12)
作成。

©1997-99 Kazuya 'Sharl' Masuda <sharl @ hauN.org>

$Id: autoconf.html,v 1.16 1999/09/30 01:45:42 sharl Exp sharl $