Swift PackageのBuildToolPluginのハマりポイント
BuildToolPlugin
を使ってファイルを生成し、そのファイルをアプリで用いる場合、気をつけないといけないポイントがあります。
実行タイミング
まず、.prebuildCommand
を使って全体のビルド前にファイルを生成しようと考えるかも知れませんが、prebuildCommandの実行時にはPluginそのもののビルドもできていないためうまくいきません。ビルド前の時点で何かコマンドを動かしたい場合は、ビルド済みの実行ファイルをArtifact Bundleで配布しておき、それを使うようにしましょう。
成果物のパス解決
次に、BuildToolPluginで生成したファイルは、context.pluginWorkDirectory
配下のパスにしか配置できません。権限がないと言われます。そのため、リソースのBundleの解決は厄介で、ソースコード内においてBundle.module
やBundle.main
で直接パスを指定してなんとかできるかは場合によります。
大抵の場合はBundle.moduleでうまくパス解決ができないため、ローカルPackage (Package.swift)で完結することは諦め、Project > Build Phases > Run Build Tool Plug-insにPluginを登録して、リソースをBundle.mainで受け取るようにするのがいいと思います。
ローカルPackageで生成したファイルがResourcesでうまく利用できない理由は簡単で、Resourcesに指定されたリソースのBundleへのコピーの方がprebuildでファイルを生成するよりも早いタイミングで行われるからです。
とりあえず、現状のPluginはSPMによるマルチモジュール構成との相性が非常に悪いため、コードの自動生成を視野に入れている場合は、アーキテクチャ選定の際にPluginの仕様も考慮に入れるべきです。
xcodebuildコマンドでのビルド
xcodebuild -sdk iphonesimulator
のように-sdk
オプションを使うと、executableの実行ファイルが Build/Products/Hoge-iphonesimulator/
に配置されますが、PluginContext.tool(named:).path
で取得する実行ファイルのパスはBuild/Products/Hoge/
を指すため実行ファイルが見つからず実行できないようです。
回避するには、-sdk iphonesimulator
を指定するのではなく-destination "generic/platform=iOS Simulator"
を使うと良さそうです。これだとexecutableの実行ファイルはHogeに配置され見つかり、かつHoge-iphonesimulatorにアプリの成果物が出力されます。
Discussion