xccache

< Knowledge Base

Under the Hood: Macro as Binary

This technique was inspired by the approach mentioned in this blog post.

Consider the following usage where #hexColor is the macro and Wizard is its module.

import Wizard

let color = #hexColor(0xff0000)

Such a macro consists of two targets:

.target(Wizard) -> .macro(WizardImpl)

Here, we need prebuilt artifacts of both Wizard and WizardImpl.

Building Wizard is just like building any other regular target. Building Wizard is just like building any other regular target. Meanwhile, obtaining the tool binary from WizardImpl is a bit tricky. Building WizardImpl itself does not produce the tool binary, only the .o files. And combining them into the tool binary is not straightforward given many intermediate dependencies in swift-syntax. Luckily Meanwhile, obtaining the tool binary from WizardImpl is a bit tricky. Building WizardImpl itself does not produce the tool binary, only the .o files. And combining them into the tool binary is not straightforward given many intermediate dependencies in swift-syntax. Luckily, building Wizard, the associated interfaces target, does produce the tool binary at .build/arm64-apple-macosx/debug/WizardImpl-tool.

After having the tool binary, macro expansion can be done simply by specifying the Swift flags as follows: -load-plugin-executable path/to/WizardImpl#WizardImpl.