#!/usr/bin/env bash # set -e ## This script is initiated by either xcodebuild or Xcode.app. ## ## We must guarantee no jobserver is passed through since file-descriptors are ## clobbered by Xcode. If this is not done then make allows unlimited jobs. ## MAKEFLAGS= MFLAGS= ## validate environment case "$EXTERNAL_DRIVER" in bootstrap) ;; ## bootstrapping from terminal terminal) ;; ## building from terminal xcode) ;; ## building from Xcode.app *) echo "ERROR: unexpected value for EXTERNAL_DRIVER: $EXTERNAL_DRIVER" exit 1 ;; esac ## validate environment for name in EXTERNAL_BUILD EXTERNAL_JOBS EXTERNAL_SRC; do eval v="\$$name" if [ -z "$v" ]; then echo "ERROR: missing value for $name" exit 1 fi done ## validate environment archcount=`echo $ARCHS | awk '{ print NF }'` if [ "$archcount" -ne 1 ]; then echo "*********************************************************************" echo "***" echo "*** ERROR: multiple architectures: $ARCHS" echo "***" echo "*** This build system does not support more than one (1)" echo "*** simultaneous architecture setting." echo "***" echo "*********************************************************************" exit 1 fi exit_post_log=0 ## compute goals; these correlate with TARGET_NAME and ACTION from Xcode spec="$TARGET_NAME:$ACTION" echo "target specification: $spec" case "$spec" in external:clean) if [ "$EXTERNAL_DRIVER" == "xcode" ]; then ## driving build from Xcode.app do pristine clean if [ -z "$EXTERNAL_BUILD" ]; then echo "ERROR: unsafe rm -fr would result because EXTERNAL_BUILD is not defined" exit 1 fi if [ -d "$EXTERNAL_BUILD" ]; then cmd="/bin/rm -fr $EXTERNAL_BUILD/*" echo "$cmd" $cmd [ $? -ne 0 ] && exit 1 exit_post_log=1 else echo "already clean" fi else ## driving build from xcodebuild do xclean, preserving configuration goals=xclean fi ;; external:*) if [ -z "$EXTERNAL_GOALS" ]; then goals=build else goals="$EXTERNAL_GOALS" fi ;; *) echo "ERROR: unexpected env specification: $spec" exit 1 ;; esac ## compute if re/configure necessary if [ ! -f "$EXTERNAL_BUILD/GNUmakefile" ]; then reconfigure="no configuration present" elif [ "$EXTERNAL_SRC/make/configure.py" -nt "$EXTERNAL_BUILD/GNUmakefile" ]; then reconfigure="configure script was updated" elif [ "$EXTERNAL_DRIVER" == "bootstrap" ]; then reconfigure="driver bootstrap" elif [[ "${PATH}" == "${DEVELOPER_BIN_DIR%/bin}"* ]] || [[ "${PATH}" == "${DT_TOOLCHAIN_DIR%/bin}"* ]] || [[ "${PATH}" == "${PLATFORM_DIR%/bin}"* ]] || [[ "${PATH}" == "${PLATFORM_DEVELOPER_BIN_DIR%/bin}"* ]] || [[ "${PATH}" == "${SYSTEM_DEVELOPER_BIN_DIR%/bin}"* ]]; then reconfigure="unclobber PATH" else reconfigure= fi ## perform re/configure if [ -n "$reconfigure" ]; then echo "reconfiguring ($reconfigure)" ## respect PATH priority OIFS="${IFS}" IFS=':' read -r -a PATH_ITEMS <<< "${PATH}" IFS="${OIFS}" PATH="" APPLE_PATH="" for ITEM in "${PATH_ITEMS[@]}"; do if [[ "${ITEM}" == "${DEVELOPER_BIN_DIR%/bin}"* ]] || [[ "${ITEM}" == "${DT_TOOLCHAIN_DIR%/bin}"* ]] || [[ "${ITEM}" == "${PLATFORM_DIR%/bin}"* ]] || [[ "${ITEM}" == "${PLATFORM_DEVELOPER_BIN_DIR%/bin}"* ]] || [[ "${ITEM}" == "${SYSTEM_DEVELOPER_BIN_DIR%/bin}"* ]]; then APPLE_PATH="${APPLE_PATH}:${ITEM}" else PATH="${PATH}:${ITEM}" fi done PATH="${PATH}${APPLE_PATH}" export PATH="${PATH:1}" echo "Unclobbering PATH:" echo " export PATH=\"${PATH}\"" if [ "$EXTERNAL_DRIVER" == "bootstrap" ]; then driver="--xcode-driver=terminal" else driver="--xcode-driver=$EXTERNAL_DRIVER" fi ## determine which compiler to use based on Xcode environment (project). case "$GCC_VERSION" in com.apple.compilers.llvmgcc42) gcc="--gcc=`$DEVELOPER_BIN_DIR/xcodebuild -find-executable llvm-gcc-4.2`" ;; com.apple.compilers.llvm.clang.1_0) gcc="--gcc=`$DEVELOPER_BIN_DIR/xcodebuild -find-executable clang`" ;; *) echo "*********************************************************************" echo "***" echo "*** ERROR: unexpected value for GCC_VERSION: $GCC_VERSION" echo "***" echo "*********************************************************************" exit 1 ;; esac if [ -n "$ARCHS" ]; then arch="--arch=$ARCHS" else arch= fi case "$CONFIGURATION" in debug*) debug="--debug=std --optimize=none" ;; release*|*) debug= ;; esac if [ -n "$SDKROOT" ]; then sysroot="--sysroot=$SDKROOT" else sysroot= fi if [ -n "$MACOSX_DEPLOYMENT_TARGET" ]; then minver="--minver=$MACOSX_DEPLOYMENT_TARGET" else minver= fi ## pickup user setting from Xcode IDE and avoid recursion if [ -n "$EXTERNAL_CONFIGURE" ]; then extconf="$EXTERNAL_CONFIGURE" else extconf= fi EXTERNAL_CONFIGURE= ## invoke configure with (hidden) option which indicates conf performed by xcode (set -ex; "$EXTERNAL_SRC/configure" --force \ $EXTERNAL_CONF_ARGS \ --build="$EXTERNAL_BUILD" \ $driver \ --xcode-symroot="$SYMROOT" \ --xcode-config="$EXTERNAL_XCCONFIG" \ $gcc $arch $debug $sysroot $minver $extconf) [ $? -ne 0 ] && exit 1 fi ## log environment as provided by Xcode logdir="$EXTERNAL_BUILD/log" if [ ! -d "$logdir" ]; then mkdir -p "$logdir" fi env | sort > "$logdir/xcodemake.env.txt" [ $exit_post_log -ne 0 ] && exit 0 ## safeguard against passing blank value which would result in unlimited jobs if [ -z "$EXTERNAL_JOBS" ]; then jobs= elif [ "$EXTERNAL_JOBS" == "auto" ]; then jobs=--jobs=`sysctl -n hw.activecpu` else jobs=--jobs=$EXTERNAL_JOBS fi ## when driving from terminal; ensure $SYMROOT/external/ exists relative to SYMROOT if [ "$EXTERNAL_DRIVER" == "terminal" -a ! -e "$SYMROOT/external" ]; then ln -s "$EXTERNAL_BUILD" "$SYMROOT/external" fi ## pull the trigger ## must set XCODE.driver to prevent inifinite recursion set -x exec make -C "$EXTERNAL_BUILD" XCODE.driver=xcodemake $jobs $goals $EXTERNAL_VARS