[SwiftPM][Realm] Swift Package の Package.swift の記述方法 Realm に依存するケース

SwiftPackageManagerEyeCatch

Realm でモデル定義したライブラリを作ろうとしたのですが、意外と Package.swift でハマったので、説明します。

Package.swift

Realm を下位ライブラリとして使用するライブラリを、Swift Package として作成したいときの Package.swift を説明します。

各セクションにわけて説明していきます。

package

Package という要素で、この Swift Package が提供するものを定義していきます。Apple のドキュメントは、こちら

name

name で package の名前を定義しますが、特に難しいところはありません。Apple のドキュメントは、こちら

name

name: "MoneyClipDB",

platforms

このセクションでは、対応するプラットフォームを定義します。Apple のドキュメントは、こちら

以下では、iOS と macOS を定義しました。RealmSwift 自体は、他に、tvOS と watchOS もサポートしています。

platforms

    platforms: [
        .iOS(.v13),
        .macOS(.v10_15)
    ],

products

このセクションで、この Swift Package が提供するものを定義します。.library と .executable の2種類が定義できます。Apple のドキュメントは、こちら

ここでは、ライブラリを定義したいので以下のように記述しました。

products

    products: [
        // Products define the executables and libraries a package produces, and make them visible to other packages.
        .library(
            name: "MoneyClipDB",
            targets: ["MoneyClipDB"]),
    ],

dependencies

このセクションで、依存する外部パッケージを定義します。Apple のドキュメントは、こちら

dependencies

    dependencies: [
        // Dependencies declare other packages that this package depends on.
        // .package(url: /* package url */, from: "1.0.0"),
        .package(name: "Realm", url: "https://github.com/realm/realm-cocoa", from: Version("5.0.0")),
    ],

気をつける点として、realm-cocoa で外部に提示されるパッケージ名は、"Realm" です。realm-cocoa 側にある Package.swift で確認できます。

# name が与えられない時は、url の git リポジトリ名が採用されます。

targets

このセクションでは、このパッケージを構成するモジュールとテストを定義します。Apple のドキュメントは、こちら

Realm に依存するパッケージを作ろうとして、このセクションではまりました。

ポイントは、Realm のパッケージからは、複数のプロダクトが提供されているため、それら複数のプロダクトに依存するように定義しないと、ビルドがエラーになります。

targets

    targets: [
        // Targets are the basic building blocks of a package. A target can define a module or a test suite.
        // Targets can depend on other targets in this package, and on products in packages this package depends on.
        .target(
            name: "MoneyClipDB",
            dependencies: [
                .product(name: "Realm", package: "Realm"),      // (1)
                .product(name: "RealmSwift", package: "Realm")  // (2)
            ]),
        .testTarget(
            name: "MoneyClipDBTests",
            dependencies: ["MoneyClipDB"]),
    ]
)

(1), (2) の行がポイントです。特に、(2) の Package "Realm" 内で定義されている Product "RealmSwift" を記述しないと RealmSwift が見つからずコンパイルエラーが発生します。

Package.swift 全体

参考までに、Package.swift 全体も載せておきます。

Package.swift

// swift-tools-version:5.3
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "MoneyClipDB",
    platforms: [
        .iOS(.v13),
        .macOS(.v10_15)
    ],
    products: [
        // Products define the executables and libraries a package produces, and make them visible to other packages.
        .library(
            name: "MoneyClipDB",
            targets: ["MoneyClipDB"]),
    ],
    dependencies: [
        // Dependencies declare other packages that this package depends on.
        // .package(url: /* package url */, from: "1.0.0"),
        .package(name: "Realm", url: "https://github.com/realm/realm-cocoa", from: Version("5.0.0")),
    ],
    targets: [
        // Targets are the basic building blocks of a package. A target can define a module or a test suite.
        // Targets can depend on other targets in this package, and on products in packages this package depends on.
        .target(
            name: "MoneyClipDB",
            dependencies: [
                .product(name: "Realm", package: "Realm"),
                .product(name: "RealmSwift", package: "Realm")
            ]),
        .testTarget(
            name: "MoneyClipDBTests",
            dependencies: ["MoneyClipDB"]),
    ]
)

まとめ:Package.swift を記述するときの落とし穴

Package は、複数の Product を外部に提供することができますが、Package に依存すると定義しても、その Package に含まれる全ての Product に依存したことにはなりません。

つまり、denpendencies では、Package が依存する "Package" を定義できるのですが、それが全てのターゲットがその Package に依存していることを定義していることにはなりません。

target の dependencies では、targetが依存する target を定義できますが、依存する Product を書くこともできます。
Apple のドキュメントは、こちら

ということで、一般化すると以下になります。

Package.swift 落とし穴
Target の依存関係は、以下の2段階で定義する必要がある。

  • dependencies のセクションで、依存する外部 Package を定義する
  • target の dependencies のセクションで、依存する Product を定義する

分かってしまえば、非常に理にかなった定義方法ですが、わかるまで時間かかりました。

説明は以上です。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です