[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: -Wl,--as-needed considered possibly harmful

On Thu, 2007-12-20 at 00:51 -0800, Steve Langasek wrote:
> On Mon, Dec 10, 2007 at 09:47:36PM +0100, Simon Richter wrote:
> >>> No, what can be done is to fix upstream's broken declaration that 'you can
> >>> assume glib functions are available when doing "#include <gtk/gtk.h>"'.  It
> >>> doesn't follow that just because this works in practice, it should be a
> >>> supported usage.
> >> When many of the types used by GTK+ are those provided by GLib, it
> >> sounds wrong to ask developers to include the GLib headers to have these
> >> types available.
> > If it is really expected that type declarations are to be shared between a 
> > program and a library, then the program becomes dependent on the library's 
> > ABI without this dependency being formally expressed in any usable form, 
> > which is broken in and by itself.
> > GTK needs to provide its own definitions of types and not expose interfaces 
> > it does not control.
> Fine in theory, in practice this can be a significant burden to the library
> maintainer.  FWIW, I don't see any reason why a library can't use
> externally-defined types directly, /as long as/ they have some mechanism for
> ensuring ABI consistency between the two libraries (i.e., an ABI change in
> the underlying library is always accompanied by an soname change in the
> dependent library).

I'd make a stronger statement and say that reusing types is a positive
thing. If you are reusing a glib list in your pet library, creating your
own type makes your library incompatible with other libraries also using
glib lists and providing code to manipulate them... and if it doesn't
make it incompatible then its not going to achieve the ABI
considerations that are under discussion here.

So really I think each dependant library of a library that is
dynamically linked to falls into one of two categories:
 - internal detail
 - implementation detail resulting in exposed ABI

So if I link program X against libfoo which uses libbar, if libbar is an
internal detail of libfoo then:
libfoo -> libbar@some ABI
X -> libfoo@libfoo's ABI only.

And a rebuild of libfoo to link a new libbar ABI won't break X, nor will
it require a rebuild of X. 

The conditions for internal detail only are very stringent: compiler
alignment, structure sizes etc etc for all non opaque (where opaque is
opaque to the /compiler/ not to the user's code!) exported types of
libfoo must not be dependent on libbar at all.

I doubt that many libraries will meet this requirement for all their
dependent libraries (and consider libc as just an extremely common case
of this).

For all other cases, when a used ABI gets exposed, while we may not want
X to depend (at the package level) on libbar; at an ABI level it does.
We need to decide how we represent that. We also have at least two
dimensions here:
runtime linker behaviour
package management behaviour

From the runtime linker we want:
 * an error/warning/something when two instances of the same API with
different ABI's are loaded. This commonly occurs when libbar.1 and
libbar.2 are both loaded, but it can occur more generally when libbar is
renamed to libquux and then libbar.1 and libquux.2 are loaded (by X and
libfoo respectively).
 * To be able to interrogate how something was linked sufficiently well
to generate packaging metadata automatically.

From the package manager we want:
 * To know when we have to rebuild X because libbar has changed.
 * To allow upgrades to libbar on users systems without changing X when

The case where libbar is an internal detail is trivial (detection isn't:
see abicheck and icheck - libraries really need icheck in the package
build rules IMNSHO); I'm going to ignore it here. 

For the case where libbar is not an internal detail. Starting with
packaging as thats easiest:
 * we should depend on a minimum version of the libbar we need (as we
already bump the package name when the ABI changes incompatibly in a
library this is straight forward) and gives the opportunity to upgrade
libbar within an ABI safely.
 * we can do an rdepends on e.g. libbar2 when libbar's API changes from
2 to 3 to find packages we need to rebuild.

One defect here is when symbols are shared from within a non-library -
e.g. the case with some programs plugin's. Here, a plugin may use a
symbol from within the program X, which is ABI dependent all the way
back, so treating programs as libraries - that is having an ABI - might
make sense. I haven't considered this in detail...

The runtime loader is more tricky:
 * If we link X to libfoo only:
   - libfoo's soname has to be manually changed when libbar's changes or
hilarity results
   - we don't have a robust way that I know of to interrogate X to find
out that we need a package dependency on libbar
   + we don't need to have libbar present when it is only optionally
used (that is by calling some libfoo feature that needs libbar)

 * If we link X to libbar directly:
   - because we can't tell how much of recent changes to libbar are
needed, any installation of a build of X will force an upgrade of libbar
to the version it was built against, unless a bunch of extra effort is
put in.
   + we can determine that X has a dependency on libbar specifically
   - we always require libbar to be present (IIRC)

I don't think we have a good answer to this in general, and I think we
need to do some infrastructure work to be able to have one.

> (BTW, pkg-config upstream wrongly claims that exporting dependent libs
> in the pkg-config --libs output provides this protection. :/)

It doesn't? (I must be missing something as I thought it did, just over


GPG key available at: <http://www.robertcollins.net/keys.txt>.

Attachment: signature.asc
Description: This is a digitally signed message part

Reply to: