Search code examples
iosopensslstatic-librarieslibcryptoxcframework

Create XCFramework out of two static libraries (libssl.a, libcrypto.a)


Consider OpenSSL, the project itself has two products: libssl.a and libcrypto.a. For the sake of simplicity, let's use the precompiled libraries stored in this repository and consider just iphonesimulator platform.

When looking at the repository, each platform, e.g. iphonesimulator or iphoneos will have a set of static libraries for all of the architectures needed.

My goal is to create an XCFramework that bundles those two static libraries, so that it would be convenient to use with Swift Package Manager as a single package.

I definitely can create an XCFramework supporting multiple platforms: iOS Simulator (i386, x86_64, arm64), iOS (arm64, arm7...) from static libraries with the following command:

xcodebuild -create-xcframework \
-library iphonesimulator/lib/libcrypto.a \
-headers iphonesimulator/include/ \
-library iphoneos/lib/libcrypto.a \
-headers iphoneos/include/ \
-output OpenSSL.xcframework

The output is as follows:

xcframework successfully written out to: /Users/name/OSSL_test/OpenSSL.xcframework

The structure of the framework is correct and it contains both headers and the libcrypto.a. When imported into another Xcode project, this XCFramework is recognized and used in building an app.

However, when I also try to add libssl.a, I get the following error:

xcodebuild -create-xcframework \
-library iphonesimulator/lib/libcrypto.a \
-headers iphonesimulator/include/ \
-library iphonesimulator/lib/libssl.a \
-headers iphonesimulator/include/ \
-output OpenSSL.xcframework

A library with the identifier "ios-arm64_i386_x86_64-simulator" already exists.

Which makes sense, since both libcrypto.a and libssl.a are of the same architecture.

So, my question is, is it possible to bundle two static libraries together using a single XCFramework? Or should I create two separate XCFrameworks, so that each library has it's own?

In the repository mentioned above, the static library actually used in another build phase as inputs producing a .framework per each platform. The build logic is in the OpenSSL.xcodeproj. So, I assume, what I'm asking is simply not possible?


Solution

  • You basically have two options:

    1. Create two separate XCFrameworks, one for libcrypto.a and one for libssl.a, or
    2. Combine libcrypto.a and libssl.a into a single library, let's say, libOpenSSL.a and use this combined library to create a single XCFramework.

    It looks like you know how to do (1). So what do you need to do for (2)?

    You can create a combined libOpenSSL.a by doing the following (best to copy the libraries to a clean tmp directory for this):

    ar -x libcrypto.a
    ar -x libssl.a
    ar -cr libOpenSSL.a *.o
    

    The first two commands extract all the object files from each of libcrypto.a and libssl.a and the final command creates the new combined static library.

    Update: User Steven0351 let me know in a comment that there is a more elegant way of achieving the same result as the sequence of ar commands above using libtool:

    libtool -static -o libOpenSSL.a libcrypto.a libssl.a
    

    A word of caution... If you have been using GNU tools you need to make sure that the libtool you run is the one in Xcode toolchain. So you may want to prefix the above with xcrun.