From 70819a18bf9c452d229e587e03b26bfa44f10686 Mon Sep 17 00:00:00 2001
From: Mohammad Akhlaghi <mohammad@akhlaghi.org>
Date: Thu, 8 Aug 2019 14:17:25 +0100
Subject: Static PatchELF only built when static C library exists

Until now, when building PatchELF, we would always require that it be done
statically. However, some systems don't have a static C library available
for linking. This cause a crash in the static building of PatchELF. But a
static PatchELF is necessary for correcting RPATH in GCC's outputs.

With this commit, in the configure script we check if a static C library is
linkable for the compiler. If it isn't then `host_cc' will be set to 1 and
GCC won't be built. We also pass the result of this test to `basic.mk'
(through `good_static_lib'), so if a static C library isn't available, it
builds a dynamically linked PatchELF.

This bug was reported by Elham Saremi.
---
 reproduce/software/bash/configure.sh | 66 ++++++++++++++++++++++++++++++++----
 reproduce/software/make/basic.mk     | 17 ++++++----
 2 files changed, 69 insertions(+), 14 deletions(-)

(limited to 'reproduce/software')

diff --git a/reproduce/software/bash/configure.sh b/reproduce/software/bash/configure.sh
index be9c635..14268d9 100755
--- a/reproduce/software/bash/configure.sh
+++ b/reproduce/software/bash/configure.sh
@@ -866,11 +866,11 @@ fi
 # example `/usr/include/x86_64-linux-gnu/') that are automatically included
 # in an installed GCC. HOWEVER during the build of GCC, all those other
 # directories are ignored. So even if they exist, they are useless.
-warningsleep=0
+gccwarning=0
 if [ $host_cc = 0 ]; then
     if ! [ -f /usr/include/sys/cdefs.h ]; then
         host_cc=1
-        warningsleep=1
+        gccwarning=1
         cat <<EOF
 
 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
@@ -893,7 +893,7 @@ EOF
         host_cc=$host_cc
     else
         host_cc=1
-        warningsleep=1
+        gccwarning=1
         cat <<EOF
 
 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
@@ -902,8 +902,8 @@ EOF
 
 This system doesn't have '/usr/lib/libc.a' or '/usr/lib64/libc.a'. Because
 of this, the project can't build its custom GCC to ensure better
-reproducibility. We strongly recommend installing the proper package (for
-your operating system) that installs this necessary file.
+reproducibility. We recommend installing the proper package (for your
+operating system) that installs this necessary file.
 
 Some possible solutions:
   1. On some Debian-based GNU/Linux distros, these two packages may fix the
@@ -919,8 +919,60 @@ Some possible solutions:
 
 EOF
     fi
+fi
 
-    if [ $warningsleep = 1 ]; then
+# See if a link-able static C library exists
+# ------------------------------------------
+#
+# After building GCC, we must use PatchELF to correct its RPATHs. However,
+# PatchELF links internally with `libstdc++'. So a dynamicly linked
+# PatchELF cannot be used to correct the links to `libstdc++' in general
+# (on some systems this causes no problem, but on others it doesn't!).
+#
+# However, to build a Static PatchELF, we need to be able to link with the
+# static C library, which is not always available on some GNU/Linux
+# systems. Therefore we need to check this here. If we can't build a static
+# PatchELF, we won't build any GCC either.
+if [ $host_cc = 0 ]; then
+    testprog=$tmpblddir/test-c
+    testsource=$tmpblddir/test.c
+    echo; echo; echo "Checking if static C library is available...";
+    echo "#include <stdio.h>"                       > $testsource
+    echo "#include <stdlib.h>"                     >> $testsource
+    echo "int main(void){printf(\"...yes\");"      >> $testsource
+    echo "               return EXIT_SUCCESS;}"    >> $testsource
+    if gcc $testsource -o$testprog -static -lc && $testprog; then
+        good_static_libc=1
+        rm $testsource $testprog
+    else
+        good_static_libc=0
+        rm $testsource
+        gccwarning=1
+        host_cc=1
+        cat <<EOF
+
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!         Warning        !!!!!!!!!!!!!!!!!!!!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+A usable static C library ('libc.a', in any directory) cannot be linked in
+the current settings of this system. Because of this we can't build a
+static PatchELF, hence we can't build GCC.
+
+If you have 'libc.a', but in a non-standard location (for example in
+'/PATH/TO/STATIC/LIBC/libc.a'), please run this command, then re-configure
+the project to fix this problem.
+
+export LDFLAGS="-L/PATH/TO/STATIC/LIBC \$LDFLAGS"
+
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+EOF
+    fi
+fi
+
+# Print a warning if GCC is not meant to be built.
+if [ $gccwarning = 1 ]; then
         cat <<EOF
 
 PLEASE SEE THE WARNINGS ABOVE.
@@ -932,7 +984,6 @@ compiler, then re-run './project configure'.
 
 EOF
         sleep 5
-    fi
 fi
 
 
@@ -1115,6 +1166,7 @@ fi
 # tools, but we have to be very portable (and use minimal features in all).
 echo; echo "Building necessary software (if necessary)..."
 make -f reproduce/software/make/basic.mk \
+     good_static_libc=$good_static_libc \
      rpath_command=$rpath_command \
      static_build=$static_build \
      needs_ldl=$needs_ldl \
diff --git a/reproduce/software/make/basic.mk b/reproduce/software/make/basic.mk
index 4e6d5fa..04edf1a 100644
--- a/reproduce/software/make/basic.mk
+++ b/reproduce/software/make/basic.mk
@@ -546,14 +546,17 @@ $(ibidir)/readline: $(tdir)/readline-$(readline-version).tar.gz \
 	                SHLIB_LIBS="-lncursesw" -j$(numthreads)) \
 	&& echo "GNU Readline $(readline-version)" > $@
 
-# Patchelf has to be built statically because it links with the C++
-# standard library. Therefore while fixing rpath in `libstdc++' with
-# Patchelf we can have a segmentation fault. Note that Patchelf is only for
-# GNU/Linux systems, so there is no problem with having the `-static' flag
-# in LDFLAGS.
+# When we have a static C library, PatchELF will be built statically. This
+# is because PatchELF links with the C++ standard library. But we need to
+# run PatchELF later on `libstdc++'! This circular dependency can cause a
+# crash, so when PatchELF can't be built statically, we won't build GCC
+# either, see the `configure.sh' script where we define `good_static_libc'
+# for more.
 $(ibidir)/patchelf: $(tdir)/patchelf-$(patchelf-version).tar.gz \
                     $(ibidir)/make
-	export LDFLAGS="$$LDFLAGS -static"; \
+	if [ $(good_static_libc) = 1 ]; then \
+	  export LDFLAGS="$$LDFLAGS -static"; \
+	fi; \
 	$(call gbuild, $<, patchelf-$(patchelf-version), static) \
 	&& echo "PatchELF $(patchelf-version)" > $@
 
@@ -595,7 +598,7 @@ needpatchelf = $(ibidir)/patchelf
 endif
 $(ibidir)/bash: $(tdir)/bash-$(bash-version).tar.lz \
                 $(ibidir)/readline                  \
-                $(needpatchelf)
+                | $(needpatchelf)
 
         # Delete the (possibly) existing Bash executable.
 	rm -f $(ibdir)/bash
-- 
cgit v1.2.1