Back

Autoconf projects compiled statically

Introduction

Have you ever copied an executable over to another system only to find out that it won’t work because some shared object is not of the exact version you have on your system?

Yes, dynamically linked programs are lean and they are usually compact, but they do have certain issues, especially when copying them over to another system and even when updating, package managers do make errors sometimes or it could be that you manually compiled a project (to be on the bleeding edge) but now they no longer work as some dependency got updated.

This means that the project has to be recompiled and reinstalled.

Of course you could hack this by symlinking the shared object to the older version but your mileage will vary and there can be some sad results.

There is another way.

A Solution

Statically linking executables! Yes, the result executable is bigger (and sometimes much bigger) than their dynamic counter parts, but that’s pretty much the only drawback of using this technique. It is also possible to offset this drawback by using a different C library like musl which may well create a smaller executable than its dynamic counter part. (Just make sure to strip the executable for the best size results)

It’s so nice to be able to use executables anywhere without always having to provide any dependencies (shared objects).

Statically linked executables are simply an executable that contains all the library dependencies that they depend on.

The How

It’s as simple as adding a single compilation flag to gcc or clang, you just add the ‘-static’ flag and voilà!

For projects that use Makefile or such we just have to set ‘-static’ to both CFLAGS and LDFLAGS and that works everywhere!

Not… we sure wish that was the case but it’s not.

One of the place where this doesn’t work is with projects that uses Autoconf and especially with libtool.

Autoconf with libtool

Do note that many projects support a configure flag to compile statically so it’s important to check that first, before using this technique.

Libtool is a linker/compiler superscript that helps with compatibility. (Don’t throw rocks at me please, I’ve never used libtool with my own projects so my understanding of it is limited.)

Now the issue here is that libtool does not honor the ‘-static’ flag. It just drops that flag. It does have a (kind of hidden) way to reactivate that flag for the underlying gcc call. Here’s how :

CFLAGS="-static" LDFLAGS="-static" ./configure <your configure flags here>

and then when you use make :

CFLAGS="-all-static" LDFLAGS="-all-static" make <your make flags here>

This should ensure that the resulting executables are compiled statically.

You can’t use “-all-static” for the configuration phase as this will break the tests. It must be because gcc does not support “-all-static” :).

Conclusion

I just want to make it clear that I’m not a “statically link everything!” advocate.

Dynamically linked executables are the de facto method to use on a host system for various very good reasons.

One of them is actually a legal one as the GPLv2 (and later) does not allow libraries to be statically linked into an executable.

Do note that the LGPLv2 does allow their libraries to be statically linked as far as I know. The LGPLv3 does not seem to allow it.

The goal of this article is strictly in terms of convenience when deploying containers/jails.

As a rule of thumb, it is considered bad practice to package statically linked executables for distribution to end users.

If you absolutely want to make sure that your package contain all or certain dependencies, just include the shared objects that it depends on.

Statically linked executables are more of a black box than anything else and it’s better not to trust statically linked executables distributed by peers you don’t trust.