Build an executable project with statically linked libraries for Linux Ubuntu

Hi.

Is it possible to build a swift project on Linux (Ubuntu) using the -Xswiftc -static-stdlib flags?
I'm able to build a simple script that doesn't import and use FoundationNetworking but when I'm importing and using it I'm receiving these kind of errors:

/usr/lib/swift_static/linux/libFoundation.a(NSURL.swift.o):NSURL.swift.o:function $s10Foundation15NSURLComponentsC6schemeSSSgvg: error: undefined reference to '_CFURLComponentsCopyScheme'

So I thought to pass the lib CFURLSessionInterface and now I'm not receiving anymore the errors regarding the FoundationNetworking lib but these ones:

/usr/lib/swift_static/linux/libCFURLSessionInterface.a(CFURLSessionInterface.c.o):CFURLSessionInterface.c:function CFURLSession_multi_setopt_ptr: error: undefined reference to 'curl_multi_setopt'
/usr/lib/swift_static/linux/libCFURLSessionInterface.a(CFURLSessionInterface.c.o):CFURLSessionInterface.c:function CFURLSession_multi_setopt_l: error: undefined reference to 'curl_multi_setopt'
/usr/lib/swift_static/linux/libCFURLSessionInterface.a(CFURLSessionInterface.c.o):CFURLSessionInterface.c:function CFURLSession_multi_setopt_sf: error: undefined reference to 'curl_multi_setopt'
/usr/lib/swift_static/linux/libCFURLSessionInterface.a(CFURLSessionInterface.c.o):CFURLSessionInterface.c:function CFURLSession_multi_setopt_tf: error: undefined reference to 'curl_multi_setopt'
/usr/lib/swift_static/linux/libCFURLSessionInterface.a(CFURLSessionInterface.c.o):CFURLSessionInterface.c:function CFURLSessionInit: error: undefined reference to 'curl_global_init'

Any idea?

It is exceedingly difficult to build a static Swift binary that uses FoundationNetworking due to the extensive dependency tree that brings in. You need to find .a files for all of curl and its dependencies, some (but not all) of which are available from apt-get.

@weissi and @drexin know a bit more about the current state-of-the-art here.

2 Likes

That's right. Unless you pass a ton of extra linker flags for every of the (transitive) dependencies your system's libcurl has, I don't think you'll be able to do this. You may have more luck using AsyncHTTPClient because AFAIK the only thing it requires is a static version of zlib (-Xlinker -lz).

You can interrogate pkg-config about what you'd need to link a static libcurl: On my Ubuntu, you'd need

$ pkg-config --libs --static libcurl

-L/usr/lib/x86_64-linux-gnu/mit-krb5 -lcurl -lnghttp2 -lidn2 -lrtmp -lpsl -lssl -lcrypto -lssl -lcrypto -Wl,-Bsymbolic-functions -Wl,-z,relro -lgssapi_krb5 -lkrb5 -lk5crypto -lcom_err -llber -lldap -llber -lz

So for SwiftPM, you'd start with

swift build -Xlinker -L/usr/lib/x86_64-linux-gnu/mit-krb5 -Xlinker -lcurl -Xlinker -lnghttp2 -Xlinker -lidn2 -Xlinker -lrtmp -Xlinker -lpsl -Xlinker -lssl -Xlinker -lcrypto -Xlinker -lssl -Xlinker -lcrypto -Xlinker -Wl,-Bsymbolic-functions -Xlinker -Wl,-z,relro -Xlinker -lgssapi_krb5 -Xlinker -lkrb5 -Xlinker -lk5crypto -Xlinker -lcom_err -Xlinker -llber -Xlinker -lldap -Xlinker -llber -Xlinker -lz

The problem is that not all libraries are actually available as static libraries (.a) in the package archives, so you may hit a wall.

1 Like

This is actually quite possible with a build of libcurl. FoundationNetworking requires a smaller portion of curl than the general network access it can provide. You can pare down the dependency to just libcurl and zlib, which can be statically linked. This is quite simple to do with CMake, and is how I am building Foundation for Android on Azure.

Oh sure, if you build curl yourself and you don't link anything else that links the system's curl, that works. You'll probably want nghttp2 though as otherwise you won't get HTTP/2 support?

Terms of Service

Privacy Policy

Cookie Policy