GoogleTestの使い方と仕組み

GoogleTestの使い方

(今回googlemockの説明はしません)

  1. GoogleTestのソースコードを持ってくる https://github.com/google/googletest

  2. GoogleTestをビルドする GoogleTestのビルド方法は二つある。1. あらかじめコンパイラしてライブラリ化しておく方法と、2. 自分のテストプログラムと同時にコンパイルする方法。

    1. あらかじめビルドする場合は、CMakeを使ってGNU向けのMakefile、もしくはWindowsの場合はVisual Studioのソリューションを作り、ビルドしライブラリ(静的ライブラリの場合gtest.lib)を作っておく。 具体的には、GoogleTestのソースをクローンもしくはダウンロードした際の、トップディレクトリの下にビルド用のディレクトリを作り(buildとする) buildディレクトリに入って cmake ../と打つ。cmake-guiの場合は、ソースディレクトリにGoogleTest自体のディレクトリを、ビルドディレクトリにbuildを選ぶ。出来たMakefileVisual Studioの場合はソリューションファイル)を実行して作成。
    2. テストプログラムと同時にビルドする場合は、(install directory...)/googletest/src/ にあるgtest-all.ccを、ビルドの対象に設定する。(その際には、(install directory...)/googletest, (install directory...)/googletest/includeをビルド時のインクルードパスに追加することを忘れずに)

    個人的には2. がオススメ。この方法だと、特にWindowsのようなランタイムライブラリの整合のために、テストプログラム側のビルドオプションと、GoogleTest側のビルドオプション(GoogleTestのソリューションファイルでのランタイムライブラリを、マルチスレッドにしたりしなかったり、デバッグにしたりリリースにしたり)のといった変更の必要がなくなるから。

  3. テスト用のメインプログラムと、テストケースごとのテストプログラムを作り、ビルドする。

テスト用メインプログラム

GoogleTestを使ったテストプログラムのメイン関数はこんな感じになる。

#include "gtest/gtest.h"

int main(int argc, char **argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
テストケースの記述

テストケースの記述は、TESTマクロもしくはフィクスチャを利用する場合はTEST_Fというマクロを使い、以下のように記述する。

TEST([TEST_CASE_NAME], [TEST_NAME])
{
  // user defined test routine
}

TEST_F_([CLASSS_NAME], [TEST_NAME])
{
  // user defined test routine
}

とにかくこれを好きなだけ書くと、RUN_ALL_TESTS()によって、全てのテストケースを自動で探して実行して、サマリを出してくれます。 TEST_CASE_NAME, TEST_NAMEには好きな名前を入れられる(サマリに分かりやすく表示するためのもの)。フィクスチャの場合は、[CLASS_NAME]に、フィクスチャに使うクラス名を入れる。 細かい使い方については以下を参照。 http://opencv.jp/googletestdocs/primer.html

GoogleTestの仕組み

一度分かってしまえば簡単なのだけれど、最初はフィクスチャは何の為にどうやって使うのだろう、という人もいると思うのでに、初心者向けに簡単な仕組みを説明します。

まず、フィクスチャというのは、最も良く使われるのは、複数のテストを実行するときに、テスト間で共通に実行する処理だったり、同じデータや変数を共有したい場合に使う。 例えばあるデータを読み込んで、少し変更して保存(シリアライズ)するようなテストで、読み込みは同じなのだけれど、保存はデータ変更の種別によって別々のテストケースとして分けたい、といった場合に、データの読み込み部分は共通化したい。こういうケースである。

こういうテスト間で共通の処理をやりたいケースでは、以下のようにフィクスチャを使ったテストを作る。 つまりユーザーは、テスト間に共通して持たせたいメンバを持ち、共通して実行させたい処理をSerializeTestのSetUp(), TeatDown()メソッドに書く。最後にTEST_Fのテスト関数本体のマクロ引数の一番目として、フィクスチャクラス名を書けば良い。

class SerializeTest : public testing::Test {
protected:
  // member
  FooData foo_data;
  
  // method
  SerializeTest() : foo_data() {}
  ~SerializeTest() {}
  
  virtual void SetUp() {
    openData("name");
    readFooData(&foo_data);
  }
  virtual void TearDown() {
    closeData("name");
  }
};

TEST_F(SerializeTest, change_a_type) {
  foo_data.a_type_data  = new_a_type_data;
  writeFooData(&foo_data);
  checkSerialize(&foo_data);
}

TEST_F(SerializeTest, change_b_type) {
  foo_data.b_type_data = new_b_type_data;
  writeFooData(&foo_data);
  checkSerialize(&foo_data);
}

これでテストを走らせると、RUN_ALL_TESTS()が実行され、TEST_Fのマクロを使って定義されたテスト関数を実行するときには、TEST_Fの引数の最初のクラスがフィクスチャのターゲットクラスとして呼び出されるようになる。 このプロセスの中身は以下のようになっている。

inline int RUN_ALL_TESTS() {
  return ::testing::UnitTest::GetInstance()->Run();
}

この呼び出しを追っていくと、UnitTest::Run()の中で、UnitTestImpl::RunAllTests()が呼び出され、その中で各テストケースを実行するTestCase::Run()、そしてTestInfo::Run()が呼び出されている。 TestInfo::Run()の中で実際に、フィクスチャとして定義したクラスのインスタンスがまず生成され、その時にフィクスチャクラスのコンストラクタも呼び出される。 そしてテスト実行前にSetUp()が実行され、テスト実行後にTearDown()が実行される。

ではここで、どういったクラスのインスタンスが生成されているかは、マクロの内容を追っていくことで分かる。

まず、マクロによってフィクスチャとしてテスト共通で維持すべきクラスの名前が、test_fixture_test_name_Testのように決められて(#defineの中の##は連結。上記の例ではSerializeTest_change_a_type_Testというクラス名になる)、 フィクスチャの定義でユーザーが作ったクラスを親クラスとします(上記の例ではSerializeTestクラスを親クラスとして子クラスの定義が作られる)。

この子クラスの定義では、コンストラクタと、TestBody()メソッド、TestFactoryImplを使って、インスタンスを生成しTestInfo*を返すメソッドが定義される。

そしてマクロ展開の最後が、この子クラスのメソッドのTestBody()のシグニチャ部までとなっており、メソッドの定義が、ユーザーが書いたテストルーチンとなるようになっている。

void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() <-- expanded by Macro
{
  // user defined body routine ...
}

まとめ

つまり、ユーザ視点で簡単にまとめると、各テスト毎にユーザーが書いたフィクスチャクラスがインスタンス化されて、コンストラクタ、SetUp()が実行される。 (テストケース毎では無いので、各テスト毎に毎回インスタンス化され、実行されることに注意。テストケースにつき一度しか実行したくない場合については、staticなメンバとメソッドを使う方法が上級ガイドに記述されている)

そして、テストクラスのTestBody()メソッドとして定義された TEST_F(test_fixture, test_name) の部分が実行され、最後にTearDown()が実行される。 これを全テストケースで繰り返す。以上。

マクロの定義抜粋

#if !GTEST_DONT_DEFINE_TEST
# define TEST(test_case_name, test_name) GTEST_TEST(test_case_name, test_name)
#endif

#define TEST_F(test_fixture, test_name)\
  GTEST_TEST_(test_fixture, test_name, test_fixture, \
              ::testing::internal::GetTypeId<test_fixture>())

#define GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \
  test_case_name##_##test_name##_Test

// Helper macro for defining tests.
#define GTEST_TEST_(test_case_name, test_name, parent_class, parent_id)\
class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\
 public:\
  GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {}\
 private:\
  virtual void TestBody();\
  static ::testing::TestInfo* const test_info_ GTEST_ATTRIBUTE_UNUSED_;\
  GTEST_DISALLOW_COPY_AND_ASSIGN_(\
      GTEST_TEST_CLASS_NAME_(test_case_name, test_name));\
};\
\
::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_case_name, test_name)\
  ::test_info_ =\
    ::testing::internal::MakeAndRegisterTestInfo(\
        #test_case_name, #test_name, NULL, NULL, \
        ::testing::internal::CodeLocation(__FILE__, __LINE__), \
        (parent_id), \
        parent_class::SetUpTestCase, \
        parent_class::TearDownTestCase, \
        new ::testing::internal::TestFactoryImpl<\
            GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>);\
void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody()

SONYの電子ペーパーが凄い

SONY電子ペーパー買いました!

www.sony.jp

ソニーストアの定価で8万円します。しかもソニーストアでは発売後ずっと品薄・入荷待ちの状態で、それ以上の値段で出回ってましたね。 ようやく定価に近い値段に落ちてきたのでついに購入したわけです。

結果、期待していた以上の素晴らしい製品でした!

ちにみに、この製品は思い付きで買ったわけではないんです。 ちょうど10年くらい前に、会社内の課題で新しい開発提案を持ってこいっていうのがあって、その時に自分が本当に欲しいものを作る、という意気込みでE-Inkを使った電子ペーパーの提案をしたことがあります。(今もその提案資料がある) PDFを読み込めて、手書きで追記が出来て、書き味が紙同等で、拡大して小さく書き込めて、星印を付けたところは後から検索できるってのも正に思い描いてた通り。 後は、定型フォーマットに書き込んだ内容を読みだすとか、プロジェクタにページ内容を無線で投げるなんて機能も考えていましたが、個人で使う機能に関しては、その時に欲しいと思って機能がこのRT-RP1ではほぼ余すところなく実現されてます。

しかも、書き味も経験した中では最も違和感が無くて、普段紙に書いている自分の最高速で書いてもちゃんと途切れず付いてきてくれます。 いやあ、いくらでも増やせるPDFの元データに書き込めるとか、手書きのカット&ペーストという単純な機能が、これほど便利だとも思わなかった。

電子ペーパーの恩恵
  • これでまず、自分は論文とか標準書とか読む時に紙に必ず印刷していたのが、必要なくなった。
  • どの論文を読んだか、読もうとしていたのか管理出来なくなっていたのが解決した。
  • ノート・雑記帳が必要なくなった。数式の計算とか証明とか紙に書いてたのを、電子ペーパーにすることで、いくらでも編集出来るし見返せるようになった。
  • 手帳・カレンダーが必要なくなった。(とはいえ、既にアナログ品は使っていなかったのでそれ程のインパクトでは無い)

やっぱり値段的には高かったけど、購入してほんとに良かった。 論文とか、標準書とか日常的に読む人にはオススメです!

サラリーマン経営の時代は終わった

NECに引き続き、富士通がパソコン事業をレノボに統合 https://www.nikkei.com/article/DGXMZO22892340Q7A031C1TJ2000/

かつて日本を支えた大メーカーは揃って苦境に立っている。次々に入ってくるニュースは不景気なニュースばかり。

ところが一方で、今まさに元気なメーカーもある。トヨタキヤノンファナック村田製作所日本電産…これらの会社は、創業者かその一族が会社をコントロールしている。 つまり、カリスマ経営者が、会社の成長戦略とか大型買収を、経営者が自らの判断でスピーディーに行えて、権力が強固なためにトップダウンで方針が行き届きやすいのが、生き馬の目を抜く今の時代に必要なのだろう。

それに比べて、一時はグローバル化することで年毎に売り上げを伸ばして、成長を続けてきた大企業がどうしてこうなってしまったのか?

サラリーマン経営者がコントロールする企業の欠点は明確で、そういった企業のマネージャは、ほとんどがジェネラリストで占められている。彼らの仕事は、組織が大きな問題を起こさないようチェックをすることであり、また部下の仕事が円滑に回るようにすることだ。治世はこれで良かった。製品に足りない機能を追加し、小型化し、コストダウンすれば驚くほど会社が伸びた。

管理・オペレーションの仕事を地道に行いながら、昇進するテクニックを駆使して昇りつめてきた役員達が、これまた同じような人間を引き上げて一派を作る。 結果的に、高度な専門性を持ち、自分で会社が進むべき道を決めるような人は、ほとんど会社の経営には参加していない事態に陥る。 今の日本のほとんどの大企業では、取締役も社員も含めて皆が自分の日々のルーチンワークをこなすことだけ考えていて、そうでないこと、例えば新しいビジネスを作るとか、革新的な技術開発だとか、企業改革は誰かがやってくれると思っている。 これを集合依存と言う。つまり、強い個が欠落した烏合の衆。

こうなると、上から下まで完全に乱世を突破する力を持っている人がいなくなって、イノベーションを起こすどころか、イノベーションのアイデアまでも踏みつぶしてしまうような組織になる。

だから、サラリーマン経営者達は会社を削りながら延命することしか出来ない。

これからは、スペシャリストが経営を担う組織でないと戦えない。

ネットニュースの闇

インターネットで政治ニュースって見ますか?見ますよね。 じゃあコメント欄って見ますか? 見る人多いんじゃないでしょうか。自分も昔は見てました。でも今は見ません。

コメント表示オフに出来るのはオフにするし、そもそもYahooとかコメント欄で集客するようなニュースサイトは見ないことにしてます。 特に政治関連のニュースとか見ると、コメント欄には誹謗中傷の嵐。 ネトウヨの人達もそうじゃない人も、自分と異なる考えの人を型にはめて、決め付けて、相手を攻撃することに執念を燃やしてる。 たった一つか二つの思想のみで人を二分するのも特徴だ。

最近林立しているニュースサイトは、記事自体も質が低くて、事実に基づかない短絡的で独善的な記事が多い。コメント欄と同レベル。

さて、せっせと書き込みしている人達は置いておいたとして、そういう記事とかコメントを見る立場で、みんなはどう感じているんだろう。 自分にとって気に入らない方が、誹謗中傷されているのを見てスカっとしているんだろうか。それとも、いいねボタンを押して応援して正義の味方気分を味わうのだろうか。

自分は正直にいって、誹謗中傷の記事やコメントを見るのに疲れました。 あれを読んでしまうと、ひとしきり見た後ぐったりしてしまう。

それにすごく時間の無駄だと思う。 本来の情報という意味での記事はそこで終わっているのに、客観的で精度の高い情報がほとんど増えないまま、延々と非生産的なやりとりが繰り広げられる。

こんなことに人生の貴重な時間を使うべきじゃないと思う。

「老子」を読みました

論語」を読み終わり、いくつか孔子にまつわる本や記事を読んだ後に、老子を読んだ。

[商品価格に関しましては、リンクが作成された時点と現時点で情報が変更されている場合がございます。]

老子【電子書籍】[ 蜂屋邦夫 ]
価格:1166円 (2017/10/10時点)


老子道教の開祖で、本当のところは出生・死亡も詳らかでは無い、半ば伝説上の人物。 その老子が記したとされる『老子道徳経』から、その思想を紐解くしか無い。

で、今回読んでみて「良く分からん」というのが率直な感想というところ。

まず、道教についての知識が全然足りないということや、ただでさえ漢文で色々な読み方が可能な上に、文章が実践的でなくて抽象的過ぎるので意味が捉え辛いということ。 そして何より感じたのが、多分に宗教的だということだ。

アンチ儒家

道教のスタート(老子)は紛れもなくアンチ儒家である。なので当然儒家と良く比較されるのだけど、一つの区別として、少なくとも進歩主義・実践主義に基づいた孔子の考えが宗教では無いのに対し、老子の考えは宗教といっても良いと思うところ。 例えば、そもそも"道"が万物の根源で、ものごとが始まる前から存在するもの、と説き、道の道とすべきは常の道にあらず、つまり道というものが定義できたら、それは道では無いというのだ。うーん。 それから、赤子は柔弱だが、その柔弱さゆえに、決して蜂に刺されることも猛獣に襲われることも無いとか。知識を増やしすぎると、かえって迷いが生まれて良くないとか。

理性を頼りにする自分にとっては、こういう感性が先立つ世界はどうしても分からないのだ。 しかし、アプローチは違えども、共感できる教えも多くある。 小国寡民を理想とする考えや、足るを知ることが幸福にするとか。

道家を生んだのは

老子道徳経を読んだだけでは、中国において三大教と呼ばれるほど大きな位置を担うとは正直想像しがたい。 しかし、何はともあれ道教というものが発展した後漢以降の時代に、老子という存在に後から存在感が与えられたと思われる。 特に道教には、北魏や唐に代表されるように、無為の治や仏教への対抗として為政者が利用したり、病・災害に対するシャーマニズムの役目があっただろう。

ならば、老子の時代初期に、道家を増やしながらこのように発展し始めたのは、誰のどういったニーズによるものだったのか?を考え、 一つは、

  • 儒教武帝によって国教とされるなど、儒家が中央に取り入りエリート化していく時代にあって、非エリートの知識階級にとっての拠り所だったのではないか

(論理的裏付けよりも、理屈抜きの神秘的要素を端緒にして、儒家批判や儒家の君子像批判をしているから)

もう一つは、

  • 国家が中央集権化を推し進めるなかで、伝統的組織や産業の破壊が表層化していく時代における、地域社会を守るための拠り所だったのではないか

(文明批判、自然回帰の伝統主義的思想は、同じような時代背景に良く出てくるから)

などと回想してみた。

なお孔子老子の間で反対の思想が見えたのが、孔子が現実主義者であるのに対して、老子は理想主義者。 また、儒教は男尊女卑と言われる(論語では、512文のうち2文でそれに近い記述があるのみだが、後の儒教の広がりの中では確実にある)のに対し、老子道徳経は女性崇拝の思想が読み取れる。

でも、もうちょっと道教の知識を増やしてからまた読みたい。

論語を読みました

加地 伸行の訳注です。

Amazon CAPTCHA

初めて論語の全文を読んだ。

論語はそれこそ誰でも知っている故事から、そこらじゅうにある名言集のような形で触れる機会があるけど、全編を読むことで初めて、儒教の開祖的な存在としてよりも、孔子の人間個人のらしさに触れた気がする。 どういうことかと言うと、孔子はどうやって君子たるべき教えを説いているが、論語孔子を聖人君子として奉っているわけでは無いということだ。

それは例えば、 「真に政治を任せられるのは誰ですか?」と聞かれて、優秀な弟子の名前をあれこれ挙げるけれど、結局全員にダメ出ししてしまったり、所詮奴らはワシには全然及ばんよ、と言わんばかりだ。意外と孔子は他人へのディスりは多い。(顔淵だけは認めている。若くしての死が物故者を伝説化するケースは多々あり、それかも)

また例えば、 武城で詩を歌っているのを聞いた孔子が、「こんな田舎町で詩をやるのは鶏を割くのに牛切り包丁を使うようなものだ」、と言ったことに対して弟子の子遊が「師が礼楽を大切にしなさいと言ったではありませんか」、と言い返すところで、「おまえが正しい。先ほどのは冗談だ」のように素直に過ちを認めるやりとりがある。

これなど孔子は全くもって成人君子として書かれてはいない。

人知らずして・・・

そして大いに感じさせられたのが、孔子の言葉で何度も形を変えて出てくる表現である。 「人の己を知らざることを患(うれ)えず、人を知らざることを患う」 「位(くらい)なきことを患(うれ)えず、立つ所以を患う。己を知ること莫きを患えず、知らるべきことを為すを求む。」 さらに有名な学而第一でも「人知らずして慍らず」が出てくる。

ここで孔子は繰り返し、人に自分の能力を認めてもらえなくても怒らず恨まず、自分の足りないところを反省して励めと説いている。 何故だろうか。

個人的に、これは孔子が自分自身への戒めとしたのだと思う。 孔子は良家に生まれたわけでは無く、魯の国で一度下っ端の仕事に仕官させてもらうが、それ以外は斉の景公に取り立てられそうだったが上手くいかず、自分の能力と名声からすると望むような仕官に付けないもどかしさが必ずやあったと思う。

それでも腐らず、人々に教えを説くことを命と信じて、時には言い聞かせて、深く人の心や物事を考え知ることに励んだのだと思う。

正直、今の自分の身に置き換えて一番考えさせられたのが、これらの言葉なのだ。

僕の知人が、老子と対比して孔子はエリート・成功者のための思想で、老子は落ちこぼれのための思想だ、というような事を言っていたけど、それは違うと思った。 確かに儒教啓蒙主義進歩主義に根ざすところは確実にあると思うけれど、エリートの為の思想かな?そもそも思想って悩みとかコンプレックスを始点にしているんじゃないかな?

好きな言葉

最後に凄いなと思わされた言葉が、 「学んで思わざれば則(すなわ)ち罔(くら)し。思うて学ばざれば即ち殆(あやう)し」 だね。

今でこそインターネットで何でも知識がすぐに手に入る世の中になって、物知りなだけではオンリーワンになれない、それだけでは役に立たない時代にいるけれど、当時のこの時代には、物知りなだけでも随分いい地位にいられたはずだ。 そんな時代にあって、知識だけで思想の無い学が意味の無いものだと、気づいて警鐘を鳴らすことが出来た感性に恐れ入る。

そして近年は、自分の思い込みだけで書かれた、時流に乗るだけのインスタントな啓蒙本がなんと多いことよ!

ということで終わり。次は老子を書きます。

EigenのOne Definition Rule違反

Eigenライブラリの利用法に関するバグで、丸二日間くらいはまった。 正しい原因にたどり着くのが難しいため、備忘録として残しておく。

Eigenは数値演算の高速かつ使いやすいライブラリで、かつtemplateを使ったヘッダファイルだけで構成されているため、あらゆる環境でビルドしやすく重宝されている。 最適化演算ライブラリのCeres, OpenCVなどでも使われている。

ところが、その有用性が徒となるケースがあった。

Eigenのようなヘッダファイルを使ったアプリケーションが実行時にクラッシュなどで落ちて原因が分からない場合は、今回のケースを疑ってみて欲しい。

エラー内容

今回遭遇したバグは、コンパイル・リンクは問題無いが、Ceres solverの最適化実行時にアプリがクラッシュ。 障害モジュールの名前:StackHash_**** 例外コード:c0000374 と出る(Windows) さらに、Linuxでビルドしたものも同じようにCeres solver実行時に落ちた。 最終的に解決したのだが、これは予想外の原因で落ちていたことが分かった。

原因

まず、C++にはOne Definition Ruleというものがあり、関数でも何でも同じ名前では定義(実装)は一つしか取れない。

One Definition Rule - Wikipedia

Eigenはヘッダファイルのみで構成されるおり、Eigenを使っているプログラム間で同じ定義が出来てしまう可能性がある。例えばEigenを使っているCeres solverのライブラリを使い、さらに自分で作った本体でもEigenを使っていると、コンパイルはライブラリと本体で独立に行っているため、同じ関数に二つの定義が出来てしまうことになる。 リンカエラーになるケースは良いが、今回はそうならなかったケースだ。

どういう状況で問題があるかというと、

  1. バージョンの異なるライブラリ(今回はEigen)を複数インクルードしていて、そのバージョン間でコードが異なっている時

  2. バージョンは同じライブラリ(Eigen)を複数インクルードしていて、インクルードしたそれぞれの呼び出し間で、コンパイルに関わる環境が変わっている時

今回自分のケースは2だ。Eigenを使っているCeres solverライブラリをビルドし、Ceres solverを使っている本体側でもEigenを使っていた。

独立にビルド済みのライブラリを使っている場合は、リンク時に一つのライブラリインスタンスしかリンクしないので通常問題にならない。

同じバージョンのEigenを使えば問題無いかと思っていたら、本体側のコードでAVX命令を使っているため、本体側のみがコンパイラオプションとしてAVX有効にしていたために起こった。

実はEigenのコードは、AVXやSSEといったSIMDコンパイルオプションが設定されていると、高速な実装のためにSIMD命令を使うのだが、その際メモリアロケーションを自前で書いたものを使うようになっている。 それが、Core下のutil\Memory.hに定義されているもので、handmade_aligned_mallocという関数をインラインで定義している。 SIMDを使ったことが無い人にはチンプンカンプンかもしれないが、これはSIMD命令を使うときに良く使うテクニックで、SIMD命令に必要なメモリアラインメントを揃えるために大きめにmalloc()しておいて、アラインメントされたポインタを返すというものだ。解放する時は演算に使ったポインタではなく、ちゃんと元のmalloc()したポインタを使ってfree()しないといけない。

/* ----- Hand made implementations of aligned malloc/free and realloc ----- */

/** \internal Like malloc, but the returned pointer is guaranteed to be 16-byte aligned.
  * Fast, but wastes 16 additional bytes of memory. Does not throw any exception.
  */
inline void* handmade_aligned_malloc(std::size_t size)
{
  void *original = std::malloc(size+EIGEN_DEFAULT_ALIGN_BYTES);
  if (original == 0) return 0;
  void *aligned = reinterpret_cast<void*>((reinterpret_cast<std::size_t>(original) & ~(std::size_t(EIGEN_DEFAULT_ALIGN_BYTES-1))) + EIGEN_DEFAULT_ALIGN_BYTES);
  *(reinterpret_cast<void**>(aligned) - 1) = original;
  return aligned;
}

/** \internal Frees memory allocated with handmade_aligned_malloc */
inline void handmade_aligned_free(void *ptr)
{
  if (ptr) std::free(*(reinterpret_cast<void**>(ptr) - 1));
}

解決方法

この二つの実装の齟齬によって今回のAppCrushは引き起こされた。 解決策は以下である。

Windowsの場合、ライブラリをDLLにすることで、Exportされた関数以外は外からは見えないのでconflictが起きない。 Linuxの場合や静的ライブラリを使いたい場合は、万事ハッピーな解決策はあまり無くて、Eigenをバージョンが全く同じで、同じコンパイル環境でビルドする。 もしくは、別のバージョンを使いたければ、それぞれのEigenに異なるnamespaceを付けることだ。

以下が参考になる。

http://eigen.tuxfamily.narkive.com/fweQWUaX/eigen-and-the-one-definition-rule