Swift Package Manager as a Generic Package Manager?

Swift Package Manger is kind of a newcomer to the package manager field. But there are a lot of things it does really well. And it can manage non-Swift code projects (like C++).

The ease of setup is one big plus to SPM - even for C++ packages. It's really easy to get setup and building. XCTest doesn't work with C++ yet, but might in the future once C++ bridging is in place. And while there are other C++ source based package managers out there, SPM is easier to configure than a lot of the binary based package managers. We use a lot of CMake as well - but the higher setup cost tends to cause it not to be implemented in smaller projects. And CMake isn't a full dependency manager.

Clear downsides are that SPM really only has downstream integration with other SPM packages or Xcode at this point. There's no downstream support for SPM in IDEs like Visual Studio or build systems like CMake.

Has anyone tried using SPM as a generic C++ package manager? I think it would be a really interesting use case to be able to SPM enable all our C++ Git repositories. I'm not aware of a way to integrate SPM dependencies into a non-SPM aware environment though.

We package some C++ libraries as Swift packages (so that they can be consumed by Swift via a wrapper library), and so end up using SPM in a pure-C++ environment for some development and for running the tests. It's been fairly painful and I wouldn't particularly recommend it if you can avoid it. There's a very long tail of things that a C++ build system needs which SPM mostly doesn't do. If SPM is actually sufficient for your needs then your CMake projects should also be extremely trivial; if your CMakeLists.txt is more than something like 50 lines of code you're probably either doing something wrong in CMake or you're doing something that SPM currently can't do.

If you can get buy-in for universally adopting a new package manager and build system, you'll probably have a better time with something like Meson or Bazel.

Yeah, in posting this I realize I'm bringing up a topic that exists on the edge of what SPM is typically used for, or possibly far off the edge. But theres a few reasons I'm considering it, and or at least bringing it up in the Swift forums to see what people think.

Any organization is going to want to maximize their investment in something, and minimize redundancies. Like you've found, exposing C++ packages as SPM packages is really convenient for anyone doing Swift development, or even Xcode development. We've had a lot of success in just providing some C++ packages to Xcode users who aren't even working in Swift. But the trade off is redundancy. It takes more time for developers to support SPM in addition to something like Conan/CMake.

Sometimes binary packages are the solution. Like you were hinting at, there still are situations that are beyond SPM, and CMake is really the only ideal candidate. CMake alone is not a package manager, but you can export binaries into SPM.

The other place that has me thinking about wider SPM usage is the in development Swift/C++ bridging. That would open a lot more possibilities. C++ packages could become first class citizens in Swift (and would need some way to be brought into an SPM project.) And Swift packages could become first class C++ libraries (and SPM would need to have wider support in popular C++ tooling to be used.)

It's a big hypothetical hill to climb to get wider SPM adoption for C++ packages in general. So I suppose I'm just starting with more of a "how would we integrate our C++ and SPM teams tighter and more effectively internally" hypothetical. It would be great if our C++ and Swift developers could trade dependencies without friction. And making SPM a more core part of workflows would help.

I'd prefer to see SwiftPM not attempt to be the "one ring to rule them all", but instead focus on improving the ability to let it work in concert with other build tools and systems.

The use case I've been struggling with is one where I'm leveraging a library written in Rust, exposing C API bindings - and getting that into a form (XCFramework today) that can be consumed by swift files and libraries for both server-side swift and app development. Today it's an ugly accumulation of shell scripts and manually generating platform specific libraries that I stitch together to form a result.

This project has recently migrated from Rust specific tooling to CMake running the Rust tooling (cargo and xargo). CMake appears to be the dominant cross-platform and cross-OS build system tooling that runs through a variety of languages, even though every time I start trying to use it I feel like I'm being punished for a past life. I've had similar struggles with getting to the cascade of options for compiling C++ code, last time stepping over to using vcpkg to get the dependencies aligned and available. None of the options fit together well as build solutions, but those that try to "take over the world and control all aspects" (cough Bazel) just seem to make the whole process notably harder, which I'd like to avoid in the case of SwiftPM.

That said I don't know how to achieve this - no concrete "this would make it better" kinds of statements. The escape hatch I use today is often shell scripts to invoke another build system to get the right pieces and parts in place, and then hand over those build artifacts to the next tooling. Maybe there's something there, but I'm not certain.

4 Likes

TL;DR this reply is slightly off topic. The takeaway (if there is one) is to maybe consider layering something on top of SPM, rather than using SPM directly.


I actually built a "package manager" on top of SPM - sort of:

It's really for personal use (though I'd be delighted if anyone else ever expressed an interest).

I use it as a way to configure my machines - both macOS and Linux. I have something approximating a standard setup and a bunch of things I usually do - installing files in certain locations, putting aliases in places like /usr/local/bin, switching shells, adding global configs for git, installing vscode plugins, and so on.

They evolved into a horrible morass of bash scripts, and I realised that over time lots of things became obsolete - like all those Perforce aliases that I now no longer needed because using Perforce stopped two jobs back.

So one day I decided to rewrite the whole thing in a modular way. What can I say - I guess I felt the need for some serious Yak shaving :slight_smile:. As part of it I realised that I needed a way to manage dependencies, and a way to run some code to "install", "update", and "remove" each module. I figured that SPM did all the dependency and updating really well already, and that I wanted to write the code in Swift, so it felt like a natural choice. I made each "module" a swift package. The management tool writes an über-manifest which pulls in the installed modules, and then invokes SPM to resolve dependencies and build & run the modules to install/remove/update them.

Now I can install one tool onto a new machine and then use that to install the bits of my standard setup that I need, as and when I need them.

That's the theory anyway! The reality is about as stable as you'd expect for a personal-use-hairy-yak kind of thing. It does work though.

1 Like