Eigen(C++の線形代数ライブラリ)を用いた実装を共有ライブラリとしてビルドし、それをリンクして実行ファイルをビルドしようとしたところ、以下の参照エラーが起きてしまいました。
undefined reference to `Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >::determinant() const
Eigen::MatrixBase::determinant()への参照が未定義だそうです。
結論
“Eigen/Core”だけでなく他のヘッダファイルもincludeする必要があり、determinantの導出に関しては“Eigen/LU”をincludeする必要がありました。
#include <Eigen/Core> #include <Eigen/LU> // Coreだけでは上記の参照エラーが起こる
公式のドキュメントにも書いてありますね。ちゃんと読みましょう…。
事の顛末
ただ単にヘッダファイルをincludeし忘れているだけのように思えますが、「共有ライブラリのビルド時にエラーが出ないのに、実行ファイルのビルド時に参照エラーが出る」という問題が起こっています。
行列やベクトルとしてふるまうクラスはすべてEigen::MatrixBaseを基底クラスとしており、これはEigen/src/Core/MatrixBase.hに宣言・実装されています。今回問題となった行列式を求めるメンバ関数、Eigen::MatrixBase::determinant()はここに宣言されています。
さて、Eigen3.3におけるEigen/src/Core/MatrixBase.hは以下の通りです。
344行目にdeterminant()の宣言があります。
この少し上の行に“LU module”とコメントされているのが分かります。
どうやらこれは、ここに宣言されているメンバ関数の実装は“Eigen/LU”に存在するということを示しているようです。
実際、determinant()は“Eigen/src/LU”下に実装されていました。
少し下の行を見ると、同様に“Cholesky module”や“QR module”とコメントされているのが分かります。これらの区間に宣言されているメンバ関数も、それぞれ“Eigen/Cholesky”、”Eigen/QR“に実装されていました。
このような実装になっているため、“Eigen/Core”をincludeしただけでは、Matrixクラスの一部のメンバ関数が参照できないという事態が起こるようです。共有ライブラリのビルド時にエラーが出なかったのは、これらのメンバ関数の“宣言”は“Eigen/Core”内で問題なく行われていたからでした。
実行ファイルサイズを抑えるための工夫でしょうけど、header-onlyなライブラリにおいてはこれが一般的なんでしょうか?