どうしてどうしてぼくたちはGentooのバグを直してきたんだろう。

Gentoo のバグの直しかた、について Gentoo の開発者でもなんでもないですが、書いてみようかと思います。

バグに遭遇

Gentoo を ~x86-fbsd や ~amd64 で使っていると日常茶飯事のごとくバグに出くわします。今回は net-libs/libpcap がビルドできなくなりました。

とりあえずログを

なにはともあれ build.log を見ましょう。 net-libs/libpcap-1.1.1-r1 なら ${PORTAGE_TMPDIR}/portage/net-libs/libpcap-1.1.1-r1/temp/build.log です。
${PORTAGE_TMPDIR}は /etc/make.conf で変更してなければ /var/tmp なので /var/tmp/portage/net-libs/libpcap-1.1.1-r1/temp/build.log です。

とりあえず、末尾を見ます。そして最後のエラーを見ます。

i686-gentoo-freebsd7.1-gcc -O2 -fpic -O2 -pipe -march=prescott --param l1-cache-size=16 --param l1-cache-line-size=64 -mtune=prescott -I.  -DHAVE_CONFIG_H  -D_U_="__attribute__((unused))" -c ./bpf_dump.c
./runlex.sh flex -Ppcap_ -oscanner.c scanner.l
bison -y -p pcap_ -d grammar.y
bison: m4 subprocess failed: Invalid argument
gmake: *** [grammar.c] エラー 1
 * ERROR: net-libs/libpcap-1.1.1-r1 failed:
 *   compile problem
 * 
 * Call stack:
 *     ebuild.sh, line  48:  Called src_compile
 *   environment, line 2875:  Called die
 * The specific snippet of code:
 *       emake all shared || die "compile problem"
 * 
 * If you need support, post the output of 'emerge --info =net-libs/libpcap-1.1.1-r1',
 * the complete build log and the output of 'emerge -pqv =net-libs/libpcap-1.1.1-r1'.
 * The complete build log is located at '/usr/tmp/portage/net-libs/libpcap-1.1.1-r1/temp/build.log'.
 * The ebuild environment file is located at '/usr/tmp/portage/net-libs/libpcap-1.1.1-r1/temp/environment'.
 * S: '/usr/tmp/portage/net-libs/libpcap-1.1.1-r1/work/libpcap-1.1.1'

bison が起動されて、 m4 がうまくいってないっぽいですね。 FreeBSD なので /usr/bin/m4 と /usr/bin/gm4 とがあってそこらへんの仕様の違いによるものかもしれません。起動するものを切り替えて、うまくいくかどうかやってみたいところです。
ここで推測します。 Unix では外部プロセスを呼びだす時に EIDTOR やら LESS やらの環境変数を使ってそのプロセスの名前を取得していることが多いです。多分 m4 の起動も M4 あたりを設定してやればいいのでは?

bison のコードへ

ということで、 bison のコードにあたってみましょう。 equery b /usr/bin/bison して bison がどのパッケージから来たものか調べます。 BSD でなければ、 qfile /usr/bin/bison でもいいのですが portage-utils は BSD だと qfile がうまく動きません。

# equery b /usr/bin/bison
 * Searching for /usr/bin/bison
sys-devel/bison-2.4.2 (/usr/bin/bison)

ソースコードを展開します。 ebuild /usr/portage/sys-devel/bison/bison-2.4.2.ebuild unpack です。
/var/tmp/portage/sys-devel/bison-2.4.2/work/bison-2.4.2 下に bison のコードが出てきます。目的のコードを探していきましょう。

# cd /var/tmp/portage/sys-devel/bison-2.4.2/work/bison-2.4.2
# find . | xargs grep getenv | grep M4
./src/output.c:  char const *m4 = (p = getenv ("M4")) ? p : M4;

思ったとおりに環境変数を取得しています。切り替えて実行してみます。

# M4=/usr/bin/m4 bison -y -p pcap_ -d grammar.y
bison: m4 subprocess failed: Invalid argument
# M4=/usr/bin/gm4 bison -y -p pcap_ -d grammar.y
bison: m4 subprocess failed: Invalid argument

だめです…
よくよくコードを読むと、 trace_flag なるものがあります。これで なにが起動されているのか確認できそう…。

# grep trace_flag src/* | grep -v if
src/getargs.c:int trace_flag = trace_none;
src/getargs.h:extern int trace_flag;
src/main.c:  timevar_report = trace_flag & trace_time;
src/reader.c:  gram__flex_debug = trace_flag & trace_scan;
src/reader.c:  gram_debug = trace_flag & trace_parse;
src/scan-skel.c:  skel__flex_debug = trace_flag & trace_skeleton;
src/scan-skel.l:  skel__flex_debug = trace_flag & trace_skeleton;

src/getargs.c を見たところ --trace=tool をつければいい感じ。 man にも bison --help にも出てこないって……。

# bison -y -p pcap_ -d grammar.y --trace=tool
running: /usr/bin/gm4 /usr/share/bison/m4sugar/m4sugar.m4 - /usr/share/bison/bison.m4 /usr/share/bison/c-skel.m4
bison: m4 subprocess failed: Invalid argument
# M4=/usr/bin/true bison -y -p pcap_ -d grammar.y
running: /usr/bin/true /usr/share/bison/m4sugar/m4sugar.m4 - /usr/share/bison/bison.m4 /usr/share/bison/c-skel.m4
bison: m4 subprocess failed: Invalid argument

なにをやっても "bison: m4 subprocess failed: Invalid argument" と…。bison のバグじゃないかという疑惑になってきました。

# find . |xargs grep 'subprocess failed'
./m4/posix_spawn.m4:          perror ("subprocess failed");
./m4/posix_spawn.m4:      perror ("subprocess failed");
./configure:          perror ("subprocess failed");
./configure:      perror ("subprocess failed");
./lib/wait-process.c:                   _("%s subprocess failed"), progname);
./lib/wait-process.c:               _("%s subprocess failed"), progname);
./lib/pipe.c:               _("%s subprocess failed"), progname);
./lib/pipe.c:               _("%s subprocess failed"), progname);

エラーメッセージは ./lib/wait-process.c か ./lib/pipe.c からっぽいです。 ./lib/wait-process.c は wait_subprocess ./lib/pipe.c は create_pipe の部分です。
./lib/wait-process.c のほうは if (WEXITSTATUS (status) == 127) してあるのに /usr/bin/true を渡しても同じ結果だったので違うでしょう。

オチ

さて、ここで…他の環境で追試してみると…再現しません… orz
よくよく /usr/portage/sys-devel/bison/ChangeLog を見ると…

  04 Apr 2010; Javier Villavicencio <the_paya@gentoo.org>
  bison-2.4.2.ebuild, +files/bison-2.4.2-gnulib_spawn.patch:
  Add patch to fix gnulib's spawn, fixes bug #312697.

多分これで直ったんですね…。 こういうのは -r1 つけてほしい…。

結論: まず直ってないかとか bug report ないか確認しようね!