This Time Self-Hosted
dark mode light mode Search

Autotools Mythbuster: who’s afraid of libtool?

This is a follow-up on my last post for autotools introduction. I’m trying to keep these posts bite sized both because it seems to work nicely, and because this way I can avoid leaving the posts rotting in the drafts set.

So after creating a simple autotools build system in the previous now you might want to know how to build a library — this is where the first part of complexity kicks in. The complexity is not, though, into using libtool, but into making a proper library. So the question is “do you really want to use libtool?”

Let’s start from a fundamental rule: if you’re not going to install a library, you don’t want to use libtool. Some projects that only ever deal with programs still use libtool because that way they can rely on .la files for static linking. My suggestion is (very simply) not to rely on them as much as you can. Doing it this way means that you no longer have to care about using libtool for non-library-providing projects.

But in the case you are building said library, using libtool is important. Even if the library is internal only, trying to build it without libtool is just going to be a big headache for the packager that looks into your project (trust me I’ve seen said projects). Before entering the details on how you use libtool, though, let’s look into something else: what you need to make sure you think about, in your library.

First of all, make sure to have an unique prefix to your public symbols, be them constants, variables or functions. You might also want to have one for symbols that you use within your library on different translation units — my suggestion in this example is going to be that symbols starting with foo_ are public, while symbols starting with foo__ are private to the library. You’ll soon see why this is important.

Reducing the amount of symbols that you expose is not only a good performance consideration, but it also means that you avoid the off-chance to have symbol collisions which is a big problem to debug. So do pay attention.

There is another thing that you should consider when building a shared library and that’s the way the library’s ABI is versioned but it’s a topic that, in and by itself, takes more time to discuss than I want to spend in this post. I’ll leave that up to my full guide.

Once you got these details sorted out, you should start by slightly change the configure.ac file from the previous post so that it initializes libtool as well:

AC_INIT([myproject], [123], [flameeyes@flameeyes.eu], [https://flameeyes.blog/tag/autotools-mythbuster/])
AM_INIT_AUTOMAKE([foreign no-dist-gz dist-xz])
LT_INIT

AC_PROG_CC

AC_OUTPUT([Makefile])

Now it is possible to provide a few options to LT_INIT for instance to disable by default the generation of static archives. My personal recommendation is not to touch those options in most cases. Packagers will disable static linking when it makes sense, and if the user does not know much about static and dynamic linking, they are better off getting everything by default on a manual install.

On the Makefile.am side, the changes are very simple. Libraries built with libtool have a different class than programs and static archives, so you declare them as lib_LTLIBRARIES with a .la extension (at build time this is unavoidable). The only real difference between _LTLIBRARIES and _PROGRAMS is that the former gets its additional links from _LIBADD rather than _LDADD like the latter.

bin_PROGRAMS = fooutil1 fooutil2 fooutil3
lib_LTLIBRARIES = libfoo.la

libfoo_la_SOURCES = lib/foo1.c lib/foo2.c lib/foo3.c
libfoo_la_LIBADD = -lz
libfoo_la_LDFLAGS = -export-symbols-regex '^foo_[^_]'

fooutil1_LDADD = libfoo.la
fooutil2_LDADD = libfoo.la
fooutil3_LDADD = libfoo.la -ldl

pkginclude_HEADERS = lib/foo1.h lib/foo2.h lib/foo3.h

The _HEADERS variable is used to define which header files to install and where. In this case, it goes into ${prefix}/include/${PACKAGE}, as I declared it a pkginclude install.

The use of -export-symbols-regex ­– further documented in the guide – ensures that only the symbols that we want to have publicly available are exported and does so in an easy way.

This is about it for now — one thing that I haven’t added in the previous post, but which I’ll expand in the next iteration or the one after, is that the only command you need to regenerate autotools is autoreconf -fis and that still applies after introducing libtool support.

Comments 6
  1. For those who already have a messed up API there is also the possibility to generate a file with all symbols that should be exported (possibly automatically from a header file) and specify it as -export-symbols.Just mentioning because it reminds me of the rather hilarious libmp3lame situation where they have such a file, except that it wasn’t actually working and wasn’t used: http://sourceforge.net/p/la…Since it seems to be ignored upstream (and by Debian, though deb-multimedia applied them at least) that might be interesting to look at for some Gentoo developer as well, since libmp3lame currently exports such symbols as get_bits, which is fairly likely to cause issues (and does, this patch comes from actual user issues).Btw. I’d suggest to never export variables, it will cause lots of troubles if you ever want the code to work on Windows for example.

  2. Yeah I didn’t want to go into the details of symbols export because this is meant as a quick tutorial and not a comprehensive one. But I’ll check out libmp3lame soonish, promised.

  3. This may look like a n00b question (and maybe I really AM still a rookie in this field), but — what is the correct way to support static linking of your package through autotools without pulling in libtool? I have no idea, really… 😮

  4. I’m a bit late here, but I’d like to ask: what about C++ ?More exactly, I’ve noticed an old problem with -export-symbols and mailed the list with a question (http://lists.gnu.org/archiv…, but have yet to get an answer.As for dolt :roll:IIRC, it happened at about the time when release of libtool 2 has dealt with a major part of the problem it was “trying” to solve.

  5. The problem with C++ and name-based symbol white/blacklisting is that you have to be extremely careful. If you were to hide part of a class’s content, such as the vtable, you’d have a broken librray. So I’m not surprised, nor opposed, to ignoring C++ libraries in that situation.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.