gccでビルドされたライブラリをg++から呼ぼうとするとundefined reference
またしてもC/C++で落とし穴に落ちた.
Cで書かれたライブラリをC++で普通に使っていて,普通に使えていたわけだが,
そのライブラリのあるヘッダをインクルードした瞬間にg++が
undefined reference to 'function name'
のコンパイルエラーで止まる.
gccを使えばコンパイルできるが,C++の標準ライブラリを使いたいので
ぜひともg++でコンパイルしたい.
調べてみると,どうやらCとC++の互換の微妙な部分にいきついた.
「Name Mangling,名前修飾」という機能の有無が関係しているようだ.
簡単に言うと,Cでは重複する関数名は許されないが,
C++では関数名が同じでも引数の型や数が異なれば定義できる(オーバーロード).
ではC++のコンパイラが実際どうしているかというと,
func(char) なら__func_c, func(int)なら__func_iみたいに名前を書き換えているらしい.これが名前修飾.
当然,オーバーロードを許さないCのコンパイラはこれをする必要はない.
別にやってもいいんだろうけど.
するとどうなるか.
gccでコンパイルされたオブジェクトファイルの関数名と,
g++でコンパイルされたオブジェクトファイルの関数名は,
ソースコードの上では全く同じでも,オブジェクトファイルでは異なる名前になる.
すると,それらをリンクしようとすると,関数を見つけることができずに,めでたく
undefined reference.
名前修飾の標準はないらしく,どのように名前を変えるかはコンパイラ依存らしい.
つまり異なるコンパイラで作られたオブジェクトファイルをリンクしてはいけない
という話になる.
それを解決するための方法が,
extern "C".
解決:
gccでコンパイルされたライブラリのヘッダファイルを探します.
関数宣言がずらずら並んでいるところを探します.
#ifdef __cplusplus extern "C" { #endif (見つけた関数宣言) #ifdef __cplusplus } #endif
にします.
おしまい.