1#!/bin/bash 2# 3# Script that rsyncs a source/build tree to a remote server, performs a build, 4# and copies the result back 5# 6 7# This script is invoked instead of the initial recursive make(1) in ./Makefile. 8# First it must cache all binaries that might be used during the build by 9# calling "make print_exports" (any target would work) with an overriden xcrun(1) 10# which caches tools an SDKs into ./BUILD/obj/BuildTools. When the combined 11# source+build tree is rsync-ed to the remote server, we run a script to 12# re-initiate the build using an overriden xcrun(1) which hands back 13# cached tools in ./BUILD/obj/BuildTools instead of whatever Xcode tools are on 14# the remote system (or if no Xcode tools are installed remotely). Finally, 15# the build results are copied back locally. 16# 17 18function die() { 19 echo "$1" 1>&2 20 exit 1 21} 22 23 24TARGET= 25declare -a ARGS 26declare -a REMOTEARGS 27index=0 28for arg in "$@"; do 29 case $arg in 30 _REMOTEBUILD_TARGET=*) 31 TARGET=`echo $arg | awk -F= '{print $2}'` 32 continue 33 ;; 34 _REMOTEBUILD_MAKE=*) 35 MAKE=`echo $arg | awk -F= '{print $2}'` 36 continue 37 ;; 38 REMOTEBUILD=*) 39 # Don't restart another remote build remotely 40 ;; 41 SRCROOT=*) 42 continue 43 ;; 44 OBJROOT=*) 45 continue 46 ;; 47 SYMROOT=*) 48 continue 49 ;; 50 DSTROOT=*) 51 continue 52 ;; 53 CCHROOT=*) 54 continue 55 ;; 56 RC_XBS=*) 57 # Remote build isn't chrooted or special in any way 58 arg="VERBOSE=YES" 59 continue 60 ;; 61 VERBOSE=YES) 62 set -x 63 ;; 64 esac 65 ARGS[$index]="$arg" 66 REMOTEARGS[$index]="\"$arg\"" 67 index=$(($index+1)) 68done 69 70 71ARGS[$index]="REMOTEBUILD=" 72REMOTEARGS[$index]="\"REMOTEBUILD=\"" 73 74# For some targets like installsrc, we can't to a remote build 75SKIPREMOTE=0 76case $TARGET in 77 clean) 78 SKIPREMOTE=1 79 ;; 80 installsrc) 81 SKIPREMOTE=1 82 ;; 83 installopensource) 84 SKIPREMOTE=1 85 ;; 86 cscope) 87 SKIPREMOTE=1 88 ;; 89 tags) 90 SKIPREMOTE=1 91 ;; 92 help) 93 SKIPREMOTE=1 94 ;; 95esac 96 97if [ $SKIPREMOTE -eq 1 ]; then 98 exec "$MAKE" "$TARGET" "${ARGS[@]}" 99fi 100 101SRC="$(pwd -P)" 102SRCNAME="$(basename $SRC)" 103 104# Pick up build locations passed in the environment 105OBJROOT="${OBJROOT}" 106SYMROOT="${SYMROOT}" 107DSTROOT="${DSTROOT}" 108 109if [ -z "${OBJROOT}" ]; then 110 die "OBJROOT not set in environment" 111fi 112mkdir -p "${OBJROOT}" || die "Could not create ${OBJROOT}" 113 114if [ -z "${SYMROOT}" ]; then 115 die "SYMROOT not set in environment" 116fi 117mkdir -p "${SYMROOT}" || die "Could not create ${SYMROOT}" 118 119if [ -z "${DSTROOT}" ]; then 120 die "DSTROOT not set in environment" 121fi 122mkdir -p "${DSTROOT}" || die "Could not create ${DSTROOT}" 123 124if [ "$REMOTEBUILD" = "$SPECIALREMOTEBUILD" ]; then 125 : 126else 127 DOINSTALLSRC=0 128 REMOTE_SRCREL="./" 129 BUILDTOOLSDIR="$OBJROOT" 130 REMOTE_BUILDTOOLSREL="./BUILD/obj" 131 BUILDSCRIPTDIR="$OBJROOT" 132 REMOTE_BUILDSCRIPTREL="./BUILD/obj" 133 BUILDSCRIPTNAME="build.sh" 134 if [ ! -d "${OBJROOT}/SETUP" ]; then 135 RSYNC_ARGS="--delete-excluded" 136 else 137 RSYNC_ARGS="" 138 fi 139 TARBUILDDIRS=0 140fi 141 142echo "Caching build tools..." 1>&2 143mkdir -p "${BUILDTOOLSDIR}" || die "Could not create BUILDTOOLSDIR" 144$MAKE print_exports "${ARGS[@]}" XCRUN="${SRC}/tools/xcrun_cache.sh -c \"${BUILDTOOLSDIR}\"" >/dev/null || die "Could not cache build tools" 145 146# Cache the make(1) binary itself 147MAKE_SDKROOT=`"${SRC}/tools/xcrun_cache.sh" -u "${BUILDTOOLSDIR}" -sdk / -show-sdk-path` 148"${SRC}/tools/xcrun_cache.sh" -c "${BUILDTOOLSDIR}" -sdk "${MAKE_SDKROOT}" -find make >/dev/null || die "Could not cache make" 149 150# Create a canned build script that can restart the build on the remote server. 151mkdir -p "${BUILDSCRIPTDIR}" || die "Could not create BUILDSCRIPTDIR" 152cat > "${BUILDSCRIPTDIR}/${BUILDSCRIPTNAME}" <<EOF 153#!/bin/sh 154mkdir -p /private/tmp 155mkdir -p /private/var/tmp 156mkdir -p "\${TMPDIR}" 157cd "${REMOTE_SRCREL}" 158mkdir -p ./BUILD/obj 159mkdir -p ./BUILD/sym 160mkdir -p ./BUILD/dst 161MAKE=\`\$PWD/tools/xcrun_cache.sh -u "\$PWD/${REMOTE_BUILDTOOLSREL}" -sdk / -find make\` 162if [ -z "\${MAKE}" ]; then exit 1; fi 163\${MAKE} ${TARGET} ${REMOTEARGS[@]} XCRUN="\$PWD/tools/xcrun_cache.sh -u \"\$PWD/${REMOTE_BUILDTOOLSREL}\"" 164ret=\$? 165if [ \$ret -eq 0 ]; then 166if [ ${TARBUILDDIRS} -eq 1 ]; then 167tar jcf ./BUILD/obj.tar.bz2 --exclude=\*.o --exclude=\*.cpo --exclude=\*.d --exclude=\*.cpd --exclude=\*.non_lto --exclude=\*.ctf --exclude=conf -C ./BUILD/obj . || exit 1 168tar jcf ./BUILD/sym.tar.bz2 -C ./BUILD/sym . || exit 1 169tar jcf ./BUILD/dst.tar.bz2 -C ./BUILD/dst . || exit 1 170fi 171fi 172exit \$ret 173EOF 174chmod a+x "${BUILDSCRIPTDIR}/${BUILDSCRIPTNAME}" 175#echo "Build script is:" 176#cat "${BUILDSCRIPTDIR}/${BUILDSCRIPTNAME}" 177 178if [ "$REMOTEBUILD" = "$SPECIALREMOTEBUILD" ]; then 179 : 180else 181 182 REMOTEBUILD="$REMOTEBUILD" 183 REMOTEBUILDPATH="$REMOTEBUILDPATH" 184 185 if [ -z "$REMOTEBUILDPATH" ]; then 186 WHOAMI=`whoami` 187 case "${REMOTEBUILD}" in 188 *@*) 189 WHOAMI=`echo "${REMOTEBUILD}" | awk -F@ '{print $1}'` 190 ;; 191 esac 192 REMOTEBUILDPATH="/tmp/$WHOAMI" 193 fi 194 195# Construct a unique remote path 196 eval `stat -s "${SRC}"` 197 198 REMOTEBUILDPATH="${REMOTEBUILDPATH}/$st_ino/${SRCNAME}/" 199 echo "Remote path is ${REMOTEBUILD}:${REMOTEBUILDPATH}" 1>&2 200 201 ssh $REMOTEBUILD "mkdir -p \"${REMOTEBUILDPATH}/BUILD/obj\"" || die "Could not make remote build directory" 202 203 # Copy source only 204 rsync -azv --delete --exclude=\*~ --exclude=.svn --exclude=.git --exclude=/BUILD . $REMOTEBUILD:"${REMOTEBUILDPATH}" || die "Could not rsync source tree" 205 206 # Copy partial OBJROOT (just build tools and build script), and optionally delete everything else 207 rsync -azv --delete $RSYNC_ARGS --include=/build.sh --include=/BuildTools --include=/BuildTools/\*\* --exclude=\* "${OBJROOT}/" $REMOTEBUILD:"${REMOTEBUILDPATH}/BUILD/obj/" || die "Could not rsync build tree" 208 209 # Start the build 210 echo ssh $REMOTEBUILD "cd \"${REMOTEBUILDPATH}\" && ${REMOTE_BUILDSCRIPTREL}/${BUILDSCRIPTNAME}" 1>&2 211 ssh $REMOTEBUILD "cd \"${REMOTEBUILDPATH}\" && ${REMOTE_BUILDSCRIPTREL}/${BUILDSCRIPTNAME}" || die "Could not complete remote build" 212 213 # Copy back build results except for object files (which might be several GB) 214 echo "Copying results back..." 215 rsync -azv --no-o --no-g --exclude=\*.o --exclude=\*.cpo --exclude=\*.d --exclude=\*.cpd --exclude=\*.non_lto --exclude=\*.ctf --exclude=conf $REMOTEBUILD:"${REMOTEBUILDPATH}/BUILD/obj/" "${OBJROOT}/" || die "Could not rsync build results" 216 rsync -azv --no-o --no-g $REMOTEBUILD:"${REMOTEBUILDPATH}/BUILD/sym/" "${SYMROOT}/" || die "Could not rsync build results" 217 rsync -azv --no-o --no-g $REMOTEBUILD:"${REMOTEBUILDPATH}/BUILD/dst/" "${DSTROOT}/" || die "Could not rsync build results" 218 219fi 220 221exit 0 222