Autotools
はじめに
[編集]GNU autotoolsの概要
[編集]GNU autotoolsは、ソースコードからユニックス系OSにおけるビルド済みバイナリを生成するためのツール群です。主要コンポーネントは次の3つです。
- autoconf
- ポータブルなconfigureスクリプトを生成する
- automake
- Makefileの生成を自動化する
- libtool
- 共有/静的ライブラリのビルド、インストールを簡単化する
これらのツールを使うことで、複数のプラットフォームに対応したポータブルなビルドシステムを構築できます。
ビルドシステムの概要
[編集]一般的なソフトウェアのビルドプロセスは以下の手順で行われます。
- 設定 (Configure)
- ホスト環境に合わせて設定を行う
- ビルド (Build)
- ソースからオブジェクトファイルやライブラリを生成する
- インストール (Install)
- ビルド済みのファイルをシステムにインストールする
autotoolsは主にこの手順を自動化するためのフレームワークです。autoconfが設定ステップ、automakeがビルドとインストールのルールを提供します。
autoconfの利用
[編集]概要
[編集]autoconfはconfigure スクリプトを生成するツールです。configure.acと呼ばれる入力ファイルに、マクロと呼ばれる特殊な命令を記述することで、様々な処理を行うスクリプトを出力できます。
生成されたconfigureスクリプトは、ホストマシンの環境(OSの種類、アーキテクチャ、コンパイラの有無など)を検出し、それに合わせた設定を行います。
configure.acの構文
[編集]configure.acは、シェルスクリプトと同様の構文で記述されますが、autoconfマクロも多数使用します。以下は基本的な構造です。
- configure.ac
AC_INIT(パッケージ名, バージョン, バグレポートメールアドレス) AM_INIT_AUTOMAKE(オプション) # 環境検査用マクロ AC_PROG_CC AC_PROG_INSTALL ... # パッケージ固有のマクロ AC_ARG_WITH([gnupg], ...) AC_CHECK_LIB([gcrypt], ...) ... AC_CONFIG_FILES(Makefile src/Makefile ...) # 出力ファイルの指定 AC_OUTPUT
AC_INIT
でパッケージの情報を設定し、AC_CONFIG_FILES
で生成するファイル一覧を指定します。マクロの記述順序が重要です。
マクロ
[編集]autoconfには数多くの事前定義マクロが用意されており、環境検査やユーザ入力の処理に使われます。いくつか紹介します。
AC_PROG_CC
- C コンパイラの検出
AC_PROG_INSTALL
- インストールプログラムの検出
AC_CHECK_LIB(ライブラリ, 関数)
- 特定のライブラリと関数の存在を検査
AC_ARG_WITH(スイッチ名, ヘルプ文字列, 保管先変数)
--with-スイッチ
オプションの処理AC_DEFINE(定義名, 値, 説明)
- プリプロセッサマクロの定義
さらに、プラットフォーム固有の設定用に、autoconf 2.14以降では AC_CANONICAL_HOST
などのマクロが利用できます。
出力ファイル
[編集]configure.acからは主に以下のファイルが生成されます。
configure
- 設定スクリプト本体
config.status
configure
が更新するファイル一覧Makefile
- makefileのひな形(automakeが更に書き加える)
confdefs.h
、conftest.*
- 一時ファイル
configure
の実行により、これらのファイルが更新され、最終的なビルド環境が整えられます。
automakeの利用
[編集]概要
[編集]automakeは、autoconfから出力されたMakefileにさらなる指示を加え、本格的なMakefileを生成します。この入力ファイルをMakefile.amと呼び、特別なディレクティブを記述できます。
Makefile.amの構文
[編集]Makefile.amは、普通のMakefileと類似した構文で記述されますが、automakeディレクティブが追加で使えます。通常の構成は以下のようになります。
- Makefile.am
AUTOMAKE_OPTIONS = クロスツリーの有無 コンパイラフラグ ... bin_PROGRAMS = プログラム名 プログラム名_SOURCES = ソースファイル一覧 プログラム名_CFLAGS = コンパイラオプション lib_LTLIBRARIES = ライブラリ名.la ライブラリ名_la_SOURCES = ソースファイル一覧 dist_man_MANS = マニュアルファイル # ビルドルール .PHONY: ターゲット ターゲット: 依存ファイル コマンド
bin_PROGRAMS
では実行ファイルのビルド対象を、lib_LTLIBRARIES
では共有ライブラリの作成対象を指定します。
プログラムのインストール
[編集]automakeでは、インストール先ディレクトリがデフォルトで設定されています。
bin_PROGRAMS
- >
$(bindir)
lib_LTLIBRARIES
- >
$(libdir)
dist_man_MANS
- >
$(mandir)/man$(manext)
デフォルトの変更は可能ですが、オーバーヘッドがあるため基本的には標準の場所を使うことが推奨されています。
サブディレクトリ
[編集]automakeはサブディレクトリ内のMakefileも自動生成します。そのためには、トップディレクトリのMakefile.amで以下を記述します。
SUBDIRS = src utils doc
これにより、ビルド時にサブディレクトリのMakefileが再帰的に参照されます。
条件付きコンパイル
[編集]featuresあるいはオプションコードを有条件で組み込むには、automakeの条件コンパイル構文を使います。
if SOMECOND プログラム名_SOURCES += module.c else プログラム名_SOURCES += altmodule.c endif
SOMECOND
の値はautoconfで設定された変数で、真(true)か偽(false)を取ります。この値に応じて、module.c
かaltmodule.c
がプログラムのソースファイルに追加されます。
この条件分岐は、特定の環境やオプションでのみコードを有効化したい場合に便利です。例えば、以下のようにしてGUIサポートの有無を切り替えることができます。
if GUI_SUPPORT prog_SOURCES += gui.c gui_utils.c else prog_SOURCES += cui.c endif
GUI_SUPPORT
はconfigure時の--enable-gui
オプションで設定される変数です。trueならGUIコード、falseならCUIコードがコンパイル対象に含まれます。
automakeのif
ディレクティブでは、さらに複雑な条件分岐も可能です。
if COND1 ... else IF COND2 ... else ... endif
この例のように、ネストしたif
...else
...endif
の構造も使えます。COND1
とCOND2
は別々の条件を表す変数です。
このように、autotoolsを使えばさまざまな条件でのビルドルールを柔軟に設定できるため、ポータビリティの高いソフトウェアが開発しやすくなります。
libtoolの利用
[編集]概要
[編集]libtoolはautotoolsスイートの一部で、共有ライブラリと静的ライブラリの作成とインストールを簡単に行えるようにするツールです。ライブラリの種類やビルドルールはプラットフォームによって異なりますが、libtoolはそれらを自動的に処理してくれます。
共有ライブラリの作成
[編集]Makefile.amでlib_LTLIBRARIES
変数にライブラリ名を割り当てると、共有ライブラリのビルドが行われます。
lib_LTLIBRARIES = libfoo.la libfoo_la_SOURCES = foo.c bar.c
上記により、libfoo.laという名前の共有ライブラリが生成されます。.la
拡張子はlibtools独自の形式です。
静的ライブラリの作成
[編集]静的ライブラリはnoinst_LIBRARIES
変数で指定します。noinst
接頭辞により、インストールされない(非インストール)ライブラリとなります。
noinst_LIBRARIES = libutil.a libutil_a_SOURCES = util1.c util2.c
インストールルール
[編集]共有ライブラリのインストール先は通常$(libdir)
ですが、libtoolでは複数のインストール場所を指定できます。
libfoo_la_LDFLAGS = -version-info x:y:z install_fooHEADERS = foo.h fooincludedir = $(includedir)/foosubdir
libfoo_la_LDFLAGS
でバージョン情報を指定し、install_fooHEADERS
でインストールするヘッダファイルを、fooincludedir
でそのディレクトリを指定しています。
プラットフォーム依存の処理
[編集]libtoolは内部でプラットフォーム情報を利用し、OSごとにビルドルールを自動生成します。例えばライブラリのリンク方法は以下のように異なります。
- Linux
gcc -shared
- Solaris
/usr/ccs/bin/ld -G
- AIX
/usr/ccs/bin/ld -bhared
ユーザーはプラットフォームに依存しない統一的な方法で記述できるため、ポータビリティが高まります。
高度な機能
[編集]マルチスレッドプログラムのビルド
[編集]automakeには、POSIX スレッドを利用したマルチスレッドプログラムのビルドをサポートする機能があります。以下の手順で有効にできます。
configure.ac
にAC_PROG_CC_C99
を追加(C99規格のスレッドサポートが必要)Makefile.am
でAM_CPPFLAGS
にマルチスレッドフラグ-pthread
を追加
AM_CPPFLAGS = -pthread
これで各ソースコードが -pthread
フラグ付きでコンパイルされ、必要なスレッドライブラリもリンクされるようになります。
国際化とローカライズ
[編集]GNU gettext を使った国際化(I18N)とローカライズ(L10N)もautotoolsでサポートされています。主な手順は以下の通りです。
configure.ac
にAM_GNU_GETTEXT_VERSION
とAM_GNU_GETTEXT
を追加Makefile.am
にgettextマクロを記述AC_CONFIG_FILES
にpo/Makefile.in
を追加make update-po
でPOファイルテンプレートを生成
翻訳者はPOファイルに翻訳文字列を記入し、コンパイル時にそれらがプログラムに組み込まれます。
ソースコード生成
[編集]autoconfには、Cソースコードを生成するための機能も搭載されています。configure時にテストを実行し、その結果に基づいて使用する関数を切り替えたりできます。
例えば、標準のstrchrがない環境ではその実装が生成されます。
AC_FUNC_STRCHR :<syntaxhighlight lang= > <code>autoconf</code>は、独自の<code>confdefs.h</code>ファイルにこれらの関数を書き出します。 === Automake条件分岐 === automakeには条件分岐のための<code>if</code>ディレクティブが用意されており、ビルド対象ファイルをホストマシンの環境に応じて切り替えられます。 :<syntaxhighlight lang=make> if CROSS_COMPILING bin_PROGRAMS = util_cross else bin_PROGRAMS = util_native endif
CROSS_COMPILING
はautoconfで定義された変数で、クロスコンパイル環境であればutil_cross
、そうでなければutil_native
がコンパイルの対象となります。
トラブルシューティング
[編集]一般的なエラーとその対処
[編集]autotoolsを使っていてよくあるエラーとその対処法を紹介します。
- aclocal: 'openssl' hasn't been installed**
エラーの原因は/usr/share/aclocal/openssl.m4
がないことです。Debian系の場合、libssl-dev
パッケージをインストールすると解決できます。
- automake failed: gnu/libtool.m4 not found in /usr/share/aclocal**
この場合、libtool-devel
パッケージをインストールする必要があります。
- X11.m4 couldn't be found**
Xライブラリのインストールが必要なエラーです。環境によって異なりますが、例えばlibx11-dev
パッケージなどを追加インストールしてください。
デバッグ方法
[編集]autotoolsスクリプトのバグを探すには、それぞれのツールの-d
オプションを使うとよいでしょう。
autoreconf -iv --debug=automake
automake -a -v
autoconf -dv
これらはautotoolsの内部処理の詳細なログを出力するので、エラーの原因を特定しやすくなります。
Makefile自体をデバッグする際は、make -d
を実行すると標準出力に詳細なログが表示されます。
分かりました。autoconfとautomakeのトレース機能について、続けて説明します。
autoconfおよびautomakeのトレース
[編集]autoconfの実行時の検査内容を細かく追跡するには、autoreconf
時に--trace
オプションを付けます。
autoreconf -iv --trace=AC_CANONICAL_HOST
上記の例ではAC_CANONICAL_HOSTマクロの挙動がトレースされます。また、info autoconf
でマクロ探索の詳細を確認できます。
トレース対象を複数指定する場合は:
(コロン)で区切ります。
--trace=AC_CANONICAL_HOST:AC_PROG_CC
--trace
オプションを指定しないと、autoconfはトレース情報をほとんど出力しません。問題解決の際は是非このオプションを活用してください。
一方、automakeのトレースはAUTOMAKE_TRACE
環境変数で制御します。
AUTOMAKE_TRACE=true export AUTOMAKE_TRACE
これで、automakeの処理ステップが全て出力されるようになります。特定の情報のみを出力したい場合は、以下のように指定します。
AUTOMAKE_TRACE='categories=condition:foo'
categories
で指定したカテゴリ(condition
とfoo
)の情報のみがトレースされます。他のカテゴリはすべて以下のように表示されます。
condition:... foo:...
categories
以外の指定方法もあり、rules
ではパターンマッチでルールを選択できます。
AUTOMAKE_TRACE='rules=libtool'
この設定なら、libtoolに関連するルールのみがトレースされます。
このようにトレース機能を適切に使えば、autotoolsの内部動作を詳細に追跡でき、問題の特定が容易になります。
automakeのトレース
[編集]automakeの動作をトレースするには、AUTOMAKE_TRACE
環境変数を使います。
export AUTOMAKE_TRACE=':-1' automake -a
この設定で、automakeの実行ステップが全て表示されるようになります。特定の種類の情報のみを出力したい場合は以下のように指定します。
AUTOMAKE_TRACE=categories=CATEGORY1[:CATEGORY2]...
-
- 例
categories=recursive:condition
でRecursiveとConditionのカテゴリ情報のみ表示
AUTOMAKE_TRACE=rules=REGEX
-
- 例
rules='install\-data'
でインストールデータルールに関する情報のみ表示
このようにトレース機能を使えば、autotoolsの内部動作を詳細に追跡でき、問題の特定が容易になります。
ツールリファレンス
[編集]autoconf
[編集]autoconfのコマンドライン引数は次の通りです。
autoconf [OPTION]... [SHELL-FILE]...
主なオプションは以下です。
-o file
- 出力ファイル名を指定-f file
- 補助スクリプトファイル名を指定-B dir
- 一時ファイルの出力先ディレクトリを指定-d
- 詳細なデバッグ情報を出力-v, --verbose
- 処理内容を詳しく表示--trace=ITEM
- 特定の処理をトレース
代表的なマクロ
[編集]一般的に利用されるautoconfマクロを紹介します。
- プログラム検査
-
AC_PROG_CC
- Cコンパイラを検出
AC_PROG_CXX
- C++コンパイラを検出
AC_PROG_F77
- Fortranコンパイラを検出
- ライブラリ検査
-
AC_CHECK_LIB(LIBRARY, FUNC)
- ライブラリとその関数の存在をチェック
AC_CHECK_HEADER(HEADER-FILE...)
- ヘッダファイルの存在をチェック
- オプション処理
-
AC_ARG_WITH(PACKAGE...)
--with-package
オプションを処理AC_ARG_ENABLE(FEATURE...)
--enable-feature
オプションを処理
- その他
-
AC_DEFINE(DEFINITION...)
- プリプロセッサ定義を出力
AC_CHECK_FUNCS(FUNC...)
- 関数の存在をチェック
マクロの詳細は、info autoconf
を参照してください。
automake
[編集]automakeのコマンドライン引数は以下の通りです。
automake [OPTION]... [DIR]...
主なオプションは次のとおりです。
-a, --add-missing
- 必要な設定ファイルを生成
--foreign
- 非GNUプロジェクトの扱いにする
-i, --ignore-deps
- 非ストリクトな依存関係チェックを行う
--warnings=CATEGORY
- 特定のカテゴリの警告を表示
主要なディレクティブ
[編集]automakeで使用される主要なディレクティブは以下の通りです。
- 実行ファイル**
bin_PROGRAMS
- インストール対象の実行ファイル
noinst_PROGRAMS
- インストールされない実行ファイル
xxxxx_SOURCES
- プログラムのソースファイル
- ライブラリ**
lib_LTLIBRARIES
- インストール対象の共有ライブラリ
noinst_LIBRARIES
- インストールされない静的ライブラリ
- その他ファイル**
dist_man_MANS
- インストール対象のマニュアルファイル
dist_pkgdata_DATA
- パッケージデータファイル
- インストール先**
xxxdirname
- インストール先ディレクトリの変更
- 条件分岐**
if ... else ... endif
- 条件によるコード分岐
libtool
[編集]libtools のコマンドライン引数は以下のとおりです。
libtool [OPTION]... [MODE-ARGS]...
主なモードとオプションは次の通りです。
- モード**
--mode=link
- オブジェクトからライブラリを作成
--mode=install
- ライブラリをインストール
--mode=uninstall
- ライブラリをアンインストール
- オプション**
--silent
- 実行状況を表示しない
-n, --dry-run
- 実際のコマンドを実行せずに表示のみ行う
--preserve-dup-deps
- 重複した依存関係を残す
-static
- 共有ライブラリの代わりに静的ライブラリを作成
libtools自体の詳細はinfo libtool
を参照してください。
付録
[編集]サンプルコード
[編集]本書で説明した内容を踏まえ、簡単なサンプルプロジェクトを作成してみましょう。フォルダ構成は以下のようにします。
sampleproj/ |-- src/ | |-- main.c |-- doc/ | |-- sampleproj.txt |-- configure.ac |-- Makefile.am `-- README
最初にconfigure.ac
を作成します。
AC_INIT([sampleproj],[1.0],[ info@example.com ]) AM_INIT_AUTOMAKE([foreign -Wall]) AC_PROG_CC AC_CONFIG_SRCDIR([src/main.c]) AC_CONFIG_HEADERS(config.h) AC_CONFIG_FILES([Makefile src/Makefile]) AC_OUTPUT
次にMakefile.am
を作ります。
SUBDIRS = src doc dist_doc_DATA = README # プログラムメインソース bin_PROGRAMS = sampleproj sampleproj_SOURCES = src/main.c
src/Makefile.am
も必要です。
AM_CFLAGS = -Wall sampleproj_LDADD = @LIBS@
src/main.c
の中身は単に"Hello World"を表示するだけの簡単なものとします。
#include <stdio.h> int main(void) { printf("Hello World\n"); return 0; }
$ autoreconf --install $ ./configure $ make $ src/sampleproj Hello World
うまくビルドが行えました。このように、autotoolsを適切に設定すれば、ソースコードからバイナリまでの一連のビルドプロセスを自動化できます。
autoreconf --install
コマンドで、configure、config.statusなどのスクリプトファイルが生成されます。./configure
では環境に応じた設定が行われ、最終的にmake
でコンパイル・リンクされてバイナリが作られます。
このサンプルではごくシンプルな例を示しましたが、実際のプロジェクトではもっと複雑な設定が必要になることでしょう。例えば、以下のような機能を追加することが考えられます。
- 外部ライブラリの検出と利用設定
- GUIコードとCUIコードの分岐ビルド
- 国際化(gettext)のサポート
- サブディレクトリの並列ビルド
- 各種インストール先の変更
これらはすべてautotoolsで実現可能です。設定ファイルにマクロやディレクティブを適切に記述することで、用途に合わせてカスタマイズできます。
関連リソース
[編集]本書で紹介したtoolsの他にも、autotoolsと関連するユーティリティがいくつか存在します。
- autoconf-archive
autoconf-archive (https://www.gnu.org/software/autoconf-archive/) は、一般的に使われるautoconfマクロを収集したオンラインリポジトリです。ここに登録されているマクロを使えば、環境検査やコーディングの手間が大幅に省けます。
例えば以下のようにしてZLIBライブラリの有無を検査できます。
AX_ZLIB([ ZLIB_LIBS="-lz" ],[ AC_MSG_ERROR([zlib is required but wasn't found]) ])
- glib-gettext
glib-gettextは、GNUプロジェクトでの国際化(I18N)とローカリズ(L10N)をサポートするツールです。gettext toolkitとの連携により、POファイルの更新や翻訳文字列の抽出が容易になります。
$ glib-gettextize --force --copy $ intltoolize --force --copy --automake
- gnulib
gnulib(https://www.gnu.org/software/gnulib/) は、ポータブルなシステムユーティリティの集合体です。gnulibの関数をソースコードに組み込むことで、古いシステムでも最新の処理が利用できるようになります。
autoconfにはgl_FUNC_STRCHR
のようなマクロが用意されており、strchr関数の有無を検査し、ない場合はgnulibの実装を使うことができます。
まとめ
[編集]本書では、GNU autotoolsの主要3ツールであるautoconf、automake、libtoolについて解説しました。環境に応じたconfigureスクリプトの生成、Makefileの自動生成、共有ライブラリのビルドとインストールの自動化など、autotoolsを利用することでポータブルなビルドシステムが構築できます。
一方で、autotoolsの設定ファイルはかなり複雑で、理解と習熟に一定の時間がかかります。本書で基本的な使い方を理解したうえで、実際のプロジェクトに適用しながら経験を積むことが肝心です。
autoconfマクロやautomakeディレクティブの詳細については、info
マニュアルをぜひ参照してください。本書でカバーしきれなかった部分も多々あると思われます。autotoolsを十分に活用し、高品質で可搬性の高いソフトウェアを開発できるようになることを願っています。