Environment Constrained Shared Libraries
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.jsonのschemaVersionを1.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
スキーマ上は次のように ArtifactType に dynamicLibrary が追加されます。
public enum ArtifactType: String, RawRepresentable, Decodable {
case executable
case dynamicLibrary
case staticLibrary
case swiftSDK
}
1つの Artifact Bundle のトップレベルに複数のライブラリを置くことはできますが、各ライブラリは1環境向けの1 variant に限られます。
ECSL の利用
利用側では、実行ファイルのバイナリ依存と同様に Package.swift の binaryTarget として ECSL を追加します。PackageDescription API には新しいフィールドは追加されません。
組織の環境定義に応じて Artifact Bundle のホスティング URL や選択ロジックは異なるため、「どの環境向けのバンドルを取得するか」を Package.swift 内で環境変数などを使って組み立てるのが想定されている使い方です。SwiftPM が誤った環境向けの ECSL のインストールを検出・防止することはありません。
ECSL のデプロイ
ECSL のデプロイには SwiftPM や Artifact Bundle の仕組みは関与しません。各マシンの所定の @rpath 上の場所に新しいバイナリをコピーするだけです。@rpath の場所自体は組織ごとの環境定義の一部で、SwiftPM の管理対象外です。組織によっては @rpath を使わず、システム全体に共通の場所にインストールする運用もあり得ます。
Future Directions(今後の見通し)
info.json の variants の構造が「1要素だけ」という制約付きながらリストの形のまま残されているのは、将来的に汎用的なダイナミックライブラリのサポートに拡張する余地を残すためです。Triple ベースで variant を選ぶ既存の仕組みと組み合わせて、より広い用途に発展させていく方向性が示唆されていますが、本提案のスコープには含まれず、実現を約束するものでもありません。