はじめに
今回は, SwiftGen
を Swift Package Manager (以下 SwiftPM ) を使って導入する方法です.
SwiftGen
を使用することはたびたびあるかと思います.
今までは私は R.swift
でしたが最近は差分ビルドのこととかを考えてこっちに移行しました.
また,
xcassets: inputs: - App/Assets.xcassets outputs: templateName: swift5 output: Generated/Assets.swift
のような swiftgen.yml
を作るかと思います.
SwiftPM で導入した場合のエラーの解決も紹介します.
あと, SwiftGen の Package.swift
が swift-tools-version: 5.3
になったら Swift Package Manager ( PackageDescription
) の Target
に resources: [Resource]?
が追加されるので簡単に対応できるようになるのではないかと思います.
環境
SwiftGen を CLI として使用する
Mint
先に書くと,当環境では Mint で SwiftGen をビルドすることはできません!
$ mint install SwiftGen/SwiftGen@6.4.0 --verbose
ビルドログ (クリックして開きます)
🌱 Cloning SwiftGen 6.4.0 Cloning into 'github.com_SwiftGen_SwiftGen'... remote: Enumerating objects: 1059, done. remote: Counting objects: 100% (1059/1059), done. remote: Compressing objects: 100% (835/835), done. remote: Total 1059 (delta 318), reused 486 (delta 164), pack-reused 0 Receiving objects: 100% (1059/1059), 11.15 MiB | 3.26 MiB/s, done. Resolving deltas: 100% (318/318), done. Note: switching to '0c67b63f43814a8d7eb71f685f0bf504b03223f3'. You are in 'detached HEAD' state. You can look around, make experimental changes and commit them, and you can discard any commits you make in this state without impacting any branches by switching back to a branch. If you want to create a new branch to retain commits you create, you may do so (now or later) by using -c with the switch command. Example: git switch -c <new-branch-name> Or undo this operation with: git switch - Turn off this advice by setting config variable advice.detachedHead to false 🌱 Resolving package /private/var/folders/fq/nvfqtqj11nl06cfd24z_yd240000gn/T/mint/github.com_SwiftGen_SwiftGen: error: manifest parse error(s): <unknown>:0: error: invalid Darwin version number: macos11.3 <unknown>:0: error: invalid version number in '--target=x86_64-apple-macos11.3' <unknown>:0: error: failed to load module 'Combine' <unknown>:0: error: invalid Darwin version number: macos11.3 <unknown>:0: error: invalid version number in '--target=x86_64-apple-macos11.3' /private/var/folders/fq/nvfqtqj11nl06cfd24z_yd240000gn/T/mint/github.com_SwiftGen_SwiftGen/Package.swift:2:8: error: failed to load module 'PackageDescription' import PackageDescription ^ 🌱 Encountered error during "swift package resolve" 🌱 Failed to resolve SwiftGen 6.4.0 with SPM
ここらへんなんでビルドできないかは詳しい人に任せた!
Package.swift
となると Package.swift
でやるっていうことになりますね.
Xcode のプロジェクトに追加できる SwiftPM は CLI をビルドしていい感じしてくれる仕組みはありませんから.
じゃあとりあえず書いてみるか.
SwiftGen のみを CLI ツールとして管理している場合
シンプルに Package.swift
に
// swift-tools-version:5.3 import PackageDescription let package = Package( name: "Tools", platforms: [ .macOS(.v11) ], dependencies: [ .package( url: "https://github.com/SwiftGen/SwiftGen.git", .upToNextMajor(from: "6.4.0") ) ], targets: [ .target(name: "Tools", path: "") ] )
のようにしてあげれば上手くいくはず!
$ swift build -c release --product swiftgen
としてあげてビルドしてあげれば ./.build/release/swiftgen
にバイナリがビルドされます.
他の CLI ツールも一緒に使う場合
ちなみにここでは XcodeGen を一緒に使っていると想定しますね.
// swift-tools-version:5.3 import PackageDescription let package = Package( name: "Tools", platforms: [ .macOS(.v11) ], dependencies: [ .package( url: "https://github.com/yonaskolb/XcodeGen.git", .upToNextMajor(from: "2.24.0") ), .package( url: "https://github.com/SwiftGen/SwiftGen.git", .upToNextMajor(from: "6.4.0") ) ], targets: [ .target(name: "Tools", path: "") ] )
こんな感じを想定します.
Fetching https://github.com/SwiftGen/SwiftGen.git from cache Fetching https://github.com/yonaskolb/XcodeGen.git from cache Fetching https://github.com/tid-kijyun/Kanna.git from cache Fetching https://github.com/jpsim/Yams.git from cache Fetching https://github.com/SwiftGen/StencilSwiftKit.git from cache Fetching https://github.com/kylef/Stencil.git from cache Fetching https://github.com/kylef/PathKit.git from cache Fetching https://github.com/kylef/Commander.git from cache error: Dependencies could not be resolved because root depends on 'XcodeGen' 2.24.0..<3.0.0 and root depends on 'SwiftGen' 6.4.0..<7.0.0. 'SwiftGen' is incompatible with 'XcodeGen' because 'SwiftGen' depends on 'PathKit' 0.9.0..<1.0.0 and 'XcodeGen' >= 2.6.0 depends on 'PathKit' 1.0.0..<2.0.0. 'Tools' /path/to/App: warning: found 1 file(s) which are unhandled; explicitly declare them as resources or exclude from the target /path/to/App/App/Info.plist 'Tools' /path/to/App: error: manifest property 'defaultLocalization' not set; it is required in the presence of localized resources
依存関係の解決に失敗します.
はい.ということでどうしようかなって考えてたら,
SwiftFormat がいい感じな解説 *1 を README.md に書いてくれていました.
./Tools/ToolsSwiftGen/Package.swift
を作成して以下のようにしました.
// swift-tools-version:5.3 import PackageDescription let package = Package( name: "ToolsSwiftGen", platforms: [ .macOS(.v11) ], dependencies: [ .package( url: "https://github.com/SwiftGen/SwiftGen.git", .upToNextMajor(from: "6.4.0") ) ], targets: [ .target(name: "ToolsSwiftGen", path: "") ] )
パッケージ名とターゲット名を一緒にしておくと良いそうです!
App.xcodeproj
等がある場所で
Fetching https://github.com/tid-kijyun/Kanna.git from cache Fetching https://github.com/jpsim/Yams.git from cache Fetching https://github.com/kylef/Stencil.git from cache Fetching https://github.com/SwiftGen/StencilSwiftKit.git from cache Fetching https://github.com/kylef/Spectre.git from cache Fetching https://github.com/SwiftGen/SwiftGen.git from cache Fetching https://github.com/kylef/Commander.git from cache Fetching https://github.com/kylef/PathKit.git from cache Cloning https://github.com/kylef/Stencil.git Resolving https://github.com/kylef/Stencil.git at 0.13.1 Cloning https://github.com/SwiftGen/SwiftGen.git Resolving https://github.com/SwiftGen/SwiftGen.git at 6.4.0 Cloning https://github.com/SwiftGen/StencilSwiftKit.git Resolving https://github.com/SwiftGen/StencilSwiftKit.git at 2.7.2 Cloning https://github.com/kylef/PathKit.git Resolving https://github.com/kylef/PathKit.git at 0.9.2 Cloning https://github.com/tid-kijyun/Kanna.git Resolving https://github.com/tid-kijyun/Kanna.git at 5.2.7 Cloning https://github.com/kylef/Spectre.git Resolving https://github.com/kylef/Spectre.git at 0.9.2 Cloning https://github.com/jpsim/Yams.git Resolving https://github.com/jpsim/Yams.git at 4.0.6 Cloning https://github.com/kylef/Commander.git Resolving https://github.com/kylef/Commander.git at 0.9.1 'ToolsSwiftGen' /path/to/App/Tools/ToolsSwiftGen: warning: Source files for target ToolsSwiftGen should be located under /path/to/App/Tools/ToolsSwiftGen /path/to/App/Tools/ToolsSwiftGen/.build/checkouts/PathKit/Sources/PathKit.swift:98:14: warning: 'Hashable.hashValue' is deprecated as a protocol requirement; conform type 'Path' to 'Hashable' by implementing 'hash(into:)' instead public var hashValue: Int { ^ /path/to/App/Tools/ToolsSwiftGen/.build/checkouts/Stencil/Sources/Node.swift:65:9: warning: variable 'components' was never mutated; consider changing to 'let' constant var components = token.components() ~~~ ^ let /path/to/App/Tools/ToolsSwiftGen/.build/checkouts/Stencil/Sources/Template.swift:11:3: warning: 'internal(set)' modifier is redundant for an internal property internal(set) var environment: Environment ^~~~~~~~~~~~~~ /path/to/App/Tools/ToolsSwiftGen/.build/checkouts/StencilSwiftKit/Sources/StencilSwiftKit/Environment.swift:10:3: warning: 'public' modifier is redundant for instance method declared in a public extension public func registerStencilSwiftExtensions() { ^~~~~~~ [15/15] Build complete!
そうするとこちらは, ./Tools/ToolsSwiftGen/.build/release/swiftgen
にバイナリがビルドされます!
これでようやくいい感じになりました.
実際に swiftgen を実行する
$ ./Tools/ToolsSwiftGen/.build/release/swiftgen Template named swift5 not found. Use `swiftgen template list` to list available named templates or use `templatePath` to specify a template by its full path.
テンプレートが見つかりません!!
ここでようやく本題になりました.
テンプレートエラーの解決
SwiftGen
を CLI としてビルドするときに流れるログとか SwiftGen のバイナリ自体を使用するときなどに .build
が少なからず自動で作られます.
そこにリポジトリの checkouts などが保存されることを知っているのでそこに指定を当ててあげれば解決できます.
結論は templatePath
を指定することでこれが解決できます.
swiftgen.yml
を以下のように outputs
を変更します.
xcassets: inputs: - App/Assets.xcassets outputs: - templatePath: Tools/ToolsSwiftGen/.build/checkouts/SwiftGen/templates/xcassets/swift5.stencil output: Generated/Assets.swift
$ ./Tools/ToolsSwiftGen/.build/release/swiftgen File written: Generated/Assets.swift
CocoaPods
一応...
前述した通り, CocoaPods で使用する場合は本当に何も考える必要がありませんね.(要出典)
詳しくは知らないけどうまくいくっていう事実はある.
pod 'SwiftGen'
最後に
だらだら長くなりましたが,今回は SwiftGen を Swift Package Manager で導入したときにテンプレートのエラーが発生することに対するテンプレートの指定方法のご紹介でした.
結論は前章で書いたとおり, templateName
ではなく templatePath
を使って swift5.stencil
を相対パス指定するということでした.
CocoaPods をまだ剥がしきれない場合は無理して SwiftPM に移行は別にする必要はないかと思いますが, SwiftGen のために SwiftPM 移行を頑張ってるのに上手く行かないから諦めるみたいな方を救えたらと思います(私がそう)