Kyle Fuller

← View all posts

Using Swift Package Manager with Carthage

Some users of my libraries have asked how they can integrate these libraries into their applications using Carthage dependency manager.

Carthage requires libraries to provide an Xcode project or a binary framework. However, since many of my Swift libraries are cross-platform, I am not developing them in Xcode. In addition, distributing binary frameworks from Swift source is not recommended by Apple because the Swift ABI is not yet stable. Therefore the frameworks are tied to specific releases of Xcode.

"While distribution and use of 3rd-party binary frameworks is not recommended (as mentioned in a previous blog post), Swift supports construction and distribution of frameworks in source form." [source]

Since Swift Package Manager offers the ability to generate an Xcode project, it would allow Carthage to be able to build a Swift Package Manager dependency with Xcode.

This post provides instructions on how to generate Xcode projects with Swift Package Manager manually. In the future, I think it would be possible for Carthage to do this automatically with changes to Carthage if desired.

NOTE: These instructions should work for simple dependency graphs. If you have the same dependency resolved by Swift Package Manger and Carthage you may hit some problems.

Installing your dependencies

As the first step, you will need to add your Swift Package Manager dependency into your Cartfile.

For example, if we want to integrate Stencil and Commander we could use the following Cartfile:

github "kylef/Stencil" ~> 0.6.0
github "kylef/Commander" ~> 0.7.0

Then you can use Carthage to checkout and fetch the source of your dependencies.

$ carthage update

Once you have the source of your Swift Package Manager dependencies you can use Swift command line tool to generate an Xcode project for each dependency. The command line tool provides an generate-xcodeproj subcommand.

$ swift package generate-xcodeproj --help
OVERVIEW: Generates an Xcode project

  --enable-code-coverage   Enable code coverage in the generated project
  --output                 Path where the Xcode project should be generated
  --xcconfig-overrides     Path to xcconfig file

To generate Xcode projects for our example above, we can change into the source directories and invoke swift package generate-xcodeproj:

$ (cd Carthage/Checkouts/Stencil && swift package generate-xcodeproj)
$ (cd Carthage/Checkouts/Commander && swift package generate-xcodeproj)

Then you can use Carthage to build the dependencies.

$ carthage build
*** Building scheme "Commander" in Commander.xcodeproj
*** Building scheme "Stencil" in Stencil.xcodeproj

Finally, you can integrate your dependencies into your application using the instructions from Carthage on adding frameworks to an application.

For a macOS application, you would need to copy the frameworks that Carthage built (which can be located in Carthage/Builds/Mac) into the "Embedded Binaries" section of your Xcode project.

NOTE: You do not need to embed any of the dependencies testing frameworks into your application.