C++ template instanceのシンボルを隠す

Pocket

ここ数日、C++がらみで苦労しています。自分がC++を覚えたのが学生の頃、20年以上前になるので、今時のC++についていけていません。

ChaSenのライブラリをビルドしていると、基本的にABIとしてはC言語の範囲でしか定義していないのに、一部のC++シンボルがexportされてしまいます。ざっと調べてみたところ、どうやらtemplateのインスタンスを定義した場合には有無をいわさず外部参照できてしまうようです。

GCC拡張であればvisibilityの制御でこの挙動を変えられるようなので、pragmaを使ってdartsのインスタンスシンボルを隠すことはできるようになりました(参考: Visibility – GCC Wiki)。

#include <string>
#include <vector>
#include <map>
#include <iostream>
#pragma GCC visibility push(hidden)
#include <darts.h>
#pragma GCC visibility pop
extern "C" {
#include <stdlib.h>
#include <stdio.h>
#include "dartsdic.h"
#include "chalib.h"
}

typedef Darts::DoubleArrayImpl<char, unsigned char, long, unsigned long>
DoubleArrayL;

そもそもなぜこんなことをする必要があるかいうと、Debian packageのsymbolsの仕組みに引っかかるからです。C++のsymbol name mangling ruleはgccのメジャーバージョンが上がると微妙に変わることがあって、現在stable標準のgcc 5.xとunstable標準のgcc 6.xでまさにこれが影響しています。これまでビルドしていたライブラリのシンボル情報をdebian/<package-name>.symbols.<arch>という名前で保存していて、ビルド結果のバイナリーに含まれるシンボルがこのファイルと異なった場合、ビルドエラーとなるようになっています。これはABI互換性が壊れないことを保証するための仕組みです。

そもそも内部で使っているだけのC++シンボルが見えてしまっているのを回避して、この問題を根本から対応したかったのでした。

しかしまだ一部の標準ライブラリのC++ template instance symbol(std::ctype<char>とか)が残ってしまっているので、それをどうしたものかと苦慮しているところです。