Macros and XCFrameworks

Alright, I created GitHub - sjavora/swift-syntax-xcframeworks. The README has usage instructions. Currently only 509.0.2 XCFrameworks are available.

I'm not claiming this is ready for any kind of deployment, by the way, but it does seem to work as expected for macros.

12 Likes

@sjavora Thanks so much for putting up that repo and making such great progress on this! I have the same use case as you with a highly modularized codebase, and building Swift-Syntax to get macro support seems untenable due to its large build time cost.

Using your repo, I'm able to successfully build and run tests when targeting MacOS with macros, so this seems incredibly promising and possibly even viable for real-world use! However, since the .xcframeworks only include the macos-arm64 architecture, trying to run the same tests on an iOS simulator emits errors for each target in the package:

"While building for iOS Simulator, no library for this platform was found in .../swift-syntax-xcframeworks/<target>/<target>.xcframework".

It seems like it might be possible to solve this by building the frameworks to support iOS as well. Would you be able to provide any info on how you created these .xcframeworks so that others like myself could help out where you've left off?

1 Like

Just integrated a package with a macro into a release build for the first time. Build times ballooned from ~1:30 to 4 minutes, and that's on a bare M1 Ultra in CI. So getting a binary solution here would help a lot.

This I don't understand, as the macros obviously only execute on the host system. Is this actually necessary or is SPM just doing something wrong here?

2 Likes

Hi, the repo contains the workflow that generates those XCFrameworks. Adding another architecture should be very easy, but I have the same question as John - what is the use case for building this on iOS? I never anticipated needing other architectures because macros are not a part of the actual final executable, but rather plugins to the compiler…

Wouldn't you expect this package to work in Swift Playgrounds? Or am I misremembering whether Swift Playgrounds supports binary targets?

Not 100% sure, but I believe Swift Playgrounds may not support macros, yet.

I interpreted @dafurman's issue as a compilation for iOS simulator in Xcode, not a playground, so there may be two issues here.

Sorry about the confusion! Yeah I was focusing just on the iOS simulator in Xcode, not playgrounds. I put up a repo to replicate the issue I'm facing here:

This mimics a real-world setup I have, where I'm using a package to modularize my app.

I have an iOS feature that's dependent on my macros, and I'm finding that running with an iOS simulator works properly, but running tests does not, leading to these "no library for this platform" errors. I'm actually a little surprised that building and running for a simulator works at all, so I could just be doing something wrong here, but nothing's glaringly obvious to me.

Well, as I wrote above, I should be able to add other platforms quite easily - only, now I'd like to preserve the original release on github in case someone's depending on that :thinking: The swift-syntax version won't change with this...

So the question is what to name this new one so it won't be confusing :sweat_smile:

1 Like

So the question is what to name this new one so it won't be confusing :sweat_smile:

Heh that's a toughie if we wanted to match the official releases 1:1. Given that this is all still somewhat experimental, and that the official releases are coming out at a decent rate (509.0.1 @ 3 weeks ago & 509.0.2 @ 2 weeks ago), I think even just putting up a tag to specifically support "509.0.2-all-archs" might be useful to have something to work with, and then we could get back on track with naming for 509.0.3 whenever that's released.

Are there any other variants besides iOS that could potentially be useful?

All variants could potentially be useful to someone, whether it's TVOS, WatchOS, or VisionOS. But you're right, a name like macos-ios or some variation may be a more accurate name if you don't want to be troubled with supporting all of them right now.

I'd still like to understand why Xcode thinks you need anything other than host OS support. AFAIK, macros are a compiler plugin that generates textual content and shouldn't need to know anything about the integrating platform.

5 Likes

I'm also wondering, if there's any benefit or necessity of the macro dependencies going through the heavy weight release mode compilation. In the end the code output of the macro should be the same as in debug and only when the generated code is compiled again it benefits from all the optimizations in release mode right?

There isn't really, it was something we discussed not doing (I believe prior to the initial pitch). The main problem was that none of the build systems we're using with packages were really set up to support building just the macros and their dependencies with a different build configuration and it also wasn't clear what that would mean for other potential clients of swift-syntax in the same build graph (which would essentially lead to the "multiple versions" issue again in a different way).

1 Like

Hey @dafurman, sorry it took me so long to get to this. I can confirm those tests won't build and I find that super puzzling.

/path/to/DerivedData/MacroExample-main-fuhnxwfbmvrktndcowgjatctjkvs/SourcePackages/artifacts/swift-syntax-xcframeworks/SwiftBasicFormat/SwiftBasicFormat.xcframework:1:1: While building for iOS Simulator, no library for this platform was found in /path/to/DerivedData/MacroExample-main-fuhnxwfbmvrktndcowgjatctjkvs/SourcePackages/artifacts/swift-syntax-xcframeworks/SwiftBasicFormat/SwiftBasicFormat.xcframework'.

I looked in the Products folder in DerivedData. When building the feature target (for the simulator), all the swift-syntax entries appear under Debug as opposed to Debug-iphonesimulator:

Now, when building the tests (using Macros-Package), the swift-syntax entries appear under both Debug and Debug-iphonesimulator :sweat_smile::

(the whole thing won't fit my screen, but the Debug folder looks pretty much the same as before).

So this looks like the macros get built for the simulator in this case. @NeoNacho is this expected or did we stumble upon a bug?

1 Like

By the way, this only seems to happen when you put "feature" code in the same package as your macros. I just tested this in one of our packages - the macros we have are all defined in their own package that is only imported into the packages with features. Building tests for the feature package works fine, even though the feature (and test code) uses macro output.

2 Likes

What about if the condition was done as part of the dependency instead? Would it be possible for a package to vend a product that contains a binary target on some platforms and a regular target on others? For consumers of the dependency, they just reference the package and product as usual, but get the faster build times if the product comes from a binary target on their platform.

afaik you can work around this with the -module-abi-name flag in the swiftinterface — I wonder if that would help here.

Hey @NeoNacho it seems like macros need to be built for the simulator to work in SwiftUI Previews. Since swift build can't do that, I'm looking into how to do it with xcodebuild.

I'm once again stuck on only gettting .o files as output. Unlike swift build, xcodebuild requires a -scheme to be specified, which seems to be similar to --target when using swift build. The solution to getting .a files was to get rid of --target, which I can't do here. I tried building a target specifically set to be .static and also building the generated swift-syntax-Package scheme. I only get .o files in both cases. Could you please advise?

I'm calling something like this:

xcodebuild build \
-scheme swift-syntax-Package \
-destination "generic/platform=iOS Simulator" \
SKIP_INSTALL=NO \
BUILD_LIBRARY_FOR_DISTRIBUTION=YES