libtool doesn't provide library dependencies to link
Asked Answered
I

3

5

I am using libtool 2.2.6b on ubuntu lucid, and libtool 2.4.2 on ubuntu precise. On lucid my project will link properly. On precise it fails to link. Here's example code that demonstrates my problem;

configure.ac

AC_INIT([ltp], [0.0.1], [someone])
AM_INIT_AUTOMAKE
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIR([.m4])
AC_CONFIG_FILES([Makefile foo/Makefile bar/Makefile wah/Makefile])
AC_PROG_CXX
AC_PROG_LIBTOOL
AM_SANITY_CHECK
AC_LANG_CPLUSPLUS
AC_OUTPUT

Makefile.am

SUBDIRS = foo bar wah
ACLOCAL_AMFLAGS = -I .m4

foo/Foo.h

#ifndef FOO_FOO_H_
#define FOO_FOO_H_
namespace Foo
{
  class Foo
  {
  public:
    Foo(long l);
  private:
    long l;
  };
}
#endif

foo/Foo.cpp

#include "foo/Foo.h"
namespace Foo
{
  Foo::Foo(long l) : l(l) {}
}

foo/Makefile.am

lib_LTLIBRARIES = libfoo.la
libfoo_la_SOURCES = Foo.cpp
libfoo_la_CPPFLAGS =
libfoo_la_LDFLAGS = -release 0.0.1
libfoo_la_LIBADD =

bar/Bar.h

#ifndef BAR_BAR_H_
#define BAR_BAR_H_
#include "foo/Foo.h"
namespace Bar
{
  class Bar
  {
  public:
    Bar(const Foo::Foo & f);
  private:
    Foo::Foo f;
  };
}
#endif

bar/Bar.cpp

#include "bar/Bar.h"
namespace Bar
{
  Bar::Bar(const Foo::Foo & f) : f(f) { }
}

bar/Makefile.am

lib_LTLIBRARIES = libbar.la
libbar_la_SOURCES = Bar.cpp
libbar_la_CPPFLAGS =
libbar_la_LDFLAGS = -release 0.0.1
libbar_la_LIBADD = -L../foo -lfoo

wah/main.cpp

#include "bar/Bar.h"
int main(int argc, char * argv[])
{
  Bar::Bar( 5 );
  return 0;
}

wah/Makefile.am

bin_PROGRAMS = wah
wah_SOURCES = main.cpp
wah_CPPFLAGS =
wah_LDADD = -L../bar -lbar

On Lucid, wah links, on Precise, it fails with:

wah/main.cpp:5 undefined reference to `Foo::Foo::Foo(long)'

I can fix this by adding -L../foo -lfoo to wah_LDADD, but really, isn't libtool supposed to do that for me automagically? The libtool manual section on `Linking executables' seems to indicate that is exactly what it should do.

Inhalator answered 3/8, 2012 at 20:19 Comment(6)
What do libfoo_LIBADD, libbar_LIBADD, libfoo_LDFLAGS, libbar_LDFLAGS look like? The flags '–ldl –lboost_filesystem –lboost_system' are dependencies of their respective libs, not the test executable. Since these are shared libs (not static), why do you think the second line is wrong?Monday
libfoo_la_LDFLAGS = -release $(PACKAGE_VERSION) libfoo_la_LIBADD = -L$(libdir) -lboost_filesystem -ldl libbar_la_LDFLAGS = -release $(PACKAGE_VERSION) libbar_la_LIBADD = -L$(libdir) -lfoo -lboost_systemInhalator
an executable that links with exe_LDADD -lbar links and runs with no errors. I'll have to look more closely at what happens there. So, I would think a unit test executable would be similar. Although, there is no AM_LDADD. But, from the libtool manual; "That looks too simple to be true. All libtool did was transform libhello.la to ./.libs/libhello.a, ... Notice that Libtool also remembered that libhello.la depends on -lm, so even though we didn't specify -lm on the libtool command line3 Libtool has added it to the gcc link line for us." So what magic happens for the exe, but not the unit test?Inhalator
What is wrong with the test executable?Monday
With 2.2.6b on lucid, nothing. With 2.4.2 on precise, unresolved symbols from the missing transitive dependencies (libs need by libfoo). Perhaps related to the DSO link change in ubuntu natty? As I mentioned, exe using exe_LDADD, link fine. It's unit tests relying on AM_LDFLAGS that fail.Inhalator
@Monday - I edited my original post to include example code for my problem. Could you perhaps take another look at it for me? Thanks.Inhalator
S
5

On any Debian machine I use for development, I have to compile and install Libtool by hand, because the Debian-supplied version is patched and ignores dependencies in a way that break my builds.

If Ubuntu's version is similar, you might want to install Libtool from source too.

Serration answered 13/8, 2012 at 10:7 Comment(5)
Can you give more info/links on the patch? I'd like to understand what's driving the change, and see if I can find a more autotools-flavored solution.Inhalator
I think the troublesome patch is link_all_deplibs.patch because it sets $link_all_deplibs to no. The mail lists.gnu.org/archive/html/libtool/2007-09/msg00017.html gives an example of what this breaks.Serration
Yes, using a vanilla libtoolize fixes my build problems too. I got a whole lot of problems with indirect library dependencies after I ran libtoolize on Ubuntu 12.04. In particular, library dependencies which were not reflected in the binary library files (but only via inline functions in header files). It is beyond me how the Debian / Ubuntu folks could decide that it is ok to break Libtool so severely.Nickynico
Since then I have found a way to cancel the effect of Debian's patch in my own project, so that developers do not need to reinstall libtool on every Debian machine they work on. git.lrde.epita.fr/…Serration
For a long time my apps worked without any change, while unit test fell by the wayside, so I haven't revisited this issue. But just recently, for reasons I can't understand, 4 of 24+ apps started to fail as well. Which is all the more puzzling because all 24+ apps use a common base app framework. So, I employed @adl's configure.ac fix from the git reference above, and it works like a charm. Thanks!Inhalator
P
2

I suppose you could say it's more of a difference in philosophy. The point of Debian's change is to encourage users to be explicit about what they depend on, which reduces the amount of unnecessary churn when dependencies deep down the tree get upgraded.

When link_all_deplibs=yes (unmodified libtool), if your program wah depends on bar and bar depends on foo, then it is implied that wah depends foo as well.

When link_all_deplibs=no (Debian's modified libtool), if your program wah depends on bar and bar depends on foo, then it is not implied that wah depends foo as well.

So, taking Debian's perspective, this is false in your program: wah does depend on foo by virtue of this line:

  Bar::Bar( 5 );

Here, you are calling the constructor of Foo::Foo implicitly. As far as the C++ compiler is concerned, your program is really more like:

  Bar::Bar( Foo::Foo( 5 ) );

Therefore, wah depends on foo not just indirectly, but directly. Hence, from Debian's perspective, you are should explicitly link to foo via -lfoo.

In particular, this is not the same situation as libtool's example for Linking Executables. In that example, main.o does not explicitly depend on libm, thus -lm should, in principle, be unnecessary when linking the main.o (main.c does not call cos directly). Perhaps the reason why libtool links recursively is as a work around for older systems where linkers are unable to handle indirect dependencies?

Palace answered 15/11, 2016 at 0:36 Comment(0)
M
1

Works for me on Ubuntu 12.04 (Precise Pangolin) 32-bit, libtool 2.4.2.

I did have to change your Makefiles a bit to make dist (more) correctly:

foo/Makefile.am:

lib_LTLIBRARIES = libfoo.la
libfoo_la_SOURCES = Foo.cpp Foo.h
libfoo_la_CPPFLAGS =
libfoo_la_LDFLAGS = -release 0.0.1
libfoo_la_LIBADD =

bar/Makefile.am:

lib_LTLIBRARIES = libbar.la
libbar_la_SOURCES = Bar.cpp Bar.h
libbar_la_CPPFLAGS =
libbar_la_LDFLAGS = -release 0.0.1
libbar_la_LIBADD = -L../foo -lfoo

wah/Makefile.am

bin_PROGRAMS = wah
wah_SOURCES = main.cpp ../bar/Bar.h
wah_CPPFLAGS =
wah_LDADD = -L../bar -lbar

Here's how it links main.cpp:

make[2]: Entering directory `/xxx/ltp-0.0.1/wah'
g++ -DHAVE_CONFIG_H -I. -I..     -g -O2 -MT wah-main.o -MD -MP -MF .deps/wah-main.Tpo -c -o wah-main.o `test -f 'main.cpp' || echo './'`main.cpp
mv -f .deps/wah-main.Tpo .deps/wah-main.Po
/bin/bash ../libtool --tag=CXX   --mode=link g++  -g -O2   -o wah wah-main.o -L../bar -lbar 
libtool: link: g++ -g -O2 -o .libs/wah wah-main.o  -L../bar /xxx/ltp-0.0.1/bar/.libs/libbar.so -L../foo /xxx/ltp-0.0.1/foo/.libs/libfoo.so

isn't libtool supposed to do that for me automagically?

Yes, it does, at least when the distribution tarball is created on a non-Ubuntu distribution. After I autoreconf on an Ubuntu box, I get the same error you do. Apparently (according to adl) the Ubuntu distro has a patched version of libtool which sets the libtool script variable:

link_all_deplibs=no

I patched the configure generated libtool script to replace all these instances with:

link_all_deplibs=unknown

and everything linked as expected. I suppose you could do the same in a script that invokes autoreconf. Or install a non-patched version of libtool on the Ubuntu host. Or patch the patched libtool on the Ubuntu host. So there's a few options on how to fix it.

Monday answered 18/8, 2012 at 3:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.