Swift Digest
SE-0490 | Swift Evolution

Environment Constrained Shared Libraries

Proposal
SE-0490
Authors
tayloraswift
Review Manager
Alastair Houghton
Status
Returned for revision

01 何が問題だったのか

サーバ用途などで Swift で作られた大きなアプリを運用していると、「アプリ全体の中でごく一部だけが頻繁に変わる」という構成にしばしば出会います。たとえばフィルタやアルゴリズム、継続的にチューニングし続けるプラグインなどです。こうしたコンポーネントだけを差し替えてデプロイし直したい、という要求は自然です。

macOS では XCFramework によるダイナミックライブラリの配布が使えますが、Linux ではこれに相当する仕組みが SwiftPM に存在しません。そのため、ごく一部の差し替えのためだけにアプリ全体を再ビルドして再デプロイする必要があり、無駄が大きくなります。

一方で、Linux 向けに「公開ライブラリとして誰のところでも動くダイナミックライブラリ」を提供するのは現実的ではありません。Linux 上の Swift は ABI 安定ではなく、Linux 自体も実態としては多数のディストリビューションの集合で、バイナリ互換の保証がほとんどないためです。SwiftPM 側で完全に汎用的なダイナミックライブラリを扱おうとすると、この本質的な難しさにぶつかります。

そこで、利用側を「同じ組織が管理する既知の環境」に絞ったうえで、その範囲でだけ動的差し替えを可能にする仕組みが求められていました。

02 どのように解決されるのか

SwiftPM に Environment Constrained Shared Library(ECSL、環境制約付き共有ライブラリ)という新しい配布形態を導入します。これは「組織が管理する特定の環境内でのみ共有・差し替えされるダイナミックライブラリ」で、既存の .artifactbundle 形式に乗せて配布します。汎用的なダイナミックライブラリは目指さず、組織が責任を持って環境を定義・維持することを前提にしている点が特徴です。

なお本提案はレビューの結果 Returned for revision となっており、以下の内容は今後変更される可能性があります。

「環境」の考え方

ECSL における「プラットフォーム」は、組織側が自由に定義します。OS やアーキテクチャ、ディストリビューションといった粒度ではなく、たとえば「Ubuntu 24.04 で Swift 6.1.2 ランタイムが /home/ubuntu/swift にインストールされたマシン」と「同じ Ubuntu 24.04 で Swift ランタイムが /home/ubuntu/swift-runtime にあるマシン」を別の環境として扱える、という粒度です。Triple がたとえ同じでも、実行に必要な前提が違えば別の環境になります。

そのため、SwiftPM は環境の互換性チェックを行いません。どの環境向けのバンドルを使うかの判断と、ABI 互換の維持は、配布する組織側の責任です。Artifact Bundle 1個につき1つの環境向けバイナリだけを入れる、という制約もここから来ています。

ECSL の作成

ECSL は、通常の SwiftPM のライブラリプロダクトを -enable-library-evolution 付きでビルドするだけで作れます。SwiftPM 側に特別な変更は必要ありません。

成果物は実行ファイルと同様に .artifactbundle にまとめますが、次の点が異なります。

  • info.jsonschemaVersion1.2 以上にする。
  • artifact の type を新しく追加される dynamicLibrary にする。
  • variants には正確に1つだけ variant を入れ、supportedTriples フィールドは使えない。
  • 実体のライブラリに対応する .swiftinterface ファイルを同梱する。

info.json の例は次の通りです。

{
    "schemaVersion": "1.2",
    "artifacts": {
        "MyLibrary": {
            "type": "dynamicLibrary",
            "version": "1.0.0",
            "variants": [{ "path": "MyLibrary" }]
        }
    }
}

バンドルのレイアウト例は次のようになります。Linux 上では .so、macOS 上では .dylib を含めます。

example.artifactbundle
    MyLibrary
        libMyLibrary.so
        MyLibrary.swiftinterface
    info.json

スキーマ上は次のように ArtifactTypedynamicLibrary が追加されます。

public enum ArtifactType: String, RawRepresentable, Decodable {
    case executable
    case dynamicLibrary
    case staticLibrary
    case swiftSDK
}

1つの Artifact Bundle のトップレベルに複数のライブラリを置くことはできますが、各ライブラリは1環境向けの1 variant に限られます。

ECSL の利用

利用側では、実行ファイルのバイナリ依存と同様に Package.swiftbinaryTarget として ECSL を追加します。PackageDescription API には新しいフィールドは追加されません。

組織の環境定義に応じて Artifact Bundle のホスティング URL や選択ロジックは異なるため、「どの環境向けのバンドルを取得するか」を Package.swift 内で環境変数などを使って組み立てるのが想定されている使い方です。SwiftPM が誤った環境向けの ECSL のインストールを検出・防止することはありません。

ECSL のデプロイ

ECSL のデプロイには SwiftPM や Artifact Bundle の仕組みは関与しません。各マシンの所定の @rpath 上の場所に新しいバイナリをコピーするだけです。@rpath の場所自体は組織ごとの環境定義の一部で、SwiftPM の管理対象外です。組織によっては @rpath を使わず、システム全体に共通の場所にインストールする運用もあり得ます。

Future Directions(今後の見通し)

info.jsonvariants の構造が「1要素だけ」という制約付きながらリストの形のまま残されているのは、将来的に汎用的なダイナミックライブラリのサポートに拡張する余地を残すためです。Triple ベースで variant を選ぶ既存の仕組みと組み合わせて、より広い用途に発展させていく方向性が示唆されていますが、本提案のスコープには含まれず、実現を約束するものでもありません。