build.logの読み解き方 #0 「sys-apps/groff-1.20.1-r3」

バグを見かけては、それを解決する連載の予定…。いつまで続くことやら。

今回は今 Mac OS X prefix で emerge できない sys-apps/groff-1.20.1-r3 について。

とりあえず ~/Gentoo/var/tmp/portage/sys-apps/groff-1.20.1-r3/temp/build.log を見てみます。

i686-apple-darwin10-g++ -march=core2 -msse4.2 -m32 -pipe -fomit-frame-pointer -O2 -Wl,-dead_strip_dylibs -o troff dictionary.o div.o env.o input.o majorminor.o mtsm.o node.o number.o reg.o /Users/naota/Gentoo/var/tmp/portage/sys-apps/groff-1.20.1-r3/work/groff-1.20.1/src/libs/libgroff/libgroff.a   -lm
collect2: ld terminated with signal 6 [Abort trap]
Undefined symbols:
  "node::~node()", referenced from:
      extra_size_node::~extra_size_node()in div.o
      extra_size_node::~extra_size_node()in div.o
      vertical_size_node::~vertical_size_node()in div.o
      vertical_size_node::~vertical_size_node()in div.o
      token_node::token_node(token const&)in input.o
      non_interpreted_node::non_interpreted_node(macro const&)in input.o
      non_interpreted_char_node::non_interpreted_char_node(unsigned char)in input.o
      non_interpreted_char_node::~non_interpreted_char_node()in input.o
      non_interpreted_char_node::~non_interpreted_char_node()in input.o
      token_node::~token_node()in input.o
      token_node::~token_node()in input.o
      token_node::~token_node()in input.o
      token_node::~token_node()in input.o
      non_interpreted_node::~non_interpreted_node()in input.o
      non_interpreted_node::~non_interpreted_node()in input.o
      non_interpreted_node::~non_interpreted_node()in input.o
      non_interpreted_node::~non_interpreted_node()in input.o
got unhandled exception: symbol(s) not found
terminate called after throwing an instance of 'char const*'
make[2]: *** [troff] Error 1
make[2]: Leaving directory `/Users/naota/Gentoo/var/tmp/portage/sys-apps/groff-1.20.1-r3/work/groff-1.20.1/src/roff/troff'
make[1]: *** [src/roff/troff] Error 2
make[1]: Leaving directory `/Users/naota/Gentoo/var/tmp/portage/sys-apps/groff-1.20.1-r3/work/groff-1.20.1'
make: *** [all] Error 2

この部分が今度のエラーの核。だいたいは node::~node() が見当たらないと言ってます。

前回はbuildが通ったという知識があるので、それを元に比較します。

% eix groff
[I] sys-apps/groff
     Available versions:  [M](~)1.20.1-r1 (~)1.20.1-r2 (~)1.20.1-r3 {X examples linguas_ja}
     Installed versions:  1.20.1-r2(06時40分48秒 2010/08/11)(-X -examples -linguas_ja)
     Homepage:            http://www.gnu.org/software/groff/groff.html
     Description:         Text formatter used for man pages

成功したのは groff-1.20.1-r2, 失敗したのは groff-1.20.1-r3 で revison が1つ違うだけ。すなわち元のソースのバージョンは一緒で、 patch が追加されたり削除されたりしているってことです。

この2つの違いを見ます。

% cd ~/Gentoo/usr/portage/sys-apps/groff 
% diff -u groff-1.20.1-r2.ebuild groff-1.20.1-r3.ebuild
--- groff-1.20.1-r2.ebuild      2009-11-11 19:31:58.000000000 +0900
+++ groff-1.20.1-r3.ebuild      2010-08-07 21:31:47.000000000 +0900
@@ -1,13 +1,13 @@
-# Copyright 1999-2009 Gentoo Foundation
+# Copyright 1999-2010 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
-# $Header: /var/cvsroot/gentoo-x86/sys-apps/groff/groff-1.20.1-r2.ebuild,v 1.1 2009/11/07 06:10:09 matsuu Exp $
+# $Header: /var/cvsroot/gentoo-x86/sys-apps/groff/groff-1.20.1-r3.ebuild,v 1.2 2010/07/25 21:29:44 jer Exp $
 
 inherit autotools eutils toolchain-funcs
 
 DESCRIPTION="Text formatter used for man pages"
 HOMEPAGE="http://www.gnu.org/software/groff/groff.html"
 SRC_URI="mirror://gnu/groff/${P}.tar.gz
-       linguas_ja? ( mirror://gentoo/${PF}-japanese.patch.bz2 )"
+       linguas_ja? ( mirror://gentoo/${P}-r2-japanese.patch.bz2 )"
 
 LICENSE="GPL-2"
 SLOT="0"
@@ -29,6 +29,9 @@
        cd "${S}"
 
        epatch "${FILESDIR}"/${PN}-1.19.2-man-unicode-dashes.patch #16108 #17580 #121502
+       epatch "${FILESDIR}"/${P}-tmac-ec.patch #263524
+       epatch "${FILESDIR}"/${P}-Thtml-mem-leak.patch #294045
+       epatch "${FILESDIR}"/${P}-double-frees-mem-leaks.patch #294045
 
        # put the docs in the Gentoo-specific spot
        sed -i \
@@ -55,7 +58,7 @@
        EOF
 
        if use linguas_ja ; then
-               epatch "${WORKDIR}"/${PF}-japanese.patch #255292
+               epatch "${WORKDIR}"/${P}-r2-japanese.patch #255292
                eautoconf
                eautoheader
        fi

ここで、 ${PF} = "1.20.1-r2" あるいは "1.20.1-r3" で ${P} = "1.20.1" です。 LINGUAS="ja" は指定されてない(先の eix の出力で "-linguas_ja" であった)ことから、 "if use linguas_ja; then ... fi" の部分は無視できます。

問題は残りの patch の部分でしょう。 node::~node() あたりがあやしいので grep します。

% grep node files/groff-1.20.1-*                       
files/groff-1.20.1-Thtml-mem-leak.patch:* src/roff/troff/node.h (node::~node): Move to...
files/groff-1.20.1-Thtml-mem-leak.patch:* src/roff/troff/node.cpp: Here.  Free `state' and `push_state'.
files/groff-1.20.1-Thtml-mem-leak.patch: src/roff/troff/node.cpp |   11 ++++++++++-
files/groff-1.20.1-Thtml-mem-leak.patch: src/roff/troff/node.h   |    4 ----
files/groff-1.20.1-Thtml-mem-leak.patch:diff --git a/src/roff/troff/node.cpp b/src/roff/troff/node.cpp
files/groff-1.20.1-Thtml-mem-leak.patch:--- a/src/roff/troff/node.cpp
files/groff-1.20.1-Thtml-mem-leak.patch:+++ b/src/roff/troff/node.cpp
files/groff-1.20.1-Thtml-mem-leak.patch:+inline node::~node()
files/groff-1.20.1-Thtml-mem-leak.patch: class charinfo_node : public node {
files/groff-1.20.1-Thtml-mem-leak.patch:@@ -4643,7 +4651,7 @@ void hline_node::tprint(troff_output_file *out)
files/groff-1.20.1-Thtml-mem-leak.patch:@@ -4651,6 +4659,7 @@ void hline_node::tprint(troff_output_file *out)
files/groff-1.20.1-Thtml-mem-leak.patch:diff --git a/src/roff/troff/node.h b/src/roff/troff/node.h
files/groff-1.20.1-Thtml-mem-leak.patch:--- a/src/roff/troff/node.h
files/groff-1.20.1-Thtml-mem-leak.patch:+++ b/src/roff/troff/node.h
files/groff-1.20.1-Thtml-mem-leak.patch:@@ -132,10 +132,6 @@ inline node::node(node *n, statem *s, int divlevel)
files/groff-1.20.1-Thtml-mem-leak.patch:-inline node::~node()
files/groff-1.20.1-Thtml-mem-leak.patch: int node_list_ends_sentence(node *);
files/groff-1.20.1-double-frees-mem-leaks.patch:@@ -2213,14 +2213,15 @@ node *environment::make_tag(const char *nm, int i)
files/groff-1.20.1-double-frees-mem-leaks.patch:-    return new special_node(*m);
files/groff-1.20.1-double-frees-mem-leaks.patch:+    return new special_node(m);

"files/groff-1.20.1-Thtml-mem-leak.patch:+inline node::~node()" が見えます…。あやしい。この patch を見てみましょう。

--- a/src/roff/troff/node.cpp
+++ b/src/roff/troff/node.cpp
@@ -1811,6 +1811,14 @@ void suppress_output_file::really_transparent_char(unsigned char)
 {
 }
 
+inline node::~node()
+{
+  if (state != 0)
+    delete state;
+  if (push_state != 0)
+    delete push_state;
+}
+
 /* glyphs, ligatures, kerns, discretionary breaks */
 
 class charinfo_node : public node {

node.cpp に inline な関数が書かれています。 inline な関数は出現したところにコードが埋められる(ちょっと適当)ので、(基本的に)他から読まれない *.cpp に inline 関数があるとリンクが失敗しそうで、さっきのエラーとあっています。ここの inline を消して buildしてみましょう。

% edit files/groff-1.20.1-Thtml-mem-leak.patch
% ebuild groff-1.20.1-r3.ebuild digest
% emerge -1 groff

として、無事 build できました。

まとめると

  • 前回動いてた、という知識
    • diff とってみる
  • あやしげな patch をあやしげな言葉で grep してみる
  • C++ の inline の挙動

こんな感じですね。次回(あるかどうか…)お楽しみに。