#!/bin/bash

# Run all the steps needed to build a system image from scratch.

# The default set of stages run by this script is (in order):
#   download, host-tools, simple-cross-compiler, root-filesystem,
#   native-compiler, system-image.

# That sanitizes the host build environment and builds a cross compiler,
# cross compiles a root filesystem and a native toolchain for the target,
# and finally packages the root filesystem up into a system image bootable
# by qemu.

# The optional cross-compiler stage (after simple-cross-compiler but before
# root-filesystem) creates a more powerful and portable cross compiler
# that can be used to cross compile more stuff (if you're into that sort of
# thing).  To enable that:

#   CROSS_COMPILER_HOST=i686 ./build.sh $TARGET

# Where "i686" is whichever target you want the new cross compiler to run on.

# The simplest set of stages (if you run them yourself) is:
#   download, simple-cross-compiler, root-filesystem, system-image.

# If this script was run with no arguments, list available architectures

test ! -z $2 && setvar REBUILD = "$2" &&
  test ! -e "$2".sh && echo "no stage $2" && exit 1

if test $Argc -lt 1 || test $Argc -gt 2 || test ! -e sources/targets/"$1"
{
  echo
  echo "Usage: $0 TARGET [REBUILD_FROM_STAGE]"
  echo
  echo "Supported architectures:"
  ls sources/targets
  echo
  echo "Build stages:"
  sed -n 's/#.*//;s@.*[.]/\([^.]*\)[.]sh.*@\1@p' $0 | uniq | xargs echo
  echo

  exit 1
}
setvar ARCH = "$1"

# Use environment variables persistently set in the config file.

test -e config && source config

# Allow the output directory to be overridden.  This hasn't been tested in
# forever and probably doesn't work.

test -z $BUILD && setvar BUILD = ""build""

# Very simple dependency tracking: skip stages that have already been done
# (because the tarball they create is already there).

# If you need to rebuild a stage (and everything after it), delete its
# tarball out of "build" and re-run build.sh.

proc not_already {
  test $AGAIN == $1 && return 0
  test $REBUILD == $1 && zap $1

  if test -f "$BUILD/$1-$ARCH.tar.gz"
  {
    echo "=== Skipping $1-$ARCH (already there)"
    return 1
  }

  return 0
}

proc zap {
  for i in "$@"
  {
    rm -f "$BUILD/$i-$ARCH.tar.gz"
  }
}

# If $AFTER set, skip stages until we match $AFTER to implement $2="start here"
proc do_stage {
  setvar STAGE = "$1"
  shift

  if test $AFTER == $STAGE
  {
    unset AFTER
  } else {
    time ./"$STAGE".sh @ARGV || exit 1
  }
}

# The first two stages (download.sh and host-tools.sh) are architecture
# independent. In order to allow multiple builds in parallel, re-running
# them after they've already completed must be a safe NOP.

# Download source code. If tarballs already there, verify sha1sums and
# delete/redownload if they don't match (to handle interrupted partial
# download).

do_stage download

# Build host tools.  This populates a single directory with every command the
# build needs, so we can ditch the host's $PATH afterwards.

if test -z $NO_HOST_TOOLS
{
  do_stage host-tools
}

# Do we need to build the simple cross compiler?

if test -z $MY_CROSS_PATH && not_already simple-cross-compiler
{
  # If we need to build cross compiler, assume root filesystem is stale.

  zap root-filesystem cross-compiler native-compiler

  do_stage simple-cross-compiler $ARCH
}

# Optionally, we can build a more capable statically linked compiler via
# canadian cross.  (It's more powerful than we need here, but if you're going
# to use the cross compiler in other contexts this is probably what you want.)

if test -z $MY_CROSS_PATH && test ! -z $CROSS_COMPILER_HOST &&
  not_already cross-compiler
{
  zap root-filesystem native-compiler"

  # Build the host compiler if necessary

  if ARCH=$CROSS_COMPILER_HOST" not_already simple-cross-compiler
  {
    do_stage simple-cross-compiler $CROSS_COMPILER_HOST
  }

  do_stage cross-compiler $ARCH
}

if ! grep -q KARCH= sources/targets/"$ARCH"
{
  echo no KARCH in $1, stopping here
}

# Build the basic root filesystem.

if not_already root-filesystem
{
  do_stage root-filesystem $ARCH
}

# Build a native compiler.  It's statically linked by default so it can
# run on an arbitrary host system.

# Not trying to build nommu native compilers for the moment.

if test -z $MY_CROSS_PATH && ! grep -q ELF2FLT sources/targets/"$ARCH" &&
  not_already native-compiler
{
  do_stage native-compiler $ARCH
}

# Package it all up into something qemu can boot. Like host-tools.sh,
# this is always called and handles its own dependencies internally.

do_stage system-image $ARCH