GNU Build Systemによるプログラム・パッケージ化の簡略化

ソースからプログラムをコンパイルしたことのある人なら誰でも、GNU Build Systemの中枢を形成するAutoconfパッケージとAutomakeパッケージの効果を目にしているはずだ。しかし、実際にこれらのツールを使用してconfigureスクリプトとMakefileファイルを生成している人は少ない。その手順を見ていくことにしよう。

configure、Makefile.in、config.h.inという名前のビルド・ファイルは他のファイルから作成される。configureスクリプトはautoconfプログラムによってconfigure.acファイルから作成される。Makefile.inファイルはautomakeプログラムによってMakefile.amファイルから作成され、config.h.inヘッダー・テンプレートはconfigure.acファイルの内容に基づいてautoheaderプログラムによって生成される。このヘッダー・ファイルには、存在するヘッダー・ファイル、存在しない関数などの設定を含め、設定サイクルの結果が含まれる。 プログラムではこのヘッダー・ファイルをインクルードして、特定のコンピュータ上でのそのプログラムの機能を判断することができる。

これは複雑なプロセスに見えるかもしれない。特に、configureスクリプトが確認する内容の大部分は確認の必要がないことを考えると、何のために必要なのか疑問に思うだろう。また、生成されるMakefileファイルも複雑すぎるように見える。

ビルド・システムの背後にある原動力は移植性である。さまざまな処理の方法はプラットフォームによって異なる。しかし、これらの多様なすべてのシステムに対応するために何種類ものconfigureスクリプトとMakefileファイルを構成したくはないだろう。テストのために、これらすべてのシステムにアクセスすることが不可能なことも考えられる。他のプラットフォームについては心配せずにソフトウェアのコーディングに専念できるように、これらの保守を代わりに行ってくれるツールが必要だ。そこで役に立つのがAutoconfパッケージとAutomakeパッケージである。

Automakeでは、Makefile.amファイルを通してビルド要件を指定できる。Makefile.amファイルの構文はMakefileファイルよりも単純である。Automakeは、configureスクリプトが最終的なMakefileファイルを生成するために使用するMakefile.inファイルを生成する。Makefile.inファイルには、まだインストール・ディレクトリなどは含まれていない。この種の情報はconfigureスクリプトを実行したときに収集される。–prefix–bindirなどのオプションは、最終?Makefileファイルの内容に影響する。

“Hello World”プログラムをコンパイルおよびインストールするには、Makefile.amファイルに次のようなコードを入力する。

bin_PROGRAMS = hello
hello_SOURCES = hello.c

これに対してautomakeを実行する。すると、make allmake installmake cleanなど、標準的なすべてのmakeターゲットをサポートするMakefile.inファイルが生成される。このMakefile.inファイルは、configureスクリプトに対する–prefixオプションで指定した場所にインストールされる(指定しなかった場合はデフォルトの/usr/local/bin)。

configureスクリプトはconfigure.acファイルから生成される。autoscanプログラムを使用してこのファイルを作成および保守できる。autoscanプログラムはソース・コード内をスキャンして、最終的に生成するconfigureスクリプトが確認する一般的な移植性の問題を調べる。

Makefileファイルとconfigureスクリプトを自分で作成することもできるが、とても時間がかかるので現実的ではない。自分がアクセスできないプラットフォーム上でスクリプトを動作させる必要がある場合には、なおさらである。

実際の例

それでは、configureスクリプトとMakefileファイル、これらを生成するためのすべてのファイルを備えた摂氏から華氏への変換プログラムを作成してみよう。

まずはプログラムそのものを作成する。called ctof.cというファイルを作成し、次のコードを入力する。

#include "config.h"

#ifdef HAVE_STDIO_H
# include <stdio.h>
#endif

#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif

int main(int argc, char *argv[]) {
	if (argc!=2) {
		printf("No Celsius value given?n");
		return 1;
	}

	#ifdef HAVE_STDLIB_H
		int celsius = atoi(argv[1]);
	#else
		printf("No stdlib.h present means no atoi() function.?n");
		printf("Defaulting to 20 Celsius as the input value.?n");
		int celsius = 20;
	#endif

	double fahrenheit;

	fahrenheit=(celsius * (9.0/5.0)) + 32;

	printf("%d Celsius = %.2f Fahrenheit?n", celsius, fahrenheit);

	return 0;
}

これはとても単純なプログラムだ。コマンド・ライン引数として渡した数値を摂氏の入力値を表す整数に変換し、その値を華氏に変換する。

コマンド・ラインで渡した文字列を整数に変換する処理にはatoi()関数を使う。この関数を使用する前に、configureスクリプトを実行したときにstdlib.hヘッダーが見つかったことを確認しなければならない。stdlib.hが見つからなかった場合は、atoi()関数は使わず、代わりに既定値の20を使う。stdlib.hが存在するかどうかをconfigureが確認してくれるので、私たちが自分で確認する手間は省ける。もしconfigureがなければ、この確認を行うコードを自分で書かなければならなかっただろう。1つの関数と1つのヘッダー・ファイルくらいならば問題ではないが、数百ものファイルがある場合はどうなるか考えてみよう。1つのファイルでも数百のファイルでも、autoscanを1回呼び出すだけで、移植性に関するすべての問題に対してconfigureに確認を行わせることができる。

次に、ビルド・プロセスを定義するMakefile.amファイルの作成に移る。この例の場合、手順は簡単だ。ctof.cをコンパイルし、ctofバイナリ・プログラムを作成し、それをインストールする。このためには、次のようなMakefile.amを作成する。

bin_PROGRAMS=ctof
ctof_SOURCES=ctof.c

必要なのはこの2行だけである。1行目は実行可能プログラム名を、2行目はプログラムを構成するソース・ファイルを定義している。

次にautoscanを実行する。ソース・ファイルがスキャンされ、configure.acファイルの前身となるconfigure.scanというファイルが作成される。このファイルを使う前に、いくつか修正を加えなければならない。まず、次の行を探す。

AC_INIT(FULL-PACKAGE-NAME, VERSION, BUG-REPORT-ADDRESS)

そして、これを次のように修正する。

AC_INIT(ctof, 0.1, gerard@linuxfromscratch.org)

この行の意味は簡単に理解できるだろう。最初の引数はパッケージ名、2番目の引数はパッケージのバージョン、3番目の引数はバグを報告する電子メール・アドレスである。make distを実行する際には、パッケージ名とバージョンを組み合わせることによって、tarアーカイブのファイル名が作成される。この例の場合は、ctof-0.1.tar.gzというtarアーカイブが作成される。

AC_INIT行の下に次の行を追加する。

AM_INIT_AUTOMAKE

AM_INIT_AUTOMAKEはAutomakeを初期化する。ここでAutomakeの動作を微調整するオプションを追加し、Makefileファイルに含める機能を指定することができる。オプションを指定しないと、無難なデフォルトのオプション・セットが使われる。ほとんどの場合はこれで問題ない。例を1つ挙げると、次のようにしてdist-bzip2オプションを使うことができる。

AM_INIT_AUTOMAKE(dist-bzip2)

こうすると、make distを実行したときに、package-version.tar.gzファイルに加えてpackage-version.tar.bz2ファイルが作成される。

このファイルはこれで完成だ。変更内容を保存し、configure.scanファイルの名前をconfigure.acに変更する。

mv configure.scan configure.ac

automakeを実行する前に、automakeが使用するいくつかのファイルを作成しなければならない。これらは、NEWSREADMEAUTHORSChangeLogである。次のコマンドでこれらを作成する。

touch NEWS README AUTHORS ChangeLog

後は、各コマンドを実行してconfigureファイル、Makefile.inファイル、config.h.in ファイルを生成するだけだ。

aclocal &&
autoheader &&
autoconf &&
automake --add-missing

aclocalコマンドは、以前(configure.acに名前を変更する前に)configure.scanファイルに追加したAM_INIT_AUTOMAKEマクロを定義するaclocal.m4ファイルを生成する。autoheaderコマンドは、configureスクリプトが見つかったヘッダーや利用できない関数などの情報を保存するために使用するconfig.hファイルを作成する。autoconfコマンドはconfigureスクリプトを生成し、automake --add-missingコマンドはMakefile.inファイルを生成する。また、ソース・ツリー内のdepcompスクリプト、install-shスクリプト、missingスクリプト、mkinstalldirsスクリプトへのシンボリック・リンクを作成する。これらのスクリプトは、プログラムがビルドおよびインストールされるときに使われる。

make distを実行すると、これらのシンボリック・リンクは参照先に実際のファイルに置き換えられる。これらのヘルパー・スクリプトが配布用tarアーカイブにコピーされるのは、他のシステムに既にAutoconfとAutomakeかインストールされているという事実に依存せずに、プログラムを動作させるためである。実際、適切な方法で作成したパッケージは、パッケージをビルドするホスト上のAutoconfパッケージとAutomakeパッケージの存在に依存しない。プログラムは、./configure && make && make installを実行するだけでインストールできるようにすべきである。これは、より堅牢で移植性の高いアプリケーションを作成するのに役立つ。

これですべて準備が整ったので、プログラムをコンパイルおよびインストールできる。

./configure --prefix=/usr &&
make &&
make install

これによってctofがコンパイルされ、/usr/binにインストールされる。–prefix=/usr構成オプションを省略すると、プログラムは/usr/local/binにインストールされる。プログラムをアンインストールするにはmake uninstallを実行する。

すべて正しくビルドされたことを確認したら、GNU Build Systemの非常に便利な機能を使用して、ソース・ツリーを配布用にパッケージ化することができる。make distを実行してtarアーカイブを作成する。make cleanmake distcleanを実行する必要はない。tarアーカイブには、configureスクリプト、Makefile.in、config.h.in、アプリケーションのソース・コードなど、本当に必要なファイルだけが含められる。コンパイル済みオブジェクト・ファイルや実行可能プログラム、ログ・ファイルなど、その他のファイルは含められない。

動作確認

それでは、GNU Build Systemの実際の動作を見てみよう。

configureスクリプトを通常のシステムで実行すると、出力の一部に次の行が含まれる。

checking for stdlib.h... yes

これは、プログラムでatoi()関数を使用できることを意味する。

$ ./ctof -14 -14
Celsius = 6.80 Fahrenheit

stdlib.hヘッダー・ファイルのないシステムでconfigureを実行すると、次の行が出力される。

checking for stdlib.h... no

これは、プログラムではatoi()関数を使用しないことを意味する。

$ ./ctof -14
No stdlib.h present means no atoi() function.
Defaulting to 20 Celsius as the input value.
20 Celsius = 68.00 Fahrenheit

これで、プログラムはstdlib.hヘッダー・ファイルがあるシステムでもないシステムでも実行できる。このファイルが存在するかどうかを調べるために特別な作業を行う必要はない。すべてはGNU Build Systemによって処理される。

始めるには少し余分な作業が必要となり、実際に状況は少し複雑になる。作業を単純にしたければ、Makefile.amファイルをセットアップすればよい。これは、どのソース・ファイルがどの実行可能プログラムを構成するかを他のツールに伝えるためのファイルである。