Bug#340904: [Steve Langasek] Bug#340904: Bug#349318: fixed in xft 2.1.8.2-1

2006-02-11 Thread Steve Langasek
On Thu, Feb 09, 2006 at 06:59:02PM +0800, James Henstridge wrote:
 Steve Langasek wrote:

 If Xft is updated to a new version of either of those libraries such
 that those types are defined differently (altered struct layout,
 different type sizes, etc), then the app also needs to be updated to the
 new version.

 Ok, here's the problem with this argument.

 Yes, if one of the freetype types that's used in Xft/Xft.h changes, that is
 an ABI change... *in libXft* -- that's why we care about it!  Because it's
 an ABI change in libXft, the soname of *libXft* should change.  With the
 change of libXft's soname, there's no reason an application that is a
 consumer of libXft, but *not* a consumer of freetype, should care about
 libfreetype *at all*.[1]

 The simple matter of fact is that when you ask for the Xft API in your
 app (#include Xft/Xft.h), you also get the freetype API at the same
 time.  While some apps don't use it, we can't say that apps don't use
 those APIs in the general case.

You're right, we can't.  But as library authors/maintainers, we can say
whether we intend to *support* such abuses of the API.  You can get a valid
prototype of fprintf() on Linux by doing #include sql.h (from UnixODBC)
instead of #include stdio.h, too, and we don't know that there isn't
anybody relying on that -- but if they do, and they complain about it
breaking, they are cordially invited to blow it out their ass. ;)

The current policy of pkg-config prevents library authors from making their
own choices about whether to support such API abuses on the part of
applications.  I don't think pkg-config should be imposing policies which
prevent library authors from deciding what uses of their headers they intend
to support.  The current behavior of pkg-config *ensures* that the API
abuses you describe will work, because use of Requires means they'll get the
ldflags as well as the cflags; that makes pkg-config as it stands pretty
suboptimal for anyone who *doesn't* want to get supporting their lib
dependencies as part of the public API.

 On the other hand, there are plenty of cases in which an ABI change in
 libfreetype will *not* cause an ABI change in libXft.  Addition or removal
 of functions, addition of typedefs, or removal or changing of any typedefs
 not used in libXft's ABI are all changes that should require an soname
 change in libfreetype but not an soname change in libXft.  The present ABI
 transition in libfreetype is such a case.  But because these applications
 are being encouraged to link directly to libfreetype, *even though they
 don't use it*, they have to care about ABI changes that should not affect
 them.

 They are using it in conjunction with the Xft API.  There is no clear
 separation between the Xft APIs that use it and those that don't.  Of
 course, an app that only depends on Xft indirectly and doesn't use Xft's
 APIs doesn't need direct linkage to freetype.

They are using data types defined by freetype in conjunction with the Xft
API.  If they're using function calls from freetype without including
freetype headers, they didn't get that idea from Xft's documentation or by
reading the Xft headers themselves.  Xft's maintainers should not be
constrained by a pkg-config design decision to support people who think
#include Xft/Xft.h is an acceptable substitute for #include
freetype/freetype.h.

 The net result is that pkg-config's handling of Requires/Requires.private is
 directly causing churn in response to ABI changes in any indirect library
 dependencies, where this should be completely unnecessary on GNU/Linux
 platforms.  It increases the chances of segfaults or other failures from
 loading two different versions of a library into memory, and correspondingly
 increases the frequency with which binaries need to be rebuilt in response
 to ABI changes that don't actually concern them.  And it does this entirely
 to support a use case which, as explained above, should not actually exist.

 The app links to multiple versions of library A problem is quite easy
 to diagnose, and also makes it clear that an app needs to be rebuilt if
 the old library version is removed (i.e. the app doesn't start).  The
 app depends on the structure layout of the old version of library A but
 doesn't directly link to library A is more difficult to catch.

The app doesn't depend on the structure layout of the old version of library
A.  It depends on the structure layout of *library B*, which happens to have
*inherited* that structure from the *headers* of library A.  It's entirely
feasible for a library to do this without actually using library A at
runtime; so then you get library B not linking to library A at all, but
because it uses pkg-config to resolve the header reference, app C *does* get
linked against it for no reason...

 It sounds like your argument is that Xft shouldn't expose the freetype
 API.  Given that this isn't the case, the direct linkage makes sense. 
 The freetype change in this case might not 

Bug#340904: [Steve Langasek] Bug#340904: Bug#349318: fixed in xft 2.1.8.2-1

2006-02-09 Thread James Henstridge
Steve Langasek wrote:

If Xft is updated to a new version of either of those libraries such
that those types are defined differently (altered struct layout,
different type sizes, etc), then the app also needs to be updated to the
new version.


Ok, here's the problem with this argument.

Yes, if one of the freetype types that's used in Xft/Xft.h changes, that is
an ABI change... *in libXft* -- that's why we care about it!  Because it's
an ABI change in libXft, the soname of *libXft* should change.  With the
change of libXft's soname, there's no reason an application that is a
consumer of libXft, but *not* a consumer of freetype, should care about
libfreetype *at all*.[1]
  

The simple matter of fact is that when you ask for the Xft API in your
app (#include Xft/Xft.h), you also get the freetype API at the same
time.  While some apps don't use it, we can't say that apps don't use
those APIs in the general case.  Until we have a widely used way to
express dependencies at that granularity, you need to look at the
library level.

On the other hand, there are plenty of cases in which an ABI change in
libfreetype will *not* cause an ABI change in libXft.  Addition or removal
of functions, addition of typedefs, or removal or changing of any typedefs
not used in libXft's ABI are all changes that should require an soname
change in libfreetype but not an soname change in libXft.  The present ABI
transition in libfreetype is such a case.  But because these applications
are being encouraged to link directly to libfreetype, *even though they
don't use it*, they have to care about ABI changes that should not affect
them.
  

They are using it in conjunction with the Xft API.  There is no clear
separation between the Xft APIs that use it and those that don't.  Of
course, an app that only depends on Xft indirectly and doesn't use Xft's
APIs doesn't need direct linkage to freetype.

The net result is that pkg-config's handling of Requires/Requires.private is
directly causing churn in response to ABI changes in any indirect library
dependencies, where this should be completely unnecessary on GNU/Linux
platforms.  It increases the chances of segfaults or other failures from
loading two different versions of a library into memory, and correspondingly
increases the frequency with which binaries need to be rebuilt in response
to ABI changes that don't actually concern them.  And it does this entirely
to support a use case which, as explained above, should not actually exist.
  

The app links to multiple versions of library A problem is quite easy
to diagnose, and also makes it clear that an app needs to be rebuilt if
the old library version is removed (i.e. the app doesn't start).  The
app depends on the structure layout of the old version of library A but
doesn't directly link to library A is more difficult to catch.

It sounds like your argument is that Xft shouldn't expose the freetype
API.  Given that this isn't the case, the direct linkage makes sense. 
The freetype change in this case might not break many Xft using apps,
but that won't necessarily be the case next time this type of situation
occurs.

Changes to type definitions _do_ change the ABI.  If library A uses
library B's types in its ABI, then it's ABI will break if library B
changes those types.  An app using library A should definitely record
the version of library B being used.


However:

- If library A's soname is correctly changed in sync with library B's,
  linking application C to library B is redundant.
- If library A's soname is not changed when library B's soname changes,
  pkg-config's behavior does not prevent applications from being broken by
  the ABI change in libA.  At most, it makes it easier to detect such
  breakage due to double-linkage of libB.
  

I'd argue that this is a useful feature to have, rather than having apps
break with no indication of the cause.

The cflags of dependencies listed in Requires.private are not included
for either dynamic or static modes of pkg-config, so maps to case 3
quite well.


Ah, guess I should have looked a bit closer at the behavior in that case.
  

Case 3 was exactly the sort of use case I was trying to model with how
Requires.private functions.

This is unfortunate, because there are a great many packages that are
inheriting dependencies this way on libraries they don't use.  While it is
true that an ABI change in the dependent library will *sometimes* mean an
ABI change in the depending library, this is not always the case.  As a
result, this behavior of pkg-config causes unnecessary churn for packages
depending on libraries in this scenario.  In the case of libxft2, that's
over 400 packages in Debian that are potentially affected.
  

Sure, unnecessary churn is bad and should be avoided.  But you do want
to make sure that the churn happens when required.


Er, the whole reason I'm objecting to the current behavior is that it *is*
unnecessary churn.  If the libfreetype ABI change 

Bug#340904: [Steve Langasek] Bug#340904: Bug#349318: fixed in xft 2.1.8.2-1

2006-02-08 Thread James Henstridge
Tollef Fog Heen wrote:

Hi, any chance you could comment on this?  I'm somewhat inclined to
agree with Steve, but you know this stuff better than I do, so I'd
value a second opinion.

Also, if there's anything unclear or anything, please do mail Steve
(and the bug) with me in Cc.
  

[snip]

  

Both the xrender and freetype2 headers are included in Xft/Xft.h, and types
from both of these headers are exported in the Xft API -- so any software
using Xft.h needs to be able to find these other headers as well.
Currently, pkg-config does *not* pass cflags from packages listed in
Requires.private when called as pkg-config --cflags foo.
  


The fact that the headers are included makes them part of the _public_
ABI of Xft.  There are Xft functions that accept or return types defined
in the Xrender and freetype2 headers.

If Xft is updated to a new version of either of those libraries such
that those types are defined differently (altered struct layout,
different type sizes, etc), then the app also needs to be updated to the
new version.

So far, the maintainer has resisted changing pkg-config to export cflags
(which should really be called cppflags...) from Requires.private due to a
fallacious argument regarding the nature of private dependencies.  There
are three real use cases for libraries which depend on other libraries:

- the library intentionally exports the API and ABI of its dependencies when
  linked to, and therefore both the ldflags and the cflags of its
  dependencies should be exported by pkg-config in all cases[1]
  

Yep, this is the use case addressed by Requires.

- the library intentionally includes headers from dependencies in its own
  headers in order to inherit type definitions, but these definitions are
  not intended for direct consumption by users of this library alone;
  therefore pkg-config must export the cflags from dependencies in all
  cases, but the ldflags only when linking statically
  

Changes to type definitions _do_ change the ABI.  If library A uses
library B's types in its ABI, then it's ABI will break if library B
changes those types.  An app using library A should definitely record
the version of library B being used.

- the library's API includes no headers from its dependencies; pkg-config
  needs to export the ldflags of private dependencies when statically
  linking but not when dynamically linking, and should *never* need to
  export the cflags of these headers.
  

This is the use case for Requires.private.  If the dependency doesn't
form part of the library's API, then it obviously doesn't require direct
linkage and is private.

Please note that today, the handling of Requires.private in pkg-config maps
to *none* of these cases -- I can't think of a single situation in which
cflags of dependencies are needed when statically linking, and not needed
when dynamically linking!

The cflags of dependencies listed in Requires.private are not included
for either dynamic or static modes of pkg-config, so maps to case 3
quite well.

Consider the following two .pc files.  First foo.pc:
  Name: foo
  Description: foo
  Version: 1.0
  Cflags: foo-cflags
  Libs: foo-libs

And bar.pc:
  Name: bar
  Description: bar
  Version: 1.0
  Cflags: bar-cflags
  Libs: bar-libs
  Requires.private: foo

For the dynamic linking case:
  $ pkg-config --cflags bar
  bar-cflags
  $ pkg-config --libs bar
  bar-libs

For the static linking case:
  $ pkg-config --static --cflags bar
  bar-cflags
  $ pkg-config --static --libs bar
  bar-libs foo-libs

  Instead, the Requires.private handling is
adequate for the third case; handling of Requires is correct for the first
case; and there is no combination of options that is appropriate for the
second case.
  

I'd argue that the second case is a strawman.  If a particular library
exposes another in its API/ABI, then it is part of case 1.

This is unfortunate, because there are a great many packages that are
inheriting dependencies this way on libraries they don't use.  While it is
true that an ABI change in the dependent library will *sometimes* mean an
ABI change in the depending library, this is not always the case.  As a
result, this behavior of pkg-config causes unnecessary churn for packages
depending on libraries in this scenario.  In the case of libxft2, that's
over 400 packages in Debian that are potentially affected.
  

Sure, unnecessary churn is bad and should be avoided.  But you do want
to make sure that the churn happens when required.  Relying on indirect
linkage in a lot of cases just results in more fragile applications.

There are cases where it might make sense to move a library to
Requires.private even when it is used in some headers, but I don't
think this is one of them.  Some examples where it would be appropriate
include:

* Cairo's dependency on glitz, xlib and freetype (this one has been
  done upstream).  Apps only depend on glitz if they include
  cairo-glitz.h and use those APIs.  Apps that don't use those
 

Bug#340904: [Steve Langasek] Bug#340904: Bug#349318: fixed in xft 2.1.8.2-1

2006-02-08 Thread Steve Langasek
Hi James,

Nice to meet you!

On Wed, Feb 08, 2006 at 07:28:39PM +0800, James Henstridge wrote:
 Tollef Fog Heen wrote:

 Hi, any chance you could comment on this?  I'm somewhat inclined to
 agree with Steve, but you know this stuff better than I do, so I'd
 value a second opinion.

 Also, if there's anything unclear or anything, please do mail Steve
 (and the bug) with me in Cc.

 [snip]

 Both the xrender and freetype2 headers are included in Xft/Xft.h, and types
 from both of these headers are exported in the Xft API -- so any software
 using Xft.h needs to be able to find these other headers as well.
 Currently, pkg-config does *not* pass cflags from packages listed in
 Requires.private when called as pkg-config --cflags foo.

 The fact that the headers are included makes them part of the _public_
 ABI of Xft.  There are Xft functions that accept or return types defined
 in the Xrender and freetype2 headers.

 If Xft is updated to a new version of either of those libraries such
 that those types are defined differently (altered struct layout,
 different type sizes, etc), then the app also needs to be updated to the
 new version.

Ok, here's the problem with this argument.

Yes, if one of the freetype types that's used in Xft/Xft.h changes, that is
an ABI change... *in libXft* -- that's why we care about it!  Because it's
an ABI change in libXft, the soname of *libXft* should change.  With the
change of libXft's soname, there's no reason an application that is a
consumer of libXft, but *not* a consumer of freetype, should care about
libfreetype *at all*.[1]

On the other hand, there are plenty of cases in which an ABI change in
libfreetype will *not* cause an ABI change in libXft.  Addition or removal
of functions, addition of typedefs, or removal or changing of any typedefs
not used in libXft's ABI are all changes that should require an soname
change in libfreetype but not an soname change in libXft.  The present ABI
transition in libfreetype is such a case.  But because these applications
are being encouraged to link directly to libfreetype, *even though they
don't use it*, they have to care about ABI changes that should not affect
them.

The net result is that pkg-config's handling of Requires/Requires.private is
directly causing churn in response to ABI changes in any indirect library
dependencies, where this should be completely unnecessary on GNU/Linux
platforms.  It increases the chances of segfaults or other failures from
loading two different versions of a library into memory, and correspondingly
increases the frequency with which binaries need to be rebuilt in response
to ABI changes that don't actually concern them.  And it does this entirely
to support a use case which, as explained above, should not actually exist.

 - the library intentionally includes headers from dependencies in its own
   headers in order to inherit type definitions, but these definitions are
   not intended for direct consumption by users of this library alone;
   therefore pkg-config must export the cflags from dependencies in all
   cases, but the ldflags only when linking statically

 Changes to type definitions _do_ change the ABI.  If library A uses
 library B's types in its ABI, then it's ABI will break if library B
 changes those types.  An app using library A should definitely record
 the version of library B being used.

However:

- If library A's soname is correctly changed in sync with library B's,
  linking application C to library B is redundant.
- If library A's soname is not changed when library B's soname changes,
  pkg-config's behavior does not prevent applications from being broken by
  the ABI change in libA.  At most, it makes it easier to detect such
  breakage due to double-linkage of libB.

 Please note that today, the handling of Requires.private in pkg-config maps
 to *none* of these cases -- I can't think of a single situation in which
 cflags of dependencies are needed when statically linking, and not needed
 when dynamically linking!

 The cflags of dependencies listed in Requires.private are not included
 for either dynamic or static modes of pkg-config, so maps to case 3
 quite well.

Ah, guess I should have looked a bit closer at the behavior in that case.

 This is unfortunate, because there are a great many packages that are
 inheriting dependencies this way on libraries they don't use.  While it is
 true that an ABI change in the dependent library will *sometimes* mean an
 ABI change in the depending library, this is not always the case.  As a
 result, this behavior of pkg-config causes unnecessary churn for packages
 depending on libraries in this scenario.  In the case of libxft2, that's
 over 400 packages in Debian that are potentially affected.

 Sure, unnecessary churn is bad and should be avoided.  But you do want
 to make sure that the churn happens when required.

Er, the whole reason I'm objecting to the current behavior is that it *is*
unnecessary churn.  If the libfreetype