xcodebuild -resolvePackageDependenciesは、プロジェクトが参照するSwiftパッケージの依存関係を解決する。パッケージの取得とPackage.resolvedの更新だけを実行し、ビルドはしない。
$ xcodebuild -resolvePackageDependencies -project [プロジェクト名].xcodeproj -scheme [スキーム名]
Resolve Package Graph
Fetching from [リポジトリのURL] (cached)
Creating working copy of package ‘[パッケージ名]’
Checking out [バージョン] of package ‘[パッケージ名]’
Resolved source packages:
[パッケージ名]: [リポジトリのURL] @ [バージョン]
resolved source packages: [パッケージ名]
CIでは、依存関係の解決とビルドを別のステップに分けると、失敗の原因を切り分けやすい。
実行例はXcode 27.0、macOS 27.0.1のもの。
作られるファイル
プロジェクトが依存するパッケージのバージョンは、Package.resolvedに記録される。
[プロジェクト名].xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
Package.resolvedには、パッケージごとにバージョンとリビジョンが記録される。
{
"originHash" : "[ハッシュ値]",
"pins" : [
{
"identity" : "yams",
"kind" : "remoteSourceControl",
"location" : "https://github.com/jpsim/Yams",
"state" : {
"revision" : "[リビジョン]",
"version" : "6.2.2"
}
}
],
"version" : 3
}
取得したパッケージは、DerivedDataのSourcePackagesフォルダに保存される。
$ ls [DerivedDataのパス]/SourcePackages
artifacts
checkouts
repositories
workspace-state.json
-derivedDataPathを指定するときは、-schemeも指定する。-schemeがないと、エラーで終了コード64になる。
xcodebuild: error: The flag -scheme, -testProductsPath, or -xctestrun is required when specifying -derivedDataPath.
-derivedDataPathを指定しないと、~/Library/Developer/Xcode/DerivedDataに保存される。
Package.resolvedのバージョンは維持される
Package.resolvedに記録済みのバージョンが、プロジェクトの要件を満たしているときは、より新しいバージョンがあっても、記録されたバージョンのまま解決される。要件が6.0.0以上のパッケージで、Package.resolvedを6.0.0に書き換えて解決すると、6.0.0が維持された。
$ xcodebuild -resolvePackageDependencies -project [プロジェクト名].xcodeproj -scheme [スキーム名]
Checking out 6.0.0 of package ‘[パッケージ名]’
Resolved source packages:
[パッケージ名]: [リポジトリのURL] @ 6.0.0
プロジェクトの要件を6.1.0以上に変更すると、記録されたバージョンが要件を満たさなくなる。この状態で解決すると、Package.resolvedが最新のバージョンに更新された。
$ xcodebuild -resolvePackageDependencies -project [プロジェクト名].xcodeproj -scheme [スキーム名]
Updating from [リポジトリのURL]
Checking out 6.2.2 of package ‘[パッケージ名]’
Resolved source packages:
[パッケージ名]: [リポジトリのURL] @ 6.2.2
Package.resolvedの更新を禁止する
-disableAutomaticPackageResolutionを付けると、Package.resolvedに記録されたバージョン以外には解決しない。-onlyUsePackageVersionsFromResolvedFileも、xcodebuild -helpでは同じ説明である。Package.resolvedの内容が不足していたり古かったりすると、xcodebuildは終了コード74で失敗する。
Package.resolvedがない状態でbuildすると、次のエラーになる。
$ xcodebuild build -project [プロジェクト名].xcodeproj -scheme [スキーム名] -disableAutomaticPackageResolution
xcodebuild: error: Could not resolve package dependencies:
a resolved file is required when automatic dependency resolution is disabled and should be placed at [プロジェクトのパス]/[プロジェクト名].xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved. Running resolver because the following dependencies were added: ...
$ echo $?
74
プロジェクトの要件を変えて、Package.resolvedが古くなったときも、同じ終了コード74で失敗する。
xcodebuild: error: Could not resolve package dependencies:
an out-of-date resolved file was detected at [プロジェクトのパス]/[プロジェクト名].xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved, which is not allowed when automatic dependency resolution is disabled; please make sure to update the file to reflect the changes in dependencies. ...
フラグを付けないxcodebuild buildは、Package.resolvedがなくても、自動で依存関係を解決してビルドに成功する。CIでは、Package.resolvedをコミットして、-disableAutomaticPackageResolutionを付けると、リポジトリに記録されたバージョンだけでビルドできる。
パッケージの保存先を指定する
-clonedSourcePackagesDirPathは、取得したパッケージの保存先を指定する。解決とビルドで同じフォルダを指定すると、ビルドでは取得が実行されない。
$ xcodebuild -resolvePackageDependencies -project [プロジェクト名].xcodeproj -scheme [スキーム名] -clonedSourcePackagesDirPath SourcePackages
$ ls SourcePackages
artifacts
checkouts
repositories
workspace-state.json
$ xcodebuild build -project [プロジェクト名].xcodeproj -scheme [スキーム名] -derivedDataPath DerivedData -clonedSourcePackagesDirPath SourcePackages -disableAutomaticPackageResolution
** BUILD SUCCEEDED **
実行例のビルドは、-derivedDataPathが別のフォルダでも、FetchingやChecking outは出力されずに成功した。
パッケージの保存先を、DerivedDataの外のフォルダにすると、CIのキャッシュの対象にして、取得済みのパッケージを再利用できる。
取得に失敗したとき
取得先のリポジトリが存在しないと、終了コード74で失敗する。
$ xcodebuild -resolvePackageDependencies -project [プロジェクト名].xcodeproj -scheme [スキーム名]
...
xcodebuild: error: Could not resolve package dependencies:
Failed to clone repository https://github.com/[ユーザー名]/[存在しないリポジトリ]:
...
fatal: repository 'https://github.com/[ユーザー名]/[存在しないリポジトリ]/' not found
$ echo $?
74
解決とビルドを別のステップにしておくと、ネットワークやリポジトリの問題によるエラーは、解決のステップで失敗する。ビルドのステップは、コンパイルエラーなどの失敗の確認に集中できる。
CIで使う
- name: Resolve package dependencies
run: xcodebuild -resolvePackageDependencies -project [プロジェクト名].xcodeproj -scheme [スキーム名] -clonedSourcePackagesDirPath SourcePackages
- name: Build
run: xcodebuild build -project [プロジェクト名].xcodeproj -scheme [スキーム名] -clonedSourcePackagesDirPath SourcePackages -disableAutomaticPackageResolution
参考: 【Xcode】Shared schemeをGit管理してCIのxcodebuildで使う (xcscheme)
Swiftパッケージの場合
Package.swiftを持つSwiftパッケージでは、swift package resolveで依存関係の解決だけを実行できる。Package.resolvedのバージョンを維持する動作は、xcodebuildと同じである。
$ swift package resolve
Working copy of [リポジトリのURL] resolved at [バージョン]
swift package resolveは、.xcodeprojだけがあるフォルダでは、Could not find Package.swiftのエラーになる。Xcodeプロジェクトの依存関係は、xcodebuild -resolvePackageDependenciesで解決する。
参考: 【swift package】Package.swiftの依存関係の解決だけを先に実行する (resolve)
どちらの方法を選ぶか
| やりたいこと | 方法 |
|---|---|
| 依存関係の解決だけを実行する | -resolvePackageDependencies |
Package.resolvedのバージョンでビルドする | -disableAutomaticPackageResolution |
| 取得したパッケージを再利用する | -clonedSourcePackagesDirPath |
Package.resolvedをコミットしたプロジェクトでは、CIの最初のステップに-resolvePackageDependenciesを置き、ビルドには-disableAutomaticPackageResolutionを付ける。
