![見出し画像](https://assets.st-note.com/production/uploads/images/135107403/rectangle_large_type_2_9141fb84326f2e99b499217c2ebe49e9.png?width=1200)
Swift MacroをMintでキャッシュ Now in REALITY Tech #105
先日、オフィスのキッチンでホットケーキを焼いて定例をしたiOSチームのあおやまです。
![](https://assets.st-note.com/img/1711380976099-70ls2EOWHj.jpg?width=1200)
REALITYのiOSアプリではSwift Macroを導入した際に、ビルド時間が伸びる問題が発生しました。
そこで、Swift Packge製ツールの管理ツールのMintでキャッシュし、ビルド時間を改善しました。
Swift Macro導入の背景
Xcode 15からデバッグコンソールが強化され、Loggerを使ったログのファイル、行、モジュールなどが表示されるようになりした。
REALITYではログ関数を展開して、Loggerでコンソールに出力するコードとFirebaseへ送信するコードに展開するSwift Macroを作成しました。
Swift Macroとビルド時間
Swift Macroのおかげでログを簡潔に記述できるようになりましたが、ビルド時間が伸びる問題が発生しました。
Build Timelineを見ると、クリーンビルド時にSwift Syntaxのビルドが約20秒かかっています。
![](https://assets.st-note.com/img/1711416044758-lvN91284cp.png?width=1200)
この問題に頭を悩ませていたところ、こちらの記事を見つけ、Swift Macroを定義したexecutableTargetをプレビルドすることで、ビルド時間を削減できることを知り、REALITYでもチャレンジしました。
Swift MacroをexecutableTargetでプレビルド
executableTargetの作成は、先ほどのブログを大変参考にさせて頂きました。
このnoteではREALITYに導入する上で工夫した2点をメインにご紹介します。
Swift MacroをMintでキャッシュ
REALITYのiOSアプリでは、CocoaPodsを卒業し、ツールはMint、ライブラリはSwift Package Managerで管理しています。
Mintで管理するためにSwift MacroをexecutableTargetとして公開します。
Mintはlocal packageに対応していないので、swift-macro-pluginのリポジトリを新しく作成し、executableTargetのLoggerMacroPluginをターゲットに追加します。
// Package.swift
let package = Package(
name: "swift-macro-plugin",
products: [
.executable(
name: "LoggerMacroPlugin",
targets: ["LoggerMacroPlugin"]
)
],
dependencies: [
.package(url: "https://github.com/apple/swift-syntax.git", from: "509.0.0"),
],
targets: [
.executableTarget(
name: "LoggerMacroPlugin",
dependencies: [
.product(name: "SwiftSyntaxMacros", package: "swift-syntax"),
.product(name: "SwiftCompilerPlugin", package: "swift-syntax"),
]
)
]
)
LoggerMacroPluginにCompilerPluginを継承したLoggerMacroPluginを作成し、DebugLoggerMacroなどを公開します。
// LoggerMacroPlugin.swift
@main
struct LoggerMacroPlugin: CompilerPlugin {
let providingMacros: [Macro.Type] = [
DebugLoggerMacro.self, // ...
]
}
struct DebugLoggerMacro: ExpressionMacro {
static func expansion(
of node: some FreestandingMacroExpansionSyntax,
in context: some MacroExpansionContext
) -> ExprSyntax {
// ...
}
}
swift-macro-pluginのリポジトリをMintfileに追加します。
(内製ツールのrelease versionを切る運用をしていないので、コミットハッシュを指定しています。)
// Mintfile
yonaskolb/xcodegen@2.39.1
...
git@github.com:reality-inc/swift-macro-plugin.git@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Mintを利用してビルドします。
このビルドしたLoggerMacroPluginを後述するOTHER_SWIFT_FLAGSの設定で取り込みます。
$ mint bootstrap
XcodeGenの設定
REALITYのiOSアプリではXcodeGenでxcprojectを作成しています。
また、機能ごとにモジュールを分割しています。
-load-plugin-executableの設定は、マクロを展開する全てのモジュールで設定される必要があるようです。
ログのSwift Macroはその特性上、どのモジュールからも呼び出される可能性があります。
そこで、projectのOTHER_SWIFT_FLAGSに-load-plugin-executableを設定しました。
# project.yml
settings:
OTHER_SWIFT_FLAGS: -load-plugin-executable $(SRCROOT)/.mint/bin/LoggerMacroPlugin#LoggerMacroPlugin
これで、RealityLoggerモジュールに定義されたmacro定義が解決されるようになりました。
public macro logDebug(
_ message: String,
category: LogCategory = .default
) -> Void = #externalMacro(module: "LoggerMacroPlugin", type: "DebugLoggerMacro")
結果
これらの対応の結果、Build Timelineを見ると、Swift Syntaxのビルドが無くなり、ビルド時間が短縮されました。
![](https://assets.st-note.com/img/1711416094108-KxeOiEVcQf.png?width=1200)
まとめ
REALITYのiOSアプリではSwift Macroを導入した際に、ビルド時間が伸びる問題が発生しました。
そこで、Swift MacroのexecutableTargetを作成し、Swift Package製ツールの管理ツールのMintでプレビルドしました。
その対応の結果、Swift Syntaxのビルドが無くなり、ビルド時間が短縮されました。