コンテンツにスキップ

Autotools

出典: フリー教科書『ウィキブックス(Wikibooks)』

はじめに[編集]

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.hconftest.*
一時ファイル

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.caltmodule.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の構造も使えます。COND1COND2は別々の条件を表す変数です。

このように、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 スレッドを利用したマルチスレッドプログラムのビルドをサポートする機能があります。以下の手順で有効にできます。

  1. configure.acAC_PROG_CC_C99を追加(C99規格のスレッドサポートが必要)
  2. Makefile.amAM_CPPFLAGSにマルチスレッドフラグ -pthread を追加
AM_CPPFLAGS = -pthread

これで各ソースコードが -pthreadフラグ付きでコンパイルされ、必要なスレッドライブラリもリンクされるようになります。

国際化とローカライズ[編集]

GNU gettext を使った国際化(I18N)とローカライズ(L10N)もautotoolsでサポートされています。主な手順は以下の通りです。

  1. configure.acAM_GNU_GETTEXT_VERSIONAM_GNU_GETTEXTを追加
  2. Makefile.amにgettextマクロを記述
  3. AC_CONFIG_FILESpo/Makefile.inを追加
  4. 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で指定したカテゴリ(conditionfoo)の情報のみがトレースされます。他のカテゴリはすべて以下のように表示されます。

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と関連するユーティリティがいくつか存在します。

        1. 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])
])
        1. glib-gettext

glib-gettextは、GNUプロジェクトでの国際化(I18N)とローカリズ(L10N)をサポートするツールです。gettext toolkitとの連携により、POファイルの更新や翻訳文字列の抽出が容易になります。

$ glib-gettextize --force --copy
$ intltoolize --force --copy --automake
        1. 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を十分に活用し、高品質で可搬性の高いソフトウェアを開発できるようになることを願っています。