Subject: bug#27722: libtool makes it impossible to build a package statically

From: Bruno Haible <[email-masked]>
Date: Sun, 16 Jul 2017 00:42:58 +0200

Hi,

Summary
-------

The processing of the '-static' option by "libtool --mode=link" makes it
impossible to build a package in such a way that
  1) all libraries are static,
  2) all binaries are statically linked (ldd reports "not a dynamic executable").

Motivation
----------

There are many use-cases of statically linked binaries. In my case it's
because I want to run programs under qemu in "user mode", and for big-endian
CPUs currently only statically linked binaries work. [1]

Details
-------

In packages that don't create shared libraries and therefore don't use libtool,
the way to achieve statically linked binaries (assuming GCC) is simple:

  $ ./configure LDFLAGS="-static"

For packages that create *only* shared libraries, the GNU libtool manual
provides a solution [2][3]:

  $ ./configure --enable-static --disable-shared LDFLAGS="-all-static"

But this is not a general solution: Some packages, like GNU libffcall,
create shared libraries AND static libraries. But there is only 1 LDFLAGS
parameter that can be passed to 'configure'.

'configure' (thankfully!) does not take 2 different variables LDFLAGS
(for non-libtool linking) and LTLDFLAGS (for libtool linking), because
the use of libtool is an internal detail of a package, and the user who
wants to install it should not see added complexity because of libtool.

So,
1) $ ./configure --enable-static --disable-shared LDFLAGS="-static"
   does not work for producing statically linked binaries because libtool
   intercepts the 'static' option. The result (according to 'ldd') is
   a binary that is linked against the *shared* libc.
2) $ ./configure --enable-static --disable-shared LDFLAGS="-all-static"
   does not work because GCC does not understand a '-all-static' option.
3) The hint given in [4]
   $ ./configure --enable-static --disable-shared LDFLAGS="-Xcompiler -static"
   does not work because GCC does not understand a '-Xcompiler' option.

How to reproduce
----------------

$ wget https://haible.de/bruno/gnu/libiconv-20170715.tar.gz

1) $ tar xvfz libiconv-20170715.tar.gz
   $ cd libiconv-20170715
   $ ./configure --enable-static --disable-shared LDFLAGS="-static"
   $ make
   $ make install DESTDIR=/tmp/inst
   $ LC_ALL=C ldd /tmp/inst/usr/local/bin/iconv
           linux-vdso.so.1 =>  (0x00007fff1a74d000)
           libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fddde90b000)
           /lib64/ld-linux-x86-64.so.2 (0x00005580e2f6c000)

2) $ tar xvfz libiconv-20170715.tar.gz
   $ cd libiconv-20170715
   $ ./configure --enable-static --disable-shared LDFLAGS="-all-static"
   ...
   checking whether the C compiler works... no
   configure: error: in `/tmp/libiconv-20170715':
   configure: error: C compiler cannot create executables
   See `config.log' for more details

3) $ tar xvfz libiconv-20170715.tar.gz
   $ cd libiconv-20170715
   $ ./configure --enable-static --disable-shared LDFLAGS="-Xcompiler -static"
   ...
   checking whether the C compiler works... no
   configure: error: in `/tmp/libiconv-20170715':
   configure: error: C compiler cannot create executables
   See `config.log' for more details

Past reports
------------

In 2004, this was discussed here: [5] already gave the solution, namely to
rename libtool's options. [6] gives the rationale.

For the specific case of GNU binutils, it was reported in 2011: [7][8]

Reported again in 2012: [9][10]

My workaround
-------------

I work around it with the solution from [5]. Instead of '-lt-static'
I chose '-static-uninstalled-libs', in order to reduce the confusion
with the existing option '-static-libtool-libs'.

Patch attached. It touches only the *link* mode of libtool. I don't
see a reason for touching the *compile* mode of libtool, since the
right place for the '-static' option is LDFLAGS, not CFLAGS. [11]

With this patch, it works as expected:

   $ tar xvfz libiconv-20170715.tar.gz
   $ cd libiconv-20170715
   $ patch -p1 < /tmp/libtool-allow-static.diff
   $ ./configure --enable-static --disable-shared LDFLAGS="-static"
   $ make
   $ make install DESTDIR=/tmp/inst
   $ LC_ALL=C ldd /tmp/inst/usr/local/bin/iconv
           not a dynamic executable

Best regards,

         Bruno

[1] https://bugs.launchpad.net/qemu/+bug/1701798
[2] https://www.gnu.org/software/libtool/manual/html_node/LT_005fINIT.html
[3] https://www.sourceware.org/autobook/autobook/autobook_59.html#Linking-against-Libtool-Libraries-with-Automake
[4] https://debbugs.gnu.org/cgi/bugreport.cgi?bug=11064
[5] https://lists.gnu.org/archive/html/libtool/2004-11/msg00017.html
[6] https://lists.gnu.org/archive/html/libtool/2004-11/msg00024.html
[7] https://sourceware.org/ml/binutils/2011-08/msg00159.html
[8] https://sourceware.org/bugzilla/show_bug.cgi?id=13891
[9] https://debbugs.gnu.org/cgi/bugreport.cgi?bug=11064
[10] https://lists.gnu.org/archive/html/bug-libtool/2012-03/msg00011.html
[11] https://www.gnu.org/software/autoconf/manual/autoconf-2.69/html_node/Preset-Output-Variables.html
diff --git a/build-aux/ltmain.sh b/build-aux/ltmain.sh
index 0f0a2da..1d0185a 100644
--- a/build-aux/ltmain.sh
+++ b/build-aux/ltmain.sh
@@ -3720,6 +3720,7 @@ a program from several object files.
 The following components of LINK-COMMAND are treated specially:
 
   -all-static       do not do any dynamic linking at all
+  -static           do not do any dynamic linking at all
   -avoid-version    do not add a version suffix if possible
   -bindir BINDIR    specify path to binaries directory (for systems where
                     libraries must be found in the PATH setting at runtime)
@@ -3746,7 +3747,8 @@ The following components of LINK-COMMAND are treated specially:
   -R[ ]LIBDIR       add LIBDIR to the runtime path of programs and libraries
   -shared           only do dynamic linking of libtool libraries
   -shrext SUFFIX    override the standard shared library file extension
-  -static           do not do any dynamic linking of uninstalled libtool libraries
+  -static-uninstalled-libs
+                    do not do any dynamic linking of uninstalled libtool libraries
   -static-libtool-libs
                     do not do any dynamic linking of libtool libraries
   -version-info CURRENT[:REVISION[:AGE]]
@@ -6573,9 +6575,9 @@ func_mode_link ()
 	build_old_libs=no
 	break
 	;;
-      -all-static | -static | -static-libtool-libs)
+      -all-static | -static | -static-uninstalled-libs | -static-libtool-libs)
 	case $arg in
-	-all-static)
+	-all-static | -static)
 	  if test yes = "$build_libtool_libs" && test -z "$link_static_flag"; then
 	    func_warning "complete static linking is impossible in this configuration"
 	  fi
@@ -6584,7 +6586,7 @@ func_mode_link ()
 	  fi
 	  prefer_static_libs=yes
 	  ;;
-	-static)
+	-static-uninstalled-libs)
 	  if test -z "$pic_flag" && test -n "$link_static_flag"; then
 	    dlopen_self=$dlopen_self_static
 	  fi
@@ -6883,7 +6885,7 @@ func_mode_link ()
       prevarg=$arg
 
       case $arg in
-      -all-static)
+      -all-static | -static)
 	if test -n "$link_static_flag"; then
 	  # See comment for -static flag below, for more details.
 	  func_append compile_command " $link_static_flag"
@@ -7174,9 +7176,9 @@ func_mode_link ()
 	continue
 	;;
 
-      -static | -static-libtool-libs)
-	# The effects of -static are defined in a previous loop.
-	# We used to do the same as -all-static on platforms that
+      -static-uninstalled-libs | -static-libtool-libs)
+	# The effects of -static-uninstalled-libs are defined in a previous
+	# loop.  We used to do the same as -all-static on platforms that
 	# didn't have a PIC flag, but the assumption that the effects
 	# would be equivalent was wrong.  It would break on at least
 	# Digital Unix and AIX.