diff --git a/config.toml.example b/config.toml.example
index fd1f03b9d0e24..a20e6e8f0218a 100644
--- a/config.toml.example
+++ b/config.toml.example
@@ -73,6 +73,10 @@
 # controlled by rustbuild's -j parameter.
 #link-jobs = 0
 
+# When invoking `llvm-config` this configures whether the `--shared` argument is
+# passed to prefer linking to shared libraries.
+#link-shared = false
+
 # =============================================================================
 # General build configuration options
 # =============================================================================
@@ -166,6 +170,15 @@
 # to +10 on Unix platforms, and by using a "low priority" job object on Windows.
 #low-priority = false
 
+# Arguments passed to the `./configure` script, used during distcheck. You
+# probably won't fill this in but rather it's filled in by the `./configure`
+# script.
+#configure-args = []
+
+# Indicates that a local rebuild is ocurring instead of a full bootstrap,
+# essentially skipping stage0 as the local compiler is recompiling itself again.
+#local-rebuild = false
+
 # =============================================================================
 # General install configuration options
 # =============================================================================
@@ -195,6 +208,13 @@
 # =============================================================================
 [rust]
 
+# Indicates that the build should be optimized for debugging Rust. Note that
+# this is typically not what you want as it takes an incredibly large amount of
+# time to have a debug-mode rustc compile any code (notably libstd). If this
+# value is set to `true` it will affect a number of configuration options below
+# as well, if unconfigured.
+#debug = false
+
 # Whether or not to optimize the compiler and standard library
 # Note: the slowness of the non optimized compiler compiling itself usually
 #       outweighs the time gains in not doing optimizations, therefore a
@@ -249,6 +269,10 @@
 # desired in distributions, for example.
 #rpath = true
 
+# Suppresses extraneous output from tests to ensure the output of the test
+# harness is relatively clean.
+#quiet-tests = false
+
 # Flag indicating whether tests are compiled with optimizations (the -O flag) or
 # with debuginfo (the -g flag)
 #optimize-tests = true
@@ -261,6 +285,9 @@
 # Flag indicating whether git info will be retrieved from .git automatically.
 #ignore-git = false
 
+# When creating source tarballs whether or not to create a source tarball.
+#dist-src = false
+
 # =============================================================================
 # Options for specific targets
 #
@@ -304,6 +331,10 @@
 # linked binaries
 #musl-root = "..."
 
+# Used in testing for configuring where the QEMU images are located, you
+# probably don't want to use this.
+#qemu-rootfs = "..."
+
 # =============================================================================
 # Distribution options
 #
diff --git a/configure b/configure
index 664b473b2c9d0..eeb8d081d3454 100755
--- a/configure
+++ b/configure
@@ -1,779 +1,17 @@
 #!/bin/sh
 
-# /bin/sh on Solaris is not a POSIX compatible shell, but /usr/bin/bash is.
-if [ `uname -s` = 'SunOS' -a "${POSIX_SHELL}" != "true" ]; then
-    POSIX_SHELL="true"
-    export POSIX_SHELL
-    exec /usr/bin/env bash $0 "$@"
-fi
-unset POSIX_SHELL # clear it so if we invoke other scripts, they run as bash as well
+script="$(dirname $0)"/src/bootstrap/configure.py
 
-msg() {
-    echo "configure: $*"
-}
-
-step_msg() {
-    msg
-    msg "$1"
-    msg
-}
-
-warn() {
-    echo "configure: WARNING: $1"
-}
-
-err() {
-    echo "configure: error: $1"
-    exit 1
-}
-
-run() {
-    msg "$@"
-    "$@"
-}
-
-need_ok() {
-    if [ $? -ne 0 ]
-    then
-        err "$1"
-    fi
-}
-
-need_cmd() {
-    if command -v $1 >/dev/null 2>&1
-    then msg "found program '$1'"
-    else err "program '$1' is missing, please install it"
-    fi
-}
-
-make_dir() {
-    if [ ! -d $1 ]
-    then
-        run mkdir -p $1
-    fi
-}
-
-copy_if_changed() {
-    if cmp -s $1 $2
-    then
-        msg "leaving $2 unchanged"
-    else
-        run cp -f $1 $2
-        chmod u-w $2 # make copied artifact read-only
-    fi
-}
-
-move_if_changed() {
-    if cmp -s $1 $2
-    then
-        msg "leaving $2 unchanged"
-    else
-        run mv -f $1 $2
-        chmod u-w $2 # make moved artifact read-only
-    fi
-}
-
-putvar() {
-    local T
-    eval T=\$$1
-    eval TLEN=\${#$1}
-    if [ $TLEN -gt 35 ]
-    then
-        printf "configure: %-20s := %.35s ...\n" $1 "$T"
-    else
-        printf "configure: %-20s := %s %s\n" $1 "$T" "$2"
-    fi
-    printf "%-20s := %s\n" $1 "$T" >>config.tmp
-}
-
-putpathvar() {
-    local T
-    eval T=\$$1
-    eval TLEN=\${#$1}
-    if [ $TLEN -gt 35 ]
-    then
-        printf "configure: %-20s := %.35s ...\n" $1 "$T"
-    else
-        printf "configure: %-20s := %s %s\n" $1 "$T" "$2"
-    fi
-    if [ -z "$T" ]
-    then
-        printf "%-20s := \n" $1 >>config.tmp
-    else
-        printf "%-20s := \"%s\"\n" $1 "$T" >>config.tmp
-    fi
-}
-
-probe() {
-    local V=$1
+try() {
+    cmd=$1
     shift
-    local P
-    local T
-    for P
-    do
-        T=$(command -v $P 2>&1)
-        if [ $? -eq 0 ]
-        then
-            VER0=$($P --version 2>/dev/null \
-                |  grep -o '[vV]\?[0-9][0-9.][a-z0-9.-]*' | head -1 )
-            if [ $? -eq 0 -a "x${VER0}" != "x" ]
-            then
-              VER="($VER0)"
-            else
-              VER=""
-            fi
-            break
-        else
-            VER=""
-            T=""
-        fi
-    done
-    eval $V=\$T
-    putpathvar $V "$VER"
-}
-
-probe_need() {
-    probe $*
-    local V=$1
-    shift
-    eval VV=\$$V
-    if [ -z "$VV" ]
-    then
-        err "$V needed, but unable to find any of: $*"
-    fi
-}
-
-validate_opt () {
-    for arg in $CFG_CONFIGURE_ARGS
-    do
-        isArgValid=0
-        for option in $BOOL_OPTIONS
-        do
-            if test --disable-$option = $arg
-            then
-                isArgValid=1
-            fi
-            if test --enable-$option = $arg
-            then
-                isArgValid=1
-            fi
-        done
-        for option in $VAL_OPTIONS
-        do
-            if echo "$arg" | grep -q -- "--$option="
-            then
-                isArgValid=1
-            fi
-        done
-        if [ "$arg" = "--help" ]
-        then
-            echo
-            echo "No more help available for Configure options,"
-            echo "check the Wiki or join our IRC channel"
-            break
-        else
-            if test $isArgValid -eq 0
-            then
-                err "Option '$arg' is not recognized"
-            fi
-        fi
-    done
-}
-
-# `valopt OPTION_NAME DEFAULT DOC` extracts a string-valued option
-# from command line, using provided default value for the option if
-# not present, and saves it to the generated config.mk.
-#
-# `valopt_nosave` is much the same, except that it does not save the
-# result to config.mk (instead the script should use `putvar` itself
-# later on to save it).  `valopt_core` is the core upon which the
-# other two are built.
-
-valopt_core() {
-    VAL_OPTIONS="$VAL_OPTIONS $2"
-
-    local SAVE=$1
-    local OP=$2
-    local DEFAULT=$3
-    shift
-    shift
-    shift
-    local DOC="$*"
-    if [ $HELP -eq 0 ]
-    then
-        local UOP=$(echo $OP | tr '[:lower:]' '[:upper:]' | tr '\-' '\_')
-        local V="CFG_${UOP}"
-        local V_PROVIDED="${V}_PROVIDED"
-        eval $V="$DEFAULT"
-        for arg in $CFG_CONFIGURE_ARGS
-        do
-            if echo "$arg" | grep -q -- "--$OP="
-            then
-                val=$(echo "$arg" | cut -f2 -d=)
-                eval $V=$val
-                eval $V_PROVIDED=1
-            fi
-        done
-        if [ "$SAVE" = "save" ]
-        then
-            putvar $V
-        fi
-    else
-        if [ -z "$DEFAULT" ]
-        then
-            DEFAULT="<none>"
-        fi
-        OP="${OP}=[${DEFAULT}]"
-        printf "    --%-30s %s\n" "$OP" "$DOC"
-    fi
-}
-
-valopt_nosave() {
-    valopt_core nosave "$@"
-}
-
-valopt() {
-    valopt_core save "$@"
-}
-
-# `opt OPTION_NAME DEFAULT DOC` extracts a boolean-valued option from
-# command line, using the provided default value (0/1) for the option
-# if not present, and saves it to the generated config.mk.
-#
-# `opt_nosave` is much the same, except that it does not save the
-# result to config.mk (instead the script should use `putvar` itself
-# later on to save it).  `opt_core` is the core upon which the other
-# two are built.
-
-opt_core() {
-    BOOL_OPTIONS="$BOOL_OPTIONS $2"
-
-    local SAVE=$1
-    local OP=$2
-    local DEFAULT=$3
-    shift
-    shift
-    shift
-    local DOC="$*"
-    local FLAG=""
-
-    if [ $DEFAULT -eq 0 ]
-    then
-        FLAG="enable"
-        DEFAULT_FLAG="disable"
-    else
-        FLAG="disable"
-        DEFAULT_FLAG="enable"
-        DOC="don't $DOC"
-    fi
-
-    if [ $HELP -eq 0 ]
-    then
-        for arg in $CFG_CONFIGURE_ARGS
-        do
-            if [ "$arg" = "--${FLAG}-${OP}" ]
-            then
-                OP=$(echo $OP | tr 'a-z-' 'A-Z_')
-                FLAG=$(echo $FLAG | tr 'a-z' 'A-Z')
-                local V="CFG_${FLAG}_${OP}"
-                local V_PROVIDED="CFG_${FLAG}_${OP}_PROVIDED"
-                eval $V=1
-                eval $V_PROVIDED=1
-                if [ "$SAVE" = "save" ]
-                then
-                   putvar $V
-                fi
-            elif [ "$arg" = "--${DEFAULT_FLAG}-${OP}" ]
-            then
-                OP=$(echo $OP | tr 'a-z-' 'A-Z_')
-                DEFAULT_FLAG=$(echo $DEFAULT_FLAG | tr 'a-z' 'A-Z')
-                local V_PROVIDED="CFG_${DEFAULT_FLAG}_${OP}_PROVIDED"
-                eval $V_PROVIDED=1
-            fi
-        done
-    else
-        if [ -n "$META" ]
-        then
-            OP="$OP=<$META>"
-        fi
-        printf "    --%-30s %s\n" "$FLAG-$OP" "$DOC"
-     fi
-}
-
-opt_nosave() {
-    opt_core nosave "$@"
-}
-
-opt() {
-    opt_core save "$@"
-}
-
-envopt() {
-    local NAME=$1
-    local V="CFG_${NAME}"
-    eval VV=\$$V
-
-    # If configure didn't set a value already, then check environment.
-    #
-    # (It is recommended that the configure script always check the
-    # environment before setting any values to envopt variables; see
-    # e.g.  how CFG_CC is handled, where it first checks `-z "$CC"`,
-    # and issues msg if it ends up employing that provided value.)
-    if [ -z "$VV" ]
-    then
-        eval $V=\$$NAME
-        eval VV=\$$V
-    fi
-
-    # If script or environment provided a value, save it.
-    if [ -n "$VV" ]
-    then
-        putvar $V
-    fi
-}
-
-enable_if_not_disabled() {
-    local OP=$1
-    local UOP=$(echo $OP | tr '[:lower:]' '[:upper:]' | tr '\-' '\_')
-    local ENAB_V="CFG_ENABLE_$UOP"
-    local EXPLICITLY_DISABLED="CFG_DISABLE_${UOP}_PROVIDED"
-    eval VV=\$$EXPLICITLY_DISABLED
-    if [ -z "$VV" ]; then
-        eval $ENAB_V=1
+    T=$($cmd --version 2>/dev/null)
+    if [ $? -eq 0 ]; then
+        exec $cmd "$script" "$@"
     fi
 }
 
-to_gnu_triple() {
-    case $1 in
-        i686-pc-windows-gnu) echo i686-w64-mingw32 ;;
-        x86_64-pc-windows-gnu) echo x86_64-w64-mingw32 ;;
-        *) echo $1 ;;
-    esac
-}
-
-# Prints the absolute path of a directory to stdout
-abs_path() {
-    local _path="$1"
-    # Unset CDPATH because it causes havok: it makes the destination unpredictable
-    # and triggers 'cd' to print the path to stdout. Route `cd`'s output to /dev/null
-    # for good measure.
-    (unset CDPATH && cd "$_path" > /dev/null && pwd)
-}
-
-HELP=0
-for arg; do
-    case "$arg" in
-        --help) HELP=1;;
-    esac
-done
-
-msg "looking for configure programs"
-need_cmd cmp
-need_cmd mkdir
-need_cmd printf
-need_cmd cut
-need_cmd head
-need_cmd grep
-need_cmd xargs
-need_cmd cp
-need_cmd find
-need_cmd uname
-need_cmd date
-need_cmd tr
-need_cmd sed
-need_cmd file
-need_cmd make
-
-CFG_SRC_DIR="$(abs_path $(dirname $0))/"
-CFG_SRC_DIR_RELATIVE="$(dirname $0)/"
-CFG_BUILD_DIR="$(pwd)/"
-CFG_SELF="$0"
-CFG_CONFIGURE_ARGS="$@"
-
-
-case "${CFG_SRC_DIR}" in
-    *\ * )
-        err "The path to the rust source directory contains spaces, which is not supported"
-        ;;
-    *)
-        ;;
-esac
-
-
-OPTIONS=""
-if [ "$HELP" -eq 1 ]
-then
-    echo
-    echo "Usage: $CFG_SELF [options]"
-    echo
-    echo "Options:"
-    echo
-else
-    msg "recreating config.tmp"
-    echo '' >config.tmp
-
-    step_msg "processing $CFG_SELF args"
-fi
-
-BOOL_OPTIONS=""
-VAL_OPTIONS=""
-
-opt debug 0 "debug mode; disables optimization unless \`--enable-optimize\` given"
-opt valgrind 0 "run tests with valgrind (memcheck by default)"
-opt helgrind 0 "run tests with helgrind instead of memcheck"
-opt valgrind-rpass 1 "run rpass-valgrind tests with valgrind"
-opt docs     1 "build standard library documentation"
-opt compiler-docs     0 "build compiler documentation"
-opt optimize-tests 1 "build tests with optimizations"
-opt debuginfo-tests 0 "build tests with debugger metadata"
-opt quiet-tests 0 "enable quieter output when running tests"
-opt libcpp 1 "build llvm with libc++ instead of libstdc++ when using clang"
-opt llvm-assertions 0 "build LLVM with assertions"
-opt debug-assertions 0 "build with debugging assertions"
-opt fast-make 0 "use .gitmodules as timestamp for submodule deps"
-opt ccache 0 "invoke gcc/clang via ccache to reuse object files between builds"
-opt sccache 0 "invoke gcc/clang via sccache to reuse object files between builds"
-opt local-rust 0 "use an installed rustc rather than downloading a snapshot"
-opt local-rebuild 0 "assume local-rust matches the current version, for rebuilds; implies local-rust, and is implied if local-rust already matches the current version"
-opt llvm-static-stdcpp 0 "statically link to libstdc++ for LLVM"
-opt llvm-link-shared 0 "prefer shared linking to LLVM (llvm-config --link-shared)"
-opt rpath 1 "build rpaths into rustc itself"
-opt stage0-landing-pads 1 "enable landing pads during bootstrap with stage0"
-# This is used by the automation to produce single-target nightlies
-opt dist-host-only 0 "only install bins for the host architecture"
-opt inject-std-version 1 "inject the current compiler version of libstd into programs"
-opt llvm-version-check 1 "check if the LLVM version is supported, build anyway"
-opt codegen-tests 1 "run the src/test/codegen tests"
-opt option-checking 1 "complain about unrecognized options in this configure script"
-opt ninja 0 "build LLVM using the Ninja generator (for MSVC, requires building in the correct environment)"
-opt locked-deps 0 "force Cargo.lock to be up to date"
-opt vendor 0 "enable usage of vendored Rust crates"
-opt sanitizers 0 "build the sanitizer runtimes (asan, lsan, msan, tsan)"
-opt dist-src 1 "when building tarballs enables building a source tarball"
-opt cargo-openssl-static 0 "static openssl in cargo"
-opt profiler 0 "build the profiler runtime"
-
-# Optimization and debugging options. These may be overridden by the release channel, etc.
-opt_nosave optimize 1 "build optimized rust code"
-opt_nosave optimize-cxx 1 "build optimized C++ code"
-opt_nosave optimize-llvm 1 "build optimized LLVM"
-opt_nosave llvm-assertions 0 "build LLVM with assertions"
-opt_nosave debug-assertions 0 "build with debugging assertions"
-opt_nosave llvm-release-debuginfo 0 "build LLVM with debugger metadata"
-opt_nosave debuginfo 0 "build with debugger metadata"
-opt_nosave debuginfo-lines 0 "build with line number debugger metadata"
-opt_nosave debuginfo-only-std 0 "build only libstd with debugging information"
-opt_nosave debug-jemalloc 0 "build jemalloc with --enable-debug --enable-fill"
-
-valopt localstatedir "/var/lib" "local state directory"
-valopt sysconfdir "/etc" "install system configuration files"
-
-valopt datadir "${CFG_PREFIX}/share" "install data"
-valopt infodir "${CFG_PREFIX}/share/info" "install additional info"
-valopt llvm-root "" "set LLVM root"
-valopt python "" "set path to python"
-valopt jemalloc-root "" "set directory where libjemalloc_pic.a is located"
-valopt build "" "GNUs ./configure syntax LLVM build triple"
-valopt android-cross-path "" "Android NDK standalone path (deprecated)"
-valopt i686-linux-android-ndk "" "i686-linux-android NDK standalone path"
-valopt arm-linux-androideabi-ndk "" "arm-linux-androideabi NDK standalone path"
-valopt armv7-linux-androideabi-ndk "" "armv7-linux-androideabi NDK standalone path"
-valopt aarch64-linux-android-ndk "" "aarch64-linux-android NDK standalone path"
-valopt x86_64-linux-android-ndk "" "x86_64-linux-android NDK standalone path"
-valopt nacl-cross-path  "" "NaCl SDK path (Pepper Canary is recommended). Must be absolute!"
-valopt musl-root "/usr/local" "MUSL root installation directory (deprecated)"
-valopt musl-root-x86_64 "" "x86_64-unknown-linux-musl install directory"
-valopt musl-root-i686 "" "i686-unknown-linux-musl install directory"
-valopt musl-root-arm "" "arm-unknown-linux-musleabi install directory"
-valopt musl-root-armhf "" "arm-unknown-linux-musleabihf install directory"
-valopt musl-root-armv7 "" "armv7-unknown-linux-musleabihf install directory"
-valopt extra-filename "" "Additional data that is hashed and passed to the -C extra-filename flag"
-valopt qemu-armhf-rootfs "" "rootfs in qemu testing, you probably don't want to use this"
-valopt qemu-aarch64-rootfs "" "rootfs in qemu testing, you probably don't want to use this"
-valopt experimental-targets "" "experimental LLVM targets to build"
-
-if [ -e ${CFG_SRC_DIR}.git ]
-then
-    valopt release-channel "dev" "the name of the release channel to build"
-else
-    # If we have no git directory then we are probably a tarball distribution
-    # and should default to stable channel - Issue 28322
-    probe CFG_GIT          git
-    msg "git: no git directory. Changing default release channel to stable"
-    valopt release-channel "stable" "the name of the release channel to build"
-fi
-
-# Used on systems where "cc" and "ar" are unavailable
-valopt default-linker "cc" "the default linker"
-valopt default-ar     "ar" "the default ar"
-
-# Many of these are saved below during the "writing configuration" step
-# (others are conditionally saved).
-opt_nosave manage-submodules 1 "let the build manage the git submodules"
-opt_nosave clang 0 "prefer clang to gcc for building the runtime"
-opt_nosave jemalloc 1 "build liballoc with jemalloc"
-opt full-bootstrap 0 "build three compilers instead of two"
-opt extended 0 "build an extended rust tool set"
-
-valopt_nosave prefix "/usr/local" "set installation prefix"
-valopt_nosave local-rust-root "/usr/local" "set prefix for local rust binary"
-valopt_nosave host "${CFG_BUILD}" "GNUs ./configure syntax LLVM host triples"
-valopt_nosave target "${CFG_HOST}" "GNUs ./configure syntax LLVM target triples"
-valopt_nosave mandir "${CFG_PREFIX}/share/man" "install man pages in PATH"
-valopt_nosave docdir "${CFG_PREFIX}/share/doc/rust" "install documentation in PATH"
-valopt_nosave bindir "${CFG_PREFIX}/bin" "install binaries"
-
-# On Windows this determines root of the subtree for target libraries.
-# Host runtime libs always go to 'bin'.
-valopt libdir "${CFG_PREFIX}/lib" "install libraries"
-
-case "$CFG_LIBDIR" in
-    "$CFG_PREFIX"/*) CAT_INC=2;;
-    "$CFG_PREFIX"*)  CAT_INC=1;;
-    *)
-        err "libdir must begin with the prefix. Use --prefix to set it accordingly.";;
-esac
-
-CFG_LIBDIR_RELATIVE=`echo ${CFG_LIBDIR} | cut -c$((${#CFG_PREFIX}+${CAT_INC}))-`
-
-if [ $HELP -eq 1 ]
-then
-    echo
-    exit 0
-fi
-
-# Validate Options
-if [ -z "$CFG_DISABLE_OPTION_CHECKING" ]
-then
-    step_msg "validating $CFG_SELF args"
-    validate_opt
-fi
-
-# Validate the release channel, and configure options
-case "$CFG_RELEASE_CHANNEL" in
-    nightly )
-	msg "overriding settings for $CFG_RELEASE_CHANNEL"
-        enable_if_not_disabled llvm-assertions
-        # FIXME(stage0) re-enable this on the next stage0 now that #35566 is
-        # fixed
-        case "$CFG_BUILD" in
-          *-pc-windows-gnu)
-            ;;
-          *)
-            enable_if_not_disabled debuginfo-lines
-            enable_if_not_disabled debuginfo-only-std
-            ;;
-        esac
-
-	;;
-    beta | stable)
-	msg "overriding settings for $CFG_RELEASE_CHANNEL"
-        case "$CFG_BUILD" in
-          *-pc-windows-gnu)
-            ;;
-          *)
-            enable_if_not_disabled debuginfo-lines
-            enable_if_not_disabled debuginfo-only-std
-            ;;
-        esac
-	;;
-    dev)
-	;;
-    *)
-        err "release channel must be 'dev', 'nightly', 'beta' or 'stable'"
-        ;;
-esac
-
-# Adjust perf and debug options for debug mode
-if [ -n "$CFG_ENABLE_DEBUG" ]; then
-    msg "debug mode enabled, setting performance options"
-    if [ -z "$CFG_ENABLE_OPTIMIZE_PROVIDED" ]; then
-        msg "optimization not explicitly enabled, disabling optimization"
-        CFG_DISABLE_OPTIMIZE=1
-        CFG_DISABLE_OPTIMIZE_CXX=1
-    fi
-
-    # Set following variables to 1 unless setting already provided
-    enable_if_not_disabled debug-assertions
-    enable_if_not_disabled debug-jemalloc
-    enable_if_not_disabled debuginfo
-    enable_if_not_disabled llvm-assertions
-fi
-
-# OK, now write the debugging options
-if [ -n "$CFG_DISABLE_OPTIMIZE" ]; then putvar CFG_DISABLE_OPTIMIZE; fi
-if [ -n "$CFG_DISABLE_OPTIMIZE_CXX" ]; then putvar CFG_DISABLE_OPTIMIZE_CXX; fi
-if [ -n "$CFG_DISABLE_OPTIMIZE_LLVM" ]; then putvar CFG_DISABLE_OPTIMIZE_LLVM; fi
-if [ -n "$CFG_ENABLE_LLVM_ASSERTIONS" ]; then putvar CFG_ENABLE_LLVM_ASSERTIONS; fi
-if [ -n "$CFG_ENABLE_DEBUG_ASSERTIONS" ]; then putvar CFG_ENABLE_DEBUG_ASSERTIONS; fi
-if [ -n "$CFG_ENABLE_LLVM_RELEASE_DEBUGINFO" ]; then putvar CFG_ENABLE_LLVM_RELEASE_DEBUGINFO; fi
-if [ -n "$CFG_ENABLE_DEBUGINFO" ]; then putvar CFG_ENABLE_DEBUGINFO; fi
-if [ -n "$CFG_ENABLE_DEBUGINFO_LINES" ]; then putvar CFG_ENABLE_DEBUGINFO_LINES; fi
-if [ -n "$CFG_ENABLE_DEBUGINFO_ONLY_STD" ]; then putvar CFG_ENABLE_DEBUGINFO_ONLY_STD; fi
-if [ -n "$CFG_ENABLE_DEBUG_JEMALLOC" ]; then putvar CFG_ENABLE_DEBUG_JEMALLOC; fi
-
-step_msg "looking for build programs"
-
-probe_need CFG_CURL curl
-if [ -z "$CFG_PYTHON_PROVIDED" ]; then
-    probe_need CFG_PYTHON      python2.7 python2 python
-fi
-
-python_version=$($CFG_PYTHON -V 2>&1)
-if [ $(echo $python_version | grep -c '^Python 2\.7') -ne 1 ]; then
-    err "Found $python_version, but Python 2.7 is required"
-fi
-
-# the valgrind rpass tests will fail if you don't have a valgrind, but they're
-# only disabled if you opt out.
-if [ -z "$CFG_VALGRIND" ]
-then
-    # If the user has explicitly asked for valgrind tests, then fail
-    if [ -n "$CFG_ENABLE_VALGRIND" ] && [ -n "$CFG_ENABLE_VALGRIND_PROVIDED" ]
-    then
-        err "No valgrind present, but valgrind tests explicitly requested"
-    else
-        CFG_DISABLE_VALGRIND_RPASS=1
-        putvar CFG_DISABLE_VALGRIND_RPASS
-    fi
-fi
-
-# Do some sanity checks if running on buildbot
-# (these env vars are set by rust-buildbot)
-if [ -n "$RUST_DIST_SERVER" -a -n "$ALLOW_NONZERO_RLIMIT_CORE" ]; then
-   # Frequently the llvm submodule directory is broken by the build
-   # being killed
-   llvm_lock="${CFG_SRC_DIR}/.git/modules/src/llvm/index.lock"
-   if [ -e "$llvm_lock" ]; then
-       step_msg "removing $llvm_lock"
-       rm -f "$llvm_lock"
-   fi
-fi
-
-BIN_SUF=
-if [ "$CFG_OSTYPE" = "pc-windows-gnu" ] || [ "$CFG_OSTYPE" = "pc-windows-msvc" ]
-then
-    BIN_SUF=.exe
-fi
-
-# --enable-local-rebuild implies --enable-local-rust too
-if [ -n "$CFG_ENABLE_LOCAL_REBUILD" ]
-then
-    if [ -z "$CFG_ENABLE_LOCAL_RUST" ]
-    then
-        CFG_ENABLE_LOCAL_RUST=1
-        putvar CFG_ENABLE_LOCAL_RUST
-    fi
-fi
-
-if [ -n "$CFG_ENABLE_LOCAL_RUST" ]
-then
-    system_rustc=$(which rustc)
-    if [ -f ${CFG_LOCAL_RUST_ROOT}/bin/rustc${BIN_SUF} ]
-    then
-        : # everything already configured
-    elif [ -n "$system_rustc" ]
-    then
-        # we assume that rustc is in a /bin directory
-        CFG_LOCAL_RUST_ROOT=${system_rustc%/bin/rustc}
-    else
-        err "no local rust to use"
-    fi
-
-    CMD="${CFG_LOCAL_RUST_ROOT}/bin/rustc${BIN_SUF}"
-    LRV=`LD_LIBRARY_PATH=${CFG_LOCAL_RUST_ROOT}/lib $CMD --version`
-    if [ $? -ne 0 ]
-    then
-        step_msg "failure while running $CMD --version"
-        exit 1
-    fi
-    step_msg "using rustc at: ${CFG_LOCAL_RUST_ROOT} with version: $LRV"
-    putvar CFG_LOCAL_RUST_ROOT
-fi
-
-# Same with jemalloc.  save the setting here.
-if [ -n "$CFG_DISABLE_JEMALLOC" ]
-then
-    putvar CFG_DISABLE_JEMALLOC
-fi
-
-# All safeguards based on $CFG_ENABLE_CLANG should occur before this
-# point in the script; after this point, script logic should inspect
-# $CFG_USING_CLANG rather than $CFG_ENABLE_CLANG.
-
-# Set CFG_{CC,CXX,CPP,CFLAGS,CXXFLAGS,LDFLAGS}
-envopt CC
-envopt CXX
-envopt CPP
-envopt CFLAGS
-envopt CXXFLAGS
-envopt LDFLAGS
-
-# a little post-processing of various config values
-CFG_PREFIX=${CFG_PREFIX%/}
-CFG_MANDIR=${CFG_MANDIR%/}
-CFG_DOCDIR=${CFG_DOCDIR%/}
-CFG_BINDIR=${CFG_BINDIR%/}
-CFG_HOST="$(echo $CFG_HOST | tr ',' ' ')"
-CFG_TARGET="$(echo $CFG_TARGET | tr ',' ' ')"
-
-# copy build-triples to host-triples so that builds are a subset of hosts
-V_TEMP=""
-for i in $CFG_BUILD $CFG_HOST;
-do
-   echo "$V_TEMP" | grep -qF $i || V_TEMP="$V_TEMP${V_TEMP:+ }$i"
-done
-CFG_HOST=$V_TEMP
-
-# copy host-triples to target-triples so that hosts are a subset of targets
-V_TEMP=""
-for i in $CFG_HOST $CFG_TARGET;
-do
-   echo "$V_TEMP" | grep -qF $i || V_TEMP="$V_TEMP${V_TEMP:+ }$i"
-done
-CFG_TARGET=$V_TEMP
-
-step_msg "writing configuration"
-
-putvar CFG_SRC_DIR
-putvar CFG_SRC_DIR_RELATIVE
-putvar CFG_BUILD_DIR
-putvar CFG_OSTYPE
-putvar CFG_CPUTYPE
-putvar CFG_CONFIGURE_ARGS
-putvar CFG_PREFIX
-putvar CFG_HOST
-putvar CFG_TARGET
-putvar CFG_LIBDIR_RELATIVE
-putvar CFG_DISABLE_MANAGE_SUBMODULES
-putvar CFG_AARCH64_LINUX_ANDROID_NDK
-putvar CFG_ARM_LINUX_ANDROIDEABI_NDK
-putvar CFG_ARMV7_LINUX_ANDROIDEABI_NDK
-putvar CFG_I686_LINUX_ANDROID_NDK
-putvar CFG_X86_64_LINUX_ANDROID_NDK
-putvar CFG_NACL_CROSS_PATH
-putvar CFG_MANDIR
-putvar CFG_DOCDIR
-putvar CFG_BINDIR
-putvar CFG_USING_LIBCPP
-
-msg
-copy_if_changed ${CFG_SRC_DIR}src/bootstrap/mk/Makefile.in ./Makefile
-move_if_changed config.tmp config.mk
-rm -f config.tmp
-touch config.stamp
-
-if [ -z "$CFG_ENABLE_DEBUG" ]; then
-    step_msg "configured in release mode. for development consider --enable-debug"
-else
-    step_msg "complete"
-fi
-
-if [ "$CFG_SRC_DIR" = `pwd` ]; then
-    X_PY=x.py
-else
-    X_PY=${CFG_SRC_DIR_RELATIVE}x.py
-fi
-
-msg "run \`python ${X_PY} --help\`"
-msg
+try python2.7 "$@"
+try python27 "$@"
+try python2 "$@"
+exec python $script "$@"
diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md
index 2e844ceb17831..e543b8c070bcc 100644
--- a/src/bootstrap/README.md
+++ b/src/bootstrap/README.md
@@ -76,10 +76,9 @@ The script accepts commands, flags, and arguments to determine what to do:
 There are currently two methods for configuring the rustbuild build system.
 
 First, rustbuild offers a TOML-based configuration system with a `config.toml`
-file in the same location as `config.mk`. An example of this configuration can
-be found at `config.toml.example`, and the configuration file can also be passed
-as `--config path/to/config.toml` if the build system is being invoked manually
-(via the python script).
+file. An example of this configuration can be found at `config.toml.example`,
+and the configuration file can also be passed as `--config path/to/config.toml`
+if the build system is being invoked manually (via the python script).
 
 Next, the `./configure` options serialized in `config.mk` will be
 parsed and read. That is, if any `./configure` options are passed, they'll be
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 9369a55ccb97b..4c1bd7bdca9e0 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -167,6 +167,141 @@ def format_build_time(duration):
     return str(datetime.timedelta(seconds=int(duration)))
 
 
+def default_build_triple():
+    """Build triple as in LLVM"""
+    default_encoding = sys.getdefaultencoding()
+    try:
+        ostype = subprocess.check_output(
+            ['uname', '-s']).strip().decode(default_encoding)
+        cputype = subprocess.check_output(
+            ['uname', '-m']).strip().decode(default_encoding)
+    except (subprocess.CalledProcessError, OSError):
+        if sys.platform == 'win32':
+            return 'x86_64-pc-windows-msvc'
+        err = "uname not found"
+        sys.exit(err)
+
+    # The goal here is to come up with the same triple as LLVM would,
+    # at least for the subset of platforms we're willing to target.
+    ostype_mapper = {
+        'Bitrig': 'unknown-bitrig',
+        'Darwin': 'apple-darwin',
+        'DragonFly': 'unknown-dragonfly',
+        'FreeBSD': 'unknown-freebsd',
+        'Haiku': 'unknown-haiku',
+        'NetBSD': 'unknown-netbsd',
+        'OpenBSD': 'unknown-openbsd'
+    }
+
+    # Consider the direct transformation first and then the special cases
+    if ostype in ostype_mapper:
+        ostype = ostype_mapper[ostype]
+    elif ostype == 'Linux':
+        os_from_sp = subprocess.check_output(
+            ['uname', '-o']).strip().decode(default_encoding)
+        if os_from_sp == 'Android':
+            ostype = 'linux-android'
+        else:
+            ostype = 'unknown-linux-gnu'
+    elif ostype == 'SunOS':
+        ostype = 'sun-solaris'
+        # On Solaris, uname -m will return a machine classification instead
+        # of a cpu type, so uname -p is recommended instead.  However, the
+        # output from that option is too generic for our purposes (it will
+        # always emit 'i386' on x86/amd64 systems).  As such, isainfo -k
+        # must be used instead.
+        try:
+            cputype = subprocess.check_output(
+                ['isainfo', '-k']).strip().decode(default_encoding)
+        except (subprocess.CalledProcessError, OSError):
+            err = "isainfo not found"
+            sys.exit(err)
+    elif ostype.startswith('MINGW'):
+        # msys' `uname` does not print gcc configuration, but prints msys
+        # configuration. so we cannot believe `uname -m`:
+        # msys1 is always i686 and msys2 is always x86_64.
+        # instead, msys defines $MSYSTEM which is MINGW32 on i686 and
+        # MINGW64 on x86_64.
+        ostype = 'pc-windows-gnu'
+        cputype = 'i686'
+        if os.environ.get('MSYSTEM') == 'MINGW64':
+            cputype = 'x86_64'
+    elif ostype.startswith('MSYS'):
+        ostype = 'pc-windows-gnu'
+    elif ostype.startswith('CYGWIN_NT'):
+        cputype = 'i686'
+        if ostype.endswith('WOW64'):
+            cputype = 'x86_64'
+        ostype = 'pc-windows-gnu'
+    else:
+        err = "unknown OS type: {}".format(ostype)
+        sys.exit(err)
+
+    cputype_mapper = {
+        'BePC': 'i686',
+        'aarch64': 'aarch64',
+        'amd64': 'x86_64',
+        'arm64': 'aarch64',
+        'i386': 'i686',
+        'i486': 'i686',
+        'i686': 'i686',
+        'i786': 'i686',
+        'powerpc': 'powerpc',
+        'powerpc64': 'powerpc64',
+        'powerpc64le': 'powerpc64le',
+        'ppc': 'powerpc',
+        'ppc64': 'powerpc64',
+        'ppc64le': 'powerpc64le',
+        's390x': 's390x',
+        'x64': 'x86_64',
+        'x86': 'i686',
+        'x86-64': 'x86_64',
+        'x86_64': 'x86_64'
+    }
+
+    # Consider the direct transformation first and then the special cases
+    if cputype in cputype_mapper:
+        cputype = cputype_mapper[cputype]
+    elif cputype in {'xscale', 'arm'}:
+        cputype = 'arm'
+        if ostype == 'linux-android':
+            ostype = 'linux-androideabi'
+    elif cputype == 'armv6l':
+        cputype = 'arm'
+        if ostype == 'linux-android':
+            ostype = 'linux-androideabi'
+        else:
+            ostype += 'eabihf'
+    elif cputype in {'armv7l', 'armv8l'}:
+        cputype = 'armv7'
+        if ostype == 'linux-android':
+            ostype = 'linux-androideabi'
+        else:
+            ostype += 'eabihf'
+    elif cputype == 'mips':
+        if sys.byteorder == 'big':
+            cputype = 'mips'
+        elif sys.byteorder == 'little':
+            cputype = 'mipsel'
+        else:
+            raise ValueError("unknown byteorder: {}".format(sys.byteorder))
+    elif cputype == 'mips64':
+        if sys.byteorder == 'big':
+            cputype = 'mips64'
+        elif sys.byteorder == 'little':
+            cputype = 'mips64el'
+        else:
+            raise ValueError('unknown byteorder: {}'.format(sys.byteorder))
+        # only the n64 ABI is supported, indicate it
+        ostype += 'abi64'
+    elif cputype == 'sparcv9':
+        pass
+    else:
+        err = "unknown cpu type: {}".format(cputype)
+        sys.exit(err)
+
+    return "{}-{}".format(cputype, ostype)
+
 class RustBuild(object):
     """Provide all the methods required to build Rust"""
     def __init__(self):
@@ -177,7 +312,6 @@ def __init__(self):
         self.build = ''
         self.build_dir = os.path.join(os.getcwd(), "build")
         self.clean = False
-        self.config_mk = ''
         self.config_toml = ''
         self.printed = False
         self.rust_root = os.path.abspath(os.path.join(__file__, '../../..'))
@@ -374,26 +508,6 @@ def get_toml(self, key):
                 return self.get_string(value) or value.strip()
         return None
 
-    def get_mk(self, key):
-        """Returns the value of the given key in config.mk, otherwise returns None
-
-        >>> rb = RustBuild()
-        >>> rb.config_mk = 'key := value\\n'
-        >>> rb.get_mk('key')
-        'value'
-
-        If the key does not exists, the result is None:
-
-        >>> rb.get_mk('does_not_exists') == None
-        True
-        """
-        for line in iter(self.config_mk.splitlines()):
-            if line.startswith(key + ' '):
-                var = line[line.find(':=') + 2:].strip()
-                if var != '':
-                    return var
-        return None
-
     def cargo(self):
         """Return config path for cargo"""
         return self.program_config('cargo')
@@ -407,7 +521,6 @@ def program_config(self, program):
 
         >>> rb = RustBuild()
         >>> rb.config_toml = 'rustc = "rustc"\\n'
-        >>> rb.config_mk = 'CFG_LOCAL_RUST_ROOT := /tmp/rust\\n'
         >>> rb.program_config('rustc')
         'rustc'
         >>> cargo_path = rb.program_config('cargo')
@@ -415,7 +528,6 @@ def program_config(self, program):
         ... "bin", "cargo")
         True
         >>> rb.config_toml = ''
-        >>> rb.config_mk = ''
         >>> cargo_path = rb.program_config('cargo')
         >>> cargo_path.rstrip(".exe") == os.path.join(rb.bin_root(),
         ... "bin", "cargo")
@@ -424,10 +536,6 @@ def program_config(self, program):
         config = self.get_toml(program)
         if config:
             return config
-        config = self.get_mk('CFG_LOCAL_RUST_ROOT')
-        if config:
-            return os.path.join(config, "bin", "{}{}".format(
-                program, self.exe_suffix()))
         return os.path.join(self.bin_root(), "bin", "{}{}".format(
             program, self.exe_suffix()))
 
@@ -439,10 +547,14 @@ def get_string(line):
         'devel'
         """
         start = line.find('"')
-        if start == -1:
-            return None
-        end = start + 1 + line[start + 1:].find('"')
-        return line[start + 1:end]
+        if start != -1:
+            end = start + 1 + line[start + 1:].find('"')
+            return line[start + 1:end]
+        start = line.find('\'')
+        if start != -1:
+            end = start + 1 + line[start + 1:].find('\'')
+            return line[start + 1:end]
+        return None
 
     @staticmethod
     def exe_suffix():
@@ -521,154 +633,12 @@ def build_triple(self):
         config = self.get_toml('build')
         if config:
             return config
-        config = self.get_mk('CFG_BUILD')
-        if config:
-            return config
-        try:
-            ostype = subprocess.check_output(
-                ['uname', '-s']).strip().decode(default_encoding)
-            cputype = subprocess.check_output(
-                ['uname', '-m']).strip().decode(default_encoding)
-        except (subprocess.CalledProcessError, OSError):
-            if sys.platform == 'win32':
-                return 'x86_64-pc-windows-msvc'
-            err = "uname not found"
-            if self.verbose:
-                raise Exception(err)
-            sys.exit(err)
-
-        # The goal here is to come up with the same triple as LLVM would,
-        # at least for the subset of platforms we're willing to target.
-        ostype_mapper = {
-            'Bitrig': 'unknown-bitrig',
-            'Darwin': 'apple-darwin',
-            'DragonFly': 'unknown-dragonfly',
-            'FreeBSD': 'unknown-freebsd',
-            'Haiku': 'unknown-haiku',
-            'NetBSD': 'unknown-netbsd',
-            'OpenBSD': 'unknown-openbsd'
-        }
-
-        # Consider the direct transformation first and then the special cases
-        if ostype in ostype_mapper:
-            ostype = ostype_mapper[ostype]
-        elif ostype == 'Linux':
-            os_from_sp = subprocess.check_output(
-                ['uname', '-o']).strip().decode(default_encoding)
-            if os_from_sp == 'Android':
-                ostype = 'linux-android'
-            else:
-                ostype = 'unknown-linux-gnu'
-        elif ostype == 'SunOS':
-            ostype = 'sun-solaris'
-            # On Solaris, uname -m will return a machine classification instead
-            # of a cpu type, so uname -p is recommended instead.  However, the
-            # output from that option is too generic for our purposes (it will
-            # always emit 'i386' on x86/amd64 systems).  As such, isainfo -k
-            # must be used instead.
-            try:
-                cputype = subprocess.check_output(
-                    ['isainfo', '-k']).strip().decode(default_encoding)
-            except (subprocess.CalledProcessError, OSError):
-                err = "isainfo not found"
-                if self.verbose:
-                    raise Exception(err)
-                sys.exit(err)
-        elif ostype.startswith('MINGW'):
-            # msys' `uname` does not print gcc configuration, but prints msys
-            # configuration. so we cannot believe `uname -m`:
-            # msys1 is always i686 and msys2 is always x86_64.
-            # instead, msys defines $MSYSTEM which is MINGW32 on i686 and
-            # MINGW64 on x86_64.
-            ostype = 'pc-windows-gnu'
-            cputype = 'i686'
-            if os.environ.get('MSYSTEM') == 'MINGW64':
-                cputype = 'x86_64'
-        elif ostype.startswith('MSYS'):
-            ostype = 'pc-windows-gnu'
-        elif ostype.startswith('CYGWIN_NT'):
-            cputype = 'i686'
-            if ostype.endswith('WOW64'):
-                cputype = 'x86_64'
-            ostype = 'pc-windows-gnu'
-        else:
-            err = "unknown OS type: {}".format(ostype)
-            if self.verbose:
-                raise ValueError(err)
-            sys.exit(err)
-
-        cputype_mapper = {
-            'BePC': 'i686',
-            'aarch64': 'aarch64',
-            'amd64': 'x86_64',
-            'arm64': 'aarch64',
-            'i386': 'i686',
-            'i486': 'i686',
-            'i686': 'i686',
-            'i786': 'i686',
-            'powerpc': 'powerpc',
-            'powerpc64': 'powerpc64',
-            'powerpc64le': 'powerpc64le',
-            'ppc': 'powerpc',
-            'ppc64': 'powerpc64',
-            'ppc64le': 'powerpc64le',
-            's390x': 's390x',
-            'x64': 'x86_64',
-            'x86': 'i686',
-            'x86-64': 'x86_64',
-            'x86_64': 'x86_64'
-        }
-
-        # Consider the direct transformation first and then the special cases
-        if cputype in cputype_mapper:
-            cputype = cputype_mapper[cputype]
-        elif cputype in {'xscale', 'arm'}:
-            cputype = 'arm'
-            if ostype == 'linux-android':
-                ostype = 'linux-androideabi'
-        elif cputype == 'armv6l':
-            cputype = 'arm'
-            if ostype == 'linux-android':
-                ostype = 'linux-androideabi'
-            else:
-                ostype += 'eabihf'
-        elif cputype in {'armv7l', 'armv8l'}:
-            cputype = 'armv7'
-            if ostype == 'linux-android':
-                ostype = 'linux-androideabi'
-            else:
-                ostype += 'eabihf'
-        elif cputype == 'mips':
-            if sys.byteorder == 'big':
-                cputype = 'mips'
-            elif sys.byteorder == 'little':
-                cputype = 'mipsel'
-            else:
-                raise ValueError("unknown byteorder: {}".format(sys.byteorder))
-        elif cputype == 'mips64':
-            if sys.byteorder == 'big':
-                cputype = 'mips64'
-            elif sys.byteorder == 'little':
-                cputype = 'mips64el'
-            else:
-                raise ValueError('unknown byteorder: {}'.format(sys.byteorder))
-            # only the n64 ABI is supported, indicate it
-            ostype += 'abi64'
-        elif cputype == 'sparcv9':
-            pass
-        else:
-            err = "unknown cpu type: {}".format(cputype)
-            if self.verbose:
-                raise ValueError(err)
-            sys.exit(err)
-
-        return "{}-{}".format(cputype, ostype)
+        return default_build_triple()
 
     def update_submodules(self):
         """Update submodules"""
         if (not os.path.exists(os.path.join(self.rust_root, ".git"))) or \
-                self.get_toml('submodules') == "false" or \
-                self.get_mk('CFG_DISABLE_MANAGE_SUBMODULES') == "1":
+                self.get_toml('submodules') == "false":
             return
         print('Updating submodules')
         default_encoding = sys.getdefaultencoding()
@@ -680,11 +650,9 @@ def update_submodules(self):
         ).decode(default_encoding).splitlines()]
         submodules = [module for module in submodules
                       if not ((module.endswith("llvm") and
-                               (self.get_toml('llvm-config') or
-                                self.get_mk('CFG_LLVM_ROOT'))) or
+                               self.get_toml('llvm-config')) or
                               (module.endswith("jemalloc") and
-                               (self.get_toml('jemalloc') or
-                                self.get_mk('CFG_JEMALLOC_ROOT'))))]
+                               self.get_toml('jemalloc')))]
         run(["git", "submodule", "update",
              "--init", "--recursive"] + submodules,
             cwd=self.rust_root, verbose=self.verbose)
@@ -721,21 +689,15 @@ def bootstrap():
             build.config_toml = config.read()
     except:
         pass
-    try:
-        build.config_mk = open('config.mk').read()
-    except:
-        pass
 
     if '\nverbose = 2' in build.config_toml:
         build.verbose = 2
     elif '\nverbose = 1' in build.config_toml:
         build.verbose = 1
 
-    build.use_vendored_sources = '\nvendor = true' in build.config_toml or \
-                                 'CFG_ENABLE_VENDOR' in build.config_mk
+    build.use_vendored_sources = '\nvendor = true' in build.config_toml
 
-    build.use_locked_deps = '\nlocked-deps = true' in build.config_toml or \
-                            'CFG_ENABLE_LOCKED_DEPS' in build.config_mk
+    build.use_locked_deps = '\nlocked-deps = true' in build.config_toml
 
     if 'SUDO_USER' in os.environ and not build.use_vendored_sources:
         if os.environ.get('USER') != os.environ['SUDO_USER']:
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index f43035fbfe8a1..2c25f374e12a4 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -10,12 +10,12 @@
 
 //! Serialized configuration of a build.
 //!
-//! This module implements parsing `config.mk` and `config.toml` configuration
-//! files to tweak how the build runs.
+//! This module implements parsing `config.toml` configuration files to tweak
+//! how the build runs.
 
 use std::collections::HashMap;
 use std::env;
-use std::fs::{self, File};
+use std::fs::File;
 use std::io::prelude::*;
 use std::path::PathBuf;
 use std::process;
@@ -23,7 +23,7 @@ use std::cmp;
 
 use num_cpus;
 use toml;
-use util::{exe, push_exe_path};
+use util::exe;
 use cache::{INTERNER, Interned};
 use flags::Flags;
 pub use flags::Subcommand;
@@ -124,14 +124,12 @@ pub struct Config {
     pub nodejs: Option<PathBuf>,
     pub gdb: Option<PathBuf>,
     pub python: Option<PathBuf>,
-    pub configure_args: Vec<String>,
     pub openssl_static: bool,
-
+    pub configure_args: Vec<String>,
 
     // These are either the stage0 downloaded binaries or the locally installed ones.
     pub initial_cargo: PathBuf,
     pub initial_rustc: PathBuf,
-
 }
 
 /// Per-target configuration stored in the global configuration structure.
@@ -190,6 +188,8 @@ struct Build {
     sanitizers: Option<bool>,
     profiler: Option<bool>,
     openssl_static: Option<bool>,
+    configure_args: Option<Vec<String>>,
+    local_rebuild: Option<bool>,
 }
 
 /// TOML representation of various global install decisions.
@@ -219,6 +219,7 @@ struct Llvm {
     targets: Option<String>,
     experimental_targets: Option<String>,
     link_jobs: Option<u32>,
+    link_shared: Option<bool>,
 }
 
 #[derive(Deserialize, Default, Clone)]
@@ -265,6 +266,9 @@ struct Rust {
     debuginfo_tests: Option<bool>,
     codegen_tests: Option<bool>,
     ignore_git: Option<bool>,
+    debug: Option<bool>,
+    dist_src: Option<bool>,
+    quiet_tests: Option<bool>,
 }
 
 /// TOML representation of how each build target is configured.
@@ -374,6 +378,8 @@ impl Config {
         set(&mut config.sanitizers, build.sanitizers);
         set(&mut config.profiler, build.profiler);
         set(&mut config.openssl_static, build.openssl_static);
+        set(&mut config.configure_args, build.configure_args);
+        set(&mut config.local_rebuild, build.local_rebuild);
         config.verbose = cmp::max(config.verbose, flags.verbose);
 
         if let Some(ref install) = toml.install {
@@ -385,6 +391,17 @@ impl Config {
             config.mandir = install.mandir.clone().map(PathBuf::from);
         }
 
+        // Store off these values as options because if they're not provided
+        // we'll infer default values for them later
+        let mut llvm_assertions = None;
+        let mut debuginfo_lines = None;
+        let mut debuginfo_only_std = None;
+        let mut debug = None;
+        let mut debug_jemalloc = None;
+        let mut debuginfo = None;
+        let mut debug_assertions = None;
+        let mut optimize = None;
+
         if let Some(ref llvm) = toml.llvm {
             match llvm.ccache {
                 Some(StringOrBool::String(ref s)) => {
@@ -397,31 +414,35 @@ impl Config {
             }
             set(&mut config.ninja, llvm.ninja);
             set(&mut config.llvm_enabled, llvm.enabled);
-            set(&mut config.llvm_assertions, llvm.assertions);
+            llvm_assertions = llvm.assertions;
             set(&mut config.llvm_optimize, llvm.optimize);
             set(&mut config.llvm_release_debuginfo, llvm.release_debuginfo);
             set(&mut config.llvm_version_check, llvm.version_check);
             set(&mut config.llvm_static_stdcpp, llvm.static_libstdcpp);
+            set(&mut config.llvm_link_shared, llvm.link_shared);
             config.llvm_targets = llvm.targets.clone();
             config.llvm_experimental_targets = llvm.experimental_targets.clone();
             config.llvm_link_jobs = llvm.link_jobs;
         }
 
         if let Some(ref rust) = toml.rust {
-            set(&mut config.rust_debug_assertions, rust.debug_assertions);
-            set(&mut config.rust_debuginfo, rust.debuginfo);
-            set(&mut config.rust_debuginfo_lines, rust.debuginfo_lines);
-            set(&mut config.rust_debuginfo_only_std, rust.debuginfo_only_std);
-            set(&mut config.rust_optimize, rust.optimize);
+            debug = rust.debug;
+            debug_assertions = rust.debug_assertions;
+            debuginfo = rust.debuginfo;
+            debuginfo_lines = rust.debuginfo_lines;
+            debuginfo_only_std = rust.debuginfo_only_std;
+            optimize = rust.optimize;
+            debug_jemalloc = rust.debug_jemalloc;
             set(&mut config.rust_optimize_tests, rust.optimize_tests);
             set(&mut config.rust_debuginfo_tests, rust.debuginfo_tests);
             set(&mut config.codegen_tests, rust.codegen_tests);
             set(&mut config.rust_rpath, rust.rpath);
-            set(&mut config.debug_jemalloc, rust.debug_jemalloc);
             set(&mut config.use_jemalloc, rust.use_jemalloc);
             set(&mut config.backtrace, rust.backtrace);
             set(&mut config.channel, rust.channel.clone());
             set(&mut config.ignore_git, rust.ignore_git);
+            set(&mut config.rust_dist_src, rust.dist_src);
+            set(&mut config.quiet_tests, rust.quiet_tests);
             config.rustc_default_linker = rust.default_linker.clone();
             config.rustc_default_ar = rust.default_ar.clone();
             config.musl_root = rust.musl_root.clone().map(PathBuf::from);
@@ -476,224 +497,26 @@ impl Config {
             None => stage0_root.join(exe("cargo", &config.build)),
         };
 
-        // compat with `./configure` while we're still using that
-        if fs::metadata("config.mk").is_ok() {
-            config.update_with_config_mk();
-        }
+        // Now that we've reached the end of our configuration, infer the
+        // default values for all options that we haven't otherwise stored yet.
 
-        config
-    }
+        let default = config.channel == "nightly";
+        config.llvm_assertions = llvm_assertions.unwrap_or(default);
 
-    /// "Temporary" routine to parse `config.mk` into this configuration.
-    ///
-    /// While we still have `./configure` this implements the ability to decode
-    /// that configuration into this. This isn't exactly a full-blown makefile
-    /// parser, but hey it gets the job done!
-    fn update_with_config_mk(&mut self) {
-        let mut config = String::new();
-        File::open("config.mk").unwrap().read_to_string(&mut config).unwrap();
-        for line in config.lines() {
-            let mut parts = line.splitn(2, ":=").map(|s| s.trim());
-            let key = parts.next().unwrap();
-            let value = match parts.next() {
-                Some(n) if n.starts_with('\"') => &n[1..n.len() - 1],
-                Some(n) => n,
-                None => continue
-            };
-
-            macro_rules! check {
-                ($(($name:expr, $val:expr),)*) => {
-                    if value == "1" {
-                        $(
-                            if key == concat!("CFG_ENABLE_", $name) {
-                                $val = true;
-                                continue
-                            }
-                            if key == concat!("CFG_DISABLE_", $name) {
-                                $val = false;
-                                continue
-                            }
-                        )*
-                    }
-                }
-            }
-
-            check! {
-                ("MANAGE_SUBMODULES", self.submodules),
-                ("COMPILER_DOCS", self.compiler_docs),
-                ("DOCS", self.docs),
-                ("LLVM_ASSERTIONS", self.llvm_assertions),
-                ("LLVM_RELEASE_DEBUGINFO", self.llvm_release_debuginfo),
-                ("OPTIMIZE_LLVM", self.llvm_optimize),
-                ("LLVM_VERSION_CHECK", self.llvm_version_check),
-                ("LLVM_STATIC_STDCPP", self.llvm_static_stdcpp),
-                ("LLVM_LINK_SHARED", self.llvm_link_shared),
-                ("OPTIMIZE", self.rust_optimize),
-                ("DEBUG_ASSERTIONS", self.rust_debug_assertions),
-                ("DEBUGINFO", self.rust_debuginfo),
-                ("DEBUGINFO_LINES", self.rust_debuginfo_lines),
-                ("DEBUGINFO_ONLY_STD", self.rust_debuginfo_only_std),
-                ("JEMALLOC", self.use_jemalloc),
-                ("DEBUG_JEMALLOC", self.debug_jemalloc),
-                ("RPATH", self.rust_rpath),
-                ("OPTIMIZE_TESTS", self.rust_optimize_tests),
-                ("DEBUGINFO_TESTS", self.rust_debuginfo_tests),
-                ("QUIET_TESTS", self.quiet_tests),
-                ("LOCAL_REBUILD", self.local_rebuild),
-                ("NINJA", self.ninja),
-                ("CODEGEN_TESTS", self.codegen_tests),
-                ("LOCKED_DEPS", self.locked_deps),
-                ("VENDOR", self.vendor),
-                ("FULL_BOOTSTRAP", self.full_bootstrap),
-                ("EXTENDED", self.extended),
-                ("SANITIZERS", self.sanitizers),
-                ("PROFILER", self.profiler),
-                ("DIST_SRC", self.rust_dist_src),
-                ("CARGO_OPENSSL_STATIC", self.openssl_static),
-            }
+        let default = match &config.channel[..] {
+            "stable" | "beta" | "nightly" => true,
+            _ => false,
+        };
+        config.rust_debuginfo_lines = debuginfo_lines.unwrap_or(default);
+        config.rust_debuginfo_only_std = debuginfo_only_std.unwrap_or(default);
 
-            match key {
-                "CFG_BUILD" if value.len() > 0 => self.build = INTERNER.intern_str(value),
-                "CFG_HOST" if value.len() > 0 => {
-                    self.hosts.extend(value.split(" ").map(|s| INTERNER.intern_str(s)));
+        let default = debug == Some(true);
+        config.debug_jemalloc = debug_jemalloc.unwrap_or(default);
+        config.rust_debuginfo = debuginfo.unwrap_or(default);
+        config.rust_debug_assertions = debug_assertions.unwrap_or(default);
+        config.rust_optimize = optimize.unwrap_or(!default);
 
-                }
-                "CFG_TARGET" if value.len() > 0 => {
-                    self.targets.extend(value.split(" ").map(|s| INTERNER.intern_str(s)));
-                }
-                "CFG_EXPERIMENTAL_TARGETS" if value.len() > 0 => {
-                    self.llvm_experimental_targets = Some(value.to_string());
-                }
-                "CFG_MUSL_ROOT" if value.len() > 0 => {
-                    self.musl_root = Some(parse_configure_path(value));
-                }
-                "CFG_MUSL_ROOT_X86_64" if value.len() > 0 => {
-                    let target = INTERNER.intern_str("x86_64-unknown-linux-musl");
-                    let target = self.target_config.entry(target).or_insert(Target::default());
-                    target.musl_root = Some(parse_configure_path(value));
-                }
-                "CFG_MUSL_ROOT_I686" if value.len() > 0 => {
-                    let target = INTERNER.intern_str("i686-unknown-linux-musl");
-                    let target = self.target_config.entry(target).or_insert(Target::default());
-                    target.musl_root = Some(parse_configure_path(value));
-                }
-                "CFG_MUSL_ROOT_ARM" if value.len() > 0 => {
-                    let target = INTERNER.intern_str("arm-unknown-linux-musleabi");
-                    let target = self.target_config.entry(target).or_insert(Target::default());
-                    target.musl_root = Some(parse_configure_path(value));
-                }
-                "CFG_MUSL_ROOT_ARMHF" if value.len() > 0 => {
-                    let target = INTERNER.intern_str("arm-unknown-linux-musleabihf");
-                    let target = self.target_config.entry(target).or_insert(Target::default());
-                    target.musl_root = Some(parse_configure_path(value));
-                }
-                "CFG_MUSL_ROOT_ARMV7" if value.len() > 0 => {
-                    let target = INTERNER.intern_str("armv7-unknown-linux-musleabihf");
-                    let target = self.target_config.entry(target).or_insert(Target::default());
-                    target.musl_root = Some(parse_configure_path(value));
-                }
-                "CFG_DEFAULT_AR" if value.len() > 0 => {
-                    self.rustc_default_ar = Some(value.to_string());
-                }
-                "CFG_DEFAULT_LINKER" if value.len() > 0 => {
-                    self.rustc_default_linker = Some(value.to_string());
-                }
-                "CFG_GDB" if value.len() > 0 => {
-                    self.gdb = Some(parse_configure_path(value));
-                }
-                "CFG_RELEASE_CHANNEL" => {
-                    self.channel = value.to_string();
-                }
-                "CFG_PREFIX" => {
-                    self.prefix = Some(PathBuf::from(value));
-                }
-                "CFG_SYSCONFDIR" => {
-                    self.sysconfdir = Some(PathBuf::from(value));
-                }
-                "CFG_DOCDIR" => {
-                    self.docdir = Some(PathBuf::from(value));
-                }
-                "CFG_BINDIR" => {
-                    self.bindir = Some(PathBuf::from(value));
-                }
-                "CFG_LIBDIR" => {
-                    self.libdir = Some(PathBuf::from(value));
-                }
-                "CFG_LIBDIR_RELATIVE" => {
-                    self.libdir_relative = Some(PathBuf::from(value));
-                }
-                "CFG_MANDIR" => {
-                    self.mandir = Some(PathBuf::from(value));
-                }
-                "CFG_LLVM_ROOT" if value.len() > 0 => {
-                    let target = self.target_config.entry(self.build.clone())
-                                     .or_insert(Target::default());
-                    let root = parse_configure_path(value);
-                    target.llvm_config = Some(push_exe_path(root, &["bin", "llvm-config"]));
-                }
-                "CFG_JEMALLOC_ROOT" if value.len() > 0 => {
-                    let target = self.target_config.entry(self.build.clone())
-                                     .or_insert(Target::default());
-                    target.jemalloc = Some(parse_configure_path(value).join("libjemalloc_pic.a"));
-                }
-                "CFG_ARM_LINUX_ANDROIDEABI_NDK" if value.len() > 0 => {
-                    let target = INTERNER.intern_str("arm-linux-androideabi");
-                    let target = self.target_config.entry(target).or_insert(Target::default());
-                    target.ndk = Some(parse_configure_path(value));
-                }
-                "CFG_ARMV7_LINUX_ANDROIDEABI_NDK" if value.len() > 0 => {
-                    let target = INTERNER.intern_str("armv7-linux-androideabi");
-                    let target = self.target_config.entry(target).or_insert(Target::default());
-                    target.ndk = Some(parse_configure_path(value));
-                }
-                "CFG_I686_LINUX_ANDROID_NDK" if value.len() > 0 => {
-                    let target = INTERNER.intern_str("i686-linux-android");
-                    let target = self.target_config.entry(target).or_insert(Target::default());
-                    target.ndk = Some(parse_configure_path(value));
-                }
-                "CFG_AARCH64_LINUX_ANDROID_NDK" if value.len() > 0 => {
-                    let target = INTERNER.intern_str("aarch64-linux-android");
-                    let target = self.target_config.entry(target).or_insert(Target::default());
-                    target.ndk = Some(parse_configure_path(value));
-                }
-                "CFG_X86_64_LINUX_ANDROID_NDK" if value.len() > 0 => {
-                    let target = INTERNER.intern_str("x86_64-linux-android");
-                    let target = self.target_config.entry(target).or_insert(Target::default());
-                    target.ndk = Some(parse_configure_path(value));
-                }
-                "CFG_LOCAL_RUST_ROOT" if value.len() > 0 => {
-                    let path = parse_configure_path(value);
-                    self.initial_rustc = push_exe_path(path.clone(), &["bin", "rustc"]);
-                    self.initial_cargo = push_exe_path(path, &["bin", "cargo"]);
-                }
-                "CFG_PYTHON" if value.len() > 0 => {
-                    let path = parse_configure_path(value);
-                    self.python = Some(path);
-                }
-                "CFG_ENABLE_CCACHE" if value == "1" => {
-                    self.ccache = Some(exe("ccache", &self.build));
-                }
-                "CFG_ENABLE_SCCACHE" if value == "1" => {
-                    self.ccache = Some(exe("sccache", &self.build));
-                }
-                "CFG_CONFIGURE_ARGS" if value.len() > 0 => {
-                    self.configure_args = value.split_whitespace()
-                                               .map(|s| s.to_string())
-                                               .collect();
-                }
-                "CFG_QEMU_ARMHF_ROOTFS" if value.len() > 0 => {
-                    let target = INTERNER.intern_str("arm-unknown-linux-gnueabihf");
-                    let target = self.target_config.entry(target).or_insert(Target::default());
-                    target.qemu_rootfs = Some(parse_configure_path(value));
-                }
-                "CFG_QEMU_AARCH64_ROOTFS" if value.len() > 0 => {
-                    let target = INTERNER.intern_str("aarch64-unknown-linux-gnu");
-                    let target = self.target_config.entry(target).or_insert(Target::default());
-                    target.qemu_rootfs = Some(parse_configure_path(value));
-                }
-                _ => {}
-            }
-        }
+        config
     }
 
     pub fn verbose(&self) -> bool {
@@ -705,30 +528,6 @@ impl Config {
     }
 }
 
-#[cfg(not(windows))]
-fn parse_configure_path(path: &str) -> PathBuf {
-    path.into()
-}
-
-#[cfg(windows)]
-fn parse_configure_path(path: &str) -> PathBuf {
-    // on windows, configure produces unix style paths e.g. /c/some/path but we
-    // only want real windows paths
-
-    use std::process::Command;
-    use build_helper;
-
-    // '/' is invalid in windows paths, so we can detect unix paths by the presence of it
-    if !path.contains('/') {
-        return path.into();
-    }
-
-    let win_path = build_helper::output(Command::new("cygpath").arg("-w").arg(path));
-    let win_path = win_path.trim();
-
-    win_path.into()
-}
-
 fn set<T>(field: &mut T, val: Option<T>) {
     if let Some(v) = val {
         *field = v;
diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py
new file mode 100755
index 0000000000000..0e11635c3a0b1
--- /dev/null
+++ b/src/bootstrap/configure.py
@@ -0,0 +1,408 @@
+#!/usr/bin/env python
+# Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+# ignore-tidy-linelength
+
+import sys
+import os
+rust_dir = os.path.dirname(os.path.abspath(__file__))
+rust_dir = os.path.dirname(rust_dir)
+rust_dir = os.path.dirname(rust_dir)
+sys.path.append(os.path.join(rust_dir, "src", "bootstrap"))
+import bootstrap
+
+class Option:
+    def __init__(self, name, rustbuild, desc, value):
+        self.name = name
+        self.rustbuild = rustbuild
+        self.desc = desc
+        self.value = value
+
+options = []
+
+def o(*args):
+    options.append(Option(*args, value=False))
+
+def v(*args):
+    options.append(Option(*args, value=True))
+
+o("debug", "rust.debug", "debug mode; disables optimization unless `--enable-optimize` given")
+o("docs", "build.docs", "build standard library documentation")
+o("compiler-docs", "build.compiler-docs", "build compiler documentation")
+o("optimize-tests", "rust.optimize-tests", "build tests with optimizations")
+o("debuginfo-tests", "rust.debuginfo-tests", "build tests with debugger metadata")
+o("quiet-tests", "rust.quiet-tests", "enable quieter output when running tests")
+o("ccache", "llvm.ccache", "invoke gcc/clang via ccache to reuse object files between builds")
+o("sccache", None, "invoke gcc/clang via sccache to reuse object files between builds")
+o("local-rust", None, "use an installed rustc rather than downloading a snapshot")
+v("local-rust-root", None, "set prefix for local rust binary")
+o("local-rebuild", "build.local-rebuild", "assume local-rust matches the current version, for rebuilds; implies local-rust, and is implied if local-rust already matches the current version")
+o("llvm-static-stdcpp", "llvm.static-libstdcpp", "statically link to libstdc++ for LLVM")
+o("llvm-link-shared", "llvm.link-shared", "prefer shared linking to LLVM (llvm-config --link-shared)")
+o("rpath", "rust.rpath", "build rpaths into rustc itself")
+o("llvm-version-check", "llvm.version-check", "check if the LLVM version is supported, build anyway")
+o("codegen-tests", "rust.codegen-tests", "run the src/test/codegen tests")
+o("option-checking", None, "complain about unrecognized options in this configure script")
+o("ninja", "llvm.ninja", "build LLVM using the Ninja generator (for MSVC, requires building in the correct environment)")
+o("locked-deps", "build.locked-deps", "force Cargo.lock to be up to date")
+o("vendor", "build.vendor", "enable usage of vendored Rust crates")
+o("sanitizers", "build.sanitizers", "build the sanitizer runtimes (asan, lsan, msan, tsan)")
+o("dist-src", "rust.dist-src", "when building tarballs enables building a source tarball")
+o("cargo-openssl-static", "build.openssl-static", "static openssl in cargo")
+o("profiler", "build.profiler", "build the profiler runtime")
+
+# Optimization and debugging options. These may be overridden by the release
+# channel, etc.
+o("optimize", "rust.optimize", "build optimized rust code")
+o("optimize-llvm", "llvm.optimize", "build optimized LLVM")
+o("llvm-assertions", "llvm.assertions", "build LLVM with assertions")
+o("debug-assertions", "rust.debug-assertions", "build with debugging assertions")
+o("llvm-release-debuginfo", "llvm.release-debuginfo", "build LLVM with debugger metadata")
+o("debuginfo", "rust.debuginfo", "build with debugger metadata")
+o("debuginfo-lines", "rust.debuginfo-lines", "build with line number debugger metadata")
+o("debuginfo-only-std", "rust.debuginfo-only-std", "build only libstd with debugging information")
+o("debug-jemalloc", "rust.debug-jemalloc", "build jemalloc with --enable-debug --enable-fill")
+
+v("prefix", "install.prefix", "set installation prefix")
+v("localstatedir", "install.localstatedir", "local state directory")
+v("datadir", "install.datadir", "install data")
+v("sysconfdir", "install.sysconfdir", "install system configuration files")
+v("infodir", "install.infodir", "install additional info")
+v("libdir", "install.libdir", "install libraries")
+v("mandir", "install.mandir", "install man pages in PATH")
+v("docdir", "install.docdir", "install documentation in PATH")
+v("bindir", "install.bindir", "install binaries")
+
+v("llvm-root", None, "set LLVM root")
+v("python", "build.python", "set path to python")
+v("jemalloc-root", None, "set directory where libjemalloc_pic.a is located")
+v("android-cross-path", "target.arm-linux-androideabi.android-ndk",
+  "Android NDK standalone path (deprecated)")
+v("i686-linux-android-ndk", "target.i686-linux-android.android-ndk",
+  "i686-linux-android NDK standalone path")
+v("arm-linux-androideabi-ndk", "target.arm-linux-androideabi.android-ndk",
+  "arm-linux-androideabi NDK standalone path")
+v("armv7-linux-androideabi-ndk", "target.armv7-linux-androideabi.android-ndk",
+  "armv7-linux-androideabi NDK standalone path")
+v("aarch64-linux-android-ndk", "target.aarch64-linux-android.android-ndk",
+  "aarch64-linux-android NDK standalone path")
+v("x86_64-linux-android-ndk", "target.x86_64-linux-android.android-ndk",
+  "x86_64-linux-android NDK standalone path")
+v("musl-root", "target.x86_64-unknown-linux-musl.musl-root",
+  "MUSL root installation directory (deprecated)")
+v("musl-root-x86_64", "target.x86_64-unknown-linux-musl.musl-root",
+  "x86_64-unknown-linux-musl install directory")
+v("musl-root-i686", "target.i686-unknown-linux-musl.musl-root",
+  "i686-unknown-linux-musl install directory")
+v("musl-root-arm", "target.arm-unknown-linux-musleabi.musl-root",
+  "arm-unknown-linux-musleabi install directory")
+v("musl-root-armhf", "target.arm-unknown-linux-musleabihf.musl-root",
+  "arm-unknown-linux-musleabihf install directory")
+v("musl-root-armv7", "target.armv7-unknown-linux-musleabihf.musl-root",
+  "armv7-unknown-linux-musleabihf install directory")
+v("qemu-armhf-rootfs", "target.arm-unknown-linux-gnueabihf.qemu-rootfs",
+  "rootfs in qemu testing, you probably don't want to use this")
+v("qemu-aarch64-rootfs", "target.aarch64-unknown-linux-gnu.qemu-rootfs",
+  "rootfs in qemu testing, you probably don't want to use this")
+v("experimental-targets", "llvm.experimental-targets",
+  "experimental LLVM targets to build")
+v("release-channel", "rust.channel", "the name of the release channel to build")
+
+# Used on systems where "cc" and "ar" are unavailable
+v("default-linker", "rust.default-linker", "the default linker")
+v("default-ar", "rust.default-ar", "the default ar")
+
+# Many of these are saved below during the "writing configuration" step
+# (others are conditionally saved).
+o("manage-submodules", "build.submodules", "let the build manage the git submodules")
+o("jemalloc", "rust.use-jemalloc", "build liballoc with jemalloc")
+o("full-bootstrap", "build.full-bootstrap", "build three compilers instead of two")
+o("extended", "build.extended", "build an extended rust tool set")
+
+v("build", "build.build", "GNUs ./configure syntax LLVM build triple")
+v("host", None, "GNUs ./configure syntax LLVM host triples")
+v("target", None, "GNUs ./configure syntax LLVM target triples")
+
+v("set", None, "set arbitrary key/value pairs in TOML configuration")
+
+def p(msg):
+    print("configure: " + msg)
+
+def err(msg):
+    print("configure: error: " + msg)
+    sys.exit(1)
+
+if '--help' in sys.argv or '-h' in sys.argv:
+    print('Usage: ./configure [options]')
+    print('')
+    print('Options')
+    for option in options:
+        if 'android' in option.name:
+            # no one needs to know about these obscure options
+            continue
+        if option.value:
+            print('\t{:30} {}'.format('--{}=VAL'.format(option.name), option.desc))
+        else:
+            print('\t{:30} {}'.format('--enable-{}'.format(option.name), option.desc))
+    print('')
+    print('This configure script is a thin configuration shim over the true')
+    print('configuration system, `config.toml`. You can explore the comments')
+    print('in `config.toml.example` next to this configure script to see')
+    print('more information about what each option is. Additionally you can')
+    print('pass `--set` as an argument to set arbitrary key/value pairs')
+    print('in the TOML configuration if desired')
+    print('')
+    print('Also note that all options which take `--enable` can similarly')
+    print('be passed with `--disable-foo` to forcibly disable the option')
+    sys.exit(0)
+
+# Parse all command line arguments into one of these three lists, handling
+# boolean and value-based options separately
+unknown_args = []
+need_value_args = []
+known_args = {}
+
+p("processing command line")
+i = 1
+while i < len(sys.argv):
+    arg = sys.argv[i]
+    i += 1
+    if not arg.startswith('--'):
+        unknown_args.append(arg)
+        continue
+
+    found = False
+    for option in options:
+        value = None
+        if option.value:
+            keyval = arg[2:].split('=', 1)
+            key = keyval[0]
+            if option.name != key:
+                continue
+
+            if len(keyval) > 1:
+                value = keyval[1]
+            elif i < len(sys.argv):
+                value = sys.argv[i]
+                i += 1
+            else:
+                need_value_args.append(arg)
+                continue
+        else:
+            if arg[2:] == 'enable-' + option.name:
+                value = True
+            elif arg[2:] == 'disable-' + option.name:
+                value = False
+            else:
+                continue
+
+        found = True
+        if not option.name in known_args:
+            known_args[option.name] = []
+        known_args[option.name].append((option, value))
+        break
+
+    if not found:
+        unknown_args.append(arg)
+p("")
+
+if 'option-checking' not in known_args or known_args['option-checking'][1]:
+    if len(unknown_args) > 0:
+        err("Option '" + unknown_args[0] + "' is not recognized")
+    if len(need_value_args) > 0:
+        err("Option '{0}' needs a value ({0}=val)".format(need_value_args[0]))
+
+# Parse all known arguments into a configuration structure that reflects the
+# TOML we're going to write out
+config = {}
+
+def build():
+    if 'build' in known_args:
+        return known_args['build'][0][1]
+    return bootstrap.default_build_triple()
+
+def set(key, value):
+      s = "{:20} := {}".format(key, value)
+      if len(s) < 70:
+          p(s)
+      else:
+          p(s[:70] + " ...")
+
+      arr = config
+      parts = key.split('.')
+      for i, part in enumerate(parts):
+          if i == len(parts) - 1:
+              arr[part] = value
+          else:
+              if not part in arr:
+                  arr[part] = {}
+              arr = arr[part]
+
+for key in known_args:
+    # The `set` option is special and an be passed a bunch of times
+    if key == 'set':
+        for option, value in known_args[key]:
+            keyval = value.split('=', 1)
+            set(keyval[0], True if len(keyval) == 1 else keyval[1])
+        continue
+
+    # Ensure each option is only passed once
+    arr = known_args[key]
+    if len(arr) > 1:
+        err("Option '{}' provided more than once".format(key))
+    option, value = arr[0]
+
+    # If we have a clear avenue to set our value in rustbuild, do so
+    if option.rustbuild is not None:
+        set(option.rustbuild, value)
+        continue
+
+    # Otherwise we're a "special" option and need some extra handling, so do
+    # that here.
+    if option.name == 'sccache':
+        set('llvm.ccache', 'sccache')
+    elif option.name == 'local-rust':
+        for path in os.environ['PATH'].split(os.pathsep):
+            if os.path.exists(path + '/rustc'):
+                set('build.rustc', path + '/rustc')
+                break
+        for path in os.environ['PATH'].split(os.pathsep):
+            if os.path.exists(path + '/cargo'):
+                set('build.cargo', path + '/cargo')
+                break
+    elif option.name == 'local-rust-root':
+        set('build.rustc', value + '/bin/rustc')
+        set('build.cargo', value + '/bin/cargo')
+    elif option.name == 'llvm-root':
+        set('target.{}.llvm-config'.format(build()), value + '/bin/llvm-config')
+    elif option.name == 'jemalloc-root':
+        set('target.{}.jemalloc'.format(build()), value + '/libjemalloc_pic.a')
+    elif option.name == 'host':
+        set('build.host', value.split(','))
+    elif option.name == 'target':
+        set('build.target', value.split(','))
+    elif option.name == 'option-checking':
+        # this was handled above
+        pass
+    else:
+        raise RuntimeError("unhandled option {}".format(option.name))
+
+set('build.configure-args', sys.argv[1:])
+
+# "Parse" the `config.toml.example` file into the various sections, and we'll
+# use this as a template of a `config.toml` to write out which preserves
+# all the various comments and whatnot.
+#
+# Note that the `target` section is handled separately as we'll duplicate it
+# per configure dtarget, so there's a bit of special handling for that here.
+sections = {}
+cur_section = None
+sections[None] = []
+section_order = [None]
+targets = {}
+
+for line in open(rust_dir + '/config.toml.example').read().split("\n"):
+    if line.startswith('['):
+        cur_section = line[1:-1]
+        if cur_section.startswith('target'):
+            cur_section = 'target'
+        elif '.' in cur_section:
+            raise RuntimeError("don't know how to deal with section: {}".format(cur_section))
+        sections[cur_section] = [line]
+        section_order.append(cur_section)
+    else:
+        sections[cur_section].append(line)
+
+# Fill out the `targets` array by giving all configured targets a copy of the
+# `target` section we just loaded from the example config
+configured_targets = [build()]
+if 'build' in config:
+    if 'host' in config['build']:
+        configured_targets += config['build']['host']
+    if 'target' in config['build']:
+        configured_targets += config['build']['target']
+if 'target' in config:
+    for target in config['target']:
+        configured_targets.append(target)
+for target in configured_targets:
+    targets[target] = sections['target'][:]
+    targets[target][0] = targets[target][0].replace("x86_64-unknown-linux-gnu", target)
+
+# Here we walk through the constructed configuration we have from the parsed
+# command line arguemnts. We then apply each piece of configuration by
+# basically just doing a `sed` to change the various configuration line to what
+# we've got configure.
+def to_toml(value):
+    if isinstance(value, bool):
+        if value:
+            return "true"
+        else:
+            return "false"
+    elif isinstance(value, list):
+        return '[' + ', '.join(map(to_toml, value)) + ']'
+    elif isinstance(value, str):
+        return "'" + value + "'"
+    else:
+        raise 'no toml'
+
+def configure_section(lines, config):
+    for key in config:
+        value = config[key]
+        found = False
+        for i, line in enumerate(lines):
+            if not line.startswith('#' + key + ' = '):
+                continue
+            found = True
+            lines[i] = "{} = {}".format(key, to_toml(value))
+            break
+        if not found:
+            raise RuntimeError("failed to find config line for {}".format(key))
+
+for section_key in config:
+    section_config = config[section_key]
+    if not section_key in sections:
+        raise RuntimeError("config key {} not in sections".format(key))
+
+    if section_key == 'target':
+        for target in section_config:
+            configure_section(targets[target], section_config[target])
+    else:
+        configure_section(sections[section_key], section_config)
+
+# Now that we've built up our `config.toml`, write it all out in the same
+# order that we read it in.
+p("")
+p("writing `config.toml` in current directory")
+with open('config.toml', 'w') as f:
+    for section in section_order:
+        if section == 'target':
+            for target in targets:
+                for line in targets[target]:
+                    f.write(line + "\n")
+        else:
+            for line in sections[section]:
+                f.write(line + "\n")
+
+with open('Makefile', 'w') as f:
+    contents = os.path.join(rust_dir, 'src', 'bootstrap', 'mk', 'Makefile.in')
+    contents = open(contents).read()
+    contents = contents.replace("$(CFG_SRC_DIR)", rust_dir + '/')
+    contents = contents.replace("$(CFG_PYTHON)", sys.executable)
+    f.write(contents)
+
+# Finally, clean up with a bit of a help message
+relpath = os.path.dirname(__file__)
+if relpath == '':
+    relpath = '.'
+
+p("")
+p("run `python {}/x.py --help`".format(relpath))
+p("")
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index bfcfb5f9a37f8..153ffe509f308 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -822,6 +822,7 @@ impl Step for PlainSourceTarball {
             "RELEASES.md",
             "configure",
             "x.py",
+            "config.toml.example",
         ];
         let src_dirs = [
             "man",
diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in
index 9410927824cc1..67495b891f80d 100644
--- a/src/bootstrap/mk/Makefile.in
+++ b/src/bootstrap/mk/Makefile.in
@@ -8,8 +8,6 @@
 # option. This file may not be copied, modified, or distributed
 # except according to those terms.
 
-include config.mk
-
 ifdef VERBOSE
 Q :=
 BOOTSTRAP_ARGS := -v