Announcing Dolt, a drop-in Libtool replacement which cuts build times in half
- From: Josh Triplett <josh freedesktop org>
- To: debian-devel lists debian org, xorg lists freedesktop org, libtool gnu org, kde-devel kde org, kde-core-devel kde org, gtk-devel-list gnome org, gtk-app-devel-list gnome org, gnome-hackers gnome org, gnome-devel-list gnome org, gnome-devtools gnome org
- Cc: keithp keithp com, bart cs pdx edu, jamey minilop net
- Subject: Announcing Dolt, a drop-in Libtool replacement which cuts build times in half
- Date: Wed, 09 Apr 2008 03:34:18 -0700
Many packages use GNU autotools (automake and autoconf) to build, to
the point that "./configure && make" represents one of the most common
build procedures for Free Software packages. Libraries using
autotools typically use GNU Libtool, partly because it works on almost
any system and partly because autotools makes it difficult to do
otherwise. Packages which use these libraries sometimes use libtool
as well.
Yet for many of these libraries and other packages, more than half of
the build time goes into running the libtool shell script.
Libtool knows how to handle libraries for umpteen different systems,
including many ancient systems that have terrible shared library
support. It has some extensive shell script logic to figure out how
to build libraries for your system, and how to compile objects that go
in those libraries. This logic does an amazingly impressive job of
coping with adverse conditions. However, this logic all lives in an
~8500 line, ~250kB shell script, which runs *every single time you
compile a source file*.
This does not do wonders for performance.
Meanwhile, modern systems such as GNU/Linux have reasonable library
mechanisms, and need relatively little of the machinery in libtool.
On these common systems, it would significantly improve build times to
avoid running that libtool machinery for every compilation.
Thus, I wrote Dolt, a drop-in replacement for libtool's compilation
mode. Dolt runs any necessary system-specific or
configuration-specific logic as part of configure, writes out a simple
shell script "doltcompile"[1], and substitutes it for libtool in the
automake variables LTCOMPILE and LTCXXCOMPILE. If you use automake,
autoconf, and libtool, then using Dolt just requires two steps:
1) add "DOLT" after the call to LT_INIT, AC_PATH_LIBTOOL, or
AM_PATH_LIBTOOL in your configure.ac or configure.in script, and
2) append dolt.m4 to your project's acinclude.m4.
For any system Dolt does not support, it will transparently fall back
to libtool.
dolt.m4 takes up less than 4kB; it writes out a minimal doltcompile
script which never forks except to run the compiler or to mkdir the
.libs directory if it doesn't already exist. I have tested it with
various projects, and benchmarked[2] its performance against the same
projects using only libtool. Results:
kdelibs without dolt: 8m6.115s
kdelibs with dolt: 3m50.065s
gtk+-2.0 without dolt: 2m31.825s
gtk+-2.0 with dolt: 1m33.858s
libx11 without dolt: 1m50.163s
libx11 with dolt: 0m53.417s
libxml2 without dolt: 0m25.722s
libxml2 with dolt: 0m19.576s
dbus without dolt: 0m20.062s
dbus with dolt: 0m8.940s
I have attached a snapshot of dolt.m4 for convenience. You can also
obtain the current version of Dolt from Git with:
git clone git://svcs.cs.pdx.edu/git/dolt
or download a snapshot tarball from
<http://svcs.cs.pdx.edu/gitweb?p=dolt.git;a=snapshot;h=master;sf=tgz>.
Please try Dolt with your project, and see if you get comparable
performance improvements. If you want to make Dolt replace libtool on
your system, feel free to send me a patch to dolt.m4; just remember
the basic tenet that any logic must run at configure time, not build
time. You can figure out what compiler flags libtool uses by running
"touch dummy.c && libtool --mode=compile gcc -c dummy.c -o dummy.lo";
that will print two compiler command lines, one for the shared object
and one for the static object.
Future directions:
* Support GNU/Linux on architectures other than x86 and x86-64. I
think most will work with exactly the same compiler flags, but I
didn't want to add any architecture I couldn't test.
* Support other systems.
* Possibly try to run libtool on a dummy source file at configure time
to figure out the necessary flags to use when building library
objects, but that seems error-prone.
* Replace libtool --mode=link.
* Replace libtool --mode=install.
* Optionally stop installing .la files.
* Make dolt.m4's output of doltcompile cleaner.
- Josh Triplett
[1] "doltcompile" stands for "do ltcompile"; the alternate reading
"dolt compile" led to the name "dolt".
[2] General testing methodology:
* Run ./configure && make && make clean, to make sure it builds and to get
everything cached.
* Get the "before" time: time make >/dev/null 2>&1
* Remove and re-extract the source.
* Add dolt.m4 to acinclude.m4 and add DOLT to configure.in or configure.ac.
* autoreconf -v -f -i && ./configure && make && make clean, to
make sure it still builds and to get everything cached again.
* Get the "after" time: time make >/dev/null 2>&1
dnl dolt, a replacement for libtool
dnl Copyright © 2007-2008 Josh Triplett <josh freedesktop org>
dnl Copying and distribution of this file, with or without modification,
dnl are permitted in any medium without royalty provided the copyright
dnl notice and this notice are preserved.
dnl
dnl To use dolt, invoke the DOLT macro immediately after the libtool macros.
dnl Optionally, copy this file into acinclude.m4, to avoid the need to have it
dnl installed when running autoconf on your project.
AC_DEFUN([DOLT], [
AC_REQUIRE([AC_CANONICAL_HOST])
# dolt, a replacement for libtool
# Josh Triplett <josh freedesktop org>
AC_PATH_PROG(DOLT_BASH, bash)
AC_MSG_CHECKING([if libtool sucks])
AC_MSG_RESULT([yup, it does])
AC_MSG_CHECKING([if dolt supports this host])
dolt_supported=yes
if test x$DOLT_BASH = x; then
dolt_supported=no
fi
if test x$GCC != xyes; then
dolt_supported=no
fi
case $host in
i?86-*-linux*|x86_64-*-linux*) ;;
*) dolt_supported=no ;;
esac
if test x$dolt_supported = xno ; then
AC_MSG_RESULT([no, falling back to libtool])
else
AC_MSG_RESULT([yes, replacing libtool])
dnl Start writing out doltcompile.
cat <<__DOLTCOMPILE__EOF__ >doltcompile
#!$DOLT_BASH
__DOLTCOMPILE__EOF__
cat <<'__DOLTCOMPILE__EOF__' >>doltcompile
args=("$[]@")
for ((arg=0; arg<${#args@<:@@@:>@}; arg++)) ; do
if test x"${args@<:@$arg@:>@}" = x-o ; then
objarg=$((arg+1))
break
fi
done
if test x$objarg = x ; then
echo 'Error: no -o on compiler command line' 1>&2
exit 1
fi
lo="${args@<:@$objarg@:>@}"
obj="${lo%.lo}"
if test x"$lo" = x"$obj" ; then
echo "Error: libtool object file name \"$lo\" does not end in .lo" 1>&2
exit 1
fi
objbase="${obj##*/}"
__DOLTCOMPILE__EOF__
dnl Write out shared compilation code.
if test x$enable_shared = xyes; then
cat <<'__DOLTCOMPILE__EOF__' >>doltcompile
libobjdir="${obj%$objbase}.libs"
if test ! -d "$libobjdir" ; then
mkdir "$libobjdir"
mkdir_ret=$?
if test "$mkdir_ret" -ne 0 && test ! -d "$libobjdir" ; then
exit $mkdir_ret
fi
fi
pic_object="$libobjdir/$objbase.o"
args@<:@$objarg@:>@="$pic_object"
"${args@<:@@@:>@}" -fPIC -DPIC
__DOLTCOMPILE__EOF__
fi
dnl Write out static compilation code.
dnl Avoid duplicate compiler output if also building shared objects.
if test x$enable_static = xyes; then
cat <<'__DOLTCOMPILE__EOF__' >>doltcompile
non_pic_object="$obj.o"
args@<:@$objarg@:>@="$non_pic_object"
__DOLTCOMPILE__EOF__
if test x$enable_shared = xyes; then
cat <<'__DOLTCOMPILE__EOF__' >>doltcompile
"${args@<:@@@:>@}" >/dev/null 2>&1
__DOLTCOMPILE__EOF__
else
cat <<'__DOLTCOMPILE__EOF__' >>doltcompile
"${args@<:@@@:>@}"
__DOLTCOMPILE__EOF__
fi
fi
dnl Write out the code to write the .lo file.
dnl The second line of the .lo file must match "^# Generated by .*libtool"
cat <<'__DOLTCOMPILE__EOF__' >>doltcompile
{
echo "# $lo - a libtool object file"
echo "# Generated by doltcompile, not libtool"
__DOLTCOMPILE__EOF__
if test x$enable_shared = xyes; then
cat <<'__DOLTCOMPILE__EOF__' >>doltcompile
echo "pic_object='$pic_object'"
__DOLTCOMPILE__EOF__
else
cat <<'__DOLTCOMPILE__EOF__' >>doltcompile
echo pic_object=none
__DOLTCOMPILE__EOF__
fi
if test x$enable_static = xyes; then
cat <<'__DOLTCOMPILE__EOF__' >>doltcompile
echo "non_pic_object='$non_pic_object'"
__DOLTCOMPILE__EOF__
else
cat <<'__DOLTCOMPILE__EOF__' >>doltcompile
echo non_pic_object=none
__DOLTCOMPILE__EOF__
fi
cat <<'__DOLTCOMPILE__EOF__' >>doltcompile
} > "$lo"
__DOLTCOMPILE__EOF__
dnl Done writing out doltcompile; substitute it for libtool compilation.
chmod +x doltcompile
LTCOMPILE='$(top_builddir)/doltcompile $(COMPILE)'
AC_SUBST(LTCOMPILE)
LTCXXCOMPILE='$(top_builddir)/doltcompile $(CXXCOMPILE)'
AC_SUBST(LTCXXCOMPILE)
fi
# end dolt
])
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]