Packaging .a static C libraries in Swift Package Manager

Hello guys. I'm working on an iOS project and trying to add SPM support to it.
The problem is that one of the dependencies uses OpenSSL, a C static library which consists of
libcrypto.a, libssl.a and a bunch of header files respectively.

So what I've been trying to do is put the libcrypto.a, libssl.a and the headers inside the package and bundle them together to use this package as a dependency, so that others can easily integrate the openssl functionality.

Here's my setup:

Project structure:

    . 
    β”œβ”€β”€ Package.swift
    └── Sources 
        └── OpenSSL
        β”œβ”€β”€ include 
        | β”œβ”€β”€ openssl 
        | | └── aes.h, asn.h ... 
        | β”œβ”€β”€ module.modulemap
        | └── shim.h 
        β”œβ”€β”€ lib 
        | β”œβ”€β”€ libcrypto.a 
        | └── libssl.a 
        └── dummy.c

package.swift

// swift-tools-version:5.1
    
import PackageDescription
    
let package = Package(
    name: "OpenSSL",
    products: [
        .library(name: "OpenSSL", targets: ["OpenSSL"])
    ],
    targets: [
        .target(name: "OpenSSL"),
    ]
)

module.modulemap

module OpenSSL {
    umbrella header "shim.h"
    export *
    link "ssl"
    link "crypto"
}

shim.h

#include <openssl/bio.h>
#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/md4.h>
#include <openssl/md5.h>
#include <openssl/sha.h>
...

The package builds, it can be added as a dependency, but that's about it.
I assume this is due to the package not being linked to the library.

This might do the trick, but it is stated that packages using unsafeFlags() cannot be added as dependencies.

.linkerSettings(LinkerSetting.unsafeFlags("-LSources/OpenSSL/lib"))

Is there some way I could achieve this?
I'm relatively new to this and could have missed something. Any help would be greatly appreciated.

Thanks!

4 Likes

There is no way to publish binaries yet, but much thought is going into making it possible:

That means you have three options:

  1. Depend on OpenSSL as source. Its GitHub repository is here. Fork it, add a Package.swift, tag a version, and depend on that. (And maybe submit your Package.swift back to them as a pull request.) Sometimes this strategy requires generating and checking in files the project normally leaves Git‐ignored.

  2. Distribute the binary separately, and instruct your clients to install it on the system first. (And your clients’ clients will have to do the same thing.) Once it is installed on the system, linkedLibrary should just work without needing unsafe flags.

  3. Use unsafeFlags and never release semantic versions, telling your clients to depend on branches instead. Branch dependencies allow unsafe flags, because they are only intended for development. The branches in the dependency tree will in turn prevent clients from release semantic versions too.

All these strategies see quite a lot of use, so which one you choose is up to you. (I’m partial to option 1.)

6 Likes

Thanks @SDGGiesbrecht, option 1 does seem to be the most viable in my case.
Cheers.

1 Like

@mpetrenco - What about the other library libcrypto.a, how you implemented the Swift PM in above mentioned case ? Please provide some guidelines.

If you use Xcode to build, then what I'm doing is:

  • add the .a file to my Swift Package - in a directory "Libraries" - it gets downloaded along with the source
  • the .a shows up in Frameworks (why? got me) and in the Build Phase, drag it to the link section
  • add a Library Search path of "$(BUILD_DIR)/../../SourcePackages/checkouts/PhotoScrollerSwiftPackage/Libraries"

That path lets Xcode find it.

Tested with debug builds but not release builds yet. Its not perfect but will make it relatively easy for others using my package to incorporate it.

1 Like

Any update on this? I am trying .xcframework, but I am still failing to make it work with .a files...

1 Like

I think this solution doesn’t work anymore, I cannot see SourcePackages in between build files.

Is there any working way to include a .a static C library in a Swift Package, without having source code (so @SDGGiesbrecht solution 1 is not an option)?