#! /usr/bin/env bash # Upgrade remote packages in a bdep-managed build2 toolchain build (default # configurations), essentially as if by executing: # # bdep sync -fur && b # # In each project of the toolchain. # # Note that we can't just do that because as soon as we drop some dependency # package, the tools (b, bpkg, etc) become non-runnable (missing shared # libraries, etc). The script expects the current build of the toolchain # to be runnable. # # This script only upgrades the default configurations (including -libs, if # present). To upgrade the rest you can use the normal way, for example: # # bdep sync -Fur @|-a # # If the -c option is specified, the configuration is upgraded and configured # but only the build system is updated. This can be done at a later stage by # running the build system in the configuration directory: # # BDEP_SYNC=0 b builds/gcc7/ # owd="$(pwd)" trap "{ cd '$owd'; exit 1; }" ERR set -o errtrace # Trap in functions. function info () { echo "$*" 1>&2; } function error () { info "$*"; exit 1; } # Run a command with tracing (similar to set -x). # # 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). # function run () { echo "+ $@" 1>&2 "$@" } function run_no_sync () { echo "+ BDEP_SYNC=0 $@" 1>&2 BDEP_SYNC=0 "$@" } # Make sure the build2 tools are runnable. # b --version >/dev/null bpkg --version >/dev/null bdep --version >/dev/null configure_only= while [ $# -gt 0 ]; do case $1 in -c) configure_only=--configure-only shift ;; *) error "unexpected $1" ;; esac done # Get the configuration directories. # tcfg="$(b info: build2/ | sed -n -re 's/^out_root: (.+)$/\1/p')" lcfg="$(b info: libbutl/ | sed -n -re 's/^out_root: (.+)$/\1/p')" if [ -z "$tcfg" -o -z "$lcfg" ]; then error "unable to determine build configuration directories" fi tcfg="$(dirname "$tcfg")" lcfg="$(dirname "$lcfg")" if [ "$tcfg" = "$lcfg" ]; then lcfg= fi # The plan is as follows: # # 0. First, make backup copies of configurations. If something goes wrong, # it's likely the tools will be left in a non-runnable state. # # 1. Next, setup the environment (PATH, LD_LIBRARY_PATH) so that we use the # toolchain from the backup copy. Then upgrade the configurations using # that. # Step 0. # if test -e "$tcfg.bak"; then error "$tcfg.bak already exist" fi if [ -n "$lcfg" ]; then if test -e "$lcfg.bak"; then error "$lcfg.bak already exist" fi fi run cp -rp "$tcfg" "$tcfg.bak" if [ -n "$lcfg" ]; then run cp -rp "$lcfg" "$lcfg.bak" fi # Step 1. # # The main problem with running the toolchain from the backup location is the # rpaths embedded into the executables. We can make sure the libraries are # found in the backup location with LD_LIBRARY_PATH (or equivalent). But for # good measure let's also remove all the libraries from the original location # to make they don't interfere. # if [[ "$OSTYPE" == "darwin"* ]]; then so=dylib else so=so fi libs=() for f in $(find "$tcfg" -name "*.$so" -a '(' -type f -o -type l ')'); do libs+=("$f") done run rm -rf "${libs[@]}" declare -A lib_dirs for f in $(find "$tcfg.bak" -name "*.$so" -a '(' -type f -o -type l ')'); do lib_dirs["$(dirname "$f")"]= done # Note that the order should not matter. # ldpath= for d in "${!lib_dirs[@]}"; do ldpath="$d:$ldpath" done if [[ "$OSTYPE" == "darwin"* ]]; then oldpath="$DYLD_LIBRARY_PATH" run export DYLD_LIBRARY_PATH="$ldpath$DYLD_LIBRARY_PATH" else oldpath="$LD_LIBRARY_PATH" run export LD_LIBRARY_PATH="$ldpath$LD_LIBRARY_PATH" fi opath="$PATH" run export PATH="$tcfg.bak/build2/build2:$tcfg.bak/bpkg/bpkg:$tcfg.bak/bdep/bdep:$PATH" # Make sure the backup toolchain is runnable. # run which b bpkg bdep run b --version >/dev/null run bpkg --version >/dev/null run bdep --version >/dev/null # Upgrade. # run bpkg fetch -d "$tcfg" run_no_sync bpkg build -d "$tcfg" --keep-out -ur $configure_only # In configure-only we update the build system manually. # if [ -n "$configure_only" ]; then run_no_sync b build2/ fi if [ -n "$lcfg" ]; then run bpkg fetch -d "$lcfg" run_no_sync bpkg build -d "$lcfg" --keep-out -ur $configure_only fi # Restore the original environment. # if [[ "$OSTYPE" == "darwin"* ]]; then run export DYLD_LIBRARY_PATH="$oldpath" else run export LD_LIBRARY_PATH="$oldpath" fi run export PATH="$opath" run b --version >/dev/null if [ -z "$configure_only" ]; then run bpkg --version >/dev/null run bdep --version >/dev/null run b build2/ bpkg/ bdep/ # Should be a noop. fi run rm -rf "$tcfg.bak" if [ -n "$lcfg" ]; then run rm -rf "$lcfg.bak" fi