カルボナーラ街道

計測と観察

Nuke 11.0から学ぶPackage, Product, Module

Nuke 10->11のアップデートで詰まった。そこからPackage, Product, Moduleの区別が以前と比べてつくようになったので備忘録として残す。

モチベーション

github.com

Nuke 11.0でNukeUI*1がNukeに吸収され、UIImageView などのextensionがNukeExtensionsという新規のターゲット*2に移動された。そのため、Nuke 10系から11へのアップデート時且つXcodeGenを使っている場合には project.yml を以下のように更新する必要があった。自分はシュッと対応ができなかった。

packages:
  Nuke:
    url: https://github.com/kean/Nuke
    exactVersion: 11.0.0
targets:
  App:
    dependencies:
      - package: Nuke
        product: NukeUI
      - package: Nuke
        product: NukeExtensions

なぜシュッとできなかったのか?ひとえにProductというワードを知らなかった。もとい、SwiftPMの理解が浅かった。SwiftPMの仕様、仕組みを理解していればスムーズに対応できたかもしれない。Package? Product? Module? それらの区別をつけられていなかった。今回はこの反省をバネにSwiftPMについて学んだことをNukeに当てはめて整理した。

Package

Packages
A package consists of Swift source files and a manifest file. The manifest file, called Package.swift, defines the package’s name and its contents using the PackageDescription module.
(https://www.swift.org/package-manager/)

Nuke(https://github.com/kean/Nuke 自体)はSwift source files(Sources/)とPackage.swiftから構成されるため、Packageに該当する。Packageは一つ以上のターゲットを持ち、各ターゲットは Product(後述) を指定する。 Package.swift*3を見る。

// swift-tools-version:5.6
import PackageDescription

let package = Package(
    name: "Nuke",
    platforms: [
        .iOS(.v13),
        .tvOS(.v13),
        .macOS(.v10_15),
        .watchOS(.v6)
    ],
    products: [
        .library(name: "Nuke", targets: ["Nuke"]),
        .library(name: "NukeUI", targets: ["NukeUI"]),
        .library(name: "NukeExtensions", targets: ["NukeExtensions"])
    ],
    targets: [
        .target(name: "Nuke"),
        .target(name: "NukeUI", dependencies: ["Nuke"]),
        .target(name: "NukeExtensions", dependencies: ["Nuke"])
    ]
)

Nuke PackageはNuke, NukeUI, NukeExtensionsのターゲットを持つ。 そして各ターゲットはProductを指定する。Productとは何か。

Product

Products
A target may build either a library or an executable as its product. A library contains a module that can be imported by other Swift code. An executable is a program that can be run by the operating system.

ターゲットは、そのproductとしてlibraryまたは実行可能ファイルをビルドできる。

  • library: Swiftコードによってimportされるモジュールを含む概念(おそらくSwiftのコードの集合体のことだろう)
  • 実行ファイル: OSで実行できるプログラム

Nukeのコードを見てみる。

上記のいずれにも実行可能ファイルは含まれていないので、それぞれのターゲットはlibraryとしてそれぞれNuke, NukeUI, NukeExtensionをビルドしてProductとする。

Module

importができる単位。Moduleで名前空間を指定して各コードでアクセス制御を行う。利用時にNuke, NukeUI, NukeExtensionsのそれぞれを利用箇所でimportするため、Nuke PackageはNuke, NukeUI, NukeExtensionsのModuleを持つ。

まとめ

  • Package: 1つ以上のSwiftのソースファイルと Package.swift から構成される概念
  • Product: ターゲットがlibraryまたは実行可能ファイルをビルドするもの
  • Module: importができる単位。module単位で名前空間を持つ

平たく言うとおそらく、

  • Package: SwiftPM文脈での最上位の概念。ターゲットを一つ以上持つ
  • Product: ターゲットの成果物
  • Module: importができる単位。Module単位で名前空間を持つ(もともと平たかった)

自分でPackage作ると理解深まりそうな気配を感じる。

参考