2
votes

I have a project, where I want to link one of system libraries statically. The project uses GNU build system.

In configure.ac I have:

AC_CHECK_LIB(foobar, foobar_init)

On development machine this library is installed in /usr/lib/x86_64-linux-gnu. It is detected, but it is linked dynamically, which causes issues, as it is not present on some machines. Linking it statically (-Wl,-Bstatic etc.) works fine, but I don't know how to set this up in autotools. I tried forcing this into Makefile.am link flags for the project, but it still gives a preference to dynamic library. I also tried using --enable-static with ./configure, but it seems to have no effect on system libraries.

1

1 Answers

4
votes

If you want to link the whole program statically, then you should pass the --disable-shared option to configure. You might or might not need also to pass --enable-static, depending on the default value for that option (which you can influence via your configure.ac file). You really should consider doing this.

You should also consider making this the installer's problem, not the build system's. Let it be the installer's responsibility to ensure that all the shared libraries needed by the program are provided by the systems where it is installed. This is very common; in fact, it is one of the inspirations for package-management systems such as yum / dnf and apt, and their underlying packaging formats.

If you insist on linking only one library statically, while linking everything else dynamically, then you'll need to jump through a few more hoops. The objective will be to emit link options that cause just that library to be linked statically, without changing other libraries' linking. With the GNU toolchain, and supposing that the program is otherwise being linked dynamically, that would be this combination of options:

-Wl,-Bstatic -lfoobar -Wl,-Bdynamic

Now consider the documentation of the AC_CHECK_LIB() macro:

Macro: AC_CHECK_LIB (library, function, [action-if-found], [action-if-not-found], [other-libraries])

[...] action-if-found is a list of shell commands to run if the link with the library succeeds; action-if-not-found is a list of shell commands to run if the link fails. If action-if-found is not specified, the default action prepends -llibrary to LIBS and defines 'HAVE_LIBlibrary' (in all capitals). [...]

Note in particular the default behavior in the event that the optional arguments are not provided (your present case) -- that's not quite what you want, at least not by itself. I suggest providing at least an alternative behavior for action-if-found case, and you could consider also making configure fail in the action-if-not-found case. The latter is left as an exercise; implementing just the former might look like this:

AC_CHECK_LIB([foobar], [foobar_init], [
  LIBS="-Wl,-Bstatic -lfoobar -Wl,-Bdynamic $LIBS"
  AC_DEFINE([HAVE_LIBFOOBAR], [1], [Define to 1 if you have libfoobar.])
])

You should also pay attention to the order of your AC_CHECK_LIB() invocations. As its docs go on to say:

This macro is intended to support building LIBS in a right-to-left (least-dependent to most-dependent) fashion such that library dependencies are satisfied as a natural side effect of consecutive tests. Linkers are sensitive to library ordering so the order in which LIBS is generated is important to reliable detection of libraries.

If you find that you still aren't getting what you want, then have a look at the link commands that make actually executes. You need to understand what's wrong about them before you can determine how to fix the problem.

With all that said, I observe that the above treatment is basically a hack, and it makes your build system much less resilient. It introduces dependencies on GNU toolchain options (which some other toolchains may nevertheless accept), and it assumes dynamic linking is being performed overall. It may be possible to resolve those issues with additional Autoconf code, but I urge you to instead go with one of the first two alternatives I described.