Add support for Canadian cross-compiles.

Restructure the build to clean up some ambiguity (e.g., the
difference between host+target for CONFIG variables) and add
support for doing 3-way builds (BUILD != HOST != TARGET).
This is useful for building fuchsia->bare metal tools from a
linux or mac workstation.

Change-Id: I98d960f7ac4ea5bbe5df40ab9ca20c5e5aba98bd
diff --git a/do-build b/do-build
index b9c6614..94028af 100755
--- a/do-build
+++ b/do-build
@@ -10,8 +10,6 @@
 
 ALL_GNU_TOOLS="ar as gcc ld nm objcopy objdump ranlib readelf"
 
-# Extra tools to build when targeting "*-none" platforms
-TOOLS_none="gdb"
 SUPPORTED_OSES="none linux fuchsia darwin"
 SUPPORTED_ARCHES="arm aarch64 x86_64"
 
@@ -24,7 +22,7 @@
 ## Uses ':' as an option delimiter, to facilitate the use of spaces inside
 ## some options (e.g., CFLAGS).
 # GMP
-CONFIG_GMP_fuchsia="--with-pic=yes"
+CONFIG_GMP_HOST_fuchsia="--with-pic=yes"
 
 # MPFR
 CONFIG_MPFR="--with-pic=yes: \
@@ -38,16 +36,16 @@
 CONFIG_BINUTILS="--with-included-gettext: \
                  --disable-werror: \
                  --enable-initfini-array"
-CONFIG_BINUTILS_none="--enable-gold"
-CONFIG_BINUTILS_x86_64_fuchsia="--enable-gold=default"
-CONFIG_BINUTILS_aarch64_fuchsia="--enable-gold"
-CONFIG_BINUTILS_fuchsia="--enable-plugins: \
-                         --enable-relro"
-CONFIG_BINUTILS_x86_64_none="--enable-targets=x86_64-pep"
+CONFIG_BINUTILS_TARGET_none="--enable-gold"
+CONFIG_BINUTILS_TARGET_x86_64_fuchsia="--enable-gold=default"
+CONFIG_BINUTILS_TARGET_aarch64_fuchsia="--enable-gold"
+CONFIG_BINUTILS_TARGET_fuchsia="--enable-plugins: \
+                                --enable-relro"
+CONFIG_BINUTILS_TARGET_x86_64_none="--enable-targets=x86_64-pep"
 
 # GDB
 CONFIG_GDB="--with-included-gettext:--disable-werror"
-CONFIG_GDB_aarch64_none="--enable-targets=arm-eabi"
+CONFIG_GDB_TARGET_aarch64_none="--enable-targets=arm-eabi"
 
 # GCC
 CONFIG_GCC="--with-included-gettext: \
@@ -56,13 +54,13 @@
             --with-gmp=: \
             --with-mpfr=: \
             --with-mpc="
-CONFIG_GCC_none="--disable-libstdcxx: \
-                 --disable-libssp: \
-                 --disable-libquadmath"
-CONFIG_GCC_fuchsia="--enable-default-pie: \
-                    --disable-multilib"
-CONFIG_GCC_arm="--with-cpu=arm926ej-s: \
-                --with-fpu=vfp"
+CONFIG_GCC_TARGET_none="--disable-libstdcxx: \
+                        --disable-libssp: \
+                        --disable-libquadmath"
+CONFIG_GCC_TARGET_fuchsia="--enable-default-pie: \
+                           --disable-multilib"
+CONFIG_GCC_TARGET_arm="--with-cpu=arm926ej-s: \
+                       --with-fpu=vfp"
 CONFIG_GCC_TOOLS_llvm="CXXFLAGS=-fbracket-depth=1024 -g -O2"
 ### End of configuration options
 
@@ -155,6 +153,9 @@
   split_arch_os "$TARGET"
   local target_arch="$RESULT_ARCH"
   local target_os="$RESULT_OS"
+  split_arch_os "$HOST"
+  local host_arch="$RESULT_ARCH"
+  local host_os="$RESULT_OS"
 
   if [ "$BUILD" == "$HOST" ]
   then
@@ -173,6 +174,9 @@
       return 1
     fi
     return 0
+  elif [ "$host_os" == "fuchsia" ] && [ "$target_os" == "none" ]
+  then
+    return 0
   fi
   return 1
 }
@@ -341,24 +345,19 @@
   RESULT="${!var_name}"
 }
 
-# See if there are any additional tools specified with TOOLS_<arch> or
-# TOOLS_<os>
+# Use the "standard" set of tools except for native builds of a bare-
+# metal toolset, for which we also build gdb.
 build_tool_list()
 {
   split_arch_os "$TARGET"
   local target_arch="$RESULT_ARCH"
   local target_os="$RESULT_OS"
 
-  RESULT="$TOOLS"
-  local arch_specific_var_name="TOOLS_${target_arch}"
-  if [ ! -z "${!arch_specific_var_name}" ]
+  if [ "$BUILD" == "$HOST" ] && [ "$target_os" == "none" ]
   then
-    RESULT="$RESULT ${!arch_specific_var_name}"
-  fi
-  local os_specific_var_name="TOOLS_${target_os}"
-  if [ ! -z "${!os_specific_var_name}" ]
-  then
-    RESULT="$RESULT ${!os_specific_var_name}"
+    RESULT="$TOOLS gdb"
+  else
+    RESULT="$TOOLS"
   fi
 }
 
@@ -419,10 +418,11 @@
 get_build_dir()
 {
   local component="$1"
+  local is_host_lib="$2"  # If set, the TARGET is not applicable
 
   get_component_attribute "$component" "VER"
   local component_ver="$RESULT"
-  if [ "$HOST" == "$TARGET" ]
+  if [ "$HOST" == "$TARGET" ] || [ "$is_host_lib" != "0" ]
   then
     RESULT="$OUT_DIR/build/${component}-${component_ver}_${HOST}"
   else
@@ -526,7 +526,12 @@
 
   if [ "$BUILD" != "$TARGET" ]
   then
-    if ! [ -z "$SYSROOT" ]
+    split_arch_os "$TARGET"
+    local target_os="$RESULT_OS"
+    canonicalize_target_name "$TARGET"
+    local normalized_target="$RESULT"
+
+    if ! [ -z "$SYSROOT" ] && [ "$target_os" != "none" ]
     then
       CONFIG_OPTIONS="$CONFIG_OPTIONS:--with-sysroot=${SYSROOT}"
     fi
@@ -537,29 +542,32 @@
     for tool in $ALL_GNU_TOOLS
     do
       uppercase_tool="$(echo "$tool" | tr '[:lower:]' '[:upper:]')"
-      add_to_flags "${uppercase_tool}_FOR_TARGET" "${TARGET}-${tool}"
+      add_to_flags "${uppercase_tool}_FOR_TARGET" "${normalized_target}-${tool}"
     done
-    add_to_flags "CC_FOR_TARGET" "${TARGET}-gcc"
-    add_to_flags "CXX_FOR_TARGET" "${TARGET}-g++"
+    add_to_flags "CC_FOR_TARGET" "${normalized_target}-gcc"
+    add_to_flags "CXX_FOR_TARGET" "${normalized_target}-g++"
   fi
 }
 
 # Build the configuration options for a specific module, including relevant
 # environment variables of the forms:
 #   CONFIG_<module>
-#   CONFIG_<module>_<arch>
-#   CONFIG_<module>_<os>
-#   CONFIG_<module>_<arch>_<os>
+#   CONFIG_<module>_{HOST|TARGET}_<arch>
+#   CONFIG_<module>_{HOST|TARGET}_<os>
+#   CONFIG_<module>_{HOST|TARGET}<arch>_<os>
 #   CONFIG_<module>_TOOLS_<host-tools>
 build_config_options()
 {
   local component="$1"
-  local is_host_lib="$2"
+  local is_host_lib="$2"  # If set, the TARGET is not applicable
   local install_dir="$3"
 
   local uppercase_component="$(echo "$component" \
                                | tr '[:lower:]' '[:upper:]')"
 
+  split_arch_os "$HOST"
+  local host_arch="$RESULT_ARCH"
+  local host_os="$RESULT_OS"
   split_arch_os "$TARGET"
   local target_arch="$RESULT_ARCH"
   local target_os="$RESULT_OS"
@@ -570,15 +578,21 @@
     canonicalize_target_name "$HOST"
     CONFIG_OPTIONS="$CONFIG_OPTIONS:--host=${RESULT}"
   fi
-  if [ "$TARGET" != "$HOST" ] && [ "$is_host_lib" == '0' ]
+  if [ "$TARGET" != "$HOST" ] && [ "$is_host_lib" == "0" ]
   then
     canonicalize_target_name "$TARGET"
     CONFIG_OPTIONS="$CONFIG_OPTIONS:--target=${RESULT}"
   fi
   add_config_options "$uppercase_component"
-  add_config_options "${uppercase_component}_${target_arch}"
-  add_config_options "${uppercase_component}_${target_os}"
-  add_config_options "${uppercase_component}_${target_arch}_${target_os}"
+  add_config_options "${uppercase_component}_HOST_${host_arch}"
+  add_config_options "${uppercase_component}_HOST_${host_os}"
+  add_config_options "${uppercase_component}_HOST_${host_arch}_${host_os}"
+  if [ "$is_host_lib" == "0" ]
+  then
+    add_config_options "${uppercase_component}_TARGET_${target_arch}"
+    add_config_options "${uppercase_component}_TARGET_${target_os}"
+    add_config_options "${uppercase_component}_TARGET_${target_arch}_${target_os}"
+  fi
 
   # Apply options that are specific to the host compiler, if we will
   # be using it (if we're doing a cross-compilation then we are
@@ -592,7 +606,7 @@
   fix_lib_configs
 
   # Indicate location of sysroot
-  if [ "$is_host_lib" == "0" ] # || [ "$BUILD" != "$HOST" ]
+  if [ "$is_host_lib" == "0" ]
   then
     add_cross_build_options
   fi
@@ -612,7 +626,7 @@
   build_config_options "$component" "$is_host_lib" "$install_dir"
   (IFS=':' && "$OUT_DIR/${component}-${component_ver}/configure" \
               $CONFIG_OPTIONS)
-  if [ "$?" != '0' ]
+  if [ "$?" != "0" ]
   then
     die "Failed to configure $component"
   fi
@@ -621,11 +635,13 @@
 build_component()
 {
   local component="$1"
+  # Host libraries don't have a separate host/target -- they are built for a
+  # single architecture. So, we can ignore the TARGET.
   local is_host_lib="$2"
 
   get_component_attribute "$component" "VER"
   local component_ver="$RESULT"
-  get_build_dir "$component"
+  get_build_dir "$component" "$is_host_lib"
   local build_dir="$RESULT"
   if [ "$is_host_lib" == "0" ]
   then
@@ -702,6 +718,14 @@
   build_components
   HOST="$TARGET"
   TARGET="$ORIG_TARGET"
+  if [ "$HOST" != "$TARGET" ]
+  then
+    # Canadian cross-compile, also build a BUILD->TARGET cross-compiler
+    ORIG_HOST="$HOST"
+    HOST="$BUILD"
+    build_components
+    HOST="$ORIG_HOST"
+  fi
 fi
 build_components
 # In certain unnamed environments, we may need an architecture-