最近、Haskell FFI を C/C++ に使用しているときに、C++ インライン関数で問題が発生しました。つまり、g++ は宣言された関数を実際にはインライン化せずinline
、それらのシンボルを生成します。最終的に、インライン関数を呼び出すオブジェクト ファイルを ghci が読み込もうとすると、リンカー エラーが発生します。
Loading object (static) solveeq.o ... done
Loading object (dynamic) /usr/lib/gcc/x86_64-linux-gnu/4.6/libstdc++.so ... done
final link ... ghc: solveeq.o: unknown symbol `_ZN5Eigen8internal19throw_std_bad_allocEv'
ここで_ZN5Eigen8internal19throw_std_bad_allocEv
はinline
、ヘッダーのみの Eigen C++ ライブラリの関数が何らかの形で実際の関数として扱われ、リンカー シンボルが与えられています。solveeq.o
その関数への(間接的な)呼び出しを行う私のオブジェクトファイルです。環境はUbuntu 12.04 64bit、ghc 7.4.1です。
問題は次のとおりですextern "C"
。自分の関数の関数名の C++ 装飾を防ぐために使用できます。しかし、他の人が定義した C++ ヘッダーを変更することはできません/すべきではありません (明らかな理由により)。私の意見では、コンパイラは、このエラーを引き起こす最初の場所で、このインライン定義の関数を作成するべきではありません。理由は簡単です。問題の関数が本当にインライン化されている場合、リンカー エラーは発生しません。コンパイラが賢くなり、実際の関数を作成することを決定した場合、このようなエラーが発生します (または、他の場所で読んだように、同じ関数の複数の定義)。したがって、コンパイル/リンクの正確さはコンパイラの気分に依存します。
また、このようなリンカーの問題は、ヘッダーのみの C++ ライブラリ (移植性が魅力的) を事実上打ち負かすと思いますextern "C"
。
これは c++ の設計上の問題ですか、それとも単なる g++ の問題ですか? 私の質問は、c++ コンパイラまたは g++ がインライン関数をインライン化しないようにする方法はありますか? たとえば、このためのコマンド ライン オプションはありますか? (ライブラリコードなのでソースコードの改変は論外)
また、C++ STL がこの問題にどのように対処しているかにも興味があります。それらもヘッダーのみですか?