Carthage is a dependency manager for Swift and Objective-C projects that aims to provide a simpler tool that’s more flexible and easier to understand and maintain. Here’s how Carthage achieves this:
Carthage builds your dependencies and provides you with binary frameworks, but you retain full control over your project structure and setup. Carthage does not automatically modify your project files or your build settings.
Note that Carthage only supports dynamic frameworks, which are only available on iOS 8 or later (or any version of OS X). Using XCFrameworks as of version 0.37.0 (January 2021), and require XCFrameworks when building on an Apple Silicon Mac.
Carthage will check to make sure that downloaded Swift (and mixed Objective-C/Swift) frameworks were built with the same version of Swift that is in use locally. If there is a version mismatch, Carthage will proceed to build the framework from source. If the framework cannot be built from source, Carthage will fail.
brew install carthage
.Cartfile
in the same directory where your .xcodeproj
or .xcworkspace
isCartfile
, for example:github "Alamofire/Alamofire" ~> 5.5
carthage update --use-xcframeworks
Cartfile.resolved
file and a Carthage
directory will appear in the same directory where your .xcodeproj
or .xcworkspace
is.xcframework
bundles from Carthage/Build
into the “Frameworks and Libraries” section of your application’s Xcode project.Make sure to commit your Cartfile.resolved
, because anyone else using the project will need that file to build the same framework versions.
After you’ve finished the above steps and pushed your changes, other users of the project only need to fetch the repository and run carthage bootstrap to get started with the frameworks you’ve added.
Cartfile
that lists the frameworks you’d like to use in your project.carthage update
. This will fetch dependencies into a Carthage/Checkouts
folder, then build each one or download a pre-compiled framework.Carthage/Build
folder on disk. Then, in the “Embed” section, select “Do Not Embed” from the pulldown menu for each item added. For Xcode 10.x and lower, in the “Linked Frameworks and Libraries” section, drag and drop each framework you want to use from the Carthage/Build
folder on disk./bin/sh
), add the following contents to the script area below the shell:/usr/local/bin/carthage copy-frameworks
input.xcfilelist
and a file named output.xcfilelist
input.xcfilelist
. For example:$(SRCROOT)/Carthage/Build/iOS/Result.framework
$(SRCROOT)/Carthage/Build/iOS/ReactiveSwift.framework
$(SRCROOT)/Carthage/Build/iOS/ReactiveCocoa.framework
output.xcfilelist
. For example:$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/Result.framework
$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/ReactiveSwift.framework
$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/ReactiveCocoa.framework
With output files specified alongside the input files, Xcode only needs to run the script when the input files have changed or the output files are missing. This means dirty builds will be faster when you haven’t rebuilt frameworks with Carthage.
input.xcfilelist
to the “Input File Lists” section of the Carthage run script phaseoutput.xcfilelist
to the “Output File Lists” section of the Carthage run script phaseThis script works around an App Store submission bug triggered by universal binaries and ensures that necessary bitcode-related files and dSYMs are copied when archiving.
The three supported origins right now are GitHub repositories, Git repositories, and binary-only frameworks served over https.
Carthage supports several kinds of version requirements:
>= 1.0
for “at least version 1.0”~> 1.0
for “compatible with version 1.0”== 1.0
for “exactly version 1.0”If no version requirement is given, any version of the dependency is allowed.
# Require version 2.3.1 or later
github "ReactiveCocoa/ReactiveCocoa" >= 2.3.1
# Require version 1.x
github "Mantle/Mantle" ~> 1.0 # (1.0 or later, but less than 2.0)
# Require exactly version 0.4.1
github "jspahrsummers/libextobjc" == 0.4.1
# Use the latest version
github "jspahrsummers/xcconfigs"
# Use the branch
github "jspahrsummers/xcconfigs" "branch"
# Use a project from GitHub Enterprise
github "https://enterprise.local/ghe/desktop/git-error-translations"
# Use a project from any arbitrary server, on the "development" branch
git "https://enterprise.local/desktop/git-error-translations2.git" "development"
# Use a local project
git "file:///directory/to/project" "branch"
# A binary only framework
binary "https://my.domain.com/release/MyFramework.json" ~> 2.3
# A binary only framework via file: url
binary "file:///some/local/path/MyFramework.json" ~> 2.3
# A binary only framework via local relative path from Current Working Directory to binary project specification
binary "relative/path/MyFramework.json" ~> 2.3
# A binary only framework via absolute path to binary project specification
binary "/absolute/path/MyFramework.json" ~> 2.3
When you run carthage update, Carthage creates a couple of files and directories for you:
Cartfile.resolved
: This file serves as a companion to the Cartfile. It defines exactly which versions of your dependencies Carthage selected for installation. It’s strongly recommended to commit this file to your version control repository. Its presence ensures that other developers can get started quickly by using the exact same dependency versions.
Carthage/Build
: This contains the built framework for each dependency. You can integrate these into your project, and you’ll do so shortly. Carthage either builds each framework from source or downloads it from the project’s Releases page on GitHub.
Carthage/Checkouts
: This is where Carthage checks out the source code for each dependency that’s ready to build into frameworks. Carthage maintains its own internal cache of dependency repositories, so it doesn’t have to clone the same source multiple times for different projects.
Whether you commit the Build and Checkouts directories to your version control repository is up to you. It’s not required, but doing so means that anybody who clones your repository will have the binaries and source for each dependency available.
Having this backup can be a useful insurance policy if GitHub is unavailable or a source repository is removed.
CocoaPods is a centralized system that relies on a single repository called Specs that hosts all the metadata and source code of the supported libraries. Carthage is a decentralized system that does not have a central repository, but instead fetches the source code directly from GitHub or other sources.
CocoaPods is an automated system that downloads the libraries, creates a workspace, and modifies the project settings for you. Carthage is a configurable system that only builds the libraries and leaves the integration to you.
CocoaPods creates a new workspace that contains your project and a Pods project that contains all the dependencies. Carthage does not create a new workspace, but instead stores the built frameworks in a Carthage folder that you can link to your project.
CocoaPods supports both static and dynamic linking of frameworks, depending on the library type and the platform. Carthage only supports dynamic linking of frameworks, which means they are loaded at runtime and not embedded in the app bundle.
Some prefer CocoaPods for its ease of use, wide range of libraries, and automated integration. Others prefer Carthage for its simplicity, flexibility, and minimal interference with the project structure.
Carthage and Swift Package Manager are both decentralized dependency managers, which means they fetch the source code directly from GitHub or other sources. This allows you to use both tools in the same project without conflicts or duplication.
However, Carthage only supports dynamic frameworks, while Swift Package Manager supports both static and dynamic libraries. This means that if you use Carthage to build a framework that depends on a Swift Package Manager library, you have to make sure that the library is also built as a dynamic framework, otherwise you will get linker errors.
To do this, you have to use the --use-xcframeworks
flag when running carthage update
or carthage build
, which will create XCFrameworks instead of regular frameworks. XCFrameworks are a new format introduced in Xcode 11 that allow you to bundle multiple variants of a framework for different platforms and architectures.
Alternatively, you can use the --no-use-binaries
flag to disable the use of prebuilt binaries from Carthage, and build all the dependencies from sourceÂą. This will ensure that the Swift Package Manager libraries are built with the same toolchain and settings as your project.
Another option is to use Carthage only for external dependencies that are not available as Swift packages, and use Swift Package Manager for internal dependencies or those that support both tools. This way, you can avoid the hassle of dealing with different formats and linking issues.
However, this option may not work well if you have transitive dependencies, i.e. dependencies that depend on other dependencies. For example, if you use Carthage to build Alamofire, which depends on AlamofireImage, which depends on SDWebImage, which is a Swift package, you will have to make sure that all the intermediate dependencies are also compatible with both tools.
In summary, using Carthage with Swift Package Manager is possible, but it requires some extra work and attention. You have to be careful about the type and format of the libraries you use, and how they interact with each other. You may also encounter some issues with versioning and compatibility between the tools.