[swift-build-dev] Building fully static binaries on Linux
Simon Evans
si at si.org
Fri Sep 9 14:57:10 CDT 2016
Hi,
Ive been looking at SR-648 (producing static binaries using swiftPM) and Ive
managed to get a static binary built on Linux/ELF. It may also work on other ELF
platforms although Ive not tested them. It doesnt currently apply to COFF or MachO
There are 4 issues:
1. -static-stdlib links in libswiftCore.a as its help text says but nothing
else. To link in all of the other .a files they need to be listed in the
ld command line including libicudata.a which is used by libicu. The list
is: libswiftCore.a, libicui18n.a, libicuuc.a, libicudata.a, libdl.a and
libpthread.a
2. The clang++ command line needs to be modified to use -static and remove
the -rpath and other dynamic options
3. Some symbols have the weak attribute set and dont get linked in by gold
so a stub is needed just to force the linker to link them, the function
doesnt actually need to be run. I couldnt find a gold option that forced
them to be resolved otherwise
4. Because the binary is static, libdl and the dl functions dlopen, dlsym
etc dont actually work. A patch needs to be applied to swift
(ProtocolConformance.cpp and MetadataLookup.cpp) that use some symbols
set by the linker to access the swift2_protocol_conformances and
swift2_type_metadata sections at startup. These would only be set when
building a static binary and bypass the libdl functions at startup.
The only other issue is that libdl would still be linked in and in future
other code that uses dl* to load data etc would fail. So it be may that
a minimal replacement of these functions to log an error is used instead
of libdl. If this approach looks ok, I'll start working on a PR that adds
a '-static' option to swiftpm to try and resolve SR-648 (for Linux)
Ive done a rough patch for swift/stdlib with some debug fprintf()
@ https://gist.github.com/spevans/17d01a687c0648a8adc5021029b6d648
Example usage
$ cat main.swift
print("hello")
$ cat main.autolink
-Xlinker --defsym=__swift2_protocol_conformances_start=.swift2_protocol_conformances_start
-Xlinker --defsym=__swift2_type_metadata_start=.swift2_type_metadata_start
static_stub.o
-lswiftCore
-licui18n
-licuuc
-licudata
-ldl
-lpthread
$ cat static_stub.c
#include <stdlib.h> // For NULL
#include <bits/pthreadtypes.h>
int pthread_once (pthread_once_t *once_control, void (*init_routine) (void));
int pthread_key_create (pthread_key_t *key, void (*destr) (void *));
pthread_t pthread_self (void);
void
_unused_func_to_force_linking()
{
pthread_once(NULL, NULL);
pthread_key_create(NULL, NULL);
pthread_self();
}
# Normal dynamic binary
$ swiftc -O -o main main.swift
$ ldd main
linux-vdso.so.1 (0x00007ffdcfcca000)
libswiftCore.so => /mnt/scratch/spse/builddir/swift-linux-x86_64/lib/swift/linux/x86_64/libswiftCore.so (0x00007fe776a38000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fe77672d000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fe77642c000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fe776216000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fe775e6b000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fe775c4e000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fe775a4a000)
libicuuc.so.52 => /usr/lib/x86_64-linux-gnu/libicuuc.so.52 (0x00007fe7756cc000)
libicui18n.so.52 => /usr/lib/x86_64-linux-gnu/libicui18n.so.52 (0x00007fe7752ba000)
/lib64/ld-linux-x86-64.so.2 (0x00007fe776e61000)
libicudata.so.52 => /usr/lib/x86_64-linux-gnu/libicudata.so.52 (0x00007fe773a4d000)
$ ./main
sectionName: .swift2_protocol_conformances_start sectionDataAddr: 0x7f16a16867f0 *sectionDataAddr: (nil)
Dynamic binary, using dl_iterate_phdr
hello
# Dynamic binary with libswiftCore.a linked in
$ swiftc -O -static-stdlib -o main main.swift
$ ldd main
linux-vdso.so.1 (0x00007ffeffb1a000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f68dfe62000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f68dfc45000)
libbsd.so.0 => /lib/x86_64-linux-gnu/libbsd.so.0 (0x00007f68dfa35000)
libicui18n.so.52 => /usr/lib/x86_64-linux-gnu/libicui18n.so.52 (0x00007f68df623000)
libicuuc.so.52 => /usr/lib/x86_64-linux-gnu/libicuuc.so.52 (0x00007f68df2a5000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f68def9a000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f68dec99000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f68dea83000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f68de6d8000)
/lib64/ld-linux-x86-64.so.2 (0x00007f68e0066000)
libicudata.so.52 => /usr/lib/x86_64-linux-gnu/libicudata.so.52 (0x00007f68dce6b000)
$ ./main
sectionName: .swift2_protocol_conformances_start sectionDataAddr: 0x72d790 *sectionDataAddr: (nil)
Dynamic binary, using dl_iterate_phdr
hello
# Static binary
$ swiftc -O -emit-object -o main.o main.swift
$ clang -Wall -O3 -c static_stub.c -o static_stub.o
$ clang++ -g -static -fuse-ld=gold -target x86_64-unknown-linux-gnu $LIBDIR/swift/linux/x86_64/swift_begin.o main.o -L $LIBDIR/swift_static/linux -Xlinker -export-dynamic -Xlinker --exclude-libs -Xlinker ALL -Xlinker --no-undefined --target=x86_64-unknown-linux-gnu @main.autolink $LIBDIR/swift/linux/x86_64/swift_end.o -o main
/mnt/scratch/spse/builddir/swift-linux-x86_64/lib/swift_static/linux/libswiftCore.a(ProtocolConformance.cpp.o):/mnt/hgfs/src/swift/swift/stdlib/public/runtime/ProtocolConformance.cpp:function _addImageProtocolConformances(dl_phdr_info*, unsigned long, void*): warning: Using 'dlopen' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.9/../../../x86_64-linux-gnu/libicuuc.a(putil.ao):function uprv_dl_open_52: warning: Using 'dlopen' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
$ ldd main
not a dynamic executable
$ ./main
sectionName: .swift2_protocol_conformances_start sectionDataAddr: 0x1fb1588 *sectionDataAddr: 0x44f0
Static binary Adding blockAddr: 0x1fb1590, blockSize: 17648
hello
$
- Simon
More information about the swift-build-dev
mailing list