Link to a Precompiled Static C Library in a Swift Library Package

I want to build a Swift library package that uses modified build of OpenSSL and Curl.

I have already statically compiled both and verified I can use them in an Objective-C framework on my target platform (iOS & iOS Simulator). I'm using XCFramework files that contain the static library binaries and headers:

openssl.xcframework/
    ios-arm64/
        openssl.framework/
            Headers/
                [...]
            openssl
    ios-arm64_x86_64-simulator/
        openssl.framework/
            Headers/
                [...]
            openssl
    Info.plist

I'm not sure how I'm supposed to set up my Swift package to import these libraries.

I can use .systemLibrary but that seems to use the embedded copies of libssl and libcurl on my system, and I can't figure out how to use the path: parameter to that.

I also tried using a .binaryTarget pointing to the XCFramework files, but that didn't seem to work as there is no module generated and I'm not sure how to make one myself.

At a basic high level, this is what I'm trying to accomplish:

where libcrypto & libssl come from the provided openssl.xcframework file, and libcurl from curl.xcframework

My go-to reference for integrating XCFrameworks into Swift packages is the Swift Evolution proposal itself, namely SE-0272. It looks like you tried that, but it’s not clear what actually went wrong. How did you set this up? And what actually failed?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Hi Quinn, let me elaborate.

When using a binary target, my Package.swift file looks like:

/Package.swift:

// swift-tools-version: 5.10
import PackageDescription

let package = Package(
    name: "MyLibrary",
    products: [
        .library(
            name: "MyLibrary",
            targets: ["MyLibrary"]),
    ],
    targets: [
        .target(
            name: "MyLibrary",
            dependencies: ["OpenSSL", "Curl"]
        ),
        .binaryTarget(name: "OpenSSL", path: "openssl.xcframework"),
        .binaryTarget(name: "Curl", path: "curl.xcframework"),
        .testTarget(
            name: "MyLibraryTests",
            dependencies: ["MyLibrary"]),
    ]
)

When I try to import either OpenSSL or Curl within any source files for MyLibrary it can't find those modules, for example:

/Sources/MyLibrary/Versions.swift:

import Foundation
import OpenSSL // No such module 'OpenSSL'
import Curl // No such module 'Curl'

public final class Versions {
    public static func openssl() -> String {
        return OPENSSL_VERSION_STR
    }

    public static func curl() -> String {
        return LIBCURL_VERSION
    }
}

I'm assuming that I need to define a module map file, but that doesn't seem to have any effect. If I create a module map for OpenSSL:

Sources/MyLibrary/openssl.modulemap:

module OpenSSL [system] {
    header "opensslv.h"
    link "ssl"
    link "crypto"
    export *
}

It doesn't seem to do anything, as I get the same error as above. In fact, I'm not even sure this file is being used at all, as if I fill it with gibberish, I don't get an expected syntax error.

I'm assuming that I need to define a module map file

Yeah, that’s definitely true.

There are a couple of things that I’d do to investigate this. First, divorce yourself from the many complexities of OpenSSL. Create a trivial C framework using Xcode, wrap that up in an XCFramework using the standard instructions, and then import that into Xcode. Can you get that to work?

Next, wrap your working XCFramework into a Swift package and import that.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Link to a Precompiled Static C Library in a Swift Library Package
 
 
Q