Xcode 16にビルドインされたswift-formatでビルド時に静的解析する
はじめに
Xcode 16からswift-formatが同梱されるようになりました。(具体的には、Swift 6のツールチェーンの一部になりました)
本記事では、フォーマットではなく、ビルトインされたswift-formatを使った静的解析する方法を2つ説明します。というのも、ちょっとした落とし穴があったためです。
swift-formatがXcode 16から動かなくなったという方もこちらが参考になるはずです。
フォーマットの実行方法はtreastrainさんの記事が大変参考になりますので、こちらもぜひ参照ください。
swift format
コマンドを実行する
方法1: Run Scriptで以下の手順でビルド時にLintを実行できるようにします。
-
Project > Build PhaseでRun Script Phaseを追加します。
追加したPhaseをCompile Sourcesより前に移動します。 -
以下のコマンドを追加します。
swift format lint -r Sources Tests
今回の場合は、Sources
とTests
が検査したい対象のフォルダです。これまでは必要であったswift-format
へのパス解決が不要になっている点がポイントです。
- Project > Build SettingsでUser Script SandboxingをNOに設定します。
ここがちょっとした落とし穴です。YESにしていると全く検査が動作しません。エラーにはなりませんので要注意です。
なお、Xcode 15以降ではプロジェクト作成時にENABLE_USER_SCRIPT_SANDBOXING=YES
が設定されているようでした。
ただ、User Script SandboxingをYES
にしたままでLintを実行する方法はないのでしょうか?それが次の方法になります。
方法2: Xcode Build Tool Pluginを利用する
- プロジェクト内にSwift packageを追加します。
mkdir BuildTool
cd BuildTool
swift package init --type build-tool-plugin --name swift-format-plugin
-
swift_format_plugin.swift
を以下のように変更します。
import PackagePlugin
@main
struct swift_format_plugin: BuildToolPlugin {
func createBuildCommands(context: PluginContext, target: Target) async throws -> [Command] {
return []
}
}
#if canImport(XcodeProjectPlugin)
import XcodeProjectPlugin
extension swift_format_plugin: XcodeBuildToolPlugin {
func createBuildCommands(context: XcodePluginContext, target: XcodeTarget) throws -> [Command] {
let directoryURL = context.xcodeProject.directoryURL;
let configFile = directoryURL.appending(path: ".swift-format")
let sourceFiles = directoryURL.appending(path: "Sources")
let testFiles = directoryURL.appending(path: "Tests")
return [
.buildCommand(
displayName: "Run swift format(xcode)",
executable: try context.tool(named: "swift").url,
arguments: [
"format",
"lint",
"--configuration",
configFile.path(),
"-r",
sourceFiles.path(),
testFiles.path(),
],
inputFiles: [],
outputFiles: []
)
]
}
}
#endif
- Xcode project内にLocal packageとしてを追加した[1]上で、Project > Build Phases > Run Build Tool Plug-insに、build-toolsを追加します。
これでUser Script Sandboxingが有効であってもLintが動作するようになります!
-
Editing a package dependency as a local package https://developer.apple.com/documentation/xcode/editing-a-package-dependency-as-a-local-package ↩︎
Discussion