This Time Self-Hosted
dark mode light mode Search

A shared object is (not) enough

In my immediately previous post I have thrown in a couple of nods to two particularly nasty issues related to shared object plugins; I have written extensively, or even excessively, about the issue so I’m not going to write more about the presentation of shared objects (or dynamic libraries if you prefer the Microsoft term for the same concept), and I’d rather go on with the two current problems at hand, which I’ll try to cover in a proper manner.

Shared objects as plugins

When building shared objects for plugin usage, like the case for NSS I noted, PAM plugins or extensions for languages like Ruby, Python, Perl, Java… you don’t need static libraries at all, so a shared object is enough!

While some of those system do support statically linking engine and plugins in an application, this rarely works out as intended; for instance FreeBSD (used to?) support statically linked PAM, but that worked only for the default modules, and if you configured your service authentication chain to use non-default modules you have a non-working setup. So the net result is definitely against having to support statically-linked PAM, or any other statically linked system.

Since you cannot link this stuff statically in, you can easily see that there is no need to install (nor build!) the static archive version of those things; this is usually done properly by both custom-tailored build system (as upstream likely tries to minimise the effort) and by the language-specific buildsystems (like the various incarnation of mkmf and rake-compiler in Ruby, distutils in Python, ant for Java, and so on so forth). On the other hand, especially with autotools-based build system, most people seem to forget that there is a nasty overhead in building both version, beside the waste of installing the extra file.

Indeed, since libtool will prefer building PIC objects for the shared objects (as it’s required for AMD64 and most of non-x86 architectures), and non-PIC objects for static archives (to reduce overhead); since you cannot build once for both (nor you can pre-process once, as you can have __PIC__ conditional code!) you end up having to call the compiler twice for each source file. To reduce this overhead you can usually default to disable static libraries (or disable it through ./configure invocation) or you can disable it altogether as instructed so that it only ever builds the shared object version, and not the static one. Unfortunately this does not stop libtool from installing a pointless .la file but that’s a different story.

While there is a safety check in Portage proper to check for .la and .a files in /lib, there is no such check for Ruby, Python, Perl, Java extensions. My tinderbox has an extra check for that and is usually able to find them; I also have a bug report template that tries explaining the maintainers involved why I report to them that a .la file is pointless and that they might want to fix the eventual static archives at the same time as well. Unfortunately, sometimes people decide it’s too much of a hassle to prepare the patch to send upstream and apply that in Gentoo, so you end up with ebuilds that avoid using make install to avoid installing the already built archives, or just delete them after install (works okay for .la files, since they are usually small and it’s definitely not trivial to avoid installing them), causing the double-build to still be performed.

Boot-critical programs and shared objects

Different page, correlated issue happens with boot-critical programs: things that need to be started before you mount all your local filesystems (maybe because they are needed to mount such filesystems, like lvm) need to have all their shared objects being available at that time. This becomes a problem when you end up needing libraries installed in /usr/lib and you split out /usr (similarly to what I said about /boot I don’t think the general case should be for splitting it out; sure there are cases where it’s needed for various reasons, but it shouldn’t be by default!), as they wouldn’t be able to run.

To solve this problem you either move the libraries (and all their dependencies) to /lib, or you have to statically link applications. The former creates a chain reaction that makes the whole point of splitting /usr mostly moot; the latter problem actually moves the problem down to the user: since Gentoo policy is to never force static linking on the user, as shared object linking has many many advantages, this is usually made conditional to the static USE flag; such a flag will build the software with static linking, and will thus require the dependent libraries to be available in static archive form (which is why rather than Portage features or whatever else, static libraries are usually made optional via an USE flag: it can be depended upon).

Mix the two! Shared object plugins for boot-critical programs!

And here is the reason why I merged the two problems, as they might seem just barely related: there is a case where you actually need a static archive to build a shared object plugin; that’s the case for PAM plugins that need libraries, such as pam_userdb uses Berkeley DB library for storage.

It’s not an easy case to solve, because of course you’d be looking to have the library available as static archive, but at the same time it has to be PIC to work properly… up to the 0.99 version, the solution was to build an internal copy of Berkeley DB within the PAM ebuild; without counting the additional problems with security, we ended up with a very complex ebuild, a lot more complex than it would be needed for PAM alone. I discarded that solution when I took over PAM, and split the Berkeley DB support in its own ebuild… doing the same thing as before. That ebuild has been, up to now, pretty much untouched, and the result is that we have a stale ebuild in tree using a stale version of Berkeley DB. I don’t like that situation at all.

Sincerely, after thinking about it I think the best solution at this point is simply to get rid of the stale ebuild, and decide that even though PAM is installed in /lib, it does not warrant total coverage: we won’t be moving, or building statically, things like PostgreSQL, LDAP, MySQL and so on so forth, and yes, those are all possible providers for the PAM modules. I guess we should just add one very simple statement: don’t use external-dependent modules for authenticating users and services that are boot-critical.

If I’ll still be a Gentoo developer next month, after I free myself up from my current work tasks, I’ll be merging back sys-auth/pam_userdb into sys-libs/pam, and then take care of getting the new PAM stable, and the old ebuild removed. This should solve quite a few of our problems and set a better precedent than what we have right now.

Comments 8
  1. > Unfortunately, sometimes people decide it’s too much of a hassle to prepare the patch to send upstream and apply that in GentooProbably, I misunderstood something here, but why should adding the configure option –disable-static be sent upstream? It is the distributor and not upstream who has to decide whether he wants to build static or dynamic libraries. (OK, for .la file there is no such option, but it is autotools/libtool upstream who should include such an option and not all projects which use these tools.)

  2. BTW: Wouldn’t it be a good idea to make –disable static be part of econf? Those few projects which need static libs could still append –enable-static.I say this, because I have run my gentoo boxes since several months with a containing the line: ${enable_static=no}and had practically never any problems with it: So far, the only projects which wouldn’t build with it are audacity, streamtuner, and gdb (apparently, because they use static libs internally during the build process).

  3. I obviously meant sending upstream the fix for @-shared@ flag in when it makes no sense to have static versions of them (I did so for a few, like libvirt’s Python binding). And it’s not really a good idea to start passing –disable-static unconditionally as it’s going go break the semantic of @econf@ quite badly. It could be done with an EAPI bump but I don’t think it’s worth it.

  4. Of course, it can only be done in a future EAPI. However, when I see suggestions like even including –disable-dependency-tracking to econf (bug 211529, pms already lists it for EAPI=4 despite some protest in this bug) then –disable-static appears to me to be a better idea.

  5. I wonder how things like i.e. splashutils fit into this scheme.Those not only link statically, but alsoneed sources of the libs they link to.While they may have a very good reason for it,it still feels a bit off – especially requiring the sources.

  6. bq. If I’ll still be a Gentoo developer next monthThere’s no alternative to gentoo out there. Without your help, gentoo is doomed. Please, what can we users do to ease your pain?

  7. I don’t think I’m *that* necessary for Gentoo. But unfortunately the problem is not with users, although having more support, and getting those users who *need* bleeding edge *now* even when they don’t really have an use for it to understand that they are just damaging the whole ecosystem would definitely be appreciated 🙂

  8. hi, do you think it would make sense to add static useflags to many ebuilds or the eclasses? i would like to help to make the gentoo install a big smaller and compiletime a bit shorter. or the other “best” approach to this issue?i thought of non-critical stuff, like libpython.a here or similar (at least i think its non-critical :p) thanks

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.