Xcodeのデフォルト設定では、フレームワークや共有ライブラリで実装した関数や定数のシンボルがすべて出力されます。この記事ではすべてのシンボルが出力されてしまうことで起きる問題や制御方法について解説します。
シンボルがすべて出力されることで起きる問題
フレームワークや共有ライブラリのシンボルがすべて出力されてしまうと、次のような問題が起きます。
- 内部専用関数、特に一般的な名称の関数が出力されてしまうと、ライブラリ利用側のプログラム内で定義する関数と衝突する可能性が高くなる。
- 動的にロードされる複数のライブラリで同じ名前のグローバルシンボルがいると実行時に衝突し、どの関数が使われるか不定状態になる。
- 外部から使われることを想定していない関数が直接使われることで、設計や実装の変更に弱くなる。意図しない使われ方をする可能性がある。
大規模なプログラム内で使われるときには特にシンボル名の衝突は起きやすくなります。
出力されているシンボルの調べ方
ライブラリが出力しているシンボルを調べるには、nm
を次のようにします。
nm -gm path-to-binary
例えば、次のようなCの関数を持ったフレームワークがあるとします。
/* ExpSymbol.c */ #include "ExpSymbol.h" int private_add(int i, int j) { return i + j; } int add(int i, int j) { return private_add(i, j); }
/* ExpSymbol.h */ #ifndef EXP_SYMBOL_H #define EXP_SYMBOL_H #ifdef __cplusplus extern "C" { #endif extern int add(int i, int j); #ifdef __cplusplus } #endif #endif /* EXP_SYMBOL_H */
このフレームワークの出力シンボルを調べてみると、次のようになります。
% nm -gm nm -gm ExpSymbol.framework/Versions/A/ExpSymbol 0000000000003fa8 (__TEXT,__const) external _ExpSymbolVersionNumber 0000000000003f78 (__TEXT,__const) external _ExpSymbolVersionString 0000000000003f4c (__TEXT,__text) external _add 0000000000003f2c (__TEXT,__text) external _private_add (undefined) external dyld_stub_binder (from libSystem)
この例では4つのシンボルが出力されています。ExpSymbol.c
で実装した2つの関数も出力されています。しかし、公開したいAPIはExpSymbo.h
で宣言しているadd
だけの想定でした。add
が使っているprivate_add
はプライベート関数の位置づけで出力しない想定です。
このように、デフォルト設定では実装した関数のシンボルがすべて出力されてしまいます。
出力シンボルファイルを使う
Xcodeで出力されるシンボルを制御するには、出力シンボルファイルを使います。
出力シンボルファイルの作成方法
出力シンボルファイルを作成するには次のように操作します。
(1) 「File」メニューの「New」から「File…」を選択します。
(2) 「Exports File」を選択して、「Next」ボタンをクリックします。
(3) ファイル名はライブラリ名など分かりやすいものを設定します。ここでは「ExpSymbol」としました。「Targets」はすべてチェックオフです。
出力シンボルファイルの設定
出力シンボルファイルは、次のようにフレームワークやライブラリのターゲットのビルド設定の「Linking」の「Exported Symbols File」に設定します。
出力するシンボルを定義する
出力シンボルファイルは、1行に1シンボルで出力するシンボルを列挙します。#
以降は行末までコメントとして扱われます。
例えば、この例ではadd
だけ出力したいので次のようになります。
# ExpSymbol.exp # ExpSymbolTest # # Created by Akira Hayashi on 2021/04/19. # _add
シンボルをどのように書いたら良いか分からないときは、「Exported Symbols File」の設定をクリアして、すべてのシンボルを出力し、nm
でどのように出力されているか調べると分かります。
検証
ExpSymbol.exp
でadd
だけ出力されるように設定しビルドします。ビルドしたライブラリの出力シンボルを調べてみると、次のようになり、意図したようにadd
だけが出力されていることが分かります。
% nm -gm nm -gm ExpSymbol.framework/Versions/A/ExpSymbol 0000000000003f4c (__TEXT,__text) external _add (undefined) external dyld_stub_binder (from libSystem)