2011/11/06

[boost]regexのリンクがうまくいかん

うまくいかんシリーズ。
boostのregexで、リンクがうまくいかんようなのだ。
使っているboostは、1.47.0。
コンパイラは「gcc バージョン 4.6.1 (Ubuntu/Linaro 4.6.1-9ubuntu3) 」だ。

#include <boost/regex.hpp>
int main()
{
	boost::regex  r("");
	return 0;
}

$ g++ -o tst -I/usr/local/boost/include -L/usr/local/boost/lib -lboost_regex regex.cpp
/tmp/ccaCv8B6.o: In function `boost::basic_regex<char, boost::regex_traits<char, boost::cpp_regex_traits<char> > >::assign(char const*, char const*, unsigned int)':
regex.cpp:(.text._ZN5boost11basic_regexIcNS_12regex_traitsIcNS_16cpp_regex_traitsIcEEEEE6assignEPKcS7_j[boost::basic_regex<char, boost::regex_traits<char, boost::cpp_regex_traits<char> > >::assign(char const*, char const*, unsigned int)]+0x2a): undefined reference to `boost::basic_regex<char, boost::regex_traits<char, boost::cpp_regex_traits<char> > >::do_assign(char const*, char const*, unsigned int)'
collect2: ld はステータス 1 で終了しました

boost_regexがうまくいってないのかと思ってboost_regeとかにしてみると、ちゃんと「ライブラリがない」エラーが出た。
ってことは、libboost_regexがあることはわかってるんだ。
なのに・・・なぜ・・・。

これがリンクできない、といっているのはわかった。
_ZN5boost11basic_regexIcNS_12regex_traitsIcNS_16cpp_regex_traitsIcEEEEE6assignEPKcS7_j

では、ビルドしたファイルのあるboost_1_47_0/bin.v2/libs/regex/build/gcc-4.6.1/release/threading-multiを見てみよう。

$ nm *.o | grep _ZN5boost11basic_regexIcNS_12regex_traitsIcNS_16cpp_regex_traitsIcEEEEE6assignEPKcS7_j

確かに、ない。
では、何ならあるんだ?

$ nm *.o | grep _ZN5boost11basic_regexIcNS_12regex_traitsIcNS_16cpp_regex_traits
U _ZN5boost11basic_regexIcNS_12regex_traitsIcNS_16cpp_regex_traitsIcEEEEE9do_assignEPKcS7_j
W _ZN5boost11basic_regexIcNS_12regex_traitsIcNS_16cpp_regex_traitsIcEEEEE5imbueESt6locale

うーん・・・。

ちなみに今は、こんな環境だ。

Linux kurokiri 3.0.0-12-generic #20-Ubuntu SMP Fri Oct 7 14:56:25 UTC 2011 x86_64 x86_64 x86_64 GNU/Linux


これを対策できれば、いいんだと思う。
`boost::basic_regex<char, boost::regex_traits<char, boost::cpp_regex_traits<char> > >::do_assign(char const*, char const*, unsigned int)'

boost::regexは、こういう定義だ。

typedef basic_regex<char>      regex;

なので、このエラーはboost::regexのことであることは間違いがない。
では、basic_regexクラスのdo_assign()を見てみよう。

class basic_regex : public regbase
{
(略)
private:
   basic_regex& do_assign(const charT* p1,
                          const charT* p2,
                          flag_type f);
(略)

宣言はある。
では、実装はどこにあるのだろう。

その下にある、これしかなさそうだ。

template <class charT, class traits>
basic_regex<charT, traits>& basic_regex<charT, traits>::do_assign(const charT* p1,
                        const charT* p2,
                        flag_type f)
{
   shared_ptr<re_detail::basic_regex_implementation<charT, traits> > temp;
   if(!m_pimpl.get())
   {
      temp = shared_ptr<re_detail::basic_regex_implementation<charT, traits> >(new re_detail::basic_regex_implementation<charT, traits>());
   }
   else
   {
      temp = shared_ptr<re_detail::basic_regex_implementation<charT, traits> >(new re_detail::basic_regex_implementation<charT, traits>(m_pimpl->m_ptraits));
   }
   temp->assign(p1, p2, f);
   temp.swap(m_pimpl);
   return *this;
}

ヘッダにdo_assign()定義があるということは、ライブラリうんぬんは関係ないことになる。
なんかおかしい・・・。

とりあえず、プリプロセスを展開させよう。

__extension__ extern template basic_regex<char , boost::regex_traits<char > >&
   basic_regex<char , boost::regex_traits<char > >::do_assign(
      const char* p1,
      const char* p2,
      flag_type f);

定義がないのは、これ。

boost::basic_regex<char, boost::regex_traits<char, boost::cpp_regex_traits<char> > >
  ::do_assign(char const*, char const*, unsigned int)

もしcpp_regex_traits<T>がbasic_regexをtypedefしたものだったらいいんだけど、別のclassだ。
確かに、定義はないな。


しかし、変だ。
だって、basic_regex<charT, traits>::do_assign()って書いているのだから、traitsがcpp_regex_traitsから置き換わる、なんてのは考えにくい。
nmでbasic_regexのコンストラクタを見ると、

boost::basic_regex<char, boost::regex_traits<char, boost::cpp_regex_traits<char> > >::basic_regex(char const*, unsigned int)

と、cpp_regex_traitsのバージョンしかなさそうだ・・・ん?
似たようなのがあったぞ。

boost::shared_ptr<boost::re_detail::basic_regex_implementation<char, boost::regex_traits<char, boost::cpp_regex_traits<char> > > >::shared_ptr()

すまん、もう訳がわからん・・・。
あ、でもこのshared_ptrは、do_assign()の実装で使われているものではなかろうか。

shared_ptr<re_detail::basic_regex_implementation<charT, traits> > temp;

do_assign()の定義は

template <class charT, class traits>
basic_regex<charT, traits>& basic_regex<charT, traits>::do_assign()

なので、traitsとしてはbasic_regexと同じものが使われるべきで、regex_traitsが急に出てくるのはおかしいような。
でも、そもそもの話が、

typedef basic_regex<char, regex_traits<char> > regex;

なので、regexの定義としてはおかしくないのか。

でも、nmで見ると、regex_traitsは出てこず、cpp_regex_traitsしかないんだよなぁ。
まあ、今日はこの辺にしておこう。

0 件のコメント:

コメントを投稿

コメントありがとうございます。
スパムかもしれない、と私が思ったら、
申し訳ないですが勝手に削除することもあります。

注: コメントを投稿できるのは、このブログのメンバーだけです。