Skip to content

Instantly share code, notes, and snippets.

@jaredsinclair
Forked from zwaldowski/repackage.md
Created September 1, 2021 21:34
Show Gist options
  • Save jaredsinclair/e4afa65bf16cc28ce3240625afce0d1d to your computer and use it in GitHub Desktop.
Save jaredsinclair/e4afa65bf16cc28ce3240625afce0d1d to your computer and use it in GitHub Desktop.

Revisions

  1. @zwaldowski zwaldowski revised this gist Sep 1, 2021. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions repackage.md
    Original file line number Diff line number Diff line change
    @@ -98,7 +98,7 @@ let package = Package(
    Use the following template:

    ```modulemap
    framework module OwningTheLibs {
    module OwningTheLibs {
    umbrella header "OwningTheLibs.h"
    export *
    module * { export * }
    @@ -110,7 +110,7 @@ Drop that into the `include/OwningTheLibs` directory to enable `import OwningThe
    If the library is less like an ObjC project and more like a C project, you may have multiple `header` entries instead:

    ```modulemap
    framework module OwningTheLibs {
    module OwningTheLibs {
    header "one.h"
    header "two.h"
    export *
  2. @zwaldowski zwaldowski revised this gist Sep 1, 2021. 1 changed file with 50 additions and 5 deletions.
    55 changes: 50 additions & 5 deletions repackage.md
    Original file line number Diff line number Diff line change
    @@ -11,7 +11,8 @@ OwningTheLibs/
    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.)
    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:

    @@ -20,25 +21,32 @@ Run the lipo tool on the `.a` to get a check for its contents:
    Architectures in the fat file: OwningTheLibs/libOwningTheLibs.a are: x86_64 arm64
    ```

    If you get `Non-fat file`, stop.
    If you see `Non-fat file: OwningTheLibs/libOwningTheLibs.a` instead, stop.
    You cannot proceed.

    Thin the binary using `lipo`:

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

    Create the xcframework:

    ```shell
    xcodebuild -create-xcframework -library simulator/libOwningTheLibs.a -headers include -library device/libOwningTheLibs.a -headers include -output OwningTheLibs.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.
    > **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.
    > See `xcodebuild -create-xcframework -help` for more details.
    The resulting xcframework will look like this:

    @@ -84,3 +92,40 @@ let package = Package(
    ]
    )
    ```

    ## Making a modulemap for Swift if they didn't provide you with one

    Use the following template:

    ```modulemap
    framework module OwningTheLibs {
    umbrella header "OwningTheLibs.h"
    export *
    module * { export * }
    }
    ```

    Drop that into the `include/OwningTheLibs` directory to enable `import OwningTheLibs` in Swift.

    If the library is less like an ObjC project and more like a C project, you may have multiple `header` entries instead:

    ```modulemap
    framework module OwningTheLibs {
    header "one.h"
    header "two.h"
    export *
    module * { export * }
    }
    ```

    If the vendor says things like "you must link against `SystemConfiguration`" or "you must link against `libz`", you can also do that:

    ```modulemap
    module OwningTheLibs {
    umbrella header "OwningTheLibs.h"
    export *
    module * { export * }
    link "z"
    link framework "SystemConfiguration"
    }
    ```
  3. @zwaldowski zwaldowski revised this gist Sep 1, 2021. 1 changed file with 3 additions and 1 deletion.
    4 changes: 3 additions & 1 deletion repackage.md
    Original file line number Diff line number Diff line change
    @@ -35,9 +35,11 @@ Thin the binary using `lipo`:
    Create the xcframework:

    ```shell
    xcodebuild -create-xcframework -library simulator/libOwningTheLibs.a -headers include -library device/libOwningTheLibs.a -headers include-output OwningTheLibs.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:

    ```raw
  4. @zwaldowski zwaldowski created this gist Sep 1, 2021.
    84 changes: 84 additions & 0 deletions repackage.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,84 @@
    # Repackaging a Fat Static Library as an xcframework

    Consider this directory tree from a vendor:

    ```raw
    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:

    ```shell
    ~ 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`:

    ```shell
    ~ 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:

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

    The resulting xcframework will look like this:

    ```raw
    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
    // 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")
    ]
    )
    ```