Make your favourite Carthage frameworks static
After expounding the benefits of static frameworks for inclusion in your next iOS et al. app, I’ve had a few of you ask me:
How do you build third-party static frameworks under a dependency manager, like Carthage?
Carthage supports building static frameworks, as described in its documentation. However, the script detailed in that example is dated, because since Xcode 9 beta 4, Xcode natively supports static libraries with Swift sources. Making the
LD hack no longer necessary.
I’ve written a BASH script to simplify the process of building static frameworks with Carthage. I’ll detail what it does and how to use it.
The frameworks built by Carthage are dynamic by default.
It is necessary to override some
xcconfig properties with a temporary file to make static frameworks build successfully.
MACH_O_TYPE determines what is being built — executable, dynamic library, static library, bundle, or relocatable object file. As we are building static frameworks the setting must be
Debug information format
Make sure that
xcodebuild is not attempting to produce
dSYM (debug symbol) files, as this will cause a build failure. Static libraries already contain debug symbols. When the static framework is used by an executable, that executable can produce
dSYM files containing its own symbols and that of the framework. Setting
dwarf (debugging with attributed record formats) the debugging information adheres to the standard dwarf debug format.
Framework search paths
Carthage builds static frameworks to the
/Static sub-directory along its normal build path. i.e.
The main problem exists when a Carthage framework is dependent on another Carthage framework and the path to the dependency is explicit because it is merely linked, and it does not have
FRAMEWORK_SEARCH_PATHS set to a recursive look up. As is the case, for example, with RxSwiftExt and its dependency on RxSwift.
In this case, looking at the linked frameworks in the
Frameworks group, you will notice that the path is, for example in the case of the RxRelay.framework — is explicitly
Carthage/Build/iOS/RxRelay.framework. When the compiler looks up this path, it will not find RxRelay.framework and will result in a build failure.
We need to help out the compiler to find the location of the linked static frameworks by overriding the
FRAMEWORK_SEARCH_PATHS, in this case with
./Carthage/Build/iOS/**. This tells the compiler to recursively scan through sub-directories of
./Carthage/Build/iOS to find the linked framework relative to the group.
Download the sample project to follow this example.
I’ll also assume you have Carthage installed.
If you open the
BuildStaticCarthage.xcworkspace now, you should get multiple build errors, as all the dependent frameworks have not been check-out or built yet.
The project has a number of commonly used Carthage frameworks in its
Cartfile. Two of the frameworks — RxGesture and RxSwiftExt — are dependent on RxSwift.
Open the Terminal and navigate to the directory that contains the
Cartfile. Now update the checked-out source code without building, by running:
It will take a while to download the sources.
Once completed, we are ready to use the script.
build-static-carthage.sh script has the following options:
Required. The target build platform. Only one platform at a time. Valid options are
Required. List of frameworks to be built. As they appear in the
Optional. List of additional framework search paths in addition to the default
To use the script, to build our static frameworks for iOS, in the Terminal run:
After working out your CPU for a good few minutes, you should now find yourself with four successfully built static frameworks, and be ready to build and run the example app.
BuildStaticCarthage.xcodeproj, there are a few settings that make the static frameworks available to the app build target:
In the Xcode project navigator, within the
Config group, you will see a
Base.xcconfig file. This contains two
FRAMEWORK_SEARCH_PATHS points to the directory containing the static frameworks relative to the project directory.
OTHER_LINKER_FLAGS tells the compiler to merge the full static framework into the executable. The
-ObjC flag is required for frameworks that contain Objective-C extensions.
This could also be set in the BuildStaticCarthage.app target’s Build Settings Other Linker Flags setting.
Realm is dependent on the SDK libraries:
libc++.tbd. These dependencies must be linked to separately to those framework from the Carthage build process. You can find these libraries from your target’s Linked Frameworks and Libraries menu by pressing the
+ button and selecting them appropriately.
So, there you have it. A simple method to build static frameworks under Carthage.
Now try and add your favourite Carthage-managed frameworks to your
Cartfile and see if you can make them static.
The example project that utilises the
build-static-carthage.sh script can be found here: https://github.com/markjarecki/CarthageStaticFrameworks
This code is provided as-is.