"The manifest is Swift, but read it like a contract: what exists, for which platforms, built from what."
Why the Family Builds Mac Apps From a Manifest
Every Mac app in this family is a Swift package — no .xcodeproj anywhere on the desktop side. Package.swift is short, diffs cleanly, reviews like code, and builds the same way from a terminal, a script or a coding agent: swift build -c release --product Spark. The price is that the bundle, signing and install steps become your script's job, which is Track 6. For iOS and watch apps the family uses XcodeGen instead, because app targets need things a package cannot express — you will meet that in lesson four.
The Parts of a Manifest
- The first line is load-bearing.
// swift-tools-version: 6.2selects which manifest API is available. It is a comment the tool parses; get it wrong and newer settings do not exist. platformssets deployment targets: the oldest macOS, iOS and watchOS the package promises to run on.productsare what the outside world can depend on:.libraryfor code other packages import,.executablefor a runnable tool or app binary.targetsare the modules:.targetfor Swift or C code,.executableTargetfor a program,.testTargetfor tests. Each lives inSources/<Name>orTests/<Name>unless you give a path.dependenciesname other packages by URL and version, or by localpath.swiftSettings/linkerSettingsper target: language mode exceptions, upcoming features, linked system libraries and frameworks.swiftLanguageModes: [.v6]at the end sets the package default.swift package initwith the 6.3 toolchain already writes it.
The Module Split That Pays Off
Family Mac apps split into a pure core module with no AppKit import, the app module that composes AppKit and the core, and sometimes a module of shared kit code. The core builds and tests fast on any Mac, including one with only the Command Line Tools; the app module is thin. When the same app later grows an iPhone client, the core is already the thing the phone links.
Two Facts That Bite
A path dependency's identity is its directory name. When the family moved its shared package from a folder named swift/ to CwkKit/, every consumer that asked for package: "CwkKit" had failed until then with "unknown package 'CwkKit'; valid packages are: 'swift'". And after that rename, the package's own .build cache still remembered the old absolute path and failed with a bare error: fatalError — cleared by rm -rf .build. Read past fatalError; it is SwiftPM's wrapper and says nothing on its own.