xref: /netbsd/build.sh (revision c4a72b64)
1#! /usr/bin/env sh
2#  $NetBSD: build.sh,v 1.73 2002/12/08 08:42:51 lukem Exp $
3#
4# Top level build wrapper, for a system containing no tools.
5#
6# This script should run on any POSIX-compliant shell.  For systems
7# with a strange /bin/sh, "ksh" or "bash" may be an ample alternative.
8#
9# Note, however, that due to the way the interpreter is invoked above,
10# if a POSIX-compliant shell is the first in the PATH, you won't have
11# to take any further action.
12#
13
14bomb () {
15	echo ""
16	echo "ERROR: $@"
17	echo "*** BUILD ABORTED ***"
18	exit 1
19}
20[ -d usr.bin/make ] || bomb "build.sh must be run from the top source level"
21[ -f share/mk/bsd.own.mk ] || bomb "src/share/mk is missing; please re-fetch the source tree"
22
23# If $PWD is a valid name of the current directory, POSIX mandates that pwd
24# return it by default which causes problems in the presence of symlinks.
25# Unsetting PWD is simpler than changing every occurrence of pwd to use -P.
26#
27# XXX Except that doesn't work on Solaris.
28unset PWD
29if [ "x`uname -s`" = "xSunOS" ]; then
30	TOP=`pwd -P`
31else
32	TOP=`pwd`
33fi
34
35getarch () {
36	# Translate a MACHINE into a default MACHINE_ARCH.
37	case $MACHINE in
38		acorn26|acorn32|cats|netwinder|shark|*arm)
39			MACHINE_ARCH=arm;;
40
41		sun2)
42			MACHINE_ARCH=m68000;;
43
44		amiga|atari|cesfic|hp300|sun3|*68k)
45			MACHINE_ARCH=m68k;;
46
47		mipsco|newsmips|sbmips|sgimips)
48			MACHINE_ARCH=mipseb;;
49
50		algor|arc|cobalt|evbmips|hpcmips|playstation2|pmax)
51			MACHINE_ARCH=mipsel;;
52
53		pc532)
54			MACHINE_ARCH=ns32k;;
55
56		bebox|prep|sandpoint|walnut|*ppc)
57			MACHINE_ARCH=powerpc;;
58
59		evbsh3|mmeye)
60			MACHINE_ARCH=sh3eb;;
61
62		dreamcast|hpcsh)
63			MACHINE_ARCH=sh3el;;
64
65		hp700)
66			MACHINE_ARCH=hppa;;
67
68		evbsh5)
69			MACHINE_ARCH=sh5el;;
70
71		alpha|i386|sparc|sparc64|vax|x86_64)
72			MACHINE_ARCH=$MACHINE;;
73
74		*)	bomb "unknown target MACHINE: $MACHINE";;
75	esac
76}
77
78validatearch () {
79	# Ensure that the MACHINE_ARCH exists (and is supported by build.sh).
80	case $MACHINE_ARCH in
81		alpha|arm|armeb|hppa|i386|m68000|m68k|mipse[bl]|ns32k|powerpc|sh[35]e[bl]|sparc|sparc64|vax|x86_64)
82			;;
83
84		*)	bomb "unknown target MACHINE_ARCH: $MACHINE_ARCH";;
85	esac
86}
87
88getmakevar () {
89	$make -m ${TOP}/share/mk -s -f- _x_ <<EOF
90_x_:
91	echo \${$1}
92.include <bsd.prog.mk>
93.include <bsd.kernobj.mk>
94EOF
95}
96
97resolvepath () {
98	case $OPTARG in
99	/*)	;;
100	*)	OPTARG="$TOP/$OPTARG";;
101	esac
102}
103
104usage () {
105	cat <<_usage_
106Usage:
107`basename $0` [-bdnortUu] [-a arch] [-B buildid] [-D dest] [-j njob] [-k kernel]
108	   [-M obj] [-m mach] [-O obj] [-R release] [-T tools] [-w wrapper]
109
110    -a arch	set MACHINE_ARCH to arch (otherwise deduced from MACHINE)
111    -B buildid	set BUILDID to buildid
112    -b		build nbmake and nbmake wrapper script, if needed
113    -D dest	set DESTDIR to dest
114    -d		build a full distribution into DESTDIR (including etc files)
115    -j njob	run up to njob jobs in parallel; see make(1)
116    -k kernel	build a kernel using the named configuration file
117    -M obj	set obj root directory to obj (sets MAKEOBJDIRPREFIX)
118    -m mach	set MACHINE to mach (not required if NetBSD native)
119    -n		show commands that would be executed, but do not execute them
120    -O obj	set obj root directory to obj (sets a MAKEOBJDIR pattern)
121    -o		set MKOBJDIRS=no (do not create objdirs at start of build)
122    -R release	build a release (and set RELEASEDIR to release)
123    -r		remove contents of TOOLDIR and DESTDIR before building
124    -T tools	set TOOLDIR to tools
125    -t		build and install tools only (implies -b)
126    -U		set UNPRIVED
127    -u		set UPDATE
128    -w wrapper	create nbmake script at wrapper
129		(default TOOLDIR/bin/nbmake-MACHINE)
130
131Note: if -T is unset and TOOLDIR is not set in the environment,
132      nbmake will be [re]built unconditionally.
133_usage_
134	exit 1
135}
136
137# Set defaults.
138MAKEFLAGS=
139buildtarget=build
140do_buildsystem=true
141do_buildkernel=false
142do_buildtools=false
143do_rebuildmake=false
144do_removedirs=false
145makeenv=
146makewrapper=
147opt_a=no
148opts='a:B:bD:dhj:k:M:m:nO:oR:rT:tUuw:'
149runcmd=
150
151if type getopts >/dev/null 2>&1; then
152	# Use POSIX getopts.
153	getoptcmd='getopts $opts opt && opt=-$opt'
154	optargcmd=':'
155else
156	type getopt >/dev/null 2>&1 || bomb "/bin/sh shell is too old; try ksh or bash"
157
158	# Use old-style getopt(1) (doesn't handle whitespace in args).
159	args="`getopt $opts $*`"
160	[ $? = 0 ] || usage
161	set -- $args
162
163	getoptcmd='[ $# -gt 0 ] && opt="$1" && shift'
164	optargcmd='OPTARG="$1"; shift'
165fi
166
167# Parse command line options.
168while eval $getoptcmd; do case $opt in
169	-a)	eval $optargcmd
170		MACHINE_ARCH=$OPTARG; opt_a=yes;;
171
172	-B)	eval $optargcmd
173		BUILDID=$OPTARG;;
174
175	-b)	do_buildsystem=false;;
176
177	-D)	eval $optargcmd; resolvepath
178		DESTDIR="$OPTARG"; export DESTDIR
179		makeenv="$makeenv DESTDIR";;
180
181	-d)	buildtarget=distribution;;
182
183	-j)	eval $optargcmd
184		parallel="-j $OPTARG";;
185
186	-k)	do_buildkernel=true; do_buildsystem=false
187		eval $optargcmd
188		kernconfname=$OPTARG;;
189
190	-M)	eval $optargcmd; resolvepath
191		MAKEOBJDIRPREFIX="$OPTARG"; export MAKEOBJDIRPREFIX
192		makeobjdir=$OPTARG
193		makeenv="$makeenv MAKEOBJDIRPREFIX";;
194
195	# -m overrides MACHINE_ARCH unless "-a" is specified
196	-m)	eval $optargcmd
197		MACHINE=$OPTARG; [ "$opt_a" != "yes" ] && getarch;;
198
199	-n)	runcmd=echo;;
200
201	-O)	eval $optargcmd; resolvepath
202		MAKEOBJDIR="\${.CURDIR:C,^$TOP,$OPTARG,}"; export MAKEOBJDIR
203		makeobjdir=$OPTARG
204		makeenv="$makeenv MAKEOBJDIR";;
205
206	-o)	MKOBJDIRS=no;;
207
208	-R)	eval $optargcmd; resolvepath
209		RELEASEDIR=$OPTARG; export RELEASEDIR
210		makeenv="$makeenv RELEASEDIR"
211		buildtarget=release;;
212
213	-r)	do_removedirs=true; do_rebuildmake=true;;
214
215	-T)	eval $optargcmd; resolvepath
216		TOOLDIR="$OPTARG"; export TOOLDIR;;
217
218	-t)	do_buildtools=true; do_buildsystem=false;;
219
220	-U)	UNPRIVED=yes; export UNPRIVED
221		makeenv="$makeenv UNPRIVED";;
222
223	-u)	UPDATE=yes; export UPDATE
224		makeenv="$makeenv UPDATE";;
225
226	-w)	eval $optargcmd; resolvepath
227		makewrapper="$OPTARG";;
228
229	--)		break;;
230	-'?'|-h)	usage;;
231esac; done
232
233# Set up MACHINE*.  On a NetBSD host, these are allowed to be unset.
234if [ -z "$MACHINE" ]; then
235	if [ "`uname -s 2>/dev/null`" != "NetBSD" ]; then
236		echo "MACHINE must be set, or -m must be used, for cross builds."
237		echo ""; usage
238	fi
239	MACHINE=`uname -m`
240fi
241[ -n "$MACHINE_ARCH" ] || getarch
242validatearch
243
244# Set up default make(1) environment.
245makeenv="$makeenv TOOLDIR MACHINE MACHINE_ARCH MAKEFLAGS"
246if [ ! -z "$BUILDID" ]; then
247	makeenv="$makeenv BUILDID"
248fi
249MAKEFLAGS="-m $TOP/share/mk $MAKEFLAGS MKOBJDIRS=${MKOBJDIRS-yes}"
250export MAKEFLAGS MACHINE MACHINE_ARCH
251
252# Test make source file timestamps against installed nbmake binary,
253# if TOOLDIR is pre-set.
254#
255# Note that we do NOT try to grovel "mk.conf" here to find out if TOOLDIR
256# is set there, because it can contain make variable expansions and other
257# stuff only parseable *after* we have a working nbmake.  So this logic
258# can only work if the user has pre-set TOOLDIR in the environment or
259# used the -T option to build.sh.
260#
261make="${TOOLDIR-nonexistent}/bin/nbmake"
262if [ -x $make ]; then
263	for f in usr.bin/make/*.[ch] usr.bin/make/lst.lib/*.[ch]; do
264		if [ $f -nt $make ]; then
265			do_rebuildmake=true; break
266		fi
267	done
268else
269	do_rebuildmake=true
270fi
271
272# Build bootstrap nbmake if needed.
273if $do_rebuildmake; then
274	$runcmd echo "===> Bootstrapping nbmake"
275	tmpdir="${TMPDIR-/tmp}/nbbuild$$"
276
277	$runcmd mkdir "$tmpdir" || bomb "cannot mkdir: $tmpdir"
278	trap "cd /; rm -r -f \"$tmpdir\"" 0
279	trap "exit 1" 1 2 3 15
280	$runcmd cd "$tmpdir"
281
282	$runcmd env CC="${HOST_CC-cc}" CPPFLAGS="${HOST_CPPFLAGS}" \
283		CFLAGS="${HOST_CFLAGS--O}" LDFLAGS="${HOST_LDFLAGS}" \
284		"$TOP/tools/make/configure" \
285		|| bomb "configure of nbmake failed"
286	$runcmd sh buildmake.sh || bomb "build of nbmake failed"
287
288	make="$tmpdir/nbmake"
289	$runcmd cd "$TOP"
290	$runcmd rm -f usr.bin/make/*.o usr.bin/make/lst.lib/*.o
291fi
292
293EXTERNAL_TOOLCHAIN=`getmakevar EXTERNAL_TOOLCHAIN`
294if [ "$runcmd" = "echo" ]; then
295	TOOLCHAIN_MISSING=no
296else
297	TOOLCHAIN_MISSING=`getmakevar TOOLCHAIN_MISSING`
298fi
299if [ "${TOOLCHAIN_MISSING}" = "yes" -a \
300     "${EXTERNAL_TOOLCHAIN}" = "" ]; then
301	echo "ERROR: build.sh (in-tree cross-toolchain) is not yet available for"
302	echo
303	echo "MACHINE: ${MACHINE}"
304	echo "MACHINE_ARCH: ${MACHINE_ARCH}"
305	echo
306	echo "All builds for this platform should be done via a traditional make"
307	echo
308	echo "If you wish to use an external cross-toolchain, set"
309	echo
310	echo "EXTERNAL_TOOLCHAIN=<path to toolchain root>"
311	echo
312	echo "in either the environment or mk.conf and rerun"
313	echo
314	echo "$0 $*"
315	exit 1
316fi
317
318# If TOOLDIR isn't already set, make objdirs in "tools" in case the
319# default setting from <bsd.own.mk> is used.
320if [ -z "$TOOLDIR" ] && [ "$MKOBJDIRS" != "no" ]; then
321	$runcmd cd tools
322	$runcmd $make -m ${TOP}/share/mk obj NOSUBDIR= \
323		|| bomb "make obj failed in tools"
324	$runcmd cd "$TOP"
325fi
326
327#
328# If setting -M or -O to root an obj dir make sure the base directory is made
329# before continuing as bsd.own.mk will need this to pick up _SRC_TOP_OBJ_
330#
331if [ "$MKOBJDIRS" != "no" ] && [ ! -z "$makeobjdir" ]; then
332	$runcmd mkdir -p "$makeobjdir"
333fi
334
335# Find DESTDIR and TOOLDIR.
336if [ "$runcmd" = "echo" ]; then
337	# shown symbolically with -n because these may come from mk.conf
338	DESTDIR='$DESTDIR'
339	TOOLDIR='$TOOLDIR'
340else
341	DESTDIR=`getmakevar DESTDIR`;
342	[ $? = 0 ] || bomb "getmakevar DESTDIR failed";
343	$runcmd echo "===> DESTDIR path: $DESTDIR"
344
345	TOOLDIR=`getmakevar TOOLDIR`;
346	[ $? = 0 ] || bomb "getmakevar TOOLDIR failed";
347	$runcmd echo "===> TOOLDIR path: $TOOLDIR"
348
349	export DESTDIR TOOLDIR
350fi
351
352# Check validity of TOOLDIR and DESTDIR.
353if [ -z "$TOOLDIR" ] || [ "$TOOLDIR" = "/" ]; then
354	bomb "TOOLDIR '$TOOLDIR' invalid"
355fi
356removedirs="$TOOLDIR"
357
358if [ -z "$DESTDIR" ] || [ "$DESTDIR" = "/" ]; then
359	if $do_buildsystem; then
360		if [ "$buildtarget" != "build" ] || \
361		   [ "`uname -s 2>/dev/null`" != "NetBSD" ] || \
362		   [ "`uname -m`" != "$MACHINE" ]; then
363			bomb "DESTDIR must be set to a non-root path for cross builds or -d or -R."
364		fi
365		$runcmd echo "===> WARNING: Building to /."
366		$runcmd echo "===> If your kernel is not up to date, this may cause the system to break!"
367	fi
368else
369	removedirs="$removedirs $DESTDIR"
370fi
371
372# Remove the target directories.
373if $do_removedirs; then
374	for f in $removedirs; do
375		$runcmd echo "===> Removing $f"
376		$runcmd rm -r -f $f
377	done
378fi
379
380# Recreate $TOOLDIR.
381$runcmd mkdir -p "$TOOLDIR/bin" || bomb "mkdir of '$TOOLDIR/bin' failed"
382
383# Install nbmake if it was built.
384if $do_rebuildmake; then
385	$runcmd rm -f "$TOOLDIR/bin/nbmake"
386	$runcmd cp $make "$TOOLDIR/bin/nbmake" \
387		|| bomb "failed to install \$TOOLDIR/bin/nbmake"
388	make="$TOOLDIR/bin/nbmake"
389	$runcmd rm -r -f "$tmpdir"
390	trap 0 1 2 3 15
391fi
392
393# Build a nbmake wrapper script, usable by hand as well as by build.sh.
394if [ -z "$makewrapper" ]; then
395	makewrapper="$TOOLDIR/bin/nbmake-$MACHINE"
396	if [ ! -z "$BUILDID" ]; then
397		makewrapper="$makewrapper-$BUILDID"
398	fi
399fi
400
401$runcmd rm -f "$makewrapper"
402if [ "$runcmd" = "echo" ]; then
403	echo 'cat <<EOF >'$makewrapper
404	makewrapout=
405else
406	makewrapout=">>\$makewrapper"
407fi
408
409eval cat <<EOF $makewrapout
410#! /bin/sh
411# Set proper variables to allow easy "make" building of a NetBSD subtree.
412# Generated from:  \$NetBSD: build.sh,v 1.73 2002/12/08 08:42:51 lukem Exp $
413#
414
415EOF
416for f in $makeenv; do
417	eval echo "$f=\'\$`echo $f`\'\;\ export\ $f" $makewrapout
418done
419eval echo "USETOOLS=yes\; export USETOOLS" $makewrapout
420
421eval cat <<'EOF' $makewrapout
422
423exec "$TOOLDIR/bin/nbmake" ${1+"$@"}
424EOF
425[ "$runcmd" = "echo" ] && echo EOF
426$runcmd chmod +x "$makewrapper"
427
428if $do_buildsystem; then
429	# Build everything.
430	${runcmd-exec} "$makewrapper" $parallel $buildtarget \
431		|| bomb "failed to make $buildtarget"
432else
433	# One or more of do_buildtools and do_buildkernel
434	# might be set.  Do them in the appropriate order.
435	if $do_buildtools; then
436		if [ "$MKOBJDIRS" != "no" ]; then
437			$runcmd "$makewrapper" $parallel obj-tools \
438				|| bomb "failed to make obj-tools"
439		fi
440		$runcmd cd tools
441		if [ "$UPDATE" = "" ]; then
442			$runcmd "$makewrapper" cleandir dependall install \
443				|| bomb "failed to make tools"
444		else
445			$runcmd "$makewrapper" dependall install \
446				|| bomb "failed to make tools"
447		fi
448	fi
449	if $do_buildkernel; then
450		if ! $do_buildtools; then
451			# Building tools every time we build a kernel
452			# is clearly unnecessary.  We could try to
453			# figure out whether rebuilding the tools is
454			# necessary this time, but it doesn't seem
455			# worth the trouble.  Instead, we say it's the
456			# user's responsibility to rebuild the tools if
457			# necessary.
458			$runcmd echo "===> Building kernel" \
459				"without building new tools"
460		fi
461		$runcmd echo "===> Building kernel ${kernconfname}"
462		# The correct value of KERNOBJDIR might depend on a
463		# prior "make obj" in TOP/etc.
464		if [ "$MKOBJDIRS" != "no" ] && [ ! -z "$makeobjdir" ]; then
465			$runcmd cd "$TOP/etc"
466			$runcmd "$makewrapper" obj \
467				|| bomb "failed to make obj in etc"
468			$runcmd cd "$TOP"
469		fi
470		if [ "$runcmd" = "echo" ]; then
471			# shown symbolically with -n
472			# because getmakevar might not work yet
473			KERNCONFDIR='$KERNCONFDIR'
474			KERNOBJDIR='$KERNOBJDIR'
475		else
476			KERNCONFDIR="$( getmakevar KERNCONFDIR )"
477			[ $? = 0 ] || bomb "getmakevar KERNCONFDIR failed";
478			KERNOBJDIR="$( getmakevar KERNOBJDIR )"
479			[ $? = 0 ] || bomb "getmakevar KERNOBJDIR failed";
480		fi
481		case "${kernconfname}" in
482		*/*)
483			kernconfpath="${kernconfname}"
484			kernconfbase="$( basename "${kernconfname}" )"
485			;;
486		*)
487			kernconfpath="${KERNCONFDIR}/${kernconfname}"
488			kernconfbase="${kernconfname}"
489			;;
490		esac
491		kernbuilddir="${KERNOBJDIR}/${kernconfbase}"
492		$runcmd echo "===> Kernel build directory: ${kernbuilddir}"
493		$runcmd mkdir -p "${kernbuilddir}" \
494			|| bomb "cannot mkdir: ${kernbuilddir}"
495		if [ "$UPDATE" = "" ]; then
496			$runcmd cd "${kernbuilddir}"
497			$runcmd "$makewrapper" cleandir \
498				|| bomb "make cleandir failed in " \
499					"${kernbuilddir}"
500			$runcmd cd "$TOP"
501		fi
502		$runcmd "${TOOLDIR}/bin/nbconfig" \
503			-b "${kernbuilddir}" \
504			-s "${TOP}/sys" "${kernconfpath}" \
505			|| bomb "nbconfig failed for ${kernconfname}"
506		$runcmd cd "${kernbuilddir}"
507		$runcmd "$makewrapper" depend \
508			|| bomb "make depend failed in ${kernbuilddir}"
509		$runcmd "$makewrapper" $parallel all \
510			|| bomb "make all failed in ${kernbuilddir}"
511		$runcmd echo "===> New kernel should be in ${kernbuilddir}"
512	fi
513fi
514