Migrating Project From Carthage to SPM.
Tags: iOS, Carthage, Swift, iOS App Development, Swift Package Manager

After the support of resources in Swift packages, SPM became more attractive as an option. Apart from that let’s face it SPM is still the newish kid on the block that makes some cumbersome task easy. If I judge from my friends and colleagues, 2020 was the time that more and more people felt ready to migrate their projects on SPM. Thus I thought it would be nice to have a guide. Unfortunately, I cannot cover the migration from Cocoapods as I haven’t used it for years but I will definitely try to give a rough guide for Carthage to SPM.

Personal Story (Feel free to skip)

I don’t think any of these two systems need any introduction. Carthage has been a dependency companion for many Swift based applications. I started using it something more than 4 years ago and it proved to be reliable with an ever-growing and helpful community. Handling large-scale projects with Carthage is easy as it allows the engineers to choose the project structure they desire and at the same, it handles the dependencies as well as the building of the frameworks.

Approximately 2 years ago, even though I used Carthage for professional projects, I started using SPM (Swift Package Manager) for personal projects. The first touch was not that encouraging. Xcode didn’t provide any integration with SPM and not many third party libraries provided SPM support. But then something big happened. (I guess you all assumed I was going to mention the integration of SPM to Xcode, but no!!!) My MacBook broke down. I was devastated. But then I thought Swift works on Linux and SPM is supported in Linux so I decided to give it a try on my Ubuntu machine with VSCode.

That was the time that I fell in love with SPM for its package manifest simplicity. I couldn’t believe it but SPM made Swift coding feel so lightweight and prompted me into writing cleaner and modular code. I can provide examples of that though in a different article. (Let me know with a comment if you are interested)

What you clicked for!

Projects differ in terms of complexity and structure so I cannot give you a golden rule you can apply to every project but I can definitely provide a guide and some advice.

Ready

It’s vital to understand that before you start your migration to SPM you need to be prepared. Make sure all the third-party libraries you are using are supporting SPM. In case some don’t support it, there might be an alternative. An easy way to check is the Swift Package Index.

TIP: Check the issues page on the library’s repository. Some libraries do support SPM but the support might be in the early-stage and it might cause some issues to your project. I leave it up to you to decide if the stability of your project matters is more important than your passion for SPM.

If your project is small and has no in-house dependencies, feel free to move to the next section.

If your project is big and you have no in-house dependencies, then I have good and bad news for you. The good news is that you can skip this section and move to the next. The bad news is that possibly you are working on a monolith. You may need to start splitting the code into smaller modules. (Completely irrelevant with Carthage-to-SPM migration but take it as advice)

If your project is big and you have in-house dependencies then:

Make sure the dependency graph is clear to you and your team The order of the project migration is vital. Start migrating independent projects first and slowly move to projects with more dependencies. If your projects are interconnected in a complicated way you may want to consider if some restructuring is necessary. You will need to support both Carthage and SPM for a small period of time so make sure that your projects are working as expected on both tools. Build configurations are not genuinely supported in SPM and you may face some small issues.

Steady

Now that you have analyzed the structure of your application it’s time to restructure a single framework to a package. For this we are going to provide a simple (the simplest) example.

Probably your framework has a more complicated structure than the image you just saw, but for now, this is not of big importance.

The first step to migrate a framework to support SPM is to introduce the two folders SPM is going to use to identify where the source code files and the test files are located. So we need to wrap MyFramework and MyFrameworkTests folders into a Sources and Tests folder respectively.

You should have an outcome like the following:

At this point, you are halfway there.

The second step is to open your terminal and navigate to the root folder of your project. In this case, this should be MyFramework .

Then execute the following:

swift package init --type library

The outcome of this command is to let SPM know that we want to initiate a Swift package and that we intend the products of this package to be of the type library.

As you see the outcome is the creation of Package.swift (aka Package Manifest), a README.md and a .gitignore . In case you have the last two files, fear not as they will not be created.

The third step is to prepare your package manifest.

TIPS:

I would recommend defining the supported platform versions. Visit PackageDescription documentation for more information.

In case your folder structure under Sources or Tests is a bit complicated and SPM is struggling to detect files, then you assist by adding the path of the respective folders under the targets.

or is a bit complicated and SPM is struggling to detect files, then you assist by adding the path of the respective folders under the targets. For adding resources to your Swift Package you should check this video. Keep in mind that recognised resources (as xibs, xcassets etc) are automatically added. For the rest you will need to use the .process or .copy parameters.

or parameters. You are allowed to exclude files from your targets using the exclude property in target definition

property in target definition In case you want to add localizable resources (yes they are supported) you need to provide a defaultLocalization

Make sure you add all the direct dependencies needed by the package no matter if some of them are linked via a different framework.

Always use your tests to verify the outcome

SPM is by default going to deliver a static library. In case you need to force a dynamic framework you will need to define it in the Package Manifest.

.library(name: "MyFramework", type: .dynamic, targets: ["MyFramework"])

Attention: I felt confident and I started auto-generating Xcode project files by swift package generate-xcodeproj . What I found out is that sometimes these automated Xcode project files were causing issues to Carthage. Especially because of the plist file which was regenerated as well. So keeping in mind that the end goal is to completely migrate to SPM then I would avoid auto-generating these files.

Go

You now have the power to start your migration. In most cases, you will not find any serious issues during the path. In case you do though, make sure you check the WWDC videos, the Swift forums and ask the community.