Automake を使った実行ファイルの作成

このページでは,Automake マニュアルの「2.4 A Small Hello World」の例を参考にし,実行ファイルの配布パッケージの作り方を勉強します.
素材は,端末に「Hello world.」と出力する定番のプログラムです.C++ 言語を使っています.
ここで言う配布パッケージとは,./configure; make; sudo make install" でビルドとインストースでき,GNU 配布物を梱包したアーカイブファイルくらいの意味です.
マニュアルは C 言語用ですが,ここでは C++ 言語に変更しています.

インフォメーション

目次(ページ内リンク)

  1. 定番の実行ファイル:まず復習.端末に「Hello world.」と出力するプログラムを作成します
  2. Makefile を書いてみる:これも復習.Makefile をテキストエディタで作成します
  3. Automake によるビルド:本題.実行ファイルだけでなく,配布パッケージも簡単に作成できます
  4. 配布パッケージからのビルドとインストール:Automake で作成した配布パッケージの動作確認です
  5. autoscan による configure.ac の雛形の作成:ビルドに必要な configure.ac の雛形を自動作成します
  6. configure.ac のノート
  7. Makefile.am のノート

参考にしたページ

Debian パッケージ

このページは,Debian GNU/Linux バージョン 13 "trixie" で作成しました.
インストールしている主なパッケージを示します.

パッケージ名(バージョン)
g++ (14.2.0)GNU C++ コンパイラ
make (4.4.1)コンパイルを制御するユーティリティ
automake (1.17)GNU標準準拠のMakefile生成ツール
autoconf (2.72)configure スクリプト自動作成プログラム

GNU Autotools について

このページで利用しているツールについて,まとめておきます.

Autotools FAQ によると,GNU Autotools という名前は、一般的に Autoconf, Automake, Libtool というソフトウェアパッケージを指します.これらのパッケージは開発者が使用するいくつかのプログラムで構成されており,その中には autoreconf,autoconf,autoheader,autoscan(Autoconf パッケージ由来),aclocal と automake(Automake パッケージ由来),および libtoolize (Libtool パッケージ由来)を指し示すものということです.


定番の実行ファイル

まず,復習です.プログラミング入門の定番,端末に 「Hello World.」 と出力する実行ファイル hello を作成します,
コンパイル,リンク,およびインストール用のコマンドを使い分けます.ビルドシステムはこの作業を高度にしたものです.

ソースコード

下は実行ファイル hello のソースファイル main.cc です,

main.cc

#include <iostream>

int main() {
 std::cout << "Hello World." << std::endl;
 return 0;
}

ビルドとインストール

ここでの作業は単純で,端末にコマンドを 3 行入力するだけです,

ソースファイル main.cc をコンパイルして,オブジェクトファイル main.o を作成します,
$ g++ -c main.cc

オブジェクトファイル main.o をリンクして実行ファイル hello を生成します,
ここでは main.o しかありませんが,一般に,複数のオブジェクトファイルやライブラリとリンクします
$ g++ -o hello main.o

実行ファイル hello を /usr/local/bin/ にインストールします,これはスーパーユーザー権限で.
$ sudo install -s hello /usr/local/bin/

実行

端末に
$ ./hello
と入力したら,

Hello World.

と表示されました,どうやら成功したようです,


Makefile を書いてみる

もう一つ復習です.
上ではビルドとインストールをコマンドでおこないました.実際の開発では,これらの作業を自動化するスクリプト Makefile を作成します.
もちろん Makefile はテキストエディタで作成可能であり,上のセクションで使ったコマンドを Makefile の文法に従って書き記せば,とりあえず動作します,
Automake のようなMakefile 作成ツールはこの作業を高度化したものです.

自作 Makefile の作成

下にコードの例を記します.例では,"#" を使ってコメントを付しました.また,make clean と make install コマンドも追加してあります,


hello : main.o #オブジェクトファイル main.o から実行ファイル hello を作成
(ここは TAB)g++ -o hello main.o
main.o : main.cc #ソースファイル main.cc からオブジェクトファイル main.o を作成
(ここは TAB)g++ -c main.cc

clean: #実行ファイルとオブジェクトファイルの削除
(ここは TAB)rm -f hello main.o
install: #/usr/local/bin にインストール
(ここは TAB)install -s hello /usr/local/bin/

自作 Makefile の動作確認

作成した Makefile を上述の hello.cc と同じディレクトリにおいて,
$ make
とすれば,端末に

g++ -c main.cc
g++ -o hello main.o

と出力されて実行ファイル hello が作成されます,
$ sudo make install
とすれば,実行ファイル hello が /usr/local/bin/ にインストールされます,
$ sudo make clean
とすれば,実行ファイルとオブジェクトファイルが削除されます,

ここまでで,実行ファイルの作成,Makefile を使った実行ファイルの作成が可能になりました.


Automake によるビルド

このセクションが本題です.Autotools を使ってビルドシステムを構築します.
元ネタは GNU Automake の "2.4 A Small Hello World" です.これは C 言語版のプログラムの実行ファイル配布パッケージの作り方そ記したドキュメントです.
ここでは,C 言語を C++ 言語に改変し,配布パッケージを作成します.この系はそのままで配布パッケージの作成も可能です.

ソースファイルの作成

まず作業用のディレクトリを作成します.名前は何でも構いません.ここでは,amhello というディレクトリを作成し,そのなかに src というディレクトリを作成しました.
作成したディレクトリのなかに,以下に示すファイルを作成します.

ツリー構造で記します.
プログラムのソースファイルを src/ サブディレクトリに格納するのは,後でパッケージが進化したときに,man ページ用の man/ ディレクトリやデータファイル用の data/ ディレクトリなどの追加が容易になるからだそうです.

amhello
├── README
├── Makefile.am
├── configure.ac
└─ src
      ├── main.cc
      └── Makefile.am

amhello/README

下記の内容を記しています.Automake マニュアルの内容を多少改変したものです.


これは GNU Automake のデモパッケージです.
info パッケージがインストールされていれば,端末に info Automake と打ち込むと,Automake マニュアルが読めます.

amhello/Makefile.am

amhello/ ディレクトリに対する automake への指示を記述します.
これは Automake マニュアルのままです.


SUBDIRS = src
dist_doc_DATA = README

amhello/configure.ac

configure スクリプトを作成するための autoconf への指示が含まれています.
ここでは C++ を使っているので,Automake マニュアルの例の C 用マクロ "AC_PROG_CC" を C++ 用マクロ "AC_PROG_CXX" に変更しています.
AC_CONFIG_FILES([ Makefile src/Makefile ]) と 1 行にすることもできます.
1 行めの 1.0 という数字は,配布パッケージのファイル名に使われます.


AC_INIT([amhello], [1.0], [bug-automake@gnu.org])
AM_INIT_AUTOMAKE([-Wall -Werror foreign])
AC_PROG_CXX
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_FILES([
 Makefile
 src/Makefile
])
AC_OUTPUT

amhello/src/main.cc

Automake マニュアルの例を C++ に改変しています.
作業の過程で config.h というファイルが生成するのですが,Automake マニュアルの例では,config.h で設定された変数 PACKAGE_STRING の値も端末に出力しています.
この場合,#include "config.h" ではなくて #include <config.h> とするのだそうです.


#include <config.h>
#include <iostream>

int main(void) {
 std::cout << "Hello World!" << std::endl;
 std::cout << "This is " PACKAGE_STRING "." << std::endl;
 return 0;
}

amhello/src/Makefile.am

amhello/src/ ディレクトリに対する automake への指示を記述します.
拡張子を変更した以外は Automake マニュアルのままです.


bin_PROGRAMS = hello
hello_SOURCES = main.cc

autoreconf コマンドでビルドシステムのインスタンス化

上記 5 つのファイルができたら,Autotools を使ってビルドシステムを作成します.
ビルドシステムとは,「configure スクリプトと make コマンドが実行できる状態にしたソースファイル」くらいの理解で良さそうです.
autoreconf --install をを実行するだけで「ビルドシステムのインスタンス化」が完了します.
なお,autoreconf を実行する必要があるのは,ビルドシステムが存在しない場合の最初,あるいは,Makefile.am や configure.ac などを変更した場合です.

~/amhello$ autoreconf --install
としたら,端末に以下の内容が出力されました.

configure.ac:2: installing './install-sh'
configure.ac:2: installing './missing'
src/Makefile.am: installing './depcomp'

ここで使ったコマンド autoreconf は,autoconf や automake,その他多くのコマンドを正しい順序で呼び出すスクリプトです.
autoconf は,configure.ac から configure を作成します.automake は,Makefile.am と configure.ac から Makefile.in を作成します.

端末への出力から,新たに,install-sh,missing,および depcomp というファイルが作成されたことが読み取れます.
他にファイルとディレクトリがいくつか作成されました.
そのうち,config.h.in, Makefile.in, および src/Makefile.in は,configure によってシステムに合わせて作成される config.h,Makefile,src/Makefile のテンプレートです.

configure コマンドで Makefile を作成

次に,configure を実行します.
~/amhello$ ./configure
これで,configure がシステムを調査し,システムに合わせた Makefile,src/Makefile,config.h が作成されます.
このようにして作成される Makefile は汎用性がなければならないので,ファイルサイスが大きくなっています.
amhello ディレクトリに作成された Makefile は 839 行,src ディレクトリの Makefile は 580 行ありました.

この段階で,マニュアルには「希望するすべてのターゲットを実行できるようになりました」と書いてあります.
ターゲットとは,make に渡す引数のことで,つまり,make コマンドが使えるようになったということです.
ちなみに,今読んでいる 2.4 章に先だつ 2.2.2 章のタイトルは「標準的な Makefile のターゲット」で,以下のターゲットが紹介されています.

make コマンドで実行ファイル生成

~/amhello$ make

としたら,ビルドが始まります.
ビルドに成功したら src ディレクトリに hello という実行ファイルが生成します.
試しに実行してみます.端末に,
~/amhello$ src/hello
とすると,端末に以下の内容が出力されました.

Hello World!
This is amhello 1.0.

「This is amhello 1.0.」というのは,config.h に記述した #define PACKAGE_STRING "amhello 1.0" という部分に由来します.

ここで,
~/amhello$ sudo make install
とすれば,実行ファイルが /usr/local/bin にインストールされます.
配布パッケージの作成を意図しないなら,これで充分かもしれません.

make コマンドで配布パッケージを作成

~/amhello$ make distcheck
とすれば,配布パッケージの作成が始まります.
成功すれば,配布パッケージ amhello-1.0.tar.gz が amhello ディレクトリに作成されます.
ファイル名は,configure.ac の AC_INIT([amhello], [1.0], [bug-automake@gnu.org]) に由来します.

コマンドのまとめ

解説を加えているのでコマンドが散在してしまいました.ここでまとめます.最初から 3 コマンドは共通です.
ビルドとインストールなら,
~/amhello$ autoreconf --install
~/amhello$ ./configure
~/amhello$ make
~/amhello$ sudo make install

配布パッケージを作成するなら.
~/amhello$ autoreconf --install
~/amhello$ ./configure
~/amhello$ make
~/amhello$ make distcheck

当然,ビルドとインストールをした上で配布パッケージを作成できます.すなわち,
~/amhello$ autoreconf --install
~/amhello$ ./configure
~/amhello$ make
~/amhello$ sudo make install
~/amhello$ make distcheck


配布パッケージからのビルドとインストール

上の作業で,配布パッケージ amhello-1.0.tar.gz が amhello ディレクトリに作成されました.
amhello-1.0.tar.gz をウェブサイトで公開すれば,訪問者がダウンロードして,自分のマシンでビルドして使えるというわけです,
配布パッケージをインストールしてみます.定番の作業です.

~/amhello$ tar -xzvf amhello-1.0.tar.gz
~/amhello$ cd amhello-1.0
~/amhello/amhello-1.0$ ./configure
~/amhello/amhello-1.0$ make
~/amhello/amhello-1.0$ sudo make install
実行ファイル hello が,/usr/local/bin にインストールされます.

~/amhello/amhello-1.0$ hello
と実行すると,端末に以下の内容が出力されました.

Hello World!
This is amhello 1.0.

なお,アンインストールは,
~/amhello/amhello-1.0$ sudo make uninstall


autoscan による configure.ac の雛形の作成

上のセクションでは,configure.ac をエディタで作成しました.
このセクションでは,autoscan を使って,configure.ac の雛形を自動作成してみます.

ソースファイルの作成

上のセクションで作成したソースファイルから configure.ac を除いたソースファイルを作成しました.
ファイルの内容は同じです.

amhello
├── Makefile.am
├── README
└─ src
      ├── main.cc
      └── Makefile.am

autoscan の実行

~/amhello$ autoscan
としたら,autoscan.log と configure.scan というファイルが生成しました.

amhello
├── Makefile.am
├── README
├── autoscan.log
├── configure.scan
└─ src
      ├── main.cc
      └── Makefile.am

configure.scan が configure.ac の雛形です.
ここでは間違えても修正が可能なように,configure.ac という名前でコピーを作成して configure.ac を編集します.

~/amhello$ cp configure.scan configure.ac

configure.ac(== configure.scan)の内容を示します.


#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.

AC_PREREQ([2.72])
AC_INIT([FULL-PACKAGE-NAME], [VERSION], [BUG-REPORT-ADDRESS])
AC_CONFIG_SRCDIR([src/main.cc])
AC_CONFIG_HEADERS([config.h])

# Checks for programs.
AC_PROG_CXX

# Checks for libraries.

# Checks for header files.

# Checks for typedefs, structures, and compiler characteristics.

# Checks for library functions.

AC_CONFIG_FILES([Makefile
                 src/Makefile])
AC_OUTPUT

上のセクションで手書きで作成した configure.ac と比較すると,2 か所書き換えれば良さそうです.

AC_INIT([FULL-PACKAGE-NAME], [VERSION], [BUG-REPORT-ADDRESS]) 行の編集

上のセクションと揃えるなら,
AC_INIT([amhello], [1.0], [bug-automake@gnu.org])
マニュアルには "Exactly package" などと書いてあります.これが何を意味するのかは調べていません.

AM_INIT_AUTOMAKE 行の追加

上のセクションと揃えるなら,
AM_INIT_AUTOMAKE([-Wall -Werror foreign])

編集後の configure.ac は,次のようになります.変更箇所を赤色で示します.


#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.

AC_PREREQ([2.72])
AC_INIT([amhello], [1.0], [bug-automake@gnu.org])
AM_INIT_AUTOMAKE([-Wall -Werror foreign])
AC_CONFIG_SRCDIR([src/main.cc])
AC_CONFIG_HEADERS([config.h])

# Checks for programs.
AC_PROG_CXX

# Checks for libraries.

# Checks for header files.

# Checks for typedefs, structures, and compiler characteristics.

# Checks for library functions.

AC_CONFIG_FILES([Makefile
                 src/Makefile])
AC_OUTPUT

後は上と同じ手順で配布パッケージが作成できます.
~/amhello$ autoreconf --install
~/amhello$ ./configure
~/amhello$ make
~/amhello$ make distcheck


configure.ac のノート

何がなにかわからない時期に記したメモです.
内容が古くなってしまったのですが,状況によっては参考になるかもしれないので,そのままにしておきます.

Autotools によって読み取られる configure.ac の内容を引用します.
configure.ac を再掲します.


AC_INIT([amhello], [1.0], [bug-automake@gnu.org])
AM_INIT_AUTOMAKE([-Wall -Werror foreign])
AC_PROG_CXX
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_FILES([ Makefile src/Makefile ])
AC_OUTPUT

configure.ac の説明部分を箇条書きにまとめてみました.

C++ のバージョン

例えば C++11 を利用する場合には,configure.ac に下の行を追加します.


CXXFLAGS='-std=gnu++0x'

チェックすべきライブラリの記述

昔 gtkmm を使っていたのですが,その場合,
PKG_CHECK_MODULES([GTKMM], [gtkmm-3.0])
行を追加する必要がありました.
これは,Gtkmm マニュアルのトップベージに記載されていました.

Windows 環境で MinGW でビルドしたときにコマンドプロンプトを開かないようにする

configure.ac に下の行を追加します.


LDFLAGS=-mwindows
AC_SUBST(LDFLAGS)

Makefile.am のノート

これも,何がなにかわからない時期に記したメモです.
内容が古くなってしまったのですが,状況によっては参考になるかもしれないので,そのままにしておきます.

src/Makefile.am

Makefile.am を基にして automake は Makefile.in を作成します.Makefile.in は,configure によって Makefile に変換されます.
Makefile.am には,hello をビルドしてインストールするための automake の手順が書かれています. 再掲します.


bin_PROGRAMS = hello
hello_SOURCES = main.cc

箇条書きにまとめてみました.

Makefile.am

Autotools によって読み取られる トップレベルの Makefile.am に関する説明をまとめます.


SUBDIRS = src
dist_doc_DATA = README