SwiftPM 6 は同時ビルド/テストを回避するために Package の .build ディレクトリをロックする

Swift version

swift-driver version: 1.115 Apple Swift version 6.0 (swiftlang-6.0.0.9.10 clang-1600.0.26.2)
Target: arm64-apple-macosx14.0

挙動について

SwiftPM 6 (release/6.0 以降)は、同時ビルド/テストを回避するために Package の .build ディレクトリをロックをするようです。残念ながら、このロックする挙動は一部のケースでプラグイン実行やテストの動作を止めてしまう可能性があります。 その影響を受けた場合以下のような warning が発生します。

Another instance of SwiftPM is already running using '/path/to/your/package-directory/.build', waiting until that process has finished execution...

プロセスが終了するまでロックされ続けるので、CIなどの実行で処理が完了せずにタイムアウトするようになってしまうなどの影響があります。

どのようなパッケージや実装が対象になるかというと、実行プロセスの中でさらに dump-packagebuild コマンドを実行しているケースです。厳密には try swiftCommandState.getActiveWorkspace() の箇所で起こりうるので、他のコマンドを同プロセスの中で実行していれば起きると思います。

Swift の VSCode Extension ではパッケージの依存解決をよしなにやってくれますが、従来の挙動だとユーザーがビルドしている最中にも依存解決が実行されたりしてリポジトリを破損されることが起きていたので同時にビルドが起きないようにこの対応が入ったようです。(という理解)

対応

escape-hatch として従来の挙動に戻せるコマンドオプション --ignore-lock が同時に追加されています。プロセスの中で実行している SPM コマンドに Swift 6 以上での実行かをチェックした上で --ignore-lock オプションを追加することで対処が可能です。

// swift --version などで Swift 6 以上での実行かを判断する(Regex)
if swift6Plus {
  let output = try sh("swift package dump-package --ignore-lock")
  ...
} else {
  ...
}

問題なくオプションを渡せていれば Another instance of SwiftPM is already running using '/path/to/your/package-directory/.build', but this will be ignored since --ignore-lock has been passed というwarningと共に処理がロックされずに後続に進むようになります。

参考