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 71RSYNC_ARGS="-azvh" 72ARGS[$index]="REMOTEBUILD=" 73REMOTEARGS[$index]="\"REMOTEBUILD=\"" 74 75# For some targets like installsrc, we can't to a remote build 76SKIPREMOTE=0 77case $TARGET in 78 clean) 79 SKIPREMOTE=1 80 ;; 81 installsrc) 82 SKIPREMOTE=1 83 ;; 84 installopensource) 85 SKIPREMOTE=1 86 ;; 87 cscope) 88 SKIPREMOTE=1 89 ;; 90 tags) 91 SKIPREMOTE=1 92 ;; 93 help) 94 SKIPREMOTE=1 95 ;; 96esac 97 98if [ $SKIPREMOTE -eq 1 ]; then 99 exec "$MAKE" "$TARGET" "${ARGS[@]}" 100fi 101 102SRC="$(pwd -P)" 103SRCNAME="$(basename $SRC)" 104 105# Pick up build locations passed in the environment 106OBJROOT="${OBJROOT}" 107SYMROOT="${SYMROOT}" 108DSTROOT="${DSTROOT}" 109 110if [ -z "${OBJROOT}" ]; then 111 die "OBJROOT not set in environment" 112fi 113mkdir -p "${OBJROOT}" || die "Could not create ${OBJROOT}" 114 115if [ -z "${SYMROOT}" ]; then 116 die "SYMROOT not set in environment" 117fi 118mkdir -p "${SYMROOT}" || die "Could not create ${SYMROOT}" 119 120if [ -z "${DSTROOT}" ]; then 121 die "DSTROOT not set in environment" 122fi 123mkdir -p "${DSTROOT}" || die "Could not create ${DSTROOT}" 124 125if [ "$REMOTEBUILD" = "$SPECIALREMOTEBUILD" ]; then 126 : 127else 128 DOINSTALLSRC=0 129 REMOTE_SRCREL="./" 130 BUILDTOOLSDIR="$OBJROOT" 131 REMOTE_BUILDTOOLSREL="./BUILD/obj" 132 BUILDSCRIPTDIR="$OBJROOT" 133 REMOTE_BUILDSCRIPTREL="./BUILD/obj" 134 BUILDSCRIPTNAME="build.sh" 135 if [ ! -d "${OBJROOT}/SETUP" ]; then 136 RSYNC_DELETE_EXCLUDED="--delete-excluded" 137 else 138 RSYNC_DELETE_EXCLUDED="" 139 fi 140 if [ ! -e "${SYMROOT}/" ]; then 141 RSYNC_DELETE_SYMROOT=1 142 else 143 RSYNC_DELETE_SYMROOT=0 144 fi 145 if [ ! -e "${DSTROOT}/" ]; then 146 RSYNC_DELETE_DSTROOT=1 147 else 148 RSYNC_DELETE_DSTROOT=0 149 fi 150 TARBUILDDIRS=0 151fi 152 153echo "Caching build tools..." 1>&2 154mkdir -p "${BUILDTOOLSDIR}" || die "Could not create BUILDTOOLSDIR" 155$MAKE print_exports "${ARGS[@]}" XCRUN="${SRC}/tools/xcrun_cache.sh -c \"${BUILDTOOLSDIR}\"" >/dev/null || die "Could not cache build tools" 156 157# Cache the make(1) binary itself 158MAKE_SDKROOT=`"${SRC}/tools/xcrun_cache.sh" -u "${BUILDTOOLSDIR}" -sdk / -show-sdk-path` 159"${SRC}/tools/xcrun_cache.sh" -c "${BUILDTOOLSDIR}" -sdk "${MAKE_SDKROOT}" -find make >/dev/null || die "Could not cache make" 160 161# Create a canned build script that can restart the build on the remote server. 162mkdir -p "${BUILDSCRIPTDIR}" || die "Could not create BUILDSCRIPTDIR" 163cat > "${BUILDSCRIPTDIR}/${BUILDSCRIPTNAME}" <<EOF 164#!/bin/sh 165mkdir -p /private/tmp 166mkdir -p /private/var/tmp 167mkdir -p "\${TMPDIR}" 168cd "${REMOTE_SRCREL}" 169mkdir -p ./BUILD/obj 170mkdir -p ./BUILD/sym 171mkdir -p ./BUILD/dst 172MAKE=\`\$PWD/tools/xcrun_cache.sh -u "\$PWD/${REMOTE_BUILDTOOLSREL}" -sdk / -find make\` 173if [ -z "\${MAKE}" ]; then exit 1; fi 174\${MAKE} ${TARGET} ${REMOTEARGS[@]} XCRUN="\$PWD/tools/xcrun_cache.sh -u \"\$PWD/${REMOTE_BUILDTOOLSREL}\"" 175ret=\$? 176if [ \$ret -eq 0 ]; then 177if [ ${TARBUILDDIRS} -eq 1 ]; then 178tar 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 179tar jcf ./BUILD/sym.tar.bz2 -C ./BUILD/sym . || exit 1 180tar jcf ./BUILD/dst.tar.bz2 -C ./BUILD/dst . || exit 1 181fi 182fi 183exit \$ret 184EOF 185chmod a+x "${BUILDSCRIPTDIR}/${BUILDSCRIPTNAME}" 186#echo "Build script is:" 187#cat "${BUILDSCRIPTDIR}/${BUILDSCRIPTNAME}" 188 189mkdir -p "${BUILDTOOLSDIR}/empty" 190 191if [ "$REMOTEBUILD" = "$SPECIALREMOTEBUILD" ]; then 192 : 193else 194 195 REMOTEBUILD="$REMOTEBUILD" 196 REMOTEBUILDPATH="$REMOTEBUILDPATH" 197 198 if [ -z "$REMOTEBUILDPATH" ]; then 199 WHOAMI=`whoami` 200 case "${REMOTEBUILD}" in 201 *@*) 202 WHOAMI=`echo "${REMOTEBUILD}" | awk -F@ '{print $1}'` 203 ;; 204 esac 205 REMOTEBUILDPATH="/tmp/$WHOAMI" 206 fi 207 208# Construct a unique remote path 209 eval `stat -s "${SRC}"` 210 211 REMOTEBUILDPATH="${REMOTEBUILDPATH}/$st_ino/${SRCNAME}/" 212 echo "Remote path is ${REMOTEBUILD}:${REMOTEBUILDPATH}" 1>&2 213 214 ssh $REMOTEBUILD "mkdir -p \"${REMOTEBUILDPATH}/BUILD/\"{obj,sym,dst}" || die "Could not make remote build directory" 215 216 # Copy source only 217 rsync $RSYNC_ARGS --delete --exclude=\*~ --exclude=.svn --exclude=.git --exclude=/BUILD . $REMOTEBUILD:"${REMOTEBUILDPATH}" || die "Could not rsync source tree" 218 219 # Copy partial OBJROOT (just build tools and build script), and optionally delete everything else 220 rsync $RSYNC_ARGS --delete $RSYNC_DELETE_EXCLUDED --include=/build.sh --include=/BuildTools --include=/BuildTools/\*\* --exclude=\* "${OBJROOT}/" $REMOTEBUILD:"${REMOTEBUILDPATH}/BUILD/obj/" || die "Could not rsync build tree" 221 222 # Delete remote SYMROOT if it has been deleted locally 223 if [ "$RSYNC_DELETE_SYMROOT" -eq 1 ]; then 224 rsync $RSYNC_ARGS --delete "${BUILDTOOLSDIR}/empty/" $REMOTEBUILD:"${REMOTEBUILDPATH}/BUILD/sym/" || die "Could not rsync delete SYMROOT" 225 fi 226 227 # Delete remote DSTROOT if it has been deleted locally 228 if [ "$RSYNC_DELETE_DSTROOT" -eq 1 ]; then 229 rsync $RSYNC_ARGS --delete "${BUILDTOOLSDIR}/empty/" $REMOTEBUILD:"${REMOTEBUILDPATH}/BUILD/dst/" || die "Could not rsync delete DSTROOT" 230 fi 231 232 # Start the build 233 echo ssh $REMOTEBUILD "/bin/bash -c 'cd \"${REMOTEBUILDPATH}\" && ${REMOTE_BUILDSCRIPTREL}/${BUILDSCRIPTNAME}'" 1>&2 234 ssh $REMOTEBUILD "/bin/bash -c 'cd \"${REMOTEBUILDPATH}\" && ${REMOTE_BUILDSCRIPTREL}/${BUILDSCRIPTNAME}'" || die "Could not complete remote build" 235 236 # Copy back build results except for object files (which might be several GB) 237 echo "Copying results back..." 238 rsync $RSYNC_ARGS --no-o --no-g --exclude=\*.o --exclude=\*.cpo --exclude=\*.d --exclude=\*.cpd --exclude=\*.non_lto --exclude=\*.ctf $REMOTEBUILD:"${REMOTEBUILDPATH}/BUILD/obj/" "${OBJROOT}/" || die "Could not rsync build results" 239 rsync $RSYNC_ARGS --no-o --no-g $REMOTEBUILD:"${REMOTEBUILDPATH}/BUILD/sym/" "${SYMROOT}/" || die "Could not rsync build results" 240 rsync $RSYNC_ARGS --no-o --no-g $REMOTEBUILD:"${REMOTEBUILDPATH}/BUILD/dst/" "${DSTROOT}/" || die "Could not rsync build results" 241 242fi 243 244exit 0 245