Re: libtool (a bit more serious this time)

Date view Thread view Subject view Author view

From: Godmar Back (gback@cs.utah.edu)
Date: Mon Jan 18 1999 - 10:21:21 EST


>
> For an example, assume that a program is linked with libfoo.la, -lbaz
> and -lbar, and -lbaz defines some symbols that are also defined in
> -lbar. Since libfoo.la was linked with -lbar, any undefined symbols
> in libfoo.la but defined in -lbar should be imported from -lbar, and
> not from any other library. In order to ensure that this occurs,
> libtool will actually link the program with `libfoo.${libext} -lbar
> -lbaz -lbar'.
>

No, Alexandre, this is *exactly* what I mean by encouraging user mistakes.

Let's look at it from this perspective: In your example, the final link
line produced by libtool will be 'libfoo.${libext} -lbar -lbaz -lbar'.

In your opinion, this allows libfoo to have its symbols resolved
from -lbar and not from -lbaz, even though -lbaz defines symbols with
the same name, correct?

The proper and more useful behavior, however, would be for libtool to
shout at the user and say: "You dummy attempted to rely on the fact
that the undefined symbols in one library (libfoo) are resolved by a
*specific* second library (libbar). There is no way in this world
I can guarantee that! Don't do this! I, libtool, won't stand for such
fragile and error-prone attempts of using Unix library linking for more
than what its limits are! Take a course on how to write libraries.
If you then still want to do it, you'll have to invoke ld by yourself,
but I, libtool, won't give me reputation and integrity for that."

This is what libtool should say, in my opinion.

> If libtool tried to outsmart you, deciding that you had already
> specified -lbar, so there was no point in specifying -lbar after
> libfoo.${libext}, libfoo would end up having symbols resolved in
> -lbaz, not -lbaz. OTOH, if it decided that your additional
             ^^^^^
[you mean -lbar here, I assume.]
> specification was duplicated and removed it, you'd end up with
> unresolved symbols in -lbaz.
>

The correct way, as I argue it, is follows:

First, libtool should detect that the user tries to link with both
libbar.a and libbaz.a, and that the set of symbols defined by these
libraries define overlaps. It then tells the user about it, flags
an error, and refuses to link this program and awaits further instructions,
since it is likely the user is about to commit or fall victim of a mistake.

A likely mistake, for instance, would be for the creator of libfoo to have
relied on a specific implementation of the symbol "func", namely the one
coming from libbar.

So, libtool says: no. Then it's the user's turn to override.
If the user specifies: "-lfoo -lbaz -lbar", libtool will link it, but will
produce warnings in the manner I suggested should it have to resolve any
symbols defined in libbaz from libbar. This indicates failed attempts
of library overriding.

If the user specifies: "-lfoo -lbar -lbaz", libtool (or ld) will point
out that there are undefined symbols, and suggest a topologically
ordered link line, such as "-lfoo -lbaz -lbar".

> > Lemma 1:
> > A link line should contain every library exactly once.
> > Period. Big Period.

Let me add Lemma 2 before I reply:

    If the user uses libraries in a sane and proper fashion, then there
    exists a topological ordering of libraries on the link line that
    satisfies Lemma 1 and creates a running executable.
                
libtool would be a help if it found out what this ordering is.

>
> I'm sorry, but this lemma is completely bogus. A library should be
> listed as many times as it must in order to ensure that inter-library
> dependencies are correct.
>

We may have different opinions on what inter-library dependencies are.
>From my experience, I know what to call them: they are bugs (in the
vast majority of cases.)

In this definition, I include inter-library dependencies that are
either mutual (liba depends on libb, libb depend on liba), or dependencies
on a specific lib, as in your example above (libfoo depends on "func" in
libbar, not libbaz.)

Dependencies that can be resolved by a topological ordering are okay, so for
instance, all libraries can depend on symbols such as printf in libc.

My point is best summarized as follows:

Unix libraries provide a limited form of componentization, with each
library being a component. Componentization means that a user can create
an application from the components he chooses. Every component must be
written in a way that does not depend on the particular implementation
of another component, only on the contract provided by its interface.
It is up to the user to assemble the components from which to build his
final application.

libtool can be a useful diagnostic tool for doing that, but only if it
sticks to this component model and diagnoses attempts by the user to
violate it, because doing so has been known to highly error prone.
Only in situations where the user has to deal with legacy libraries
that did not follow a proper component model should exceptions be allowed.

Does that make sense?
I know it sounds somewhat dogmatic, but these are my lessons from the
years I spent trying to make library overriding work.

        - Godmar


Date view Thread view Subject view Author view

This archive was generated by hypermail 2b29 : Sat Sep 23 2000 - 19:57:44 EDT