rustbuild: Rewrite the configure script in Python

This commit rewrites our ancient `./configure` script from shell into Python.
The impetus for this change is to remove `config.mk` which is just a vestige of
the old makefile build system at this point. Instead all configuration is now
solely done through `config.toml`.

The python script allows us to more flexibly program (aka we can use loops
easily) and create a `config.toml` which is based off `config.toml.example`.
This way we can preserve comments and munge various values as we see fit.

It is intended that the configure script here is a drop-in replacement for the
previous configure script, no functional change is intended. Also note that the
rationale for this is also because our build system requires Python, so having a
python script a bit earlier shouldn't cause too many problems.

Closes #40730
This commit is contained in:
Alex Crichton 2017-08-26 15:01:48 -07:00
parent 398aaffc94
commit a9b0a7ba93
8 changed files with 655 additions and 1219 deletions

View File

@ -73,6 +73,10 @@
# controlled by rustbuild's -j parameter. # controlled by rustbuild's -j parameter.
#link-jobs = 0 #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 # General build configuration options
# ============================================================================= # =============================================================================
@ -166,6 +170,15 @@
# to +10 on Unix platforms, and by using a "low priority" job object on Windows. # to +10 on Unix platforms, and by using a "low priority" job object on Windows.
#low-priority = false #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 # General install configuration options
# ============================================================================= # =============================================================================
@ -195,6 +208,13 @@
# ============================================================================= # =============================================================================
[rust] [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 # Whether or not to optimize the compiler and standard library
# Note: the slowness of the non optimized compiler compiling itself usually # Note: the slowness of the non optimized compiler compiling itself usually
# outweighs the time gains in not doing optimizations, therefore a # outweighs the time gains in not doing optimizations, therefore a
@ -249,6 +269,10 @@
# desired in distributions, for example. # desired in distributions, for example.
#rpath = true #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 # Flag indicating whether tests are compiled with optimizations (the -O flag) or
# with debuginfo (the -g flag) # with debuginfo (the -g flag)
#optimize-tests = true #optimize-tests = true
@ -261,6 +285,9 @@
# Flag indicating whether git info will be retrieved from .git automatically. # Flag indicating whether git info will be retrieved from .git automatically.
#ignore-git = false #ignore-git = false
# When creating source tarballs whether or not to create a source tarball.
#dist-src = false
# ============================================================================= # =============================================================================
# Options for specific targets # Options for specific targets
# #
@ -304,6 +331,10 @@
# linked binaries # linked binaries
#musl-root = "..." #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 # Distribution options
# #

782
configure vendored
View File

@ -1,779 +1,17 @@
#!/bin/sh #!/bin/sh
# /bin/sh on Solaris is not a POSIX compatible shell, but /usr/bin/bash is. script="$(dirname $0)"/src/bootstrap/configure.py
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
msg() { try() {
echo "configure: $*" cmd=$1
}
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
shift shift
local P T=$($cmd --version 2>/dev/null)
local T if [ $? -eq 0 ]; then
for P exec $cmd "$script" "$@"
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 fi
} }
validate_opt () { try python2.7 "$@"
for arg in $CFG_CONFIGURE_ARGS try python27 "$@"
do try python2 "$@"
isArgValid=0 exec python $script "$@"
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
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

View File

@ -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. There are currently two methods for configuring the rustbuild build system.
First, rustbuild offers a TOML-based configuration system with a `config.toml` 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 file. An example of this configuration can be found at `config.toml.example`,
be found at `config.toml.example`, and the configuration file can also be passed and the configuration file can also be passed as `--config path/to/config.toml`
as `--config path/to/config.toml` if the build system is being invoked manually if the build system is being invoked manually (via the python script).
(via the python script).
Next, the `./configure` options serialized in `config.mk` will be Next, the `./configure` options serialized in `config.mk` will be
parsed and read. That is, if any `./configure` options are passed, they'll be parsed and read. That is, if any `./configure` options are passed, they'll be

View File

@ -167,6 +167,141 @@ def format_build_time(duration):
return str(datetime.timedelta(seconds=int(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): class RustBuild(object):
"""Provide all the methods required to build Rust""" """Provide all the methods required to build Rust"""
def __init__(self): def __init__(self):
@ -177,7 +312,6 @@ class RustBuild(object):
self.build = '' self.build = ''
self.build_dir = os.path.join(os.getcwd(), "build") self.build_dir = os.path.join(os.getcwd(), "build")
self.clean = False self.clean = False
self.config_mk = ''
self.config_toml = '' self.config_toml = ''
self.printed = False self.printed = False
self.rust_root = os.path.abspath(os.path.join(__file__, '../../..')) self.rust_root = os.path.abspath(os.path.join(__file__, '../../..'))
@ -374,26 +508,6 @@ class RustBuild(object):
return self.get_string(value) or value.strip() return self.get_string(value) or value.strip()
return None 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): def cargo(self):
"""Return config path for cargo""" """Return config path for cargo"""
return self.program_config('cargo') return self.program_config('cargo')
@ -407,7 +521,6 @@ class RustBuild(object):
>>> rb = RustBuild() >>> rb = RustBuild()
>>> rb.config_toml = 'rustc = "rustc"\\n' >>> rb.config_toml = 'rustc = "rustc"\\n'
>>> rb.config_mk = 'CFG_LOCAL_RUST_ROOT := /tmp/rust\\n'
>>> rb.program_config('rustc') >>> rb.program_config('rustc')
'rustc' 'rustc'
>>> cargo_path = rb.program_config('cargo') >>> cargo_path = rb.program_config('cargo')
@ -415,7 +528,6 @@ class RustBuild(object):
... "bin", "cargo") ... "bin", "cargo")
True True
>>> rb.config_toml = '' >>> rb.config_toml = ''
>>> rb.config_mk = ''
>>> cargo_path = rb.program_config('cargo') >>> cargo_path = rb.program_config('cargo')
>>> cargo_path.rstrip(".exe") == os.path.join(rb.bin_root(), >>> cargo_path.rstrip(".exe") == os.path.join(rb.bin_root(),
... "bin", "cargo") ... "bin", "cargo")
@ -424,10 +536,6 @@ class RustBuild(object):
config = self.get_toml(program) config = self.get_toml(program)
if config: if config:
return 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( return os.path.join(self.bin_root(), "bin", "{}{}".format(
program, self.exe_suffix())) program, self.exe_suffix()))
@ -439,10 +547,14 @@ class RustBuild(object):
'devel' 'devel'
""" """
start = line.find('"') start = line.find('"')
if start == -1: if start != -1:
return None end = start + 1 + line[start + 1:].find('"')
end = start + 1 + line[start + 1:].find('"') return line[start + 1:end]
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 @staticmethod
def exe_suffix(): def exe_suffix():
@ -521,154 +633,12 @@ class RustBuild(object):
config = self.get_toml('build') config = self.get_toml('build')
if config: if config:
return config return config
config = self.get_mk('CFG_BUILD') return default_build_triple()
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)
def update_submodules(self): def update_submodules(self):
"""Update submodules""" """Update submodules"""
if (not os.path.exists(os.path.join(self.rust_root, ".git"))) or \ if (not os.path.exists(os.path.join(self.rust_root, ".git"))) or \
self.get_toml('submodules') == "false" or \ self.get_toml('submodules') == "false":
self.get_mk('CFG_DISABLE_MANAGE_SUBMODULES') == "1":
return return
print('Updating submodules') print('Updating submodules')
default_encoding = sys.getdefaultencoding() default_encoding = sys.getdefaultencoding()
@ -680,11 +650,9 @@ class RustBuild(object):
).decode(default_encoding).splitlines()] ).decode(default_encoding).splitlines()]
submodules = [module for module in submodules submodules = [module for module in submodules
if not ((module.endswith("llvm") and if not ((module.endswith("llvm") and
(self.get_toml('llvm-config') or self.get_toml('llvm-config')) or
self.get_mk('CFG_LLVM_ROOT'))) or
(module.endswith("jemalloc") and (module.endswith("jemalloc") and
(self.get_toml('jemalloc') or self.get_toml('jemalloc')))]
self.get_mk('CFG_JEMALLOC_ROOT'))))]
run(["git", "submodule", "update", run(["git", "submodule", "update",
"--init", "--recursive"] + submodules, "--init", "--recursive"] + submodules,
cwd=self.rust_root, verbose=self.verbose) cwd=self.rust_root, verbose=self.verbose)
@ -721,21 +689,15 @@ def bootstrap():
build.config_toml = config.read() build.config_toml = config.read()
except: except:
pass pass
try:
build.config_mk = open('config.mk').read()
except:
pass
if '\nverbose = 2' in build.config_toml: if '\nverbose = 2' in build.config_toml:
build.verbose = 2 build.verbose = 2
elif '\nverbose = 1' in build.config_toml: elif '\nverbose = 1' in build.config_toml:
build.verbose = 1 build.verbose = 1
build.use_vendored_sources = '\nvendor = true' in build.config_toml or \ build.use_vendored_sources = '\nvendor = true' in build.config_toml
'CFG_ENABLE_VENDOR' in build.config_mk
build.use_locked_deps = '\nlocked-deps = true' in build.config_toml or \ build.use_locked_deps = '\nlocked-deps = true' in build.config_toml
'CFG_ENABLE_LOCKED_DEPS' in build.config_mk
if 'SUDO_USER' in os.environ and not build.use_vendored_sources: if 'SUDO_USER' in os.environ and not build.use_vendored_sources:
if os.environ.get('USER') != os.environ['SUDO_USER']: if os.environ.get('USER') != os.environ['SUDO_USER']:

View File

@ -10,12 +10,12 @@
//! Serialized configuration of a build. //! Serialized configuration of a build.
//! //!
//! This module implements parsing `config.mk` and `config.toml` configuration //! This module implements parsing `config.toml` configuration files to tweak
//! files to tweak how the build runs. //! how the build runs.
use std::collections::HashMap; use std::collections::HashMap;
use std::env; use std::env;
use std::fs::{self, File}; use std::fs::File;
use std::io::prelude::*; use std::io::prelude::*;
use std::path::PathBuf; use std::path::PathBuf;
use std::process; use std::process;
@ -23,7 +23,7 @@ use std::cmp;
use num_cpus; use num_cpus;
use toml; use toml;
use util::{exe, push_exe_path}; use util::exe;
use cache::{INTERNER, Interned}; use cache::{INTERNER, Interned};
use flags::Flags; use flags::Flags;
pub use flags::Subcommand; pub use flags::Subcommand;
@ -124,14 +124,12 @@ pub struct Config {
pub nodejs: Option<PathBuf>, pub nodejs: Option<PathBuf>,
pub gdb: Option<PathBuf>, pub gdb: Option<PathBuf>,
pub python: Option<PathBuf>, pub python: Option<PathBuf>,
pub configure_args: Vec<String>,
pub openssl_static: bool, pub openssl_static: bool,
pub configure_args: Vec<String>,
// These are either the stage0 downloaded binaries or the locally installed ones. // These are either the stage0 downloaded binaries or the locally installed ones.
pub initial_cargo: PathBuf, pub initial_cargo: PathBuf,
pub initial_rustc: PathBuf, pub initial_rustc: PathBuf,
} }
/// Per-target configuration stored in the global configuration structure. /// Per-target configuration stored in the global configuration structure.
@ -190,6 +188,8 @@ struct Build {
sanitizers: Option<bool>, sanitizers: Option<bool>,
profiler: Option<bool>, profiler: Option<bool>,
openssl_static: Option<bool>, openssl_static: Option<bool>,
configure_args: Option<Vec<String>>,
local_rebuild: Option<bool>,
} }
/// TOML representation of various global install decisions. /// TOML representation of various global install decisions.
@ -219,6 +219,7 @@ struct Llvm {
targets: Option<String>, targets: Option<String>,
experimental_targets: Option<String>, experimental_targets: Option<String>,
link_jobs: Option<u32>, link_jobs: Option<u32>,
link_shared: Option<bool>,
} }
#[derive(Deserialize, Default, Clone)] #[derive(Deserialize, Default, Clone)]
@ -265,6 +266,9 @@ struct Rust {
debuginfo_tests: Option<bool>, debuginfo_tests: Option<bool>,
codegen_tests: Option<bool>, codegen_tests: Option<bool>,
ignore_git: 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. /// TOML representation of how each build target is configured.
@ -374,6 +378,8 @@ impl Config {
set(&mut config.sanitizers, build.sanitizers); set(&mut config.sanitizers, build.sanitizers);
set(&mut config.profiler, build.profiler); set(&mut config.profiler, build.profiler);
set(&mut config.openssl_static, build.openssl_static); 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); config.verbose = cmp::max(config.verbose, flags.verbose);
if let Some(ref install) = toml.install { if let Some(ref install) = toml.install {
@ -385,6 +391,17 @@ impl Config {
config.mandir = install.mandir.clone().map(PathBuf::from); 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 { if let Some(ref llvm) = toml.llvm {
match llvm.ccache { match llvm.ccache {
Some(StringOrBool::String(ref s)) => { Some(StringOrBool::String(ref s)) => {
@ -397,31 +414,35 @@ impl Config {
} }
set(&mut config.ninja, llvm.ninja); set(&mut config.ninja, llvm.ninja);
set(&mut config.llvm_enabled, llvm.enabled); 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_optimize, llvm.optimize);
set(&mut config.llvm_release_debuginfo, llvm.release_debuginfo); set(&mut config.llvm_release_debuginfo, llvm.release_debuginfo);
set(&mut config.llvm_version_check, llvm.version_check); set(&mut config.llvm_version_check, llvm.version_check);
set(&mut config.llvm_static_stdcpp, llvm.static_libstdcpp); 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_targets = llvm.targets.clone();
config.llvm_experimental_targets = llvm.experimental_targets.clone(); config.llvm_experimental_targets = llvm.experimental_targets.clone();
config.llvm_link_jobs = llvm.link_jobs; config.llvm_link_jobs = llvm.link_jobs;
} }
if let Some(ref rust) = toml.rust { if let Some(ref rust) = toml.rust {
set(&mut config.rust_debug_assertions, rust.debug_assertions); debug = rust.debug;
set(&mut config.rust_debuginfo, rust.debuginfo); debug_assertions = rust.debug_assertions;
set(&mut config.rust_debuginfo_lines, rust.debuginfo_lines); debuginfo = rust.debuginfo;
set(&mut config.rust_debuginfo_only_std, rust.debuginfo_only_std); debuginfo_lines = rust.debuginfo_lines;
set(&mut config.rust_optimize, rust.optimize); 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_optimize_tests, rust.optimize_tests);
set(&mut config.rust_debuginfo_tests, rust.debuginfo_tests); set(&mut config.rust_debuginfo_tests, rust.debuginfo_tests);
set(&mut config.codegen_tests, rust.codegen_tests); set(&mut config.codegen_tests, rust.codegen_tests);
set(&mut config.rust_rpath, rust.rpath); 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.use_jemalloc, rust.use_jemalloc);
set(&mut config.backtrace, rust.backtrace); set(&mut config.backtrace, rust.backtrace);
set(&mut config.channel, rust.channel.clone()); set(&mut config.channel, rust.channel.clone());
set(&mut config.ignore_git, rust.ignore_git); 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_linker = rust.default_linker.clone();
config.rustc_default_ar = rust.default_ar.clone(); config.rustc_default_ar = rust.default_ar.clone();
config.musl_root = rust.musl_root.clone().map(PathBuf::from); config.musl_root = rust.musl_root.clone().map(PathBuf::from);
@ -476,226 +497,28 @@ impl Config {
None => stage0_root.join(exe("cargo", &config.build)), None => stage0_root.join(exe("cargo", &config.build)),
}; };
// compat with `./configure` while we're still using that // Now that we've reached the end of our configuration, infer the
if fs::metadata("config.mk").is_ok() { // default values for all options that we haven't otherwise stored yet.
config.update_with_config_mk();
} let default = config.channel == "nightly";
config.llvm_assertions = llvm_assertions.unwrap_or(default);
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);
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);
config config
} }
/// "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),
}
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)));
}
"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));
}
_ => {}
}
}
}
pub fn verbose(&self) -> bool { pub fn verbose(&self) -> bool {
self.verbose > 0 self.verbose > 0
} }
@ -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>) { fn set<T>(field: &mut T, val: Option<T>) {
if let Some(v) = val { if let Some(v) = val {
*field = v; *field = v;

408
src/bootstrap/configure.py Executable file
View File

@ -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("")

View File

@ -822,6 +822,7 @@ impl Step for PlainSourceTarball {
"RELEASES.md", "RELEASES.md",
"configure", "configure",
"x.py", "x.py",
"config.toml.example",
]; ];
let src_dirs = [ let src_dirs = [
"man", "man",

View File

@ -8,8 +8,6 @@
# option. This file may not be copied, modified, or distributed # option. This file may not be copied, modified, or distributed
# except according to those terms. # except according to those terms.
include config.mk
ifdef VERBOSE ifdef VERBOSE
Q := Q :=
BOOTSTRAP_ARGS := -v BOOTSTRAP_ARGS := -v