🛠️

Swift PackageのBuildToolPluginのハマりポイント

2022/10/13に公開

BuildToolPluginを使ってファイルを生成し、そのファイルをアプリで用いる場合、気をつけないといけないポイントがあります。

実行タイミング

まず、.prebuildCommandを使って全体のビルド前にファイルを生成しようと考えるかも知れませんが、prebuildCommandの実行時にはPluginそのもののビルドもできていないためうまくいきません。ビルド前の時点で何かコマンドを動かしたい場合は、ビルド済みの実行ファイルをArtifact Bundleで配布しておき、それを使うようにしましょう。

成果物のパス解決

次に、BuildToolPluginで生成したファイルは、context.pluginWorkDirectory配下のパスにしか配置できません。権限がないと言われます。そのため、リソースのBundleの解決は厄介で、ソースコード内においてBundle.moduleBundle.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