1#!/bin/sh
2#
3# Copyright (c) 2004-2010, Apple Computer, Inc. All rights reserved.
4# 
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions
7# are met:
8# 1.  Redistributions of source code must retain the above copyright
9#     notice, this list of conditions and the following disclaimer. 
10# 2.  Redistributions in binary form must reproduce the above copyright
11#     notice, this list of conditions and the following disclaimer in the
12#     documentation and/or other materials provided with the distribution. 
13# 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14#     its contributors may be used to endorse or promote products derived
15#     from this software without specific prior written permission. 
16# 
17# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
18# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20# ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR
21# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
26# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27# POSSIBILITY OF SUCH DAMAGE.
28#
29
30PREFIX=/usr/local
31PWDP=$(pwd -P)
32
33COMMONFILE=buildscripts/darwinbuild.common
34
35DARWIN_BUILDROOT=$(pwd)
36
37build=""
38action="install"
39target=""
40configuration=""
41version=""
42
43nosource="YES"
44
45USE_CHROOT=NO
46INSTALL_XCODE="NO"
47
48###
49### Include some common subroutines
50###
51
52. "$COMMONFILE"
53
54shopt -s nullglob
55
56###
57### DarwinBuild must be run as root.  Enforce this.
58###
59if [ "$EUID" != "0" ]; then
60	echo "Error: xnu-build must be run as root." 1>&2
61	exit 1
62fi
63
64projnam=xnu
65project=$(git tag -l | tail -n1)
66
67if [ ! $project ]; then
68	echo "You must check out this project from git."
69	exit 1
70fi
71
72###
73### We do our building in private/var/tmp since it's
74### likely to be out of the way of our dependencies
75### and is supposed to be writable by everyone.
76###
77
78vartmp="private/var/tmp"
79mkdir -p "$BuildRoot/$vartmp"
80chmod 1777 "$BuildRoot/$vartmp"
81
82###
83### Define the SRCROOT, OBJROOT, SYMROOT, and DSTROOT.
84### This script refers to the absolute paths of the build
85### directory, and should use REAL_SRCROOT, etc.
86### If USE_CHROOT, then the environment variables will have
87### the BuildRoot prefix omitted because the chroot
88### will make all paths relative to that point.
89###
90
91DARWIN_BUILDROOT="/private/var/tmp/BuildRoot"
92
93project_tag=$(git describe --dirty)
94
95buildtool="make"
96version="${project/$projnam-/}"
97build_version=$(($(GetBuildVersion $DARWIN_BUILDROOT/{Logs,Symbols,Headers,Roots}/$projnam/$project_tag.*) + 1))
98
99REAL_SRCROOT="/SourceCache/$projnam/$project_tag"
100
101if [ -e $REAL_SRCROOT ]; then
102	rm -rf $REAL_SRCROOT
103fi
104
105git clone $(pwd) $REAL_SRCROOT
106REAL_OBJROOT="$BuildRoot/$vartmp/$projnam/Objects/$project_tag~$build_version"
107REAL_SYMROOT="$BuildRoot/$vartmp/$projnam/Symbols/$project_tag~$build_version"
108REAL_DSTROOT="$BuildRoot/$vartmp/$projnam/Roots/$project_tag~$build_version"
109
110mkdir -p $REAL_SRCROOT $REAL_OBJROOT $REAL_SYMROOT $REAL_DSTROOT
111
112###
113### Read in the environment
114###
115
116LOG="$DARWIN_BUILDROOT/Logs/$projnam/$project_tag.log~$build_version"
117TRACELOG="$BuildRoot/private/var/tmp/$projnam/$project_tag.trace~$build_version"
118mkdir -p "$DARWIN_BUILDROOT/Logs/$projnam"
119
120if [ "$USE_CHROOT" == "YES" ]; then
121	prefix="$BuildRoot"
122else
123	prefix=""
124fi
125export SRCROOT="${REAL_SRCROOT/$prefix/}"
126export OBJROOT="${REAL_OBJROOT/$prefix/}"
127export SYMROOT="${REAL_SYMROOT/$prefix/}"
128export DSTROOT="${REAL_DSTROOT/$prefix/}"
129
130TARGET_CONFIGS=$(cat machine_configuration | xargs)
131
132# Hide this variable from the unset
133export -n SRCROOT OBJROOT SYMROOT DSTROOT PLATFORM
134export -n DARWIN_BUILDROOT DARWINBUILD_BUILD DARWINXREF_DB_FILE
135export -n USE_CHROOT INSTALL_XCODE TARGET_CONFIGS EXTERNAL_BUILD_FLAGS
136
137# Screen sets this to a multi-line value which causes trouble
138unset TERMCAP
139OLDIFS="$IFS"
140IFS=$'\n'
141for X in $(printenv) ; do
142	X=${X/=*/}
143	eval "unset $X"
144done
145IFS="$OLDIFS"
146
147export SRCROOT OBJROOT SYMROOT DSTROOT
148export DARWIN_BUILDROOT DARWINBUILD_BUILD DARWINXREF_DB_FILE
149export USE_CHROOT INSTALL_XCODE
150
151export PATH=/bin:/sbin:/usr/bin:/usr/sbin/:/usr/local/bin:/usr/local/sbin
152export SHELL="/bin/sh"
153export HOME="/var/root"
154export LOGNAME="root"
155export USER="root"
156export GROUP="wheel"
157
158build_string=""
159
160if [ "$buildtool" == "xcodebuild" -a "$target" != "" ]; then
161	build_string="$build_string -target \"$target\""
162elif [ "$target" != "" ]; then
163	action="$target"
164fi
165
166#
167# append build configuration to $action, if any
168# this is only applicable to xcodebuild
169#
170if [ "$buildtool" == "xcodebuild" -a "$configuration" != "" ]; then
171	build_string="$build_string -configuration \"$configuration\""
172fi
173
174###
175### Write out the build script that will be used.
176### This may or may not be executed in a chroot.
177### We want things like the gcc version to be picked
178### up from the chroot.
179###
180
181SCRIPT="$BuildRoot/$vartmp/$projnam/build-$project_tag~$build_version.sh"
182
183cat <<-EOF > $SCRIPT
184	#!/bin/sh
185	echo '++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++'
186	echo "BUILDING $project_tag~$build_version on \$(date 2>/dev/null)"
187	echo '++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++'
188	echo 'Build configuration:'
189	echo "    Build host:           \$(hostname 2>/dev/null)"
190	echo '    Build tool:           $buildtool'
191	echo '    Build action:         $action'
192	echo "    Build number:         $build"
193	echo "    Host kernel version:  \$(uname -v 2>/dev/null)"
194	echo "    cc version:           \$(gcc -v 2>&1 | tail -n 1 2>/dev/null)"
195	# Panther cctools unlinks -o target, so don't use /dev/null
196	echo "    cctools version:      \$(as -v -o /.devnull < /dev/null 2>&1 | cut -c 22- 2>/dev/null)"
197EOF
198if [ "$logdeps" == "YES" ]; then
199	if [ "$USE_CHROOT" == "YES" ]; then
200		if [ "$DARWINTRACE" -nt "$BuildRoot/usr/lib/darwintrace.dylib" ]; then
201			mkdir -p "$BuildRoot/usr/lib"
202			cp "$DARWINTRACE" \
203		   	"$BuildRoot/usr/lib/darwintrace.dylib"
204		fi
205		echo "export DARWINTRACE_LOG=\"${TRACELOG/$BuildRoot/}\"" >> $SCRIPT
206		echo "export DYLD_INSERT_LIBRARIES=/usr/lib/darwintrace.dylib" >> $SCRIPT
207	else
208		echo "export DARWINTRACE_LOG=\"${TRACELOG}\"" >> $SCRIPT
209		echo "export DYLD_INSERT_LIBRARIES=$DARWINTRACE" >> $SCRIPT
210	fi
211
212	echo "export DYLD_FORCE_FLAT_NAMESPACE=1" >> $SCRIPT
213fi
214
215if [ "$INSTALL_XCODE" == "YES" ]; then
216	echo "*** Redirecting ..."
217	echo "DARWINTRACE_REDIRECT=\"${BuildRoot}\""
218	echo "DARWINTRACE_LOG=\"${TRACELOG}\""
219	echo "DYLD_INSERT_LIBRARIES=$DARWINTRACE"
220	echo "DYLD_FORCE_FLAT_NAMESPACE=1"
221	echo ""
222	echo "export DARWINTRACE_REDIRECT=\"${BuildRoot}\"" >> $SCRIPT
223	echo "export DARWINTRACE_LOG=\"${TRACELOG}\"" >> $SCRIPT
224	echo "export DYLD_INSERT_LIBRARIES=$DARWINTRACE" >> $SCRIPT
225	echo "export DYLD_FORCE_FLAT_NAMESPACE=1" >> $SCRIPT
226fi
227
228if [ "$buildtool" == "xcodebuild" ]; then
229cat <<-EOF >> $SCRIPT
230	echo "    xcode version:        \$(sh -c \\\"$buildtool -version\\\")"
231EOF
232else
233cat <<-EOF >> $SCRIPT
234	echo "    make version:         \$(sh -c \\\"$buildtool -version\\\" | head -1 2>/dev/null)"
235EOF
236fi
237
238cat <<-EOF >> $SCRIPT
239	echo '++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++'
240	echo 'Build parameters:'
241	echo SRCROOT: '$SRCROOT'
242	echo OBJROOT: '$OBJROOT'
243	echo SYMROOT: '$SYMROOT'
244	echo DSTROOT: '$DSTROOT'
245EOF
246###
247### Add in the build environment variables from darwinxref
248###
249build_string="$build_string $EXTERNAL_BUILD_FLAGS \"SRCROOT=$SRCROOT\" \"OBJROOT=$OBJROOT\" \"SYMROOT=$SYMROOT\" \"DSTROOT=$DSTROOT\" \"TARGET_CONFIGS=$TARGET_CONFIGS\""
250
251OLDIFS="$IFS"
252IFS=$'\n'
253for X in \
254	"RC_ProjectName=$projnam" \
255	"RC_ProjectSourceVersion=$version" \
256	"RC_ProjectNameAndSourceVersion=$project" \
257	"RC_ProjectBuildVersion=$build_version" \
258	$XREF_ENV ; do
259	echo "echo '${X/=*/}: ${X/*=/}'" >> $SCRIPT
260	eval "export -- \"$X\""
261	build_string="$build_string \"$X\""
262done
263IFS="$OLDIFS"
264
265cat <<-EOF >> $SCRIPT
266	echo '++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++'
267	echo 'Environment variables:'
268EOF
269
270OLDIFS="$IFS"
271IFS=$'\n'
272for X in $(printenv | sort) ; do
273	echo "echo '$X'" >> $SCRIPT
274done
275IFS="$OLDIFS"
276
277cat <<-EOF >> $SCRIPT
278	echo '++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++'
279	echo $buildtool $action '$build_string' \< /dev/null
280	echo '++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++'
281	echo ''
282	echo 'Build log begins here:'
283	echo ''
284	cd '$SRCROOT'
285EOF
286cat <<-EOF >> $SCRIPT
287	if [ -x /bin/date ]; then
288		START_DATE=\$(date "+%s")
289	fi
290	$buildtool $action $build_string < /dev/null 
291	EXIT_STATUS="\$?"
292	if [ -x /bin/date ]; then
293		END_DATE=\$(date "+%s")
294		ELAPSED_TIME=\$((\$END_DATE - \$START_DATE))
295	fi
296	echo '++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++'
297	if [ -x /bin/date ]; then
298		echo " BUILD TIME: \$((\$ELAPSED_TIME / 3600))h \$((\$ELAPSED_TIME / 60))m \$((\$ELAPSED_TIME % 60))s"
299	fi
300	echo "EXIT STATUS: \$EXIT_STATUS"
301	exit \$EXIT_STATUS
302EOF
303
304chmod ugo+x $SCRIPT
305
306
307ExitHandler() {
308	### Once for fdsec
309	[ -z "$(echo $BuildRoot/dev/*)" ] || umount "$BuildRoot/dev"
310	### Twice for devfs
311	[ -z "$(echo $BuildRoot/dev/*)" ] || umount "$BuildRoot/dev"
312	### Thrice for volfs
313	[ -z "$(echo $BuildRoot/.vol/*)" ] || chroot "$BuildRoot" umount /.vol
314}
315
316
317if [ "$USE_CHROOT" == "YES" ] ; then
318	###
319	### Mount devfs in the chroot
320	### We'll make /dev/null our de-facto test for the existence of devfs
321	###
322	### Warning:
323	### This must be done *BEFORE* the call to chroot, otherwise there is
324	### no way to unmount the filesystem except rebooting.
325	###
326	echo "*** Mounting special filesystems ..."
327	trap ExitHandler EXIT
328
329	if [ ! -c "$BuildRoot/dev/null" ]; then
330		echo "Mounting devfs ..."
331		mkdir -p "$BuildRoot/dev"
332		mount -t devfs stdin "$BuildRoot/dev"
333		mount -t fdesc -o union stdin "$BuildRoot/dev"
334	else
335		echo "devfs appears to exist ..."
336	fi
337
338	if [ -x /sbin/mount_volfs ]; then
339		# volfs is no longer present (nor needed) on Leopard.
340		if [ -z "$(echo $BuildRoot/.vol/*)" ]; then
341 			echo "Mounting volfs ..."
342 			[ -d "$BuildRoot/sbin" ] || mkdir -p "$BuildRoot/sbin"
343 			[ -x "$BuildRoot/sbin/mount_volfs" ] || \
344				cp /sbin/mount_volfs "$BuildRoot/sbin/"
345 			[ -x "$BuildRoot/sbin/umount" ] || \
346				cp /sbin/umount "$BuildRoot/sbin/"
347 			[ -d "$BuildRoot/.vol" ] || mkdir -p "$BuildRoot/.vol"
348 			## If the directory is empty, assume volfs not mounted
349 			chroot "$BuildRoot" /sbin/mount_volfs "/.vol"
350		else
351	    		echo "volfs appears to be mounted ..."
352		fi
353	fi
354
355	###
356	### Actually invoke the build tool here
357	###
358	chroot -u root -g wheel $BuildRoot $vartmp/$projnam/build-$project_tag~$build_version.sh 2>&1 | tee -a "$LOG";
359	EXIT_STATUS="${PIPESTATUS[0]}"
360else
361	###
362	### Actually invoke the build tool here
363	###
364	$BuildRoot/$vartmp/$projnam/build-$project_tag~$build_version.sh 2>&1 | tee -a "$LOG"
365	EXIT_STATUS="${PIPESTATUS[0]}"
366
367	###
368	### Clean up the logging
369	###
370	if [ "$logdeps" == "YES" ]; then
371		export -n DYLD_INSERT_LIBRARIES DYLD_FORCE_FLAT_NAMESPACE DARWINTRACE_LOG
372	fi
373fi
374
375if [ "$EXIT_STATUS" == "0" ]; then
376	###
377	### Building was successful, copy the results out of the
378	### build root and into the Root cache
379	###
380
381	if [ "$action" == "installhdrs" ]; then
382	    	### Output the manifest
383		MANIFEST="/tmp/$projnam.$$"
384		"$DARWINXREF" register "$projnam" "$REAL_DSTROOT" | tee "$MANIFEST"
385		SHA1=$(cat "$MANIFEST" | $DIGEST)
386		mkdir -p "$REAL_DSTROOT/usr/local/darwinbuild/receipts"
387		cp "$MANIFEST" "$REAL_DSTROOT/usr/local/darwinbuild/receipts/$SHA1"
388		ln -s "$SHA1" "$REAL_DSTROOT/usr/local/darwinbuild/receipts/$projnam.hdrs"
389		rm -f "$MANIFEST"
390
391		mkdir -p "$DARWIN_BUILDROOT/Headers/$projnam/$project.hdrs~$build_version"
392		ditto "$REAL_DSTROOT" "$DARWIN_BUILDROOT/Headers/$projnam/$project.hdrs~$build_version"
393	else
394		mkdir -p "$DARWIN_BUILDROOT/Roots/$projnam/"
395		rm -f "$DARWIN_BUILDROOT/Roots/$projnam/$project_tag.root"
396		rm -f "$DARWIN_BUILDROOT/Roots/$projnam/$project_tag.sym"
397		ln -s "$REAL_DSTROOT" "$DARWIN_BUILDROOT/Roots/$projnam/$project_tag.root" 
398		ln -s "$REAL_SYMROOT" "$DARWIN_BUILDROOT/Roots/$projnam/$project_tag.sym"  
399	fi
400fi
401
402exit $EXIT_STATUS
403