Xspm a tool to easily integrate SPM packages with Xcode

Hello,

I've made a little tool to help integrating packages coming from the Swift Package Manager with Xcode projects. It's called xspm and I want to present it to you today.

The project is hosted on GitLab and is open source.

Some of us do this: create a new package of type library, add some dependencies to it and generate an Xcode project. This project is later used as a dependency provider in a target project. You directly gain the opportunity to use the frameworks coming out of this dependency project.

xspm takes care of the setup of such a dependency project and includes it in the target project. It also introduces a new file type to define swift package dependencies. This file is called manifest.xmnfst and it has its own syntax. That syntax is built with simplicity in mind. For example if you want to use Alamofire in your project just add this line to the manifest file.

+ "https://github.com/Alamofire/Alamofire.git" Alamofire >= 5.0.0-beta.3

You want to use more than one product for a package ? Type this kind of line :

+ "https://github.com/apple/swift-package-manager.git" [SwiftPM, SPMUtility]

It will make SwiftPM and SPMUtility from the swift-package-manager package available as a dependency in your project.

A typical xspm workflow goes as follow:

  1. Open a new Terminal window
  2. Navigate to the target project root
  3. Enter the command $ xspm bootstrap
  4. Edit the freshly created manifest.xmnfst file
  5. Close the target project
  6. In the terminal enter $ xspm init
  7. Open the target project and see that a Dependencies subproject has been added (you can change this name in the manifest).
  8. Link the dependencies at will.

You can find all the documentation about how to write the manifest file in the xspm repository.

I use xspm in my own project but I think it can be useful for other people. It all started as a script and grew along the months. Now I think it's mature enough for others to use it even if a ton of bugs must be lying around.

6 Likes

I know that the chance that nobody uses this tool is really high but now you can use a custom xcconfig file with xspm.

Be sure to update to xspm 0.5.0 first then :

  1. create an xcconfig file in the same folder as the manifest file (e.g. config.xcconfig)
  2. edit the manifest and add the corresponding property line (e.g. - xcconfig: "config.xcconfig")
  3. finally update the dependencies: $ xspm update
  4. voilà.

Hi @Pyroh, thank you for sharing the project! I'm currently using Accio for integrating SwiftPM packages with iOS/macOS projects built with Xcode. Would really be interested to try xspm, could you please provide a comparison between these two tools and in what cases a user would prefer one over the other?

Hi everyone, I'm the author of Accio and must admit, I didn't know of the existence of xspm. It looks interesting in any case.

But I've got one question that I couldn't get an answer to in the README: Is xspm really targeting towards dependency management of e.g. iOS frameworks, including those which use UIKit? Currently I can't find a single mention of that in the docs. Also, how did you work around the missing features SR-2866 and SR-3948?

@Max_Desiatov My feeling after reading the README is that the two tools have different goals. While Accio seeks to make SwiftPM ready for dependency management for iOS, I feel like xspm only supports fully SwiftPM-compatible frameworks only (e.g. Alamofire), but currently can't handle something like Eureka. @Pyroh Please correct me, if I'm wrong.

Please also note that I released an article today, explaining Accio in more detail. Feel free to check it out:

2 Likes

Hello @Max_Desiatov and @Dschee,

I've started preparing this answer last week and never been able to find time to finish it. I'll take it now. In the meantime I updated xspm and fixed some bugs. I also added a new installation method.

First of all I've never heard of Accio before last week. The one reason is that I never searched for it since I like to code my own tools when I can. That's why I made xspm, sort of.

So I took a look at Accio, I didn't test it to be honest but I think I have a good idea of it works. I think I can say that it's way more advanced than xspm but a bit more complicated to setup (greater things are harder to achieve :wink:). It leverages the power of both SwiftPM, Carthage and Xcode when xspm only relies on SwiftPM and Xcode to do the work. There's no cache in xspm either, Xcode compiles the dependencies when and if it's needed.

xspm works with macOS and iOS but also with tvOS and watchOS. For macOS and iOS you can test it using this sample project, the iOS version made it to TestFlight so I guess it's store-ready. Once again Xcode does all the work. SwiftPM produces xcodeproj files that can be compiled for any architecture if the code allows so. Of course it works only with SwiftPM-compatible frameworks. I made a package that build against AppKit without any issue, this should be the same for UIKit. I don't do real iOS development so I didn't test this ability so far.

Regarding SR-2866 xspm doesn't offer any solution or workaround. By the way once this is implemented in SwiftPM it will be available in xspm.

For SR-3948 Swift 5.0 partially answered it with the platforms property in Package.swift files. xspm offers you to set extra build settings through a custom xcconfig file. This configuration is applied to any dependency as well.

xspm has also been designed to ease dependency integration for shared projects. Once a project is configured and the dependencies linked it can be pushed to a repository. When cloned a single $ xspm init will do the trick by fetching the dependencies. Xcode will then find the dependency project and its content and happily build the targets.

Finally I'd say that xspm doesn't try to compete with any other tools. I think xspm has its perks and the major one is that it's easy to use. That's what I wanted to do: being able to integrate Swift packages easily in my projects and I think that from this point of view it is a success.

So should you use xspm ? Yes if it does fit your needs. :smiley:

@Dschee : You did a great work !

1 Like

@Pyroh Thank you for the detailed explanation! Much appreciated. :+1:

I also haven't tried out xspm yet, but I probably will soon and wonder if it also supports installing tools with dependencies which are separated into multiple modules, some of them being weirdly linked like CNIOAtomic within the NIO dependency of NIOTransportServices. By 'weird' I mean that CNIOAtomic is linked like a library/framework, but it's not exposed as a library within the Package.swift. When I tried to integrate NIOTransportServices into Accio, it all built fine (the frameworks and the app) but when actually running the app (in simulator) I got linker errors and the app crashed.

If libraries which have true support for SwiftPM (meaning they don't include resources, for example) build much better with the approach taken in xspm I might even consider adding such a feature into Accio. I've just created this issue to track that. Since xspm also provides xspmkit, it might even be an option to directly use it in Accio, if that's fine with you.

But before that's a possibility, you would need to fix the licensing problem in xspm first.

P.S. Is what this article is explaining the same as the approach taken in xspm?

1 Like

The licensing issue is fixed, thanks for noticing it. I often forget about licenses, my bad.

I've tested NIOTransportServices integration using xspm and it works without any linking issue. You can test it with xspm by adding + "https://github.com/apple/swift-nio-transport-services.git" NIOTransportServices >= 1.0.0 to the manifest file. Then link both NIOTransportServices and NIO to your target. This should work. Xcode 10.2 is required.

Regarding the article you linked I must admit that iOS support is sort of a happy side effect. As I said before I don't do iOS development on my own that's why xspm was aimed toward macOS at first. I started developing it around august 2018 when iOS support of Swift package was still a burden. First public release coincides with Xcode 10.2 and Swift 5.0 ones that incidentally bring iOS support to the generated xcodeproj by SwiftPM.
When I realized this and built the sample project I faced a little issue on iOS platforms. SwiftPM doesn't set any version for frameworks targets that's why xspm use a special xcconfig file that state that CURRENT_PROJECT_VERSION = 1 as a workaround. It applies to all dependencies. I plan to tweak the generated xcodeproj in order to set the versions directly in it, per package based on the resolved version (1 if not available).

You can use xspmkit in Accio of course and I'll be happy to help you integrate it. It's a formidable occasion for me to document it... :face_with_monocle:

xspm 0.6.0 is out !

Now every framework targets of the dependency project get a version. This version is either the version of the package the target originates from or 1 if there's no package version. This ensures that iOS applications upload won't be rejected, without using an hacky xcconfig file.

It works by setting the target's CURRENT_PROJECT_VERSION build setting. It's a workaround and addresses the issue documented in SR-4265. I think the way xspm handles the issue could be a decent fix for this bug. I'll perhaps try to do it.

Note: Unfortunately this release will break your current xspm integration. Worry not simply remove the Dependency folder and the manifest.xrslvd file by hand then run $ xspm init.

1 Like