MAP | TOP > 工房「藤車」 > 技術系執筆情報 > 『lsを読まずにプログラマを名乗るな!』 > ビルド時の留意点 |
このページでは、 『lsを読まずにプログラマを名乗るな!』 執筆のベースとなっている GNU coreutils 8.21 に関して、 書籍では紙面の都合から記載できなかったものを中心に、 ビルドを実施する場合の留意点について説明します。
configure
/make
実行時の留意点patch
コマンドのバージョン依存性バージョン 2.6 よりも前の
patch
コマンドを使用する環境で
./bootstrap
スクリプトを実行した場合、
以下のようなエラーで実行が中断されます。
gnulib/gnulib-tool: *** patch file gl/modules/tempname.diff didn't apply cleanly gnulib/gnulib-tool: *** Stop. missing header for unified diff at line 12 of patch The text leading up to this was: -------------------------- | | Files: | lib/tempname.c -------------------------- File to patch: EOF ※ Ctrl-D による『EOF』入力 Skip this patch? [y] ※ Enter 入力 1 out of 1 hunk ignored gnulib/gnulib-tool: *** patch file gl/modules/tempname.diff didn't apply cleanly gnulib/gnulib-tool: *** Stop. ./bootstrap[348]: build-aux/prefix-gnulib-mk: not found [No such file or directory] ./bootstrap: bootstrap_post_import_hook failed
『patch コマンドのバージョン間互換性 (ID:15255)』 に対する修正が取り込まれるまでは、 以下のいずれかの方法で回避してください。
なお、
事前に実行された
./bootstrap
が正常終了していた場合、
その際に生成された build-aux/prefix-gnulib-mk
が再利用されることにより、
./bootstrap
実行はそのまま継続され、
パッチ適用が失敗したまま正常終了してしまいます。
patch
コマンドのバージョンや、
gl/modules/tempname.diff
の内容を変えながら、
./bootstrap
の挙動確認を行う際には注意してください。
patch
コマンドのバージョンアップ使用する patch
コマンドを、
2.6 以降にバージョンアップすることで、
この問題は回避可能です。
但し、
2.6 以降の patch
コマンドを使用した場合、
『パッチ適用が成功する』のではなく、
『適用できないハンクがあっても無視して正常終了する』
という挙動になってしまいます。
本来意図した成果物をビルドしたい場合は、 次に述べる『パッチファイル自体の修正』を行ってください。
本来意図した成果物をビルドしたい場合は、
不正な内容を持つ
gl/modules/tempname.diff
に対して、
以下の修正を実施する必要があります。
diff -u a/gl/modules/tempname.diff b/gl/modules/tempname.diff --- a/gl/modules/tempname.diff +++ b/gl/modules/tempname.diff @@ -2,7 +2,7 @@ diff --git a/modules/tempname b/modules/tempname index 7fafd72..4703517 100644 --- a/modules/tempname +++ b/modules/tempname -@@ -1,2 +1,2 @@ +@@ -1,5 +1,5 @@ Description: -gen_tempname() function: create a private temporary file or directory. +gen_tempname, gen_tempname_len: create a private temporary file or directory.
上記差分をファイル tempname.diff.patch
ファイルに保存した場合、
ソースツリーのルートにおいて以下のコマンドを実行することで、
GNU coreutils に差分が適用されます。
$ patch -p1 < tempname.diff.patch
configure
/make
実行時の留意点GNU coreutils が提供する
expr
や
factor
といったコマンドは、
多倍長演算を行うための GNU MP (gmp) ライブラリ を利用可能な環境では、
GNU MP ライブラリを利用する実装になっています。
GNU coreutils では、
gmp ライブラリの利用可否を以下の方法で判定し、
利用可能な場合はソースコード中の #include <gmp.h>
が実施されるようにしています。
__gmpz_init()
を参照するソースコードを生成
-lgmp
オプション付きでコンパイル
上記の判定方法は、
libgmp.so
ファイルの有無
(+それが GNU MP ライブラリのものか否か)
の判定に関しては妥当なのですが、
『GNU MP ライブラリの利用可否=
#include <gmp.h>
実施の可否』
は必ずしも成立するとは限りません。
例えば、
Open Solaris 系列の OS である
Open Indiana
(Oracle Solaris 11 も?) 環境では、
libgmp.so
ファイルは
/usr/lib
に置かれていますが、
gmp.h
ヘッダファイルは
/usr/include/gmp/gmp.h
に置かれています。
つまり
#include <gmp/gmp.h>
と記述しなければ、
ヘッダファイル不在でコンパイルエラーとなってしまいます。
CC src/expr.o
"src/expr.c", line 54: cannot find include file: <gmp.h>
"src/expr.c", line 182: syntax error before or at: mpz_t
:
:
この問題に関しては、 状況を整理した上で GNU coreutils 宛にバグ報告しようと思っていますが、 当面は以下のいずれかの方法で回避してください。
一番簡単な回避方法は、
./configure
実施の際に
『GNU MP ライブラリを利用しない』旨を表明する
--without-gmp
オプションを指定する方法です。
$ ./configure --without-gmp
この方法を使用した場合、
expr
や
factor
コマンドは、
GNU MP ライブラリを利用しない実装となるため、
計算可能範囲/実行性能等の面で制約を受ける可能性があります。
『とりあえず ls
コマンドのビルドができればよい』
というケースでは、この方法が一番手軽でしょう。
この問題の原因は、
ソースコード中の
#include <gmp.h>
記述が
/usr/include/gmp/gmp.h
におかれたヘッダファイルを読み込めないことにあります。
コンパイル時オプションとして
-I/usr/include/gmp
が指定されれば、
#include <gmp.h>
記述でも
/usr/include/gmp/gmp.h
ヘッダファイルが読み込まれるようになりますので、
この問題は発生しません。
CPPFLAGS
環境変数に
-I/usr/include/gmp
を指定した上で
./configure
を実施することで、
生成される Makefile
では、
CPPFLAGS
マクロのデフォルト値として
-I/usr/include/gmp
が設定されます。
$ (export CPPFLAGS="-I/usr/include/gmp"; ./configure)
以後の make
経由でのコンパイルの際には、
-I/usr/include/gmp
が指定されるようになります。
既に ./configure
の実行が済んでしまっている場合は、
CPPFLAGS
環境変数を設定した上で再度
./configure
を実行するよりは、
make
コマンド実行の際に、
コマンドラインで明示的にマクロ値指定する方が手軽かもしれません。
$ make CPPFLAGS="-I/usr/include/gmp" all-am
GNU coreutils では、
"make
" あるいは "make all
" を実行した場合、
実際のソースコードのコンパイルは、
内部で再帰的に実行された "make all-am
" によって実施されます。
しかし、
『内部で再帰的な "make all-am
" を実行』する際には、
コマンドラインでの各種マクロ値指定
(この場合は CPPFLAGS
マクロ指定)
が反映されません。
結果として、
明示的なマクロ値指定を行っても、
コンパイルの際には無視されることになります。
そのため、
コマンドラインで make
に明示的なマクロ値指定をする場合は、
"make all
" ではなく
"make all-am
"
を実行する必要があります。
備考:
Makefile
を書き換えずに、
マクロ定義値を make
実行時に変更するには、
以下のような方法があります。
『make
マクロ』として指定する方法と、
『環境変数』として指定する方法では、
値指定の有効範囲が異なりますので注意してください。
make FOO=bar
make
実行の際に、
マクロ FOO
の値に bar
を設定します。
Makefile
中での
FOO
マクロ定義よりも、
コマンドラインでの指定値の方が優先されます。
export FOO=bar; make
環境変数 FOO
の値に bar
を設定した状態で
make
を実行します。
Makefile
中で
FOO
マクロが定義されている場合は、
Makefile
での定義の方が優先されます。
("FOO=
" のような『空定義』でも、
Makefile
側定義の方が優先されます)
export FOO=bar; make -e
環境変数 FOO
の値に bar
を設定した状態で
make
を実行します。
Makefile
中で
FOO
マクロが定義されている場合でも、
環境変数での定義の方が優先されます。
以下の差分を適用して、 ヘッダファイル読み込み処理を、 直接変更してしまう方法もあります。
diff -u a/src/expr.c b/src/expr.c --- a/src/expr.c Tue Apr 16 16:01:24 2013 +0900 +++ b/src/expr.c Fri Jul 26 04:02:59 2013 +0900 @@ -51,7 +51,7 @@ #endif #if HAVE_GMP -# include <gmp.h> +# include <gmp/gmp.h> #else /* Approximate gmp.h well enough for expr.c's purposes. */ typedef intmax_t mpz_t[1]; diff -u a/src/factor.c b/src/factor.c --- a/src/factor.c Tue Apr 16 16:01:24 2013 +0900 +++ b/src/factor.c Fri Jul 26 04:02:59 2013 +0900 @@ -88,7 +88,7 @@ #include <getopt.h> #include <stdio.h> #if HAVE_GMP -# include <gmp.h> +# include <gmp/gmp.h> # if !HAVE_DECL_MPZ_INITS # include <stdarg.h> # endif
上記差分をファイル gmp.patch
ファイルに保存した場合、
ソースツリーのルートにおいて以下のコマンドを実行することで、
GNU coreutils に差分が適用されます。
$ patch -p1 < gmp.patch
lib/parse-datetime.y
によるビルドエラーGNU coreutils の
lib/parse-datetime.h
および
lib/parse-datetime.c
は、
lib/parse-datetime.y
から
GNU bison によって生成されたファイルです。
何らかの契機で、
lib/parse-datetime.h
あるは
lib/parse-datetime.c
よりも、
lib/parse-datetime.y
のファイルタイムスタンプ値の方が新しくなってしまった場合、
Makefile
における依存定義によって、
GNU bison によるファイル生成処理が実施されてしまいます。
(1) GNU bison がインストールされていない場合や、
(2) インストールされている GNU bison のバージョンが、
lib/parse-datetime.y
の処理に必要なバージョン未満の場合、
lib/parse-datetime.h
や
lib/parse-datetime.c
の生成が失敗するため、
ビルドが中断されてしまいます。
以下は bison がインストールされていない場合のビルド失敗例です。
GEN lib/parse-datetime.c ./build-aux/ylwrap: line 113: bison: command not found
lib/parse-datetime.h
や
lib/parse-datetime.c
のタイムスタンプ値の方が、
lib/parse-datetime.y
よりも新しければ、
このような生成処理が抑止されますので、
以下のような方法で、
これらのファイルのタイムスタンプを更新してください。
$ touch lib/parse-datetime.[ch]
MAP | TOP > 工房「藤車」 > 技術系執筆情報 > 『lsを読まずにプログラマを名乗るな!』 > ビルド時の留意点 |