[dev] Adventures with static linking

From: Paul Onyschuk <blink_AT_bojary.koba.pl>
Date: Tue, 14 Feb 2012 20:26:10 +0100

Skip this message if you're not interested in Stali Linux concepts and
static linking in general. Apologies for my poor writing skills in
English.

BACKGROUND

I'll not write about advantages and disadvantages of static linking,
you can find informations about that on Stali web page. Moreover
creating small statically linked distro has been proved to possible by
Bifrost Linux (check older messages on mailing list).

Personally I have been interested in using existing package/ports-like
system for creating static binaries. Burden of tracking dependencies
for everything beside basic and small software is huge. I picked up
Pkgsrc for many reasons (I'll skip that to keep message shorter) and
will describe what I found. I'm sending this message, because there was
some interest on #suckless IRC channel (at least I think so).

FORCING STATIC LINKING

Bifrost Linux has simple framework for building packages. Packages are
compiled inside chrooted environment using old images provided by
uClibc project. This approach has some advantages, because you don't
pollute your working distribution (compared to chrooted one) with
libraries. Bifrost build framework uses simple shell scripts to detect
options for static linking (grep ./configure --help for --enable-static
and so on). That works pretty well for small packages, but in Pkgsrc
case it means that some big changes are needed.

As I mentioned chroot images provided by uClibc project are very
outdated. I found that similar chroot images are provided by
Aboriginal Linux, distribution maintained by Rob Landley. Rob provided
simpler solution for forcing static linking, by removing all shared
libraries (this can be done safely in Aboriginal, because binaries are
already statically linked):

# find / -name "*.so*" | xargs rm

As it turns out in that kind environment, you don't need special
options for configure part of build. Most configure scripts are
complex enough to figure out without help that only static binaries are
to be built.

LIBTOOL

It also simplifies other things. Libtool has some issues with static
linking, mainly --static option isn't working as supposed. Bifrost
build framework uses some wrappers to change --static to --all-static,
just to fix libtool. In case with shared libraries removed, this isn't
problem at all, libtool can be compiled without support for shared
libraries (--disable-shared and remove /bin/shlibtool). I used libtool
this way without problems.

OTHER ISSUES

Of course there are some other issues, when only static libraries are
available. Some software still needs additional configure options or
other steps. LDFLAGS+="-z muldefs" is your friend, especially when it
comes to bigger pieces of software. This flag forces linker to pick up
one of multiple definitions.

PYTHON

By far Python required most work to build static binaries (I don't have
any plans for Python, beside using it as build dependency - it is
common). Python build system work more or less like this: first
interpreter with builtin modules specified in Modules/Setup.dist is
compiled, then setup.py is launched and default modules (dynamic
loading) are build, beside those specified earlier in Setup.dist.

So I ended up adding every module picked up by setup.py to Setup.dist.
It turns out that sample Setup.dist is missing some modules, so it
wasn't the case of just uncommenting everything. Moreover magic option
DYNLOADFILE="dynload_stub.o" is needed for configure part, otherwise
you will end up with segfaulting Python.

PKG-CONFIG

Another trouble maker is pkg-config, dependencies for shared and static
linking are specified separately. You can find
Requires/Requires.private and Libs/Libs.private in *.pc files. The
problem is that I'm not aware of any clean solution (environment
variable etc) to force pkg-config to pickup private parts of *.pc
files. I don't line idea of patching every makefile, since most Xorg
apps are using pkg-config. I ended up with wrapper:

| mv pkg-config pkg-config.old
|
| cat > pkg-config << 'EOF'
| #!/bin/sh
|
| pkg-config.old --static "$_AT_"
| EOF

If someone knows better solution, I would like to hear about it.
Anyway this works just fine in cases I encountered so far. Still I'm
not sure about pkg-config m4 macros, which can be used by autoconf.
Some fixes to *.pc files were also needed e.g. missing "-ldl".

PKGSRC, ABORIGINAL SPECIFIC ISSUES

Pkgsrc uses static package lists: file PLIST. This means that in some
cases PLIST cleanups are needed (mainly removing *.so files), but that
didn't happen often to be huge issue.

As for Aboriginal Linux, main problems are related to cpp (C pre
processor). I hope that this will be fixed in next release, because I
patched a dozen of configure scripts (only direct use case of cpp I
can think of) to work around this problem.

Of course uClibc creates issues of it's own, but this is getting better
- uClibc matures and software is patched upstream (my memory can be
false when it comes to this, I used uClibc for first time 2 years ago).

RESULTS

I compiled almost whole Xorg (statically linked) from pkgsrc. Only
missing part is xkeyboard-config, which depends on intltool. Intltool
requires XML Parser module for Perl. I used static build of Perl, so
dynamic module can't be loaded. I'll look into this later (compiling
in XML Parser into Perl binary).

As for bigger parts I also have static build of Perl and Python
mentioned earlier. Here are some stats about biggest binaries:

| 6.8M python2.6
| 6.3M perl
| 3.7M xterm
| 2.6M Xorg

I didn't test yet if Xorg is working, because GPL-terrorists took down
ttylinux (small Linux distro I planed to use). Bifrost Linux doesn't
provide needed drivers/modules to launch X11 and I'm not in the mood to
compile kernel right now.

SUMMARY

Maybe use of Pkgsrc is questionable, but that is for separate
discussion. My main goal was to research possibility of using static
linking on larger scale. Building Xorg was first step in my opinion.

Informations about what I've been doing can be found on wiki [1], some
parts are redundant or lacking explanations. I'll probably setup
repository with fixes to Pkgsrc in future.

Finally some thoughts about static linking (I'll skip what has been
said already by others):
- no symlink hell in /usr/lib (just *.a files without version number
suffixes as in shared libraries)
- number of libraries dropped down - some packages e.g. openssl are
using internal shared libraries (I know this, because of static PLISTs)


[1]
https://github.com/blinkkin/blinkkin.github.com/wiki/Aboriginal-Pkgsrc
Received on Tue Feb 14 2012 - 20:26:10 CET

This archive was generated by hypermail 2.3.0 : Tue Feb 14 2012 - 20:36:03 CET