Using openSSL in a dependency on Linux

All of the following takes place on Linux (Mint, based on Ubuntu 18.04)

I have a project (SecureSockets) that uses openSSL 1.1.1g
OpenSSL is compiled separately for this project in its own directory under my user.
OpenSSL is encapsulated in a module called Copenssl
There is also some glue code (C-code) in CopensslGlue
In the Package.swift manifest I use "unsafeFlags" for swiftSettings and linkerSettings to find the openssl headers resp the openssl libraries.

The above works fine. It compiles and links as expected.

The problem arises when I want to use SecureSockets as a dependency in another project (Swiftfire).

Now the unsafeFlags can no longer be used, and -I believe- the compiler defaults to openSSL 1.0 in Glibc (???). Which of course fails completely.

Specifying the unsafeFlags in the Package.swift file of Swiftfire does not work.

Is there any way to still compile & link SecureSockets while using it as a dependency in Swiftfire?

If not, any advice on alternative methods?

Btw: If anybody wants to take a look at the files, both projects can be found on github: github.com/balancingrock/swiftfire resp securesockets.

For -I, you can use .headerSearchPath instead, but there is no solution beyond unsafeFlags for linking pre-compiled binaries on non-Apple platforms.

You could use a systemLibraryTarget though and advice users to install a newer OpenSSL on the host.

Thanks, I was afraid of that.
The systemLibrary target was indeed the first other approach I was going to try.
Even though it will break the "sameness" approach with macOS.

Maybe @lukasa has a suggestion on how to deal with SSL libraries between macOS and Linux.

My first order recommendation is to strongly consider whether you need to be solving this problem. In particular, both SwiftNIO and BlueSSLService provide alternative approaches you can use, and have blazed this trail before.

As to the general shape of the solution, to avoid using unsafeFlags you will have to rely on pkgConfig. This is your only choice. This will work natively on most Linux systems, and will behave well there. On macOS, there is no system OpenSSL for you to use, so you'll be relying on users pulling one in from Homebrew.

I strongly recommend not trying to deal with this yourself. OpenSSL has extremely difficult-to-use APIs, and the interaction with them in Swift is very hard, particularly if you are going to tolerate multiple OpenSSL versions (as you will need to do). You should very much investigate one of the pre-handled solutions to this problem if you possibly can.

1 Like

Thanks lukasa,

I believe I wrote SecureSockets before SwiftNIO or BlueSSLService was available. Either way that ship has sailed, its an existing code base now that -imo- works pretty well (on macOS).

I will look into pkgConfig, that may be a good alternative.

Btw, openSSL is not that difficult to use... ;-)

Just a follow-up.

In the end I was able to make it all work. It is hard -after all the experiments- to pinpoint exactly where the solution lay. I would guess three things:

  1. Quite possibly a typo in the header & linker search path settings.
  2. This is much more important though: in the linux environment I have to remove the .build directory after each try to fix a problem. Failing to do so will lead to strange error messages, even if the old error is now fixed. But one does end up chasing phantom errors.
  3. The C glue code I created proved to be "too much". The swift compiler is now able to read more of the openSSL headers than before, and I was able to remove some glue code that I needed in an earlier version. That glue code referred to some functions that are no longer available in ssl.a and crypto.a and thus failed to resolve. Reducing the glue code resolved this problem.

All in all, I can now build my server on both macOS and linux with minimal differences in code and build process.