Skip to content

Instantly share code, notes, and snippets.

@jaredsinclair
Forked from zwaldowski/repackage.md
Created September 1, 2021 21:34
Show Gist options
  • Select an option

  • Save jaredsinclair/e4afa65bf16cc28ce3240625afce0d1d to your computer and use it in GitHub Desktop.

Select an option

Save jaredsinclair/e4afa65bf16cc28ce3240625afce0d1d to your computer and use it in GitHub Desktop.

Repackaging a Fat Static Library as an xcframework

Consider this directory tree from a vendor:

OwningTheLibs/
  OwningTheLibs.a
  include/
    OwningTheLibs/
      OwningTheLibs.h
      module.modulemap

The vendor will probably say "this supports iOS and iOS simulator". (As of 2019/2020 this is no longer true, but we don't need to get in to that right now.)

Run the lipo tool on the .a to get a check for its contents:

~ lipo -info OwningTheLibs/libOwningTheLibs.a
Architectures in the fat file: OwningTheLibs/libOwningTheLibs.a are: x86_64 arm64

If you get Non-fat file, stop. You cannot proceed.

Thin the binary using lipo:

~ mkdir -p device
~ mkdir -p simulator
~ lipo -thin x86_64 libOwningTheLibs.a -output simulator/libOwningTheLibs.a
~ lipo -thin arm64 libOwningTheLibs.a -output device/libOwningTheLibs.a

Create the xcframework:

xcodebuild -create-xcframework -library simulator/libOwningTheLibs.a -headers include -library device/libOwningTheLibs.a -headers include -output OwningTheLibs.xcframework

Note: If the vendor gave you debug symbols or Bitcode maps — which is unlikely, let's be honest - add -debug-symbols after any -headers. It will need to be repeated multiple times.

The resulting xcframework will look like this:

OwningTheLibs.xcframework/
  ios-x86_64-simulator/
    Headers/
      OwningTheLibs/
        OwningTheLibs.h
        module.modulemap
    libOwningTheLibs.a
  ios-arm64/
    Headers/
      OwningTheLibs/
        OwningTheLibs.h
        module.modulemap
    libOwningTheLibs.a

The resulting xcframework can be dragged into Xcode into the "Frameworks, Libraries, and Embedded Content" of a target, or embedded into a Swift package:

// swift-tools-version:5.5
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "OwningThePackages",
    platforms: [ .iOS(.v14) ],
    products: [
        .library(
            name: "OwningThePackages",
            targets: ["OwningThePackages"]),
    ],
    targets: [
        .target(
            name: "OwningThePackages",
            dependencies: ["OwningTheLibs"]),
        .binaryTarget(
            name: "OwningTheLibs",
            path: "OwningTheLibs.xcframework")
    ]
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment