Xcodeでフレームワークや共有ライブラリの出力シンボルを制御する

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.expaddだけ出力されるように設定しビルドします。ビルドしたライブラリの出力シンボルを調べてみると、次のようになり、意図したようにaddだけが出力されていることが分かります。

% nm -gm nm -gm ExpSymbol.framework/Versions/A/ExpSymbol
0000000000003f4c (__TEXT,__text) external _add
                 (undefined) external dyld_stub_binder (from libSystem)

投稿者プロフィール

林 晃
林 晃macOS/iOSアプリ/SDK/ミドルウェア開発が専門の開発者
アールケー開発代表。macOS/iOSアプリ/SDK/ミドルウェア開発が専門の開発者。ObjC/Swift/C++使い。豊富な開発実務経験を基に、教育コンテンツ開発、技術書執筆、技術指導、技術セミナー講師、企業内研修講師、行政・自治体職員研修講師も行います。

基礎から学ぶMetal


「基礎から学ぶMetal」を執筆しました。本書はMetalを使ってGPUプログラミングを行うための最初のステップを解説するMetalの解説書です。

私が初めてGPUプログラミングを行ったとき、どこから手をつけて、学んでいけば良いのか分からず呆然としました。もし、あのとき、これを教えてくれればという部分を解説しました。本書で解説している部分はMetalの基礎となる部分で、Metalを使うときに必ず触れることになる部分です。

詳細

基礎から学ぶSwiftUI


「基礎から学ぶ SwiftUI」というタイトルの本を執筆しました。

SwiftUIの入門書です。

SwiftUIのコンセプトは「ユーザーインターフェイスを作るための最短パスを提供する」「一度学べば(Appleのプラットフォームの)どこにでも適用できる」です。

SwiftUIの概要から始まって、一つ一つのテクノロジートピックに注目しながらSwiftUIとは何か?どんなことができるのか?どのようなコードを書けば良いのかなどを丸々一冊使って解説しています。

詳細

関連記事

  1. macOS Big Sur 11以降でドライバ(KEXT)の許可を取り…

  2. 【2020/2/10更新】UIWebViewは廃止

  3. WKWebViewでBasic認証を行う

  4. Combine入門 | CombineでTimer処理を行う方法

  5. Notarization Service の条件の緩和終了

  6. コマンドライン引数でモックに差し替える

最近の著書

  1. 基礎から学ぶ SwiftUI

最近の記事