slibtool: a skinny libtool implementation, written in C
January 4, 2020 ยท View on GitHub
slibtool is an independent reimplementation of the widely used libtool,
written in C. slibtool is designed to be a clean, fast, easy-to-use
libtool drop-in replacement, and is accordingly aimed at package authors,
distro developers, and system integrators. slibtool maintains compatibility
with libtool in nearly every aspect of the tool's functionality as well as
semantics, leaving out (or turning into a no-op) only a small number of
features that are no longer needed on modern systems.
Being a compiled binary, and although not primarily written for the sake of
performance, building a package with slibtool is often faster than with its
script-based counterpart. The resulting performance gain would normally vary
between packages, and is most noticeable in builds that invoke libtool a large
number of times, and which are characterized by the short compilation duration
of individual translation units.
why reimplement libtool?
Midipix targets use the PE binary format, and so require import library integration on the one hand, yet follow ELF naming conventions (i.e. libfoo.so.x.y.z) on the other. In consequence, midipix shared libraries are not fully supported by existing libtool implementations. As an interim solution used for the porting of gcc, a libtool script generated by ltmain.sh was hand-edited so that it would correctly produce the host's shared libraries as part of the toolchain build process.
Bypassing the libtool script generated by a package's ltmain.sh requires
overriding the LIBTOOL variable as part of invoking make(1). In that
sense, and unless midipix support is added to every single ltmain.sh in
every single package that uses autotools, it does not truly matter whether
the surrogate libtool that one chooses be a script, a program written in C,
or something else.
At the time of this writing, an average libtool script consists of about
10K lines of code with several hundred case-esac statements and a similar
number of if-then blocks. In view of the length of the generated script,
and in light of its challenging logic and overall complexity, a rewrite of
the tool in C seemed to be the right choice not only with respect to quality,
readability, and anticipated performance, but also in terms of development
effort, ease of customization, and long-term maintenance.
Requirements for building slibtool
- a C toolchain, consisting of
- a C compiler such as gcc, clang, or cparser;
- the compiler should support -std=c99;
- the system's libc should support -D_XOPEN_SOURCE=700.
If building for (native) mingw development, please cross-build slibtool under your posix environment of choice (e.g. midipix, cygwin, msys2) and install it alongside the rest of your (cross-built) mingw toolchain.
If your system libc only supports -D_XOPEN_SOURCE=600 then you should be able to build slibtool after slightly tweaking the code and/or setting a few config-time environment variables (such as CFLAGS and LDFLAGS).
Usage
With most packages, simply adding LIBTOOL=slibtool to the make invocation
should suffice. To have slibtool operate in debug mode (outputting a colorized
raw argument vector), use LIBTOOL=dlibtool instead, or alternatively add
--debug to the libtool flags inside of your Makefile.
Corner cases
Some programs which make heavy use of recursive make are known to drop the
LIBTOOL value at some point in the process, and as such you may additionally
need to export the environment variable; export MAKE="make LIBTOOL=slibtool".
slibtool additionally installs two symlinks that are the equivalent of
-disable-shared and -disable-static, named slibtool-static and
slibtool-shared, respectively. These symlinks should be used when building
packages that have the above switches hard-coded into the generated libtool
script; two examples of such packages are binutils and gdb, which both
have shared library builds disabled by default. A quick way to determine
whether this invocation form is appropriate with a specific package is to
run ./libtool --features from the build directory, then check whether the
output has either shared or static library builds disabled. When slibtool
is invoked as a basic tool (i.e. slibtool, dlibtool, etc.), then building
of both a shared library and a static archive is enabled by default.
Differences from GNU libtool
While slibtool aims to be compatible with all common usages of libtool at the
build system level, there exist several differences at the implementation level
that should be noted.
-
.la wrappersare always generated, but by default are never installed;.la wrapperscontain key information that is provided to libtool when generating a shared library or static archive, and which is needed when passing the archive or library as an input argument in .la form to the compiler driver in subsequent link steps. Sinceslibtoolis entirely independent of the above wrappers with respect to its own functionality, and given its announced goal to remain compatible with the script-based libtool as much as possible,slibtool's behavior is to always produce.la wrapperson the one hand, yet fully ignore their content on the other.Despite their internal nature, installed .la wrappers are often [ab]used in strange and mysterious ways by distro-related tools other than libtool itself. For the sake of distributions that depend on the aforementioned wrappers, slibtool comes with three special symlinks named
clibtool,clibtool-shared, andclibtool-static, respectively. The'c'inclibtoolstands forcompatible, and accordingly indicates an end-user's preference towards perfect emulation of legacy behavior. -
-rpathargument values are passed to the compiler and linker as needed only;-rpathis often [mis]used by libtool to add redundant paths to a program's linker search path. When using slibtool,-rpathargument values are only forwarded to the compiler and linker when pointing to non-default linker directories, and are accordingly filtered out when pointing to default library locations (i.e./usr/lib,/lib, and so on). -
no-ops
-R, which adds a path to the generated program's run-time search path; this switch is currently not needed, and is accordingly ignored.-export-symbols, which exports symbols listed in a given file, and-export-symbols-regex, which exports symbols matching a regex; both are unimplemented because similar functionality has long been provided by the compiler or toolchain;gcchas supported setting ELF visibility since v4.0, for instance, and PE import library support is provided by slibtool via the --output-def linker switch and a subsequent invocation of dlltool.-no-install, which considers the executable wrapper to be optional; this switch is not needed on modern systems, and is accordingly ignored.
-
No
libltdl. libltdl is nowadays no longer needed; it serves to provide adlopen()functionality on systems which do not offer it, i.e. HP-UX and BeOS, however since neither HP-UX nor BeOS is currently supported by slibtool, there exists no urgent need to provide equivalent functionality.
Development
Major changes to slibtool should be discussed on #midipix prior to pursuing a considerable effort, and patches should be sent, gpg-signed, to the project maintainer; before hacking on slibtool, please take a moment of your time and read the CONTRIB document.
As you finalize your changes to the code, please consider building at least
once with cparser as the compiler. cparser is excellent at catching logical
errors and semantic flaws, and as of the time of this writing is capable of
spotting bugs that go unnoticed by other major compilers. For a few examples
of such hidden bugs, see commits 94d109f, 1142bf2, and 55c95a8.
License
slibtool is distributed under a permissive MIT license.