# HG changeset patch
# User Ray Donnelly <mingw.android@gmail.com>
# Date 1391501320 0
#      Tue Feb 04 08:08:40 2014 +0000
# Node ID c1090b01b5b41ab3a346cb946b3a51a16109b876
# Parent  56f50b772982bc99cd1a7b1c8fc5afa5e8d7c751
{e}glibc: Fix various multilib build bugs

--host=${CT_TARGET} with eg -m32 is not right.
The arch part must be correct (i686 for 32-bit
and x86_64 for 64-bit). Un-fortunately GCC has
no mechanism for returning each arches triplet
so instead some hacks are used. Debian can ask
"gcc -m32 -print-multiarch" but this flag isnt
provided on other GCC builds.

The old symlinks from lib32/64 to lib are only
made if CT_MULTILIB=n, and the comment that we
are not multilib on the target side corrected.

The stub libc.so is compiled with extra_cflags
so that it is for the correct multilib arch.

The stub libc.so and crt*.o files are moved to
the multilib os directory and not the multilib
directory if gcc arg -print-multi-os-directory
is supported.

--libdir=<> is passed to libc's configure such
that it is made inplace in the multilib-os dir
and 'Fixing up multilib location' is no longer
required.

The multilib directories are sorted in reverse
order so that x86_64 is built finally. This is
because x86_64 headers are multilib-capable as
far back as glibc-2.15 (at least) whereas i686
headers were not multilib-capable until 2.16.

Utilizes get_multilib_target by Cody P Schafer

Signed-off-by: Ray Donnelly <mingw.android@gmail.com>
Signed-off-by: Cody P Schafer <dev@codyps.com>

diff -r 56f50b772982 -r c1090b01b5b4 scripts/build/cc/gcc.sh
--- a/scripts/build/cc/gcc.sh	Tue Feb 04 07:55:11 2014 +0000
+++ b/scripts/build/cc/gcc.sh	Tue Feb 04 08:08:40 2014 +0000
@@ -375,6 +375,7 @@
 
     if [ "${CT_MULTILIB}" = "y" ]; then
         extra_config+=("--enable-multilib")
+        extra_config+=("--enable-targets=all")
     else
         extra_config+=("--disable-multilib")
     fi
diff -r 56f50b772982 -r c1090b01b5b4 scripts/build/libc/glibc-eglibc.sh-common
--- a/scripts/build/libc/glibc-eglibc.sh-common	Tue Feb 04 07:55:11 2014 +0000
+++ b/scripts/build/libc/glibc-eglibc.sh-common	Tue Feb 04 08:08:40 2014 +0000
@@ -65,6 +65,64 @@
     do_libc_backend libc_mode=final
 }
 
+
+# Usage: get_multilib_target <multilib-flags>
+# Credit: Cody Schafer
+get_multilib_target () {
+    local multi_flags="$1"
+    local target="${CT_TARGET}"
+    local m32=false
+    local m31=false
+    local m64=false
+    local mx32=false
+    local mlittle=false
+    local mbig=flase
+
+    case "$multi_flags" in
+    *-m32*) m32=true;;
+    *-m64*) m64=true;;
+    *-m31*) m31=true;; # s390
+    *-mx32*) mx32=true ;; # x86_64
+
+    # powerpc
+    *-mbig*) mbig=true ;;
+    *-mlittle*) mlittle=true ;;
+
+    # mips
+    *-EL*) mlittle=true ;;
+    *-EB*) mbig=true ;;
+
+    esac
+
+    # TODO: actually run $CC with the multi_flags and check things out
+    # Right now we make some assumptions about bitness based on the target if
+    # _not_ overriden by multiflags. triplets in CT_TARGET that indicate they
+    # 64bit are assumed to not be hiding any funky configure options to change
+    # that. Similar for 32bit.
+
+    case "${CT_TARGET}" in
+    # FIXME: do we need to adjust the target for le vs be?
+    powerpc-*|powerpcle-*)     $m64 && target=${target/powerpc-/powerpc64-} ;;
+    powerpc64-*|powerpc64le-*) $m32 && target=${target/powerpc64-/powerpc-} ;;
+
+    x86_64-*gnux32)     $m64  && target=${target/%-gnux32/-gnu} ;;
+    x86_64-*)           $m32  && target=${target/x86_64-/i686-} ;;
+    x86_64-*)           $mx32 && target=${target/%-gnux32/-gnu} ;;
+
+    i[34567]86-*gnux32) die "Invalid target \"${CT_TARGET}\"" ;; # Nope
+    i[34567]86-*)       $mx32 && {
+                                        target=${target/%-gnu/-gnux32}
+                                        target=${target/i[34567]86-/x86_64-}
+                        } ;; # This is also very questionable (and probably wrong)
+    i[34567]86-*)       $m64 && target=${target/i[34567]86-/x86_64-} ;;
+
+    # TODO: mips, arm, spark
+
+    esac
+
+    echo "$target"
+}
+
 # This backend builds the C library once for each multilib
 # variant the compiler gives us
 # Usage: do_libc_backend param=value [...]
@@ -76,6 +134,8 @@
     local multilib
     local multi_dir
     local multi_flags
+    local multi_arch
+    local target
     local extra_dir
     local libc_headers libc_startfiles libc_full
     local hdr
@@ -103,8 +163,16 @@
 
     # If gcc is not configured for multilib, it still prints
     # a single line for the default settings
-    multilibs=( $("${CT_TARGET}-gcc" -print-multi-lib 2>/dev/null) )
+    # sort -r is a hack so that x86_64 gets built last because
+    # pre-2.16 only the x86_64 headers were applicable to both
+    # i686 and x86_64.
+    # The headers were unified (x86-64 won!) between 2.15 and
+    # 2.16 (BZ14117). This hack makes too many of assumptions
+    # and needs to be replaced with more robust logic. We need
+    # to force x86_64 arch to be last element in the array.
+    multilibs=( $("${CT_TARGET}-gcc" -print-multi-lib 2>/dev/null | sort -r) )
     for multilib in "${multilibs[@]}"; do
+        multi_arch="${native_arch}"
         multi_dir="${multilib%%;*}"
         if [ "${multi_dir}" != "." ]; then
             CT_DoStep INFO "Building for multilib subdir='${multi_dir}'"
@@ -114,6 +182,10 @@
                           )"
             extra_dir="/${multi_dir}"
 
+            # If more substitutions are needed then they
+            # should be added here, AArch64 for example?
+            target = $(get_multilib_target "${extra_flags}")
+
             # glibc install its files in ${extra_dir}/{usr/,}lib
             # while gcc expects them in {,usr/}lib/${extra_dir}.
             # Prepare some symlinks so glibc installs in fact in
@@ -136,40 +208,20 @@
             extra_dir=
             extra_flags=
             libc_headers="${hdr}"
+            target="${CT_TARGET}"
         fi
 
         CT_mkdir_pushd "${CT_BUILD_DIR}/build-libc-${libc_mode}${extra_dir//\//_}"
 
-        do_libc_backend_once extra_dir="${extra_dir}"               \
-                             extra_flags="${extra_flags}"           \
-                             libc_headers="${libc_headers}"         \
-                             libc_startfiles="${libc_startfiles}"   \
+        do_libc_backend_once extra_dir="${extra_dir}"              \
+                             extra_flags="${extra_flags}"          \
+                             libc_headers="${libc_headers}"        \
+                             libc_startfiles="${libc_startfiles}"  \
+                             libc_triplet="${target}"              \
                              libc_full="${libc_full}"
 
         CT_Popd
 
-        if [ "${multi_dir}" != "." ]; then
-            if [ "${libc_mode}" = "final" ]; then
-                CT_DoLog EXTRA "Fixing up multilib location"
-
-                # rewrite the library multiplexers
-                for d in "lib/${multi_dir}" "usr/lib/${multi_dir}"; do
-                    for l in libc libpthread libgcc_s; do
-                        if [    -f "${CT_SYSROOT_DIR}/${d}/${l}.so"    \
-                             -a ! -L ${CT_SYSROOT_DIR}/${d}/${l}.so    ]
-                        then
-                            CT_DoExecLog DEBUG ${sed} -r -i                                 \
-                                                      -e "s:/lib/:/lib/${multi_dir}/:g;"    \
-                                                      "${CT_SYSROOT_DIR}/${d}/${l}.so"
-                        fi
-                    done
-                done
-                # Remove the multi_dir now it is no longer useful
-                CT_DoExecLog DEBUG rm -rf "${CT_SYSROOT_DIR}/${multi_dir}"
-            fi # libc_mode == final
-
-            CT_EndStep
-        fi
     done
 
     CT_EndStep
@@ -180,6 +232,7 @@
 #   Parameter           : Definition                            : Type      : Default
 #   libc_headers        : Build libc headers                    : bool      : n
 #   libc_startfiles     : Build libc start-files                : bool      : n
+#   libc_triplet        : Build libc triplet                    : string    : ${CT_TARGET}
 #   libc_full           : Build full libc                       : bool      : n
 #   extra_flags         : Extra CFLAGS to use (for multilib)    : string    : (empty)
 #   extra_dir           : Extra subdir for multilib             : string    : (empty)
@@ -189,6 +242,9 @@
     local libc_full
     local extra_flags
     local extra_dir
+    local extraos_dir
+    local lib_dir
+    local install_root
     local src_dir="${CT_SRC_DIR}/${CT_LIBC}-${CT_LIBC_VERSION}"
     local extra_cc_args
     local -a extra_config
@@ -196,6 +252,7 @@
     local glibc_cflags
     local float_extra
     local endian_extra
+    local libc_triplet="${CT_TARGET}"
     local arg
 
     for arg in "$@"; do
@@ -328,6 +385,29 @@
     # or even after they get installed...
     echo "ac_cv_path_BASH_SHELL=/bin/bash" >>config.cache
 
+    # GCC makes the distinction between multilib directories
+    # (gotten via -print-multilib or -print-multi-directory)
+    # and multilib-os directories (via -print-multi-os-directory)
+    # They are also often horribly mis-aligned, such as:
+    # multilib:    -m32=32      -m64=.
+    # multilib-os: -m32=../lib  -m64=../lib64
+    # it is important that multilib sub-folders of the sysroot use
+    # the multilib-os directory and *not* the multilib directory.
+    # The multilib directory is a GCC implementation detail rather
+    # than something that users need to be concerned about. Older
+    # GCCs do not understand -print-multi-os-directory so we fall
+    # back on some simple transformations (that are wrong in the
+    # above example!)
+    if "${cross_cc}" -print-multi-os-directory ${extra_cc_args} > /dev/null 2>&1; then
+        lib_dir=/usr/lib/$("${cross_cc}" -print-multi-os-directory ${extra_cc_args})
+        install_root="${CT_SYSROOT_DIR}"
+    else
+        # maintain the previous behaviour if -print-multi-os-directory doesn't work.
+        lib_dir=/usr/lib
+        install_root="${CT_SYSROOT_DIR}${extra_dir}"
+    fi
+    extraos_dir="${install_root}${lib_dir}"
+
     # Configure with --prefix the way we want it on the target...
     # There are a whole lot of settings here.  You'll probably want
     # to read up on what they all mean, and customize a bit, possibly by setting GLIBC_EXTRA_CONFIG_ARRAY
@@ -338,11 +418,14 @@
     # Run explicitly through CONFIG_SHELL, or the build breaks badly (loop-of-death)
     # when the shell is not bash... Sigh... :-(
 
-    CT_DoLog DEBUG "Using gcc for target    : '${cross_cc}'"
-    CT_DoLog DEBUG "Configuring with addons : '$(do_libc_add_ons_list ,)'"
-    CT_DoLog DEBUG "Extra config args passed: '${extra_config[*]}'"
-    CT_DoLog DEBUG "Extra CC args passed    : '${glibc_cflags}'"
-    CT_DoLog DEBUG "Extra flags (multilib)  : '${extra_flags}'"
+    CT_DoLog DEBUG "Using gcc for target     : '${cross_cc}'"
+    CT_DoLog DEBUG "Configuring with addons  : '$(do_libc_add_ons_list ,)'"
+    CT_DoLog DEBUG "Extra config args passed : '${extra_config[*]}'"
+    CT_DoLog DEBUG "Extra CC args passed     : '${glibc_cflags}'"
+    CT_DoLog DEBUG "Extra flags (multilib)   : '${extra_flags}'"
+    CT_DoLog DEBUG "Multilib os dir          : '${extraos_dir}'"
+    CT_DoLog DEBUG "Configuring with --host  : '${libc_triplet}'"
+    CT_DoLog DEBUG "Configuring with --libdir: '${lib_dir}'"
 
     CT_DoExecLog CFG                                                \
     BUILD_CC="${CT_BUILD}-gcc"                                      \
@@ -354,12 +437,13 @@
     "${src_dir}/configure"                                          \
         --prefix=/usr                                               \
         --build=${CT_BUILD}                                         \
-        --host=${CT_TARGET}                                         \
+        --host=${libc_triplet}                                      \
         --cache-file="$(pwd)/config.cache"                          \
         --without-cvs                                               \
         --disable-profile                                           \
         --without-gd                                                \
         --with-headers="${CT_HEADERS_DIR}"                          \
+        --libdir=${lib_dir}                                         \
         "${extra_config[@]}"                                        \
         "${CT_LIBC_GLIBC_EXTRA_CONFIG_ARRAY[@]}"
 
@@ -378,7 +462,7 @@
         # use the 'install-headers' makefile target to install the
         # headers
         CT_DoExecLog ALL make ${JOBSFLAGS}                          \
-                         install_root=${CT_SYSROOT_DIR}${extra_dir} \
+                         install_root="${install_root}"             \
                          install-bootstrap-headers=yes              \
                          "${extra_make_args[@]}"                    \
                          install-headers
@@ -427,22 +511,23 @@
 
             # there are a few object files needed to link shared libraries,
             # which we build and install by hand
-            CT_DoExecLog ALL mkdir -p "${CT_SYSROOT_DIR}${extra_dir}/usr/lib"
+            CT_DoExecLog ALL mkdir -p "${extraos_dir}"
             CT_DoExecLog ALL make ${JOBSFLAGS}  \
                         "${extra_make_args[@]}" \
                         csu/subdir_lib
             CT_DoExecLog ALL cp csu/crt1.o csu/crti.o csu/crtn.o    \
-                                "${CT_SYSROOT_DIR}${extra_dir}/usr/lib"
+                                "${extraos_dir}"
 
             # Finally, 'libgcc_s.so' requires a 'libc.so' to link against.
             # However, since we will never actually execute its code,
             # it doesn't matter what it contains.  So, treating '/dev/null'
             # as a C source file, we produce a dummy 'libc.so' in one step
-            CT_DoExecLog ALL "${cross_cc}" -nostdlib        \
+            CT_DoExecLog ALL "${cross_cc}" ${extra_flags}   \
+                                            -nostdlib       \
                                            -nostartfiles    \
                                            -shared          \
                                            -x c /dev/null   \
-                                           -o "${CT_SYSROOT_DIR}${extra_dir}/usr/lib/libc.so"
+                                           -o "${extraos_dir}/libc.so"
         fi # threads == nptl
     fi # libc_headers == y
 
@@ -453,9 +538,9 @@
                               all
 
         CT_DoLog EXTRA "Installing C library"
-        CT_DoExecLog ALL make ${JOBSFLAGS}                                  \
-                              "${extra_make_args[@]}"                       \
-                              install_root="${CT_SYSROOT_DIR}${extra_dir}"  \
+        CT_DoExecLog ALL make ${JOBSFLAGS}                    \
+                              "${extra_make_args[@]}"         \
+                              install_root="${install_root}"  \
                               install
 
         if [ "${CT_BUILD_MANUALS}" = "y" ]; then
