statically linking shared libraries with libtool

I run a lot of experiments on our local cluster.  Unfortunately, over time, the library versions on the cluster tend to diverge from those on my local machine. As a result, I’ve gotten used to seeing this:

/usr/bin/python: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.17' not found 
(required by /home/power/w/spartan/build/.libs/libspartan.so.0)

If I was using Go this wouldn’t be a problem, as they statically link everything.  Despite the crowd of people who think shared libraries are the bees knees, I agree with this approach — it’s just far simpler than trying to deal with errors like the above. You can solve this most of the time by simply statically linking everything (–enable-static).  Sadly, if you’re trying to build a shared library (in my case, an extension module for Python), you can’t really go this route. (Statically linking Python API calls into a library which is then hoisted into Python is going to end very, very badly). What am I supposed to do with this error? If you trawl around the web, you find that depending on the exact error, you should either:

  • find an old version of GLIBC and link against that
  • insert assembly directives to indicate the old symbol

If you happen to have a single symbol that’s pulling the newer version, the latter is an easy fix (though it’s a bit annoying to ensure you’ve always got the directive declared before you use a function). If you’ve somehow acquired a dependency on the whole library things become more annoying. In my case, this dependency seemed to result from the chain:

_spartan_wrap.so -> libspartan.so -> libstdc++.so -> libc.so

Oddly enough, depending directly on libstdc++ isn’t the problem. If I remove the dependency on libspartan (just linking directly against all of the objects), we’re fine:

ldd -v .libs/_spartan_wrap.so
...

        Version information:
        .libs/_spartan_wrap.so:
                librt.so.1 (GLIBC_2.2.5) => /lib/x86_64-linux-gnu/librt.so.1
                libgcc_s.so.1 (GCC_3.0) => /lib/x86_64-linux-gnu/libgcc_s.so.1
                libm.so.6 (GLIBC_2.2.5) => /lib/x86_64-linux-gnu/libm.so.6
                libc.so.6 (GLIBC_2.15) => /lib/x86_64-linux-gnu/libc.so.6
                libc.so.6 (GLIBC_2.14) => /lib/x86_64-linux-gnu/libc.so.6
                libc.so.6 (GLIBC_2.4) => /lib/x86_64-linux-gnu/libc.so.6
                libc.so.6 (GLIBC_2.3.2) => /lib/x86_64-linux-gnu/libc.so.6
                libc.so.6 (GLIBC_2.3.4) => /lib/x86_64-linux-gnu/libc.so.6
                libc.so.6 (GLIBC_2.2.5) => /lib/x86_64-linux-gnu/libc.so.6
                libpthread.so.0 (GLIBC_2.3.2) => /lib/x86_64-linux-gnu/libpthread.so.0
                libpthread.so.0 (GLIBC_2.2.5) => /lib/x86_64-linux-gnu/libpthread.so.0
                libstdc++.so.6 (GLIBCXX_3.4.14) => /usr/lib/x86_64-linux-gnu/libstdc++.so.6
                libstdc++.so.6 (GLIBCXX_3.4.15) => /usr/lib/x86_64-linux-gnu/libstdc++.so.6
                libstdc++.so.6 (GLIBCXX_3.4.10) => /usr/lib/x86_64-linux-gnu/libstdc++.so.6
                libstdc++.so.6 (CXXABI_1.3) => /usr/lib/x86_64-linux-gnu/libstdc++.so.6
                libstdc++.so.6 (GLIBCXX_3.4) => /usr/lib/x86_64-linux-gnu/libstdc++.so.6

Notice, no reference to GLIBC_2.17. Luckily in this case there’s a simple solution: make all of the helper libraries into convenience libraries. This causes those libraries to be statically linked and avoids pulling in the extra dependencies:

# old
# lib_LTLIBRARIES = _wrap.la liba.la libb.la

# new 
noinst_LTLIBRARIES = liba.la libb.la
lib_LTLIBRARIES = _wrap.la

If we weren’t lucky — we’re actually using the symbol that’s from a later version — than we can force static linking of your dependent library; you do this by listing it explicitly by name in your LIBADD variable:

_spartan_wrap_la_LIBADD = -module -lrt /usr/lib/gcc/x86_64-linux-gnu/4.8/libstdc++.a

libtool will complain that linking against a static library isn’t portable (which is true), but it should work correctly as long as the static library was built with -fPIC.

About these ads

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s