C++ と libc の関係など

MonaC++ RTTI・例外対応でちょっとハマったので問題を整理。こういうぐちゃぐちゃ思考の過程をまとめるのはまだ英語では書けない。

前提

Mona には core ライブラリとして C++ の MonAPI ライブラリがある。これは libc に依存しない最下層のライブラリである。そのなかでは malloc や operator new が定義されている。


一方今回導入する libsupc++ と libgcc は libc に依存したライブラリ。例えば libsupc++ には malloc を呼び出す operator new がある。また libsupc+ 内では fputs が使われている。

問題点

Mona のアプリケーションが MonAPI と libsupc++ どちらもリンクすると new が衝突する。libsupc++ が libc を要求する。
問題は多くの OS が libc を最下層としその上に C++ ライブラリを構築しているのに対して Mona は逆になっている点。

回避策1

独自 namespace で new を定義すれば良い?調べたところ namespace で operator new を区別して定義する方法はないようだ。

回避策2

libsupc++ ビルド時に new/delete の定義を消してビルドする。手順が複雑になる。 またMonAPI の new は現状 std::bad_alloc を throw していないので整合性がとれない。

回避策3

MonAPI 内は placement new を使う。placement delete がないので無理。

回避策4

MonAPI の new/delete を潰す。libsupc++ は libc の *一部にのみ* 依存することを利用して必要な libc 関数を MonAPI 内に定義する。 MonAPI に直接 libsupc++ をリンクする。
よく調べたら libsupc++ が依存する libc 関数は fputs や sprintf と少ない。
ところがご存知のように fputs は FILE* を引数にとるので fputs をMonAPI でサポートするためには stdio 全般を移動しないといけないこれは面倒だ。

回避策5

MonAPI の new/delete を潰す。libsupc++ のコードの一部を直接書き換えて libc への依存をなくす。具体的には
vterminate.cc で

extern "C" void _logprintf(const char* format, ...);
#define fputs(x, y) _logprintf(x)

して cp-demangle.cc で

extern int _sprintf(char *s, const char *format, ...);
#define sprintf _sprintf

汚いがこれが一番シンプルかなあ。