#!/bin/sh

# Cross compile a GNU build environment.

# Written by Thomas Schwinge <tschwinge@gnu.org>.

# This script is placed into the public domain; nevertheless, please feel free
# to send any suggestions, improvements, etc. back to me.

# The files are canonically found at
# <http://nic-nac-project.de/~schwinge/tmp/cross-gnu> and
# <http://nic-nac-project.de/~schwinge/tmp/cross-gnu-env>.

# Usage: see <http://www.bddebian.com/~wiki/hurd/building/cross-compiling/>.


# There are several parts marked with `TODO' in this file; feel free to have a
# look at these issues and send the outcome back to me.


# Check for `cross-gnu-env' having been ran.

if [ x"${CROSS_GNU_REINSTALL_GLIBC-not_set}" = xnot_set ]; then
  cat >&2 <<"EOT" &&
Please see <http://www.bddebian.com/~wiki/hurd/building/cross-compiling/> about
how to use this shell script.
EOT
  exit 100
EOF
else :
fi &&


# Be verbose.

set -x &&


# Create directories.

mkdir -p "$ROOT" &&
cd "$ROOT" &&
mkdir -p bin "$SYS_ROOT"/include "$SYS_ROOT"/lib "$TARGET" &&
ln -sfn "$SYS_ROOT"/include "$SYS_ROOT"/lib "$TARGET"/ &&


# Install the cross GNU Binutils.

mkdir -p "$BINUTILS_SRC".obj &&
cd "$BINUTILS_SRC".obj &&
# We use `config.status''s existence as an indicator whether the package was
# configured already.  (E.g. when running cross-gnu a second time to update the
# tool chain.)
if ./config.status --version > /dev/null 2>&1; then :; else
  "$BINUTILS_SRC"/configure \
    --target="$TARGET" \
    --prefix="$ROOT" \
    --with-sysroot="$SYS_ROOT" \
    --disable-nls
fi &&
"$MAKE" \
  all \
  install &&


# Install a minimal cross GCC to build a cross MIG and the GNU C Library.

mkdir -p "$GCC_SRC".obj &&
cd "$GCC_SRC".obj &&
# Perhaps we already have a complete cross GCC?
if "$TARGET"-gcc --version > /dev/null 2>&1; then :; else
  if ./config.status --version > /dev/null 2>&1; then :; else
    # TODO.  Why ``--with-newlib''?
    "$GCC_SRC"/configure \
      --target="$TARGET" \
      --prefix="$ROOT" \
      --with-sysroot="$SYS_ROOT" \
      --disable-nls \
      --disable-shared \
      --disable-threads \
      --without-headers \
      --with-newlib \
      --enable-languages=c \
      --with-arch=i586
  fi &&

# TODO: GCC 3.3 and GCC 3.4 need this for building libgcc.a.  Not needed for
# GCC 4.0.  Get rid of this?
  : > "$SYS_ROOT"/include/signal.h &&
  mkdir -p "$SYS_ROOT"/include/sys &&
  : > "$SYS_ROOT"/include/sys/ucontext.h &&

  if "$MAKE" \
      all-gcc \
      install-gcc &&
    if ! test -d "$GCC_SRC"/libgcc/; then :; else
      # libgcc is new with GCC 4.3.
      if test -f "$ROOT"/lib/gcc/"$TARGET"/*/include/limits.h; then :; else
        # TODO.  What is GCC 4.3 doing there?
        mv "$ROOT"/lib/gcc/"$TARGET"/*/include-fixed/limits.h \
          "$ROOT"/lib/gcc/"$TARGET"/*/include/
      fi &&
      "$MAKE" \
        configure-target-libgcc &&
      ( cd "$TARGET"/libgcc &&
#        echo '/* Empty.  */' > libgcc.a &&
#        echo '/* Empty.  */' > libgcov.a &&
#        make libgcc-extra-parts &&
#        make RANLIB=: install ) &&
        # We need the `crt*.o' files and parts of `libgcc.a'.
        make 'libgcc-objects = $(lib2funcs-o) $(lib2-divmod-o)' all install )
    fi &&
# TODO: Make glibc happy.  We can not yet build libgcc_eh, but glibc's build
# system wants to link against that library.
# <http://sources.redhat.com/ml/libc-alpha/2003-09/msg00100.html>.
    echo '/* Empty.  */' > "$SYS_ROOT"/lib/libgcc_eh.a
  then
    mv config.status config.status.removed &&
    # TODO.
    rm -f config.cache */config.cache */*/config.cache &&
    # Remove the bogus files if building the cross compiler succeeded.
    rm "$SYS_ROOT"/include/signal.h "$SYS_ROOT"/include/sys/ucontext.h
  else
    # That indication file might already have been installed, but we do not yet
    # have a complete, working cross compiler.
    rm -f "$ROOT"/bin/"$TARGET"-gcc &&
    exit 100
  fi
fi &&


# Install GNU Mach's header files.

mkdir -p "$GNUMACH_SRC".obj &&
cd "$GNUMACH_SRC".obj &&
if ./config.status --version > /dev/null 2>&1; then :; else
  # `$TARGET-gcc' doesn't work yet (to satisfy the Autoconf checks), but isn't
  # needed either.
  CC=gcc \
  "$GNUMACH_SRC"/configure \
    --host="$TARGET" \
    --prefix=
fi &&
if grep -q install-data "$GNUMACH_SRC"/Makefile.in; then
  "$MAKE" \
    DESTDIR="$SYS_ROOT" \
    install-data
else
  # Old.
  "$MAKE" \
    prefix="$SYS_ROOT" \
    no_deps=t \
    install-headers
fi &&


# Install a cross GNU MIG.

mkdir -p "$MIG_SRC".obj &&
cd "$MIG_SRC".obj &&
if ./config.status --version > /dev/null 2>&1; then :; else
  "$MIG_SRC"/configure \
    --target="$TARGET" \
    --prefix="$ROOT"
fi &&
"$MAKE" \
  all \
  install &&


# Install the GNU Hurd's header files.

mkdir -p "$HURD_SRC".obj &&
cd "$HURD_SRC".obj &&
if ./config.status --version > /dev/null 2>&1; then :; else
  # `$TARGET-gcc' doesn't work yet (to satisfy the Autoconf checks), but isn't
  # needed either.
  CC=gcc \
  "$HURD_SRC"/configure \
    --host="$TARGET" \
    --prefix= \
    --disable-profile
fi &&
"$MAKE" \
  prefix="$SYS_ROOT" \
  no_deps=t \
  install-headers &&
# Below, we will reconfigure for allowing to build the pthreads library.
if grep -q '^CC = gcc$' config.make
then rm config.status
else :
fi &&


# Install the GNU C Library.

# Do we already have the GNU C library installed?
if test -h "$SYS_ROOT"/lib/ld.so; then :; else
  mkdir -p "$GLIBC_SRC".obj &&
  cd "$GLIBC_SRC".obj &&
  if ./config.status --version > /dev/null 2>&1; then :; else
    # `--build' has to be set to make sure that glibc is cross compiled.
    "$GLIBC_SRC"/configure \
      --without-cvs \
      --build="$("$GLIBC_SRC"/scripts/config.guess)" \
      --host="$TARGET" \
      --prefix= \
      --with-headers="$SYS_ROOT"/include \
      --disable-profile
  fi &&
  if "$MAKE" \
       install_root="$SYS_ROOT" \
       all \
       install
  then
    # TODO: Why doesn't `make install' do that?
    ln -sf ld.so.1 "$SYS_ROOT"/lib/ld.so &&
    if [ "$CROSS_GNU_REINSTALL_GLIBC" = n ]; then :; else
      # Force re-linking files once libgcc and libgcc_eh are available.  TODO: Is the
      # following enough?
      rm -f "$GLIBC_SRC".obj/config.status
#      rm -rf "$GLIBC_SRC".obj
    fi
  else
    # That indication file might already have been installed, but we do not yet
    # have a complete, working installation of the GNU C library.
    rm -f "$SYS_ROOT"/lib/ld.so
    exit 100
  fi
fi &&


# Install the GNU Hurd's pthreads library.

cd "$HURD_SRC".obj &&
if ./config.status --version > /dev/null 2>&1; then :; else
  "$HURD_SRC"/configure \
    --host="$TARGET" \
    --prefix= \
    --disable-profile
fi &&
"$MAKE" \
  libpthread &&
"$MAKE" \
  prefix="$SYS_ROOT" \
  libihash-install libpthread-install &&


# Install a complete cross GCC.

cd "$GCC_SRC".obj &&
if ./config.status --version > /dev/null 2>&1; then :; else
  # TODO: At the moment we only configure for creating a C compiler.
  # GCC 4.1 (and also the newer ones without patching) don't default to
  # enabling threading support for `$TARGET', thus ``--enable-threads=posix''
  # is given.
  "$GCC_SRC"/configure \
    --target="$TARGET" \
    --prefix="$ROOT" \
    --with-sysroot="$SYS_ROOT" \
    --disable-nls \
    --enable-threads=posix \
    --enable-languages=c \
    --with-arch=i586
fi &&
"$MAKE" \
  all &&
# Remove the bogus libgcc_eh, libgcc and libgcov that may have been installed
# earlier.
rm -f "$SYS_ROOT"/lib/libgcc_eh.a \
  "$ROOT"/lib/gcc/"$TARGET"/*/libgcc.a "$ROOT"/lib/gcc/"$TARGET"/*/libgcov.a &&
"$MAKE" \
  install &&


# Install the GNU C Library.

mkdir -p "$GLIBC_SRC".obj &&
cd "$GLIBC_SRC".obj &&
if ./config.status --version > /dev/null 2>&1; then :; else
  # `--build' has to be set to make sure that glibc is cross compiled.
  "$GLIBC_SRC"/configure \
    --without-cvs \
    --build="$("$GLIBC_SRC"/scripts/config.guess)" \
    --host="$TARGET" \
    --prefix= \
    --with-headers="$SYS_ROOT"/include \
    --disable-profile
fi &&
"$MAKE" \
  install_root="$SYS_ROOT" \
  all \
  install &&


# Install a cross GDB, if requested.

if test -d "$GDB_SRC"/; then
  mkdir -p "$GDB_SRC".obj &&
  cd "$GDB_SRC".obj &&
  if ./config.status --version > /dev/null 2>&1; then :; else
    "$GDB_SRC"/configure \
      --target="$TARGET" \
      --prefix="$ROOT" \
      --with-sysroot="$SYS_ROOT" \
      --disable-nls
  fi &&
  "$MAKE" \
    all \
    install &&


  # If possible, install a cross compiled `gdbserver' to be ran on the TARGET
  # system.

  if grep -q '86-\*-gnu\*' "$GDB_SRC"/gdb/gdbserver/README; then
    mkdir -p gdb/gdbserver &&
    cd gdb/gdbserver &&
    if ./config.status --version > /dev/null 2>&1; then :; else
      "$GDB_SRC"/gdb/gdbserver/configure \
        --host="$TARGET" \
        --prefix="$SYS_ROOT"
    fi &&
    "$MAKE" \
      all \
      install
  else :
  fi
fi &&


# Success.

echo "$0"': Everything should be in place now.'
