Libtool Roadmap
Alex Ameen <[email protected]>
| Newsgroups | gmane.comp.gnu.libtool.general |
|---|---|
| Message-ID | <[email protected]> |
Howdy, a few weeks ago I talked about sending out a road-map. I've gotten that prepared today. This roadmap is informal, opinionated, and *I encourage feedback* and discussion on it. I have my own biases and opinions about things I like/dislike and want added based on my `libtool' usage over the years. However, I would be doing a disservice to users if I forced them to adopt "my way of using `libtool'" over their own. With that in mind it's important for y'all to share your own use cases and pain points so that I can address them. This might be more accurately called a "giant RFC dump" than a roadmap, because it's hard for me to imagine that this remains unchanged. The only notable item I have not included here is some organizational changes concerning how bugs/patches are submitted ( currently there's 3 ways to submit bug reports and 2 of them are miserable to process ); but I'll address that in another thread. Also note that in my discussion of "CI" ( Continuous Integration ) setup, I intend to provide sufficient abstraction that with some tailoring automated `libtool' testing can be accessible to other developers. This will not be a "core" feature of `libtool', it is rather a practical necessity for maintenance. I am not and will not be making commitments on behalf of the `libtool' team to gate releases based on regression for any particular combination of platforms or tools. Rather you can look at this as "I want to improve the existing Hydra infrastructure, make it more accessible, and find ways to support platforms which cannot natively run Nix or Hydra", this may mean creating more abstract job declarations in a format with can be processed by a wider range of CI tools, it may mean VMs will be used for some testing, it may mean that Hydra is dropped altogether ( unlikely ). Time will tell. These tasks are what I have in mind for the immediate future. Long term I'd like to work more closely with the other Autotools teams to improve integration with the rest of the family, and make `libtool' more extensible, but those are conversations for another day. ------------------------------------------------------------------------ ━━━━━━━━━━━━━━━━━ LIBTOOL-ROADMAP Alex Ameen ━━━━━━━━━━━━━━━━━ Table of Contents ───────────────── 1. Roadmap .. 1. Improve `.la' libraries, or phase them out on certain platforms. ..... 1. Libtool should not use `libfoo.la' when `libfoo.EXT' are requested. ..... 2. Make installation of `.lt' libraries optional. ..... 3. Prevent over-linking of ELF binaries. ..... 4. Security .. 2. Support `$ORIGIN' in ELF binaries’ `RPATH' and `RUNPATH' entries. .. 3. Avoid use of wrapper scripts for `noinst_' and `nodist_' binaries. .. 4. Refactor argument parsing, particularly parsing linker flags. .. 5. Migrate platform, arch, and tool specific conditionals to `autoconf'. .. 6. Expand usage of `M4SH' for creating `ltmain.sh' and `libtoolize.in'. .. 7. Simplify `bootstrap' process. .. 8. Make the creation of test cases more user friendly .. 9. Create CI pipeline resources for distribution and tool maintainers .. 10. Permit installable LTLIBRARIES to conditionally be “convenience libraries” 1 Roadmap ═════════ 1.1 Improve `.la' libraries, or phase them out on certain platforms. ──────────────────────────────────────────────────────────────────── 1.1.1 Libtool should not use `libfoo.la' when `libfoo.EXT' are requested. ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ What I mean is, if I say `-lfoo', of `-l:libfoo.la', then go right ahead, do your thing `libtool'. However, when I went out of my way to say `-l:libfoo.so' or `/trust/the/user/libfoo.a', it is evil for `libtool' to silently decide that it knows best and decide to use `libfoo.la' regardless. • This behavior leads a large number of package managers and distributions to delete `.la' files before distributing binary tarballs. • This frequently leads to incorrect/unexpected libraries and flags being used because they were written as dependencies or inherited flags in a `.la' file. 1.1.2 Make installation of `.lt' libraries optional. ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ • Closing Argument: ┌──── │ libtool: link: warning: library `/tmp/usr/lib/libstdc++.la' was moved. │ libtool: link: warning: library `/tmp/usr/lib/libstdc++.la' was moved. │ libtool: link: warning: library `/tmp/usr/lib/libstdc++.la' was moved. │ libtool: link: warning: library `/tmp/usr/lib/libstdc++.la' was moved. │ libtool: link: warning: library `/tmp/usr/lib/libstdc++.la' was moved. │ libtool: link: warning: library `/tmp/usr/lib/libstdc++.la' was moved. │ libtool: link: warning: library `/tmp/usr/lib/libstdc++.la' was moved. │ libtool: link: warning: library `/tmp/usr/lib/libstdc++.la' was moved. └──── Should people learn to use `DESTDIR'? Sure, but it’s hard enough to defend the usefulness of `.la' when it has a meltdown like this over binaries which were safely moved. 1.1.3 Prevent over-linking of ELF binaries. ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ Unless a popular patch for `ltmain.sh' was applied to a project, `libtool' will over-link unneeded dependencies in ELF binaries. This often leads to unexpected/incorrect library load/initialization ordering, particularly in cases where libraries have circular dependencies. • “Libraries shouldn’t have circular dependencies” is not a valid excuse. • This has a measurable impact on performance in large applications, and makes interposing symbols nearly impossible. • This behavior severely aggravates C++ initialization ordering issues. • Makes the use of ELF filtering extensions impractical. 1.1.4 Security ╌╌╌╌╌╌╌╌╌╌╌╌╌╌ The ability to pass flags to consumers is useful, but this behavior requires more visibility, and serious scrutiny concerning security. • Expecting users to inspect `.la' files recursively, or always build dry runs to audit flags is utterly fanciful. 1.2 Support `$ORIGIN' in ELF binaries’ `RPATH' and `RUNPATH' entries. ───────────────────────────────────────────────────────────────────── 1.3 Avoid use of wrapper scripts for `noinst_' and `nodist_' binaries. ────────────────────────────────────────────────────────────────────── “When possible” of course. While these scripts mean well, they are difficult to circumvent when a use case requires direct execution of a binary. Further, the availability of `$ORIGIN' on ELF platforms makes these wrappers unnecessary or counter-intuitive. 1.4 Refactor argument parsing, particularly parsing linker flags. ───────────────────────────────────────────────────────────────── • It’s incomprehensible, and inline comments indicate that for several years people have been unable to figure out why certain quirks like “libraries are in reverse order in this block for some reason” exist. • When performing any changes to the parser test cases should be created to ensure that behavior remains consistent ( unless a latent bug is fixed ). 1.5 Migrate platform, arch, and tool specific conditionals to `autoconf'. ───────────────────────────────────────────────────────────────────────── For example, if I configure `./configure --host_os='$(build_os)'', or if a compiler/linker is known at configure time, much of the runtime probing which is currently performed is redundant. • Obviously, for a global `libtool' install on a system, this optimization would not be performed. Rather this aims to optimize `ltmain.sh --> libtool' creation performed in a project tree alongside `autoconf'. 1.6 Expand usage of `M4SH' for creating `ltmain.sh' and `libtoolize.in'. ──────────────────────────────────────────────────────────────────────── In practice I aim to split these scripts into smaller parts which are easier to read and reason about in isolation. • More modular snippets may be easier to unit test. • Use of `M4SH' may also permit users to patch/extend `libtool' more easily. • This will allow us to phase out `funclib.sh' over time, and align idiomatically with the other `autotools'. 1.7 Simplify `bootstrap' process. ───────────────────────────────── While the bootstrapping script is really more geared for maintainers and contributors working in the repository, as opposed to the source tarballs which users download, the existing process’ complexity and dependence on external repositories complicates efforts to build `libtool' using CI. • Use of `git' and reliance on a network connection to vendor external repositories during the bootstrap phase complicates conventional hashing approaches used to cache CI artifacts. • Requiring a network connection for bootstrapping raises security concerns which would make automatic testing of patch submissions unsafe. • Ideally bootstrapping `libtool' should be possible using a minimal tool-chain. Likely `coreutils' ( or equivalent ), `awk', `sed', `grep', `tar', `cc', `binutils' ( or equivalent ), `make', `autoconf', `automake', `m4', `findutils', `tar', and `xz'. Dependence on `texinfo', `help2man', etc could be optional. • Parts of `gnulib' which we require should be vendored. The existing bootstrap process checks out a specific commit of `gnulib' and `gl/bootstrap', so vendoring this code is functionally equivalent. 1.8 Make the creation of test cases more user friendly ────────────────────────────────────────────────────── While the existing documentation recommends that folks submitting issues create a test case which reproduces their problem, the complexity of the test suite makes that impractical. • The existing test suite is robust, and I have no intention of replacing it, however creating an avenue for contributors/users to draft simple `sh' scripts or minimal `autotools' projects for reproducing issues should be as user friendly as possible. • If creating test cases is not convenient, contributors and users simply won’t do it, and the burden of authoring these tests will fall to the `libtool' team. Often `libtool' team members do not readily have access to the effected platform, or lack experience with a given platform and tool-set’s quirks. A practical and predictable, consequence is that certain platforms and tool-chains lack robust testing. 1.9 Create CI pipeline resources for distribution and tool maintainers ────────────────────────────────────────────────────────────────────── This would likely be placed in a branch or separate repository. The goal here is that a declarative CI pipeline for testing `libtool' be drafted such that members of the `libtool' team, or external projects which want to integrate with `libtool' may self-host a set of CI jobs used to build and test `libtool' with parameterized inputs. • For example, if I am a `coreutils' contributor, it may be useful to drop in an alpha build of `coreutils' to see if it blows up `libtool'. • Similarly, if I am a `libtool' contributor, it may be useful to automatically test a matrix of `autoconf' and `automake' versions to see if we have broken compatibility with a particular release of those tools. • Currently we often don’t hear about changes which broke a niche combination of platform, arch, and tool-set combinations until after a release is out, and people submit issues. While it’s not possible to expand an infinite matrix of combinations, real time feedback for systems other than a team member’s daily driver could catch a large number of issues before they are released. 1.10 Permit installable LTLIBRARIES to conditionally be “convenience libraries” ─────────────────────────────────────────────────────────────────────────────── This aims to support projects which produce different sets of libraries when a static vs. shared library build is being run. Largely this effects the handling of internal utility libraries with hidden symbol visibility. • For clarity “convenience” libraries are simply `PIC' `libfoo.a' libraries, or equivalent for a given platform. • This is particularly applicable to `noinst_PROGRAMS' used at build time which depend on installable libraries. A `noinst_PROGRAMS' executable would likely prefer linking with a static “convenience” library rather than a shared library, since they generally do not require a wrapper script. • With a plain `Makefile' it is trivial to produce either a `libfoo.so', static `libfoo.a', and `PIC' `libfoo.a' during a single run. `libtool'’s concept of “convenience” libraries make it difficult to replicate this workflow for arbitrary reasons. • Ex: Project wants to produce `libfoo.la' and `libbar.la' to make their public interfaces available to users. Both `libfoo.la' and `libbar.la' depend on `libquux.la', which does not contain “user facing” public interfaces. Project may wish to install `libfoo.so' and `libbar.so' which link `PIC' `libquux.a' with `hidden' symbol visibility when `-shared' is in effect, but may wish to install `libfoo.a', `libbar.a', and `libquux.a' when `-static' is in effect. • Ex: A project may wish to conditionally produce a `libquux.so', or roll `libquux.a' into `libfoo.so' such that `libbar.so' may satisfy its undefined references in for `libquux.la' through `libfoo.so'. • Ex: When performing unit tests linking `PIC' `libfoo.a' rather than `libfoo.so' into a test executable `mytest' allows `mytest' run without a wrapper, so that it may be moved to and run in arbitrary directories. Frankly if I’m authoring tests, the `libtool' wrapper over executables may be more of a headache than a convenience. • As niche as these use-cases may sound, there are variety of reasons for a project to produce any of `libfoo.so', static `libfoo.a', and `PIC' `libfoo.a' during a single build/install. • To accomplish this in existing releases of `libtool', project authors would be required to define `libquux.la' “twice”, once as a “convenience” library, and again as an installable `LTLIBRARY' with identical sources and flags. It might also be necessary for users to configure and/or build twice to get the desired outputs. My preference is “DRY”.