diff options
Diffstat (limited to 'build.sh.in')
-rw-r--r-- | build.sh.in | 780 |
1 files changed, 780 insertions, 0 deletions
diff --git a/build.sh.in b/build.sh.in new file mode 100644 index 0000000..43c648a --- /dev/null +++ b/build.sh.in @@ -0,0 +1,780 @@ +#!/bin/sh + +# file : build.sh.in +# license : MIT; see accompanying LICENSE file + +usage="Usage: $0 [-h|--help] [<options>] [--] <c++-compiler> [<compile-options>] [-- <link-options>]" + +# Package repository URL (or path). +# +if test -z "$BUILD2_REPO"; then + BUILD2_REPO="@BUILD2_REPO@" +fi + +# Package versions. +# +build2_ver="@BUILD2_VERSION@" +bpkg_ver="@BPKG_VERSION@" +bdep_ver="@BDEP_VERSION@" + +# Standard modules comma-separated list and versions. +# +# NOTE: we currently print the list as a single line and will need to somehow +# change that when it becomes too long. +# +standard_modules="autoconf, kconfig" +autoconf_ver="@AUTOCONF_VERSION@" +kconfig_ver="@KCONFIG_VERSION@" + +# The bpkg configuration directory. +# +cver="@CONFIG_VER@" +cdir="build2-toolchain-$cver" + +diag () +{ + echo "$*" 1>&2 +} + +# Note that this function will execute a command with arguments that contain +# spaces but it will not print them as quoted (and neither does set -x). +# +run () +{ + diag "+ $@" + "$@" + if test "$?" -ne "0"; then + exit 1 + fi +} + +owd="$(pwd)" + +local= +bpkg_install=true +bdep_install=true +modules="$standard_modules" +system= +private= +idir= +exe_prefix= +exe_suffix= +stage_suffix="-stage" +jobs= +sudo= +trust= +timeout= +make= +make_options= +verbose= + +while test $# -ne 0; do + case "$1" in + -h|--help) + diag + diag "$usage" + diag "Options:" + diag " --local Don't build from packages, only from local source." + diag " --no-bpkg Don't install bpkg nor bdep (requires --local)." + diag " --no-bdep Don't install bdep." + diag " --no-modules Don't install standard build system modules." + diag " --modules <list> Install only specified standard build system modules." + diag " --install-dir <dir> Alternative installation directory." + diag " --system <list> Use system-installed versions of specified dependencies." + diag " --exe-prefix <pfx> Toolchain executables name prefix." + diag " --exe-suffix <sfx> Toolchain executables name suffix." + diag " --stage-suffix <sfx> Staged executables name suffix ('-stage' by default)." + diag " --sudo <prog> Optional sudo program to use (pass false to disable)." + diag " --private Install shared libraries into private subdirectory." + diag " --jobs|-j <num> Number of jobs to perform in parallel." + diag " --repo <loc> Alternative package repository location." + diag " --trust <fp> Repository certificate fingerprint to trust." + diag " --timeout <sec> Network operations timeout in seconds." + diag " --make <arg> Bootstrap using GNU make instead of script." + diag " --verbose <level> Diagnostics verbosity level between 0 and 6." + diag + diag "By default the script will install into /usr/local with private" + diag "library subdirectories and using sudo(1). To enable private" + diag "subdirectories and/or use sudo for a custom installation location," + diag "you need to specify --private and/or --sudo explicitly, for example:" + diag + diag "$0 --install-dir /opt/build2 --sudo sudo g++" + diag + diag "If --jobs|-j is unspecified, then the bootstrap step is performed" + diag "serially with the rest of the process using the number of available" + diag "hardware threads." + diag + diag "The --trust option recognizes two special values: 'yes' (trust" + diag "everything) and 'no' (trust nothing)." + diag + diag "The --make option can be used to bootstrap using GNU make. The" + diag "first --make value should specify the make executable optionally" + diag "followed by additional make options, for example:" + diag + diag "$0 --make make --make -j8 g++" + diag + diag "If --jobs|-j is specified, then its value is passed to make before" + diag "any additional options." + diag + diag "If specified, <compile-options> override the default (-O3) compile" + diag "options (config.cc.coptions) in the bpkg configuration used to build" + diag "and install the final toolchain. For example, to build with the debug" + diag "information (and without optimization):" + diag + diag "$0 g++ -g" + diag + diag "Use --system <list> to specify a comma-separated list of dependencies" + diag "to use from the system rather than building them from source, for" + diag "example:" + diag + diag "$0 --system libsqlite3,libpkg-config g++" + diag + diag "The script by default installs the following standard build system" + diag "modules:" + diag + diag "$standard_modules" + diag + diag "Use --no-modules to suppress installing build system modules or" + diag "--modules <list> to specify a comma-separated subset to install." + diag + diag "See the BOOTSTRAP-UNIX file for details." + diag + exit 0 + ;; + --local) + local=true + shift + ;; + --no-bpkg) + bpkg_install= + shift + ;; + --no-bdep) + bdep_install= + shift + ;; + --no-modules) + modules= + shift + ;; + --modules) + shift + modules="$1" + shift + ;; + --system) + shift + system="$1" + shift + ;; + --private) + private=config.install.private=build2 + shift + ;; + --install-dir) + shift + if test $# -eq 0; then + diag "error: installation directory expected after --install-dir" + diag "$usage" + exit 1 + fi + idir="$1" + shift + ;; + --exe-prefix) + shift + if test $# -eq 0; then + diag "error: executables name prefix expected after --exe-prefix" + diag "$usage" + exit 1 + fi + exe_prefix="$1" + shift + ;; + --exe-suffix) + shift + if test $# -eq 0; then + diag "error: executables name suffix expected after --exe-suffix" + diag "$usage" + exit 1 + fi + exe_suffix="$1" + shift + ;; + --stage-suffix) + shift + if test $# -eq 0; then + diag "error: staged executables name suffix expected after --stage-suffix" + diag "$usage" + exit 1 + fi + stage_suffix="$1" + shift + ;; + -j|--jobs) + shift + if test $# -eq 0; then + diag "error: number of jobs expected after --jobs|-j" + diag "$usage" + exit 1 + fi + jobs="-j $1" + shift + ;; + --sudo) + shift + if test $# -eq 0; then + diag "error: sudo program expected after --sudo" + diag "$usage" + exit 1 + fi + sudo="$1" + shift + ;; + --repo) + shift + if test $# -eq 0; then + diag "error: repository location expected after --repo" + diag "$usage" + exit 1 + fi + BUILD2_REPO="$1" + shift + ;; + --trust) + shift + if test $# -eq 0; then + diag "error: certificate fingerprint expected after --trust" + diag "$usage" + exit 1 + fi + trust="$1" + shift + ;; + --timeout) + shift + if test $# -eq 0; then + diag "error: value in seconds expected after --timeout" + diag "$usage" + exit 1 + fi + timeout="$1" + shift + ;; + --make) + shift + if test $# -eq 0; then + diag "error: argument expected after --make" + diag "$usage" + exit 1 + fi + if test -z "$make"; then + make="$1" + else + make_options="$make_options $1" + fi + shift + ;; + --verbose) + shift + if test $# -eq 0; then + diag "error: diagnostics level between 0 and 6 expected after --verbose" + diag "$usage" + exit 1 + fi + verbose="$1" + shift + ;; + --) + shift + break + ;; + *) + break + ;; + esac +done + +# Compiler. +# +if test $# -eq 0; then + diag "error: compiler executable expected" + diag "$usage" + exit 1 +else + cxx="$1" + shift +fi + +# Compile and link options. +# +compile_ops= +link_ops= + +while test $# -ne 0; do + if test "$1" != "--"; then + compile_ops="$compile_ops $1" + shift + else + shift + break + fi +done + +while test $# -ne 0; do + link_ops="$link_ops $1" + shift +done + +if test -z "$compile_ops"; then + compile_ops=-O3 +fi + +if test -z "$link_ops"; then + link_ops="[null]" +fi + +# Merge jobs and make_options into make. +# +if test -n "$make"; then + if test -n "$jobs"; then + make="$make $jobs" + fi + + if test -n "$make_options"; then + make="$make$make_options" # Already has leading space. + fi +fi + +# If --no-bpkg is specified, then we require --local to also be specified +# since it won't be possible to build things from packages without bpkg. Also +# imply --no-bdep in this case, since bdep is pretty much useless without +# bpkg. +# +if test -z "$bpkg_install"; then + if test -z "$local"; then + diag "error: --no-bpkg can only be used for local installation" + diag " info: additionally specify --local" + exit 1 + fi + + bdep_install= +fi + +module_version () # <name> +{ + eval "echo \$$1_ver" +} + +# Convert the comma-separated modules list into a space-separated list. +# +module_list="$(echo "$modules" | sed 's/,/ /g')" + +for m in $module_list; do + if test -z "$(module_version "$m")"; then + diag "error: unknown standard build system module '$m'" + diag " info: available standard modules: $standard_modules" + exit 1 + fi +done + +# Convert the comma-separated list of system dependencies into a +# space-separated list. +# +system_list="$(echo "$system" | sed 's/,/ /g')" + +# If any dependencies are specified to be used from the system, then specify +# the respective config.import.*= variables for the bootstrap stage 2 command +# and for the local or staged build configurations. If the installation is not +# local, then also specify these dependencies as system for the bpkg-build +# commands. +# +# As a special case, recognize the libpkgconf dependency as a request to force +# build2 to use that instead of libpkg-config. +# +# Note that the build2 driver bootstrapped at stage 1 doesn't read .pc +# files. Thus, for the bootstrap stage 2 command it is assumed that the +# headers and libraries of the system dependencies can be found by the +# compiler and linker at the standard locations. That, however, is not the +# case for libpkgconf. Thus, if specifying libpkgconf as a system dependency +# also specify its headers location via, for example, the CPATH environment +# variable: +# +# $ CPATH=/usr/local/include/pkgconf ./build.sh --local --system libpkgconf g++ +# +bootstrap_system_imports= +system_imports= +system_packages= + +for d in $system_list; do + v="$(echo "$d" | sed 's/[.+-]/_/g')" # Convert to variable name. + + if test "$d" != "libpkgconf"; then + si="config.import.$v=" + else + if test -z "$local"; then + diag "error: '--system libpkgconf' can only be used for local installation" + diag " info: additionally specify --local" + exit 1 + fi + + si="config.build2.libpkgconf=true" + fi + + # For now these are the only third-party libraries that are used by the + # build system. + # + if test "$d" = "libpkg-config" -o "$d" = "libpkgconf"; then + bootstrap_system_imports="$si" + fi + + # Suppress the 'dropping no longer used variable' warnings. + # + if test -z "$system_imports"; then + system_imports="config.config.persist='config.*'@unused=drop" + fi + + system_imports="$system_imports $si" + + if test -z "$local"; then + if test -n "$system_packages"; then + system_packages="$system_packages ?sys:$d" + else + system_packages="?sys:$d" + fi + fi +done + +# If the installation directory is unspecified, then assume it is /usr/local. +# Otherwise, if it is a relative path, then convert it to an absolute path, +# unless the realpath program is not present on the system or doesn't +# recognize any of the options we pass, in which case fail, advising to +# specify an absolute installation directory. +# +if test -z "$idir"; then + idir=/usr/local + private=config.install.private=build2 + + # Only use default sudo for the default installation directory and only if + # it wasn't specified by the user. + # + if test -z "$sudo"; then + sudo="sudo" + fi +elif test -n "$(echo "$idir" | sed -n 's#^[^/].*$#true#p')"; then + + if ! command -v realpath >/dev/null 2>&1; then + diag "error: unable to execute realpath: command not found" + diag " info: specify absolute installation directory path" + exit 1 + fi + + # Don't resolve symlinks and allow non-existent path components. + # + if ! idir="$(realpath -s -m "$idir" 2>/dev/null)"; then + diag "error: realpath does not recognize -s -m" + diag " info: specify absolute installation directory path" + exit 1 + fi +fi + +if test "$sudo" = false; then + sudo= +fi + +# Derive the to be installed executables names based on --exe-{prefix,suffix}. +# Unless the installation is local, also derive the staged executables names +# based on --stage-suffix and verify that they don't clash with existing +# filesystem entries as well as the executables being installed. +# +b="${exe_prefix}b$exe_suffix" +bpkg="${exe_prefix}bpkg$exe_suffix" +bdep="${exe_prefix}bdep$exe_suffix" + +if test -z "$local"; then + b_stage="b$stage_suffix" + bpkg_stage="bpkg$stage_suffix" + + if test -e "$idir/bin/$b_stage"; then + diag "error: staged executable name '$b_stage' clashes with existing $idir/bin/$b_stage" + diag " info: specify alternative staged executables name suffix with --stage-suffix" + exit 1 + fi + + if test -e "$idir/bin/$bpkg_stage"; then + diag "error: staged executable name '$bpkg_stage' clashes with existing $idir/bin/$bpkg_stage" + diag " info: specify alternative staged executables name suffix with --stage-suffix" + exit 1 + fi + + if test "$stage_suffix" = "$exe_suffix" -a -z "$exe_prefix"; then + diag "error: suffix '$exe_suffix' is used for both final and staged executables" + diag " info: specify alternative staged executables name suffix with --stage-suffix" + exit 1 + fi +fi + +if test -f build/config.build; then + diag "error: current directory already configured, start with clean source" + exit 1 +fi + +if test -z "$local" -a -d "../$cdir"; then + diag "error: ../$cdir/ bpkg configuration directory already exists, remove it" + exit 1 +fi + +# Add $idir/bin to PATH in case it is not already there. +# +PATH="$idir/bin:$PATH" +export PATH + +sys="$(build2/config.guess | sed -n 's/^[^-]*-[^-]*-\(.*\)$/\1/p')" + +case "$sys" in + mingw32 | mingw64 | msys | msys2 | cygwin) + conf_rpath="[null]" + conf_rpath_stage="[null]" + conf_sudo="[null]" + ;; + *) + if test -n "$private"; then + conf_rpath="$idir/lib/build2" + else + conf_rpath="$idir/lib" + fi + + conf_rpath_stage="$idir/lib" + + if test -n "$sudo"; then + conf_sudo="$sudo" + else + conf_sudo="[null]" + fi + ;; +esac + +# We don't have arrays in POSIX shell but we should be ok as long as none of +# the configuration and option values contain spaces. Note also that the +# expansion must be unquoted. +# +conf_exe_affixes= + +if test -n "$exe_prefix"; then + conf_exe_affixes="config.bin.exe.prefix=$exe_prefix" +fi + +if test -n "$exe_suffix"; then + conf_exe_affixes="$conf_exe_affixes config.bin.exe.suffix=$exe_suffix" +fi + +bpkg_fetch_ops= +bpkg_build_ops= + +if test -n "$timeout"; then + bpkg_fetch_ops="--fetch-timeout $timeout" + bpkg_build_ops="--fetch-timeout $timeout" +fi + +if test "$trust" = "yes"; then + bpkg_fetch_ops="$bpkg_fetch_ops --trust-yes" +elif test "$trust" = "no"; then + bpkg_fetch_ops="$bpkg_fetch_ops --trust-no" +elif test -n "$trust"; then + bpkg_fetch_ops="$bpkg_fetch_ops --trust $trust" +fi + +if test -n "$verbose"; then + verbose="--verbose $verbose" +fi + +# Suppress loading of default options files. +# +BUILD2_DEF_OPT="0" +export BUILD2_DEF_OPT + +BPKG_DEF_OPT="0" +export BPKG_DEF_OPT + +BDEP_DEF_OPT="0" +export BDEP_DEF_OPT + +# Bootstrap, stage 1. +# +# Note: disable all warnings since we cannot do anything more granular during +# bootstrap stage 1. +# +run cd build2 +if test -z "$make"; then + run ./bootstrap.sh "$cxx" -w +else + run $make -f ./bootstrap.gmake "CXX=$cxx" CXXFLAGS=-w +fi +run build2/b-boot --version + +# Bootstrap, stage 2. +# +run build2/b-boot $verbose $jobs config.cxx="$cxx" config.bin.lib=static $bootstrap_system_imports build2/exe{b} +mv build2/b build2/b-boot +run build2/b-boot --version + +run cd .. + +# Local installation early return. +# +if test "$local" = true; then + + run build2/build2/b-boot $verbose configure \ +config.config.hermetic=true \ +config.cxx="$cxx" \ +config.cc.coptions="${compile_ops# }" \ +config.cc.loptions="${link_ops# }" \ +config.bin.lib=shared \ +config.bin.rpath="$conf_rpath" \ +config.install.root="$idir" \ +config.install.sudo="$conf_sudo" \ +$conf_exe_affixes \ +$private \ +$system_imports + + # Install toolchain. + # + projects="build2/" + + if test "$bpkg_install" = true; then + projects="$projects bpkg/" + fi + + if test "$bdep_install" = true; then + projects="$projects bdep/" + fi + + run build2/build2/b-boot $verbose $jobs install: $projects + + run command -v "$b" + run "$b" --version + + if test "$bpkg_install" = true; then + run command -v "$bpkg" + run "$bpkg" --version + fi + + if test "$bdep_install" = true; then + run command -v "$bdep" + run "$bdep" --version + fi + + # Install modules. + # + projects= + tests= + + for m in $module_list; do + projects="$projects libbuild2-$m/" + tests="$tests tests/libbuild2-$m-tests/" + done + + if test -n "$projects"; then + run "$b" $verbose $jobs install: '!config.install.scope=project' $projects + run "$b" $verbose noop: $tests + fi + + diag + diag "Toolchain installation: $idir/bin" + diag "Build configuration: $owd" + diag + + exit 0 +fi + +# Build and stage the build system and the package manager. +# +run build2/build2/b-boot $verbose configure \ +config.cxx="$cxx" \ +config.bin.lib=shared \ +config.bin.suffix="$stage_suffix" \ +config.bin.rpath="$conf_rpath_stage" \ +config.install.root="$idir" \ +config.install.data_root=root/stage \ +config.install.sudo="$conf_sudo" \ +$system_imports + +run build2/build2/b-boot $verbose $jobs install: build2/ bpkg/ + +run command -v "$b_stage" +run "$b_stage" --version + +run command -v "$bpkg_stage" +run "$bpkg_stage" --version + +# Build the entire toolchain from packages. +# +run cd .. +run mkdir "$cdir" +run cd "$cdir" +cdir="$(pwd)" # Save full path for later. + +run "$bpkg_stage" $verbose create \ +cc \ +config.config.hermetic=true \ +config.cxx="$cxx" \ +config.cc.coptions="${compile_ops# }" \ +config.cc.loptions="${link_ops# }" \ +config.bin.lib=shared \ +config.bin.rpath="$conf_rpath" \ +config.install.root="$idir" \ +config.install.sudo="$conf_sudo" \ +$conf_exe_affixes \ +$private + +packages="build2/$build2_ver bpkg/$bpkg_ver" + +if test "$bdep_install" = true; then + packages="$packages bdep/$bdep_ver" +fi + +run "$bpkg_stage" $verbose add "$BUILD2_REPO" +run "$bpkg_stage" $verbose $bpkg_fetch_ops fetch +run "$bpkg_stage" $verbose $jobs $bpkg_build_ops build --for install --yes --plan= $packages $system_packages +run "$bpkg_stage" $verbose $jobs install --all + +run command -v "$b" +run "$b" --version + +run command -v "$bpkg" +run "$bpkg" --version + +if test "$bdep_install" = true; then + run command -v "$bdep" + run "$bdep" --version +fi + +# Build, install, and verify the build system modules. +# +packages= +tests= + +for m in $module_list; do + packages="$packages libbuild2-$m/$(module_version "$m")" + tests="$tests tests/libbuild2-$m-tests/" +done + +if test -n "$packages"; then + run "$bpkg" $verbose $jobs $bpkg_build_ops build --for install $packages $system_packages + run "$bpkg" $verbose $jobs install '!config.install.scope=project' --all-pattern=libbuild2-* +fi + +run cd "$owd" + +if test -n "$tests"; then + run "$b" $verbose noop: $tests +fi + +# Clean up stage. +# +run "$b" $verbose $jobs uninstall: build2/ bpkg/ + +diag +diag "Toolchain installation: $idir/bin" +diag "Build configuration: $cdir" +diag |