Swift Digest
Blog | Swift.org Blog

ABI 安定性とその先へ

ABI Stability and More

このダイジェストはClaude Opus 4.7 / 4.8によって生成されたものです(License)。原文はこちら

この記事の要点

背景: バイナリ互換性という目標

Swift の ABI を安定化させることは長年の目標でした。安定した ABI は言語が成熟した証ですが、Swift エコシステムにとっての最終的な利点は、アプリとライブラリの バイナリ互換性 を実現できることにあります。この記事は、Swift 5 におけるバイナリ互換性が何を意味し、今後のリリースでどう発展していくのかを整理したものです。

ABI 安定性は、コンパイル・実行する OS ごとに実装されます。Swift 5 時点で安定と宣言されているのは Apple プラットフォームのみで、Linux や Windows など他プラットフォームについては、それらの上での Swift の開発が成熟するのに合わせて Swift Core Team が安定化を検討するとされていました。

バイナリ互換性に関わる要素は、整理すると次の 3 つに分けられます。それぞれ「いつ」「何を」変えられるようにするかが異なります。

ABI 安定性: 標準ライブラリを差し替えられる

ABI 安定性は 実行時 における Swift バージョンの混在を可能にします。Swift 5.0 でビルドしたアプリは、Swift 5 標準ライブラリが入っているシステムであれば、それが(仮の)Swift 5.1 や Swift 6 のものであっても動作します。

これは前述のとおり、Apple OS 向けアプリが標準ライブラリや overlay ライブラリを同梱しなくてよくなることを意味します。App Store に提出するアプリへの影響については、当時の Xcode 10.2 リリースノートに詳細があります。

モジュール安定性: コンパイラのバージョンをまたげる

ABI 安定性が実行時の話だったのに対し、モジュール安定性は コンパイル時 の話です。

Swift はライブラリ(たとえばフレームワーク “MagicKit”)のインターフェースを表すのに、手書きのヘッダファイルではなく “swiftmodule” という不透明なアーカイブ形式を使います。しかしこの “swiftmodule” 形式は現在のコンパイラのバージョンに結び付いているため、MagicKit が別バージョンの Swift でビルドされていると import MagicKit できません。つまりアプリ開発者とライブラリ作者が同じバージョンのコンパイラを使う必要がありました。

この制約を取り除くのがモジュール安定性です。不透明な形式に、Xcode の “Generated Interface” ビューで見られるようなモジュールのテキスト要約を付け加えることで、クライアントはどのコンパイラでビルドされたかを気にせずモジュールを使えるようになります。これにより、たとえば Swift 6 でビルドしたフレームワークのインターフェースを、Swift 6 と将来の Swift 7 コンパイラの両方から読めるようになります。

library evolution: ライブラリの API を更新できる

ここまではコンパイラを変えてもコードはそのまま、という話でした。では、アプリが使っているライブラリ自体が変わったらどうなるでしょうか。

現状では Swift ライブラリが変わると、それを使うアプリはすべて再コンパイルが必要です。これには利点もあります。コンパイラはアプリが使うライブラリの正確なバージョンを把握できるため、コードサイズを減らし実行を速くする追加の仮定を置けるのです。しかしその仮定は、次のバージョンのライブラリでは成り立たないかもしれません。

library evolution サポート は、クライアントを再コンパイルせずにライブラリの新バージョンを出荷できるようにする機能です。これは Apple が OS のライブラリを更新する場面で起きますが、ある会社のバイナリフレームワークが別の会社のバイナリフレームワークに依存する場合にも重要です。後者を更新しても、前者を再コンパイルせずに済むのが理想だからです。

たとえば、アプリが当初のバージョン(記事中の図では黄色)のフレームワークに対してビルドされていても、library evolution サポートがあれば、黄色版だけでなく、より新しく改良された版(赤)が入ったシステムでも動作します。

Swift にはすでに library evolution サポートの実装があり、非公式に resilient(resilience) と呼ばれています。これは必要なライブラリだけが選んで使えるオプトイン機能で、性能と将来の柔軟性のバランスを取るための(当時まだ確定していない)アノテーションを使います。その様子は標準ライブラリのソースコードで見られます。これらのうち最初に Swift Evolution Process を通ったのが、Swift 4.2 で追加された @inlinable(SE-0193) です。library evolution サポートに関する Proposal は今後も登場するとされていました。

まとめ

Swift 5 のバイナリ互換性は、次の 3 つの軸で整理できます。

Swift が備えると… …変えられるのは 状況(記事公開時点)
ABI 安定性 Swift 標準ライブラリ macOS / iOS / watchOS / tvOS で Swift 5 から
モジュール安定性(と ABI 安定性) コンパイラ 活発に開発中
library evolution サポート 自分のライブラリの API ほぼ実装済みだが Swift Evolution Process を通す必要あり

ABI 安定性によって Apple プラットフォームでのバイナリ互換性の土台が整い、モジュール安定性と library evolution サポートが加わることで、コンパイラ・ライブラリの両方をバージョンをまたいで安心して差し替えられる世界に近づいていく、という見取り図が示されています。

関連リンク