C
Linux
共有ライブラリ
公開制限

LinuxのC言語共有ライブラリでの、公開するAPI制限方法

共有ライブラリで公開するAPIへの悩み

私が共有ライブラリを作成する際に、ずっと悩んでいたことがあります。
libraryの規模が大きくなると、当然中をファイル分けし、ライブラリ内でAPIを定義して開発を行うと思います。

この時ずっと何か方法がないかな~と悩んでいたことがあります。

普通にやると、こうなっちゃうんですよね。
作成された共有ライブラリで利用可能なAPIの中に、ライブラリ内で定義したヘッダーAPIも含まれてしまう

公開ヘッダーは指定しますが、強引に内部で使っているヘッダーを読み込めば、そのAPIも使われてしまう。
特にgithubでライブラリ公開なんてするのに、意図しないAPIを好きに使えてしまうなんて、ちょっとダサいな~

ということで期待せずに調べてみました。

共有ライブラリで公開するAPIは制限出来る!

出来ないことなんてないんだ、そうGNUならね!
というわけで、なんとLinuxの既存機能で公開制限ができるみたい。

参考:http://0xcc.net/blog/archives/000108.html

例えばこんなライブラリ公開ヘッダーがあったとします。(以前作った時間計測ライブラリ)

timetestlog.h
void * timetestlog_init(char *delimiter, size_t maxloglen, unsigned long maxstoresize);
int timetestlog_store_printf(void * handle, const char *format, ...);
void timetestlog_exit(void * handle);

ライブラリ作成者としてはこのAPIだけを使ってほしいところ。

このライブラリを開発する際に、こんなAPIを使っていたとします。

testfile.h
int testfunction(void);

通常のコンパイル

これで普通にコンパイルすると、testfile.hをincludeしちゃえばtestfunctionが使えちゃいます。

公開されているAPIはnm -Dコマンドやobjdump -tで確認できます。
コマンド実行結果を見ると、testfunctionが入っていますね。それ以外にも余計なAPIがちらほら

Linux env$ nm -D .libs/libtimelog.so | grep " T "
0000000000000dec T _fini
00000000000007d8 T _init
0000000000000dc0 T testfunction
0000000000000d90 T timetestlog_exit
0000000000000b10 T timetestlog_init
0000000000000c90 T timetestlog_store_printf
Linux env$ objdump -t .libs/libtimelog.so | grep " g"
0000000000000dc0 g     F .text  000000000000002c              testfunction
0000000000202068 g       .data  0000000000000000              _edata
0000000000000dec g     F .fini  0000000000000000              _fini
0000000000000c90 g     F .text  00000000000000fc              timetestlog_store_printf
0000000000000b10 g     F .text  000000000000017f              timetestlog_init
0000000000202070 g       .bss   0000000000000000              _end
0000000000202068 g       .bss   0000000000000000              __bss_start
0000000000000d90 g     F .text  0000000000000022              timetestlog_exit
00000000000007d8 g     F .init  0000000000000000              _init

--version-scriptによるAPI制限

公開APIを制限するには"--version-script"を使います。このようにversion-scriptと公開APIを定義した設定ファイル(ここではlibtimelog.map)を指定します。

LDFLAGS+=-Wl,--version-script,libtimelog.map

設定ファイルにはglobalに公開したいAPIを、localにそれ以外(*)を指定します。

libtimelog.map
{
  global:
    timetestlog_init;
    timetestlog_store_printf;
    timetestlog_exit;
  local: *;
};

上記の設定ファイルを指定してビルドをしたライブラリの公開APIがこちら。
最小限のAPIだけが公開されていることがわかります。

Linux env$ nm -D .libs/libtimelog.so | grep " T "
0000000000000cb0 T timetestlog_exit
0000000000000a30 T timetestlog_init
0000000000000bb0 T timetestlog_store_printf

Linux env$ objdump -t .libs/libtimelog.so | grep " g"
0000000000000bb0 g     F .text  00000000000000fc              timetestlog_store_printf
0000000000000a30 g     F .text  000000000000017f              timetestlog_init
0000000000000cb0 g     F .text  0000000000000022              timetestlog_exit

まとめ

--version-scriptを使えば、公開APIを指定することが出来ます。
今までは公開されるAPIのことを気にして、本当は分けたいファイルを纏めたりしていましたが、
これで気兼ねなく好きなファイル構成でライブラリを作ることが出来ますね。