Creating an SPM build plugin
Posted Friday, September 8, 2023.Introduction
As seen when creating a CLI in an artifact bundle, we made a CLI and packaged it into an artifact bundle.
In this post we are going to explore using this cli in a SPM build plugin to generate code/resources for us in another target. That target will then be vended as a library with the generated content.
Package Structure
The finished file structure of this package will look like:
We are choosing to store our
input.json
in this package though that is not required
Package.swift
We will use MyCLI.artifactbundle
that we created previously as a binary target. Our Package.swift
will contain the following:
The binary target could be hosted and referenced by URL, but we are choosing to co-locate them for simplicity
Build Tool Plugin
In our build tool plugin, we will call our previously created CLI tool which will handle generating and writing content to the plugin working directory. This will create "read only" code and resources in any target that utilizes this plugin (in our case - the MyCoolLib
target).
On clean builds or if the contents of info.json
have changed, this build tool will run. Otherwise the contents generated from the previous run will be cached in DerivedData.
The arguments that we choose in .buildCommand(...)
are the arguments that our CLI requires (ie they match 1:1).
I would have thought that including only
[generatedPath, resourcesPath]
for output files would have been good enough, but it did not work unless explicitly specifying the path of each created resource (x.txt
). Hence, we load the info data just to read which txt files will be written by the cli.
MyCoolLib Target
As specified in the CLI's command code, the generated swift code is namespaced under MyCoolType
.
Lets create a file in the MyCoolLib
target named MyCoolType.swift
with the following contents:
Because of the dependency of this target to the build plugin, whenever this target is built, we will have access to the generated code. So if the info.json
had the following contents:
We would expect the following:
MyCoolType
should have 2 static membershello
andgoodbye
- Two txt files should have been written
hello.txt
with the contentsthis is a greeting message
goodbye.txt
with the contentsthis is a parting message
- the static members will read the message from the appropriate text file
Now we can do the following:
In a future post, we will explore how to use this for localization generation in an iOS application
Tagged With: