link もっと前
   2015年 12月 27日 -
      2015年 12月 18日  
link もっと後

link 未来から過去へ表示(*)
link 過去から未来へ表示

日々

link permalink

GNU autotools 入門 その 2

その 1その 2

GNU autotools は簡単なんですが、使い始めるまではかなり難儀した記憶があります。例えば、下記のように libtest_new.so という名前の「動的ライブラリ」を作成するプロジェクトを作ったとします。

GNU autotools で動的ライブラリをビルドするプロジェクト
.
|-- Makefile.am
|-- configure.ac
`-- test
    |-- Makefile.am
    |-- common
    |   |-- Makefile.am
    |   `-- utils.c
    `-- test.c

----
configure.ac
----
AC_PREREQ(2.61)
AC_INIT([automake_test], [0.1])
AC_ARG_PROGRAM()
AC_CONFIG_SRCDIR([test/test.c])
AC_CONFIG_HEADER([config.h])
AC_CONFIG_AUX_DIR([conf]) ★ここで指定したディレクトリに注目★
AM_INIT_AUTOMAKE([foreign])
LT_INIT() ★これも注目★

AC_CONFIG_FILES([Makefile
	test/Makefile test/common/Makefile])

AC_OUTPUT()


----
test/Makefile.am
----
SUBDIRS = common

test_newdir = $(libdir)
test_new_LTLIBRARIES = libtest_new.la

libtest_new_la_SOURCES = test.c

libtest_new_la_LIBADD = common/libcommon.la


----
test/common/Makefile.am
----
noinst_LTLIBRARIES = libcommon.la

libcommon_la_SOURCES = utils.c

基本的に GNU autotools を使う時は autoreconf というコマンドを実行すれば、勝手に全ての関連ファイルが更新されます。

ただ残念なことに、初回だけはそうもいきません。

初回の autoreconf の結果
$ autoreconf
configure.ac:16: error: required file 'conf/compile' not found
configure.ac:16:   'automake --add-missing' can install 'compile'
configure.ac:16: error: required file 'conf/config.guess' not found
configure.ac:16:   'automake --add-missing' can install 'config.guess'
configure.ac:16: error: required file 'conf/config.sub' not found
configure.ac:16:   'automake --add-missing' can install 'config.sub'
configure.ac:15: error: required file 'conf/install-sh' not found
configure.ac:15:   'automake --add-missing' can install 'install-sh'
configure.ac:16: error: required file 'conf/ltmain.sh' not found
configure.ac:15: error: required file 'conf/missing' not found
configure.ac:15:   'automake --add-missing' can install 'missing'
test/Makefile.am: error: required file 'conf/depcomp' not found
test/Makefile.am:   'automake --add-missing' can install 'depcomp'
autoreconf2.50: automake failed with exit status: 1

このようにたくさん怒られます。何を怒っているのかというと、AC_CONFIG_AUX_DIR([conf]) で指定したディレクトリ(詳細は automake のマニュアル参照)に、補助ツールが入ってないじゃないか!と怒っているのです。

エラーメッセージの最後に「'automake --add-missing' can install 'depcomp'」とあるように、優しい autotools さんは解決策も用意してくれています。これもやってみましょう。

add-missing を実行した結果
$ automake --add-missing
configure.ac:16: installing 'conf/compile'
configure.ac:16: installing 'conf/config.guess'
configure.ac:16: installing 'conf/config.sub'
configure.ac:15: installing 'conf/install-sh'
configure.ac:16: error: required file 'conf/ltmain.sh' not found
configure.ac:15: installing 'conf/missing'
test/Makefile.am: installing 'conf/depcomp'

まだ何か怒っています。ltmain.sh が無いそうです。これは libtool というツールの一部です。

最初に述べたようにこのプロジェクトは「動的ライブラリ」を作るプロジェクトです。GNU autotools は動的ライブラリをビルドする際に libtool という別のツールを使っています。プロジェクトの configure.ac に LT_INIT() と書いていましたよね。この行は libtool を使うことを autotools に伝えるため(詳細は libtool のマニュアル参照)にあります。

逆に言えば、LT_INIT() が無いと動的ライブラリはビルドできません。そんなの知るかって?正直言って私もそう思いました、けど、今のところそういう作りなので我慢するしかありません…。

さて ltmain.sh が何者かもわかったところで、肝心のどこから持って来るか?ですが、こんなときって find が便利ですよね?

ltmain.sh を無理やり持ってくる
$ find /usr -name ltmain.sh
/usr/share/libtool/config/ltmain.sh

$ cp /usr/share/libtool/config/ltmain.sh conf/ltmain.sh

$ automake --add-missing

$ tree
.
|-- Makefile.am
|-- Makefile.in
|-- aclocal.m4
|-- conf
|   |-- compile -> /usr/share/automake-1.14/compile
|   |-- config.guess -> /usr/share/automake-1.14/config.guess
|   |-- config.sub -> /usr/share/automake-1.14/config.sub
|   |-- depcomp -> /usr/share/automake-1.14/depcomp
|   |-- install-sh -> /usr/share/automake-1.14/install-sh
|   |-- ltmain.sh
|   `-- missing -> /usr/share/automake-1.14/missing
|-- config.h.in
|-- configure
|-- configure.ac
`-- test
    |-- Makefile.am
    |-- Makefile.in
    |-- common
    |   |-- Makefile.am
    |   |-- Makefile.in
    |   `-- utils.c
    `-- test.c

以上のように ltmain.sh を無理やり持って来たら、エラーも警告も出なくなりました。めでたしめでたし、です。

もし他の環境に持っていく場合、conf/missing などのシンボリックリンクはリンク先に何もない可能性がある(※)ので、実体に置き換えておくと良いでしょう。

(※)autotools をインストールしていない環境もあれば、インストールされていたとしても違うディレクトリに置かれている可能性があります。

全てを台無しにする

既に autotools をお使いの方はもちろんのこと、autoreconf という見慣れぬコマンドに対して、すぐにヘルプを見た方はお気づきかと思いますが、今までの手順を一撃でやってくれるコマンドがあります。

その名も autoreconf --install です。早速やってみましょう。

今までの苦労は何だったのか
$ tree
.
|-- Makefile.am
|-- configure.ac
`-- test
    |-- Makefile.am
    |-- common
    |   |-- Makefile.am
    |   `-- utils.c
    `-- test.c

$ autoreconf --install
libtoolize: putting auxiliary files in AC_CONFIG_AUX_DIR, `conf'.
libtoolize: copying file `conf/ltmain.sh'
libtoolize: Consider adding `AC_CONFIG_MACRO_DIR([m4])' to configure.ac and
libtoolize: rerunning libtoolize, to keep the correct libtool macros in-tree.
libtoolize: Consider adding `-I m4' to ACLOCAL_AMFLAGS in Makefile.am.
configure.ac:16: installing 'conf/compile'
configure.ac:16: installing 'conf/config.guess'
configure.ac:16: installing 'conf/config.sub'
configure.ac:15: installing 'conf/install-sh'
configure.ac:15: installing 'conf/missing'
test/Makefile.am: installing 'conf/depcomp'

$ tree
.
|-- Makefile.am
|-- Makefile.in
|-- aclocal.m4
|-- conf
|   |-- compile
|   |-- config.guess
|   |-- config.sub
|   |-- depcomp
|   |-- install-sh
|   |-- ltmain.sh
|   `-- missing
|-- config.h.in
|-- configure
|-- configure.ac
`-- test
    |-- Makefile.am
    |-- Makefile.in
    |-- common
    |   |-- Makefile.am
    |   |-- Makefile.in
    |   `-- utils.c
    `-- test.c

シンボリックリンクを実体に置き換えるところまで勝手にやってくれます。いやー、もう全部これだけで良いんじゃない?というくらい、素晴らしいです。

スクラッチビルドのススメ

GNU autotools を使う時は、常に autoreconf --install 頼りでもそこそこ動くはずですが、いざ autoreconf がエラーで止まった時は手も足も出なくなってしまいます。

私個人の悲しい経験から言って、この手の便利ツールって、中で何をやっているのかサッパリわからないので、トラブルが起きると非常に苦労します。

  • ツールを動かすのに最低限どんなファイルが必要か?
  • 無いときはどんなエラーが出るか?
  • エラーの解消には何をすれば良いか?

ツールのコードを読めとは言いません(私も読んだことありません)が、せめてこのくらいは調べた方が良いです。トラブルシュートの早さが断然違います。

これらを調べるには、マニュアルを当てずっぽうに読むより、スクラッチからプロジェクトを作ってみるのが一番効きます。既存プロジェクトのコピペでは得られなかった、新たな発見があると思いますよ。

[編集者: すずき]
[更新: 2018年 5月 20日 03:59]
link 編集する

コメント一覧

  • 名前 
    助かりました。勉強になります。 
    (2018年05月11日 12:40:49)
  • すずき 
    お役に立てて何よりです。 
    (2018年05月12日 21:45:10)
open/close この記事にコメントする



link permalink

GNU autotools 入門 その 1

その 1その 2

ソースコードのビルドシステムは多々あって決定打はない(個人的にはそう思う)のですが、比較的メジャーと言って良いのが GNU autotools です。ビルドする際に configure して make するヤツは、大抵 autotools が絡んでいます。

そんな GNU autotools を成すツール群の一つに autoconf/automake と言うツールがあります。こいつらは簡単に言えば Makefile を作るツールです。

autoconf, automake と Makefile の関係
configure.ac --(autoconf)--> configure

Makefile.am --(automake)--> Makefile.in --(configure)--> Makefile

最終的に生成されるのは Makefile なのに、なぜ直接書かず遠回りをするかというと、どんな環境でもそれなりに動く Makefile を直接書くのは、実は結構大変だからです。

例えば、依存関係にあるライブラリの有無をチェックしつつ、クロスコンパイルで動的ライブラリを生成するような Makefile をパッと書けますか?私には無理そうですし、仮に書けたとしても、Makefile を作るのは手段であって目的ではないので、あまり時間を使いたくありません。

ビルドでお決まりの手順はツールで自動生成して楽して作りたい、これが GNU autotools や他のビルドツールを使う目的です。

automake の非互換性

こんな便利な automake ですが、たまに仕様が変わって、以前の書き方だと怒られることがあります。

楽するためにツールを使っていたのに、ツールの仕様変更に対応するため時間を使うのは本末転倒な感じもしますが、それでも Makefile を直接書くより断然楽でしょうね。

昔のバージョンである automake-1.9 ではこういう書き方が出来たのですが、

automake で SOURCES にサブディレクトリを指定

COMMON_DIR = ./common

common_SOURCES = $(COMMON_DIR)/utils.c

これが automake-1.14 だと、

サブディレクトリを指定したときの automake の warning
test/Makefile.am:19: warning: source file '$(COMMON_DIR)/utils.c' is in a subdirectory,
test/Makefile.am:19: but option 'subdir-objects' is disabled
automake: warning: possible forward-incompatibility.
automake: At least a source file is in a subdirectory, but the 'subdir-objects'
automake: automake option hasn't been enabled.  For now, the corresponding output
automake: object file(s) will be placed in the top-level directory.  However,
automake: this behaviour will change in future Automake versions: they will
automake: unconditionally cause object files to be placed in the same subdirectory
automake: of the corresponding sources.
automake: You are advised to start using 'subdir-objects' option throughout your
automake: project, to avoid future incompatibilities.

こんな風に長々と説教されます。警告の通り subdir-objects を有効にすると、今度は $(COMMON_DIR) という名前のディレクトリが作られ、common/utils.c は無いと言われ、コンパイルエラーになります。

なんじゃそりゃ。

解決方法

この警告を解決する方法は、サブディレクトリにも Makefile.am を置くこと、のようです。

今までの Makefile.am
$ tree
.
|-- Makefile.am
|-- configure.ac
`-- test
    |-- Makefile.am
    |-- common
    |   `-- utils.c
    `-- test.c

----
configure.ac
----
AC_PREREQ(2.61)
AC_INIT([automake_test], [0.1])
AC_ARG_PROGRAM()
AC_CONFIG_SRCDIR([test/test.c])
AC_CONFIG_HEADER([config.h])
AC_CONFIG_AUX_DIR([conf])
AM_INIT_AUTOMAKE([foreign])
LT_INIT()

AC_CONFIG_FILES([Makefile
	test/Makefile])

AC_OUTPUT()

----
Makefile.am
----
SUBDIRS = test

----
test/Makefile.am
----
testdir = $(libdir)
test_LTLIBRARIES = libtest.la

libtest_la_SOURCES = test.c \
	common/utils.c

このようなプロジェクトがあったとします。このプロジェクトは automake に、下記のように怒られます。

automake-1.14 に怒られるの図
$ autoreconf --force
test/Makefile.am:5: warning: source file 'common/utils.c' is in a subdirectory,
test/Makefile.am:5: but option 'subdir-objects' is disabled
automake: warning: possible forward-incompatibility.
automake: At least a source file is in a subdirectory, but the 'subdir-objects'
automake: automake option hasn't been enabled.  For now, the corresponding output
automake: object file(s) will be placed in the top-level directory.  However,
automake: this behaviour will change in future Automake versions: they will
automake: unconditionally cause object files to be placed in the same subdirectory
automake: of the corresponding sources.
automake: You are advised to start using 'subdir-objects' option throughout your
automake: project, to avoid future incompatibilities.
autoreconf2.50: automake failed with exit status: 1

以下のように各ディレクトリに Makefile.am を作ってあげれば、警告は出なくなります。

これからの Makefile.am
.
|-- Makefile.am
|-- configure.ac ★変更★
`-- test
    |-- Makefile.am ★変更★
    |-- common
    |   |-- Makefile.am ★追加★
    |   `-- utils.c
    `-- test.c

----
configure.ac
----
AC_PREREQ(2.61)
AC_INIT([automake_test], [0.1])
AC_ARG_PROGRAM()
AC_CONFIG_SRCDIR([test/test.c])
AC_CONFIG_HEADER([config.h])
AC_CONFIG_AUX_DIR([conf])
AM_INIT_AUTOMAKE([foreign])
LT_INIT()

AC_CONFIG_FILES([Makefile
	test/Makefile test/common/Makefile])
                      ^^^^^^^^^^^^^^^^^^^^ 追加

AC_OUTPUT()


----
test/Makefile.am
----
SUBDIRS = common

test_newdir = $(libdir)
test_new_LTLIBRARIES = libtest_new.la

libtest_new_la_SOURCES = test.c

libtest_new_la_LIBADD = common/libcommon.la


----
test/common/Makefile.am
----
noinst_LTLIBRARIES = libcommon.la

libcommon_la_SOURCES = utils.c

最初は面倒くさいですが、やってみると test と test/common が分離されて見通しが良くなります。

利点と欠点

従来の方法(親ディレクトリに Makefile.am を置く方法)と、新しい方法(各ディレクトリに Makefile.am を置く方法)の利点と欠点を考えてみます。

利点は、再利用性が高くなることです。

先の例で出てきた common ディレクトリが「何らかの便利な機能を提供しているパッケージ」だとして、他のプロジェクトに common のコードを流用する場合を考えてみましょう。

従来の test/Makefile.am に全て書く方法だと、common ディレクトリのソースコードは使いまわせますが、ビルド設定である Makefile.am が親ディレクトリの test 側にあって、単純に使いまわせません。なぜなら test/Makefile.am では test のビルド設定と common のビルド設定が混ざって書かれているため、common のビルド設定だけを抽出するのが難しいためです。

これが新しい test/Makefile.am と test/common/Makefile.am に分ける方法だと、文字通り common ディレクトリをコピーするだけで Makefile.am つまりビルドの設定も使いまわすことができます。

欠点は面倒くさいことです。

無意味にディレクトリを分割したがる輩には、ディレクトリごとに Makefile.am を作らなければならない面倒くささが、ある意味の抑止力になるので、欠点だとも言い切れませんが、やはり面倒くさいものは面倒くさいです…。

ちなみに従来の方法で書くと警告が出ますが、今のところ使えない訳でもない(※)ので、ちょっと試してみるだけとか、一時的なツールに使うだけであれば、従来の方法を選べば良いと思います。

(※)今は警告だけですが、そのうち廃止されるかもしれません。

[編集者: すずき]
[更新: 2018年 5月 20日 03:59]
link 編集する

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link permalink

C++ の変数初期化

会社で大幅にソフトを置き換えるチャンスがあったので、思い切って C から C++11(gcc-4.6 で使える範囲だけ)に切り替えました。

まだまだ使いこなせてませんが C++98 より見やすいです。それでも C++ は魔界だなーと思うこともありますけど…。

Effective Modern C++ にも出てますが、C++11 で導入された uniform initialization(波括弧 { a, b, c, } での初期化)は、丸括弧や等号を置き換えることができます。大抵の場合は、ですが。

コンテナ系など std::initializer_list を引数に取れる場合は、丸括弧と置き換えると動きが変わってしまいます。

std::initializer_list を引数に取るコンストラクタがある例

int i1(5);
-> 5
int i2{5};
-> 5

std::vector<int> b1(5);
-> size:5: 0, 0, 0, 0, 0,
std::vector<int> b2{5};
-> size:1: 5,

丸括弧は丸括弧で、引数が 0個になるといきなり関数宣言扱いされる、クラスメンバ変数に使えないなど、一貫性がなくて使いづらいのです。

関数宣言扱いされる例

std::vector<int> a1();
-> a1 type is std::vector<int, std::allocator<int> > ()
std::vector<int> a2{};
-> size:0:

結局、コンストラクタが std::initializer_list を取れるかどうかを意識して、丸括弧と波括弧を使い分ける必要がありまして、だいぶ難しいですね…。

メモ: 技術系の話は Facebook から転記しておくことにした。

[編集者: すずき]
[更新: 2015年 12月 23日 23:26]
link 編集する

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link もっと前
   2015年 12月 27日 -
      2015年 12月 18日  
link もっと後

管理用メニュー

link 記事を新規作成

合計:  counter total
本日:  counter today

link About www.katsuster.net
RDF ファイル RSS 1.0
QR コード QR コード

最終更新: 7/22 04:22

カレンダー

<2015>
<<<12>>>
--12345
6789101112
13141516171819
20212223242526
2728293031--

最近のコメント 5件

  • link 18年07月04日
    すずき 「NEON にも対応してみましたが、やはり...」
    (更新:07/11 21:26)
  • link 18年05月30日
    すずき 「情報ありがとうございます。PT2 2枚差...」
    (更新:06/02 17:27)
  • link 18年05月30日
    通りすがりですみませ... 「私のPC(Win10)ではB−CAS1枚...」
    (更新:06/02 16:42)
  • link 18年05月20日
    すずき 「数えたことはありませんが Windows...」
    (更新:05/22 22:26)
  • link 18年05月20日
    hdk 「Linux も、先日の Meltdown...」
    (更新:05/21 22:55)

最近の記事 3件

link もっとみる
  • link 18年07月21日
    すずき 「[Bluetooth UART 変換] UART を Blueto...」
    (更新:07/22 04:22)
  • link 18年07月17日
    すずき 「[エアコンが臭い] 「エアコンの嫌なニオイが完全に消えた」 "窓全...」
    (更新:07/17 22:53)
  • link 18年07月16日
    すずき 「[AArch64 向け Linux 開発環境の構築 その 2] そ...」
    (更新:07/17 22:46)

こんてんつ

open/close wiki
open/close Java API

過去の日記

open/close 2002年
open/close 2003年
open/close 2004年
open/close 2005年
open/close 2006年
open/close 2007年
open/close 2008年
open/close 2009年
open/close 2010年
open/close 2011年
open/close 2012年
open/close 2013年
open/close 2014年
open/close 2015年
open/close 2016年
open/close 2017年
open/close 2018年
open/close 過去日記について

その他の情報

open/close アクセス統計
open/close サーバ一覧
open/close サイトの情報