Autotoolsについてのメモ

このメモはGNU Autotoolsのautoconfとautomakeとを使って フリーソフトウェアの配布用パッケージを作る方法を解説している。 FortranのプロジェクトにAutotoolsを使う場合の注意点も書いてある。


Table of Contents:

はじめに

たいていのGNUのフリーソフトウェアは次のようにtar ballを展開して、 ./configure && make && make installとすることで簡単にソースからインストールすることができる。

$ tar xf feram-X.YY.ZZ.tar.xz
$ cd feram-X.YY.ZZ
$ mkdir build   # Use build directory.
$ cd build
$ ../configure --help
$ ../configure
$ make
$ make check
$ sudo make install
$ make installcheck

AutotoolsはそんなGNU流のフリーソフトウェアパッケージの 構築を半自動化するための開発者用のツールである。最終目的はmake distcheck で foo-1.2.tar.gzなどという[パッケージ名]-[version].tar.gz 形式のパッケージが自動生成できるようになること。

注意: Autotoolsは開発者用のツールである。パッケージfoo-1.2.tar.gzのユーザは そのマシンにAutotoolsをインストールする必要はないし、Autotoolsについて知っている必要もない。

必要なもの

GNUの2つのパッケージautoconfとautomakeとを開発用のマシン にインストールしておく必要がある。また、GNU makeやbashそして GNU M4も最新のものを用意したほうがよい。

たいていのLinuxディストリビューションにはこれらのツールの パッケージがある。たとえばDebianやUbuntuなら

$ sudo apt-get install autoconf automake libtool autoconf-doc libtool-doc

でインストールできる。Mac OS X で Mac Ports https://www.macports.org を使っているなら

$ sudo port install automake autoconf

でインストールできる。

コマンドとファイル

Autotools (autoconf and automake) では Fig. 1 に示すとおり いくつかのコマンドとファイルとによって処理が進む。 前半の茶色の太い破線で囲まれた部分をautoreconfが自動的にやってくれる。 以下に関連すコマンドとファイルを列挙した。

doc/figures/autoreconf-automake-process.svg
Figure 1: Autotools(autoconf と automake)による作業の流れ。 実際は茶色の太い破線で囲まれた部分をautoreconfが自動でやってくれる。 (この図はクリエイティブコモンズライセンス[CC-BY-SA-3.0]の下に http://commons.wikimedia.org/wiki/File:Autoconf-automake-process.svg として配布されているJdthoodによるオリジナルに Takeshi Nishimatsuが茶色の太い破線と"autoreconf"の文字を描き加えたもの。 ファイル名はautoreconf-automake-process.svgとした。)

関連コマンド

autoscan       Autotoolsの利用を開始するときに1回だけ実行するコマンド。
               configure.acの雛形configure.scanを生成してくれる。
autoreconf     定番。-vオプションを付けて実行すれば何をしているのかがわかる。
               以下のコマンド自動的に再実行してくれる。
autoconf       configure.ac を元に configure を生成。
automake       Makefile.amからMakefile.inを生成。
               オプション --add-missing を付けて実行すると install-sh, missing, test-driver
               などの必要なスクリプトを /usr/share/automake-1.14/ からシンボリックリンクしてくれる。
autoheader     config.h.in を作ってくれる。
aclocal        aclocal.m4を作ってくれる。

関連するファイルとディレクトリ

configure.ac   configureの雛型。自分で書く。
Makefile.am    Makefileの雛型のMakefile.inの雛型。自分で書く。
config/gnu/    ファイルがごちゃごちゃ出来てイヤな場合はMakefile.amに
               AC_CONFIG_AUX_DIR(config/gnu)と指定するとmissing等がそこに置かれる。
config.guess   Makefile.amにAC_CANONICAL_TARGETなどと書くとautomake --add-missingが
               用意してくれるOSやCPUの自動判別をしてくれるスクリプト。
config.h.in    config.hの雛型。autoheaderによりMakefile.amやconfigure.acから自動的に作られる。
config.h       configure.acにAC_CONFIG_HEADERS([config.h])と指定。
               ないとコンパイルオプションが長くややこしくなるので、使ったほうがよい。
config.log     configure の実行時のログ。問題が起きたら読む。
config.status  configure を実行すると出来るスクリプト。foo.in から foo を作るのは実はこいつ。
install-sh     automake --add-missing が用意してくれるスクリプト。make installのときに使われることがある。
missing        automake --add-missing が用意してくれるスクリプト。忘れ物を教えてくれる。
depcomp        automake --add-missing が用意してくれることのあるスクリプト。ファイルの依存関係を自動的に調べてくれる。
test-driver    Makefile.amにTESTSの項目がある場合、automake --add-missing が用意するスクリプト。
               make checkのときに使われ、カラフルな表示やログファイルの書き出しをしてくれる。

使用方法

メモ

Fortranについてのメモ

手順

configure.ac, Makefile.am, src/Makefile.amを書いて、

$ autoreconf -v
$ automake --add-missing   # 初回にautoreconfで実行を要求されたとき。Cygwinの場合は--copyもつけた方がよい。
$ autoreconf -v            # ☆
$ ./configure
$ make                     # ソースの編集など開発を進め、最後にmakeでコンパイルできることを確認
$ make distclean           # Makefileなどをきれいさっぱり消す
$ ./configure
$ make distcheck           # 配布用パッケージをテストしてから作成(オプションは DISTCHECK_CONFIGURE_FLAGS で指定できる)
$ make dist                # 配布用パッケージの作成

新たにconfigure.ac, Makefile.am, src/Makefile.amを書き変えたら☆からやり直す。 実際は☆からやり直さずとも、Makefile に Fig. 1 にある依存関係が書き込まれているので、 make だけで Makefile そのものがうまい具合に更新される。他に

$ make clean               # makeでできたファイルを消去
$ make check               # コンパイルしたバイナリをテスト(後述)
$ sudo make install
$ make installcheck        # インストールしたバイナリをテスト(後述)
$ sudo make uninstall      # make installしたファイルの消去

などが便利。

make checkでテストの自動化

src/Makefile.amに

TESTS=foo.sh bar baz

と書いておけば

$ make check

でsrc/の中でfoo.shとbarとbazとがテストとして実行される。 ソフトウェアのテストを自動化できる。 foo.shとbarとbazとはカレントディレクトリになければsrcdirの中も探されるので、 build directoryの中でもテストができる。 ただし、foo.shは自動的にパッケージに入れてくれるわけではないので、 Makefile.amの中のEXTRA_DISTに次のように加えておく必要がある。

EXTRA_DIST = README foo.sh

テストのログがfoo.sh.logとbar.logとbaz.logとに、 テストの結果がfoo.sh.trsとbar.trsとbaz.trsとに保存される。 テスト全体のまとめがtest-suite.logに保存される。

一部のテストだけを選択的に行いたい場合は

$ make check TESTS='foo.sh bar'

とTESTS変数で指定するする。

テストスクリプトの中でsrcdirを明示的に参照する必要がある場合は$srcdirを用いる。

make distcheck とすると、上記テストとさらにファイルの過不足のチェックして、最終的にパッケージを作ることができる。 make distcheck で作るパッケージは、簡単かつ自動的に in-source build, out-of-source build のどちらも可能になる。

automakeのオプション

automakeのオプションはconfigure.acの中にAM_INIT_AUTOMAKEで指定する。例えば

AM_INIT_AUTOMAKE([1.14.1 no-dist-gzip dist-xz tar-pax foreign])

では、automakeのバージョン1.14.1以上を使用することを強制し、 パッケージをtar.gzでなくtar.xzで作るように指定している。 また、長いディレクトリ名/ファイル名でもパッケージに入るようなtarのオプションを指定している。 foreignを指定しておけば、NEWS, COPYING, AUTHORS, ChangeLog, READMEのファイルが勝手に作られるのを防ぐことができる。 ライセンスとしてGLPを採用するとしても、ここにforeignを指定して、 パッケージに含めたいファイルはMakefile.amのEXTRA_DISTに明示的にリストアップするのがよいだろう。

Autotools Mythbuster の該当ページ https://autotools.io/automake/options.html が詳しい。

インストールしたバイナリのテスト make installcheck

さらにAM_INIT_AUTOMAKEにstd-optionsを加えておけば

$ sudo make install

でバイナリをインストールした後に

$ make installcheck

とすると、そのインストールしたバイナリで GNU的なコマンドラインオプションの--helpと--versionとをテストできる。 エラーが起きればログが残こされ、テストが成功したなら何も残らない。

Makefile.amの中にinstallcheck-local:ルールを書いておけばそれも実行される。

installcheckは一般的なテストではないので、make installcheckとしても何も実行されないパッケージも多い。

コンパイラとコンパイラオプションの設定と決定

C, Fortran, C++コンパイラとそのオプションはそれぞれ AC_PROG_CC(), AC_PROG_FC(), AC_PROG_CXX() が configure.ac の中で決定する。コンパイラは CC, FC, CXX に、 コンパイラオプションは CFLAGS, FCFLAGS, CXXFLAGS に セットされる。 コンパイラオプションのデフォルトはたいてい -g -O2 または -O2 である。configure.ac の中で デフォルト以外に独自に設定したい場合には

cflags_save="$CFLAGS"
AC_PROG_CC()
CFLAGS="$cflags_save"
test -n "$CFLAGS" || CFLAGS="-g -Wall -O3"

などとAC_PROG_*()の前後でsave/restoreし、その後に独自設定をする。

configureにオプションや変数を与える方法

configureにオプションや変数を与える方法は

$ ./configure --help

で表示されるように、

$ ./configure --enable-openmp --with-lapack=mkl CPPFLAGS=-I/home/t-nissie/include

などと

の3つがある。それぞれconfigure.acの中で

と宣言しておく。設定される変数はconfig.hを通してプログラム内で参照できる。

注意:CPPFLAGS変数はC/C++のプロジェクトの場合は自動的に使用されるので宣言の必要はない。 Fortranのプロジェクトの場合は明示的に宣言してはじめてconfigure --helpで説明が表示されるようになる。

configureに与えられた引数はconfig.logの先頭に記録されるので、後々の再確認に便利である。 ただし、''や""のクォーテイションは消えてしまう。

Manpage

パッケージにUNIXのmanシステムの流儀に則って書いたmanpageを同梱する場合は、Makefile.amに

man_MANS = xtalgrowth.1 crystal_growth.7
EXTRA_DIST = README COPYING $(man_MANS)

などと書く。ここで数字の1や7はmanpageのセクション番号で1〜9の値をとり、 その番号にしたがってmanpageは/usr/local/share/man/man1/などにmake installでインストールされる。 manpageはデフォルトでパッケージに同梱されないのでEXTRA_DISTに加えておく。

Documents

マニュアルなどドキュメントを (prefix)/share/doc/(パッケージ名)/ にインストールするには Makefile.am の中の dist_doc_DATA にインストールしたいファイルを指定する。 さらに例えば figures/ サブディレクトリを作ってその中にJPEGファイルなどをインストールしたい場合は次の通り。

docfiguresdir = $(docdir)/figures
dist_doc_DATA = index.en.html index.es.html index.ja.html COPYING style.css favicon.ico README.md
EXTRA_DIST =    index.en.html index.es.html index.ja.html COPYING style.css favicon.ico figures\
             CMakeLists.txt ChangeLog.md $(man_MANS)
dist_docfigures_DATA = figures/cd.jpg figures/example.jpg figures/large.jpg figures/xtals.jpg

dist_doc_DATAに指定してもREADME.md以外はソースパッケージに自動で同梱されないのでEXTRA_DISTに加えておく。

Ref.: https://stackoverflow.com/questions/23839858/autotools-not-installing-directories-appends-to-directories-only

任意のディレクトリへのファイルのインストール

PREFIX/bin/やPREFIX/share/ではない任意のディレクトリへファイルをインストールしたい場合は https://stackoverflow.com/questions/3538705 とその中のproski氏のアドバイスを参考に configure.ac には

   AC_ARG_WITH([pkgconfigdir],
               [AS_HELP_STRING([--with-pkgconfigdir=DIR], [pkgconfig files [LIBDIR/pkgconfig]])],
               [pkgconfigdir=$withval],
               [pkgconfigdir='${libdir}/pkgconfig'])
   AC_SUBST(pkgconfigdir)

Makefile.am には

   dist_pkgconfig_DATA = mylibrary.pc

と書く。`--pkgconfigdir`のような新しいconfigureオプションを作るのは難しそう。

任意のファイル内の変数の置換

テキストファイルの中にconfogureで決定された変数を挿入したいことはしばしばある。 たとえば、foo.1.inに

This is a manpage of foo version @PACAGE_VERSION@.

と書いておき、configure.acの中で

AC_CONFIG_FILES([Makefile src/Makefile foo.1])

とAC_CONFIG_FILESにMakefileに加えてfoo.1を指定しておく。 config.statusがMakefile.in→Makefileと同様にfoo.1.in→foo.1の変換もするようになる。

Autotoolsの使用方法として参考になるパッケージ

LHa for Unix with Autoconf

シンプル。 https://github.com/jca02266/lha

ntp

大規模。libtoolも使われている。 http://support.ntp.org/bin/view/Main/WebHome

xtalgrowth

小規模。Cで書かれたX Window Systemのアプリケーション。 http://loto.sourceforge.net/xtalgrowth/

feram

小規模。Fortranで書かれている。 http://loto.sourceforge.net/feram/

Ruby

Rubyは独特で高度な方法でconfigureを生成している。安易に真似すべきではないかもしれない。 configure.inとMakefile.inそしていくつかのツールが独自に書かれていて、autoconfのみを使う。 configureでGNU makeでもBSD makeでもnmakeでも有効なポータブルなMakefile(とGNUmakefile)が生成される。 ソースは、src/サブディレクトリではなく、メインディレクトリに置かれている。 make V=1とverbosityを指定することで、makeの実行するコマンドの詳細が表示されるようになっている。 https://github.com/ruby/ruby

Autotoolsトラブルシューティング

Autotoolsは強力なツールで、make distcheckがエラーなく成功するようになればほぼすべてがうまく進むようになる。 しかしながら、トラブルに遭遇する場合もある。 Autotoolsやconfigure, makeに関連するバグの発見方法をいくつか紹介する。

configureとmakeとの高速化

大規模なプロジェクトではconfigureとmakeとにかかる時間が増大し、開発者をイライラさせる。 特にconfigureスクリプトは並列化が難しく、簡単には高速化できない。 以下にconfigureとmakeとの高速化の手法とそれらを解説しているページへのリンクを揚げた。

configureの高速化

makeの高速化

Autotoolsの代わりになるもの

改良版のAutotoolsやより高速なmakeを目指していくつかのパッケージングツール/ビルドシステムが開発されている。

より便利で高速(かもしれない)ビルドシステム

CMake, SCons, Meson, WafではFortranのプロジェクトもサポートされている。

Autotoolsに限らずこれらのビルドシステムを使うことによって ユーザーも他の開発者も何がどこにあってどうしたらよいかを容易に推測しやすくなる。 それぞれのビルドシステムの流儀に従えば、いくつかのプラットフォームに対応したバイナリやライブラリの コンパイル、リンク、テスト、インストール、パッケージングの自動化を簡単かつ忘れ物なく実現できる。 先人の知恵をおろそかにして独自のスクリプトでこれらをやろうとすると とんでもない我流に陥って悲惨な結果を招きがちである。

古いもの

libtoolとは

Autotoolsの仲間には他に libtool http://www.gnu.org/software/libtool/ がある。 共有ライブラリをビルドするときにautoconfとautomakeとともに使ってマシン依存性を解決する。 参考: http://klabgames.tech.blog.jp.klab.com/archives/1047107113.html

なお、Mac OS X の Mac Ports https://www.macports.org

$ sudo port install libtool

としてインストールされるGNU libtoolはglibtool/glibtoolizeとしてインストールされる。 Xcodeの /usr/bin/libtool (BSD origin) との衝突を避けるためのようである。

まとめ

autoconfとautomakeとの使い方を説明した。 configure.acとMakefile.amとを書くことによりパッケージの自動生成が可能になる。 複数のプラットフォームでMakefileを共通化できる。 これらGNU Autotoolsを活用すれば、簡単に配布用のフリーソフトウェアパッケージを作ることができる。

著者

西松 毅 (t_nissie{at}yahoo.co.jp)