I am exploring ways to review a public API for a swift package to easily see major or minor changes. While traditional code diff between two versions is probably the proper way, sometimes diffs are so big that identifying where the public interface changed is not that easy. Especially since swift supports both public and other access modifiers in the same file, looking at hunks within same file and knowing how to separate the public from the rest can be a challenge.
After some reading and research I found that the .swiftinterface file might be what I want, but generating one from a swift package turned out to be tricky. The only way I could find how to achieve that was building and archiving a library as a dynamic framework, see these instructions and replace swift-syntax with [yourmodule]
It would be really nice If I can do this by just using swift package manager and not relying on xcodebuild.
I have also started exploring the swift package diagnose-api-breaking-changes tool to help with detecting breaking changes.
If you have any alternatives to generating the swiftinterface that would assist in reviewing the public API (and changes compared to oldrer versions), please provide feedback.
I definitely try to incorporate the tool into our workflow and I think it will be very beneficial. But I still see a lot of value to be able to view the entire public API, and the swiftinterface file does just that, so my original question still stands, is there a way to create it without creating a framework? Perhaps just from SPM cli or via xcode?
Just want to add (and hopefully answer part of my question) that it is possible to generate the swiftinterface by just using:
swift build -Xswiftc=-enable-library-evolution --enable-parseable-module-interfaces
I taken this from an older forum post, can someone from the package manager team confirm if this is still the right approach since the reply I got this from is a bit older (2020)?
The current flavor of this would be -Xswiftc -enable-library-evolution -Xswiftc -emit-module-interface
But also, keep in mind that enabling library evolution will introduce new warnings and change the semantics of your code, so this won't be something that will apply to every package. You may end up needing to change import resolution and hide some imports behind internal import if you're using non-library evolution enabled dependencies.
@harlanhaskins if I understand correctly this will only impact imports and not public API produced by the module (symboles defined in the module) correct?
I use this on PRs to release branches of some of my libraries to provide an extra check that exposed API didn’t change. I haven’t hit sharp corners, and find it useful as a quick vet.
Xcode has long had the ability to generate a Swift interface… but this always included internal and package (and public) APIs… AFAIK there was (unfortunately) never the ability to view only the public interface (but this would be great to have someday).
Hey @vanvoorden , I know about this feature and I tried it again before posting but it seems it is limited to a file and not a module. So for example if I have several functions separated in different files where in that file I declare an extension and add a function, when using this, it will not show me the original type I am extending from (even though is in the same module). The swiftinterface aggregates the entire module's public api.
Ahh… hmm… it's possible something like this might (one day) ship on the VS Code Swift Extension (with some additional hacking in SourceKit). This might also open it up to engineers blocked on running xcodebuild. I am not very familiar with those repos to tell you how much scope a feature like this would be… but it would be a cool feature if it shipped!