3 # Load shlib and modules
4 _root="$(dirname "${0}")"; . "${_root}/lib/env.sh"
8 [ "${*}" ] && printf "%s\n\n" "${*}"
9 echo "Usage: $(basename "${0}") -m <makeopts> -a <arch> -c <conf> <target, ...>"
10 echo " -m <makeopts> Provide additional flags to make"
11 echo " -a <arch> World architecture (i386, amd64)"
12 echo " -c <conf> World configuration (in worlds/<arch>/<conf>)"
13 echo " -s <srctree> Override source tree selection"
15 echo " -v Verbose (show build log in real time)"
17 echo "If, for some reason, you wish to spread out builds across multiple"
18 echo "invocations, these might come in handy:"
19 echo " -p Prepare chroot environment"
20 echo " -d Don't prepare or clean up chroot during run"
21 echo " -q Clean up chroot environment"
23 echo "Available make targets:"
24 for make_tgt in ${make_tgts}
31 # Prepare chroot for build
33 [ "${CHROOT_DIRTY}" -a ! "${CHROOT_PREPARE}" ] && return 0
34 # Verify environment sanity
35 [ -d "${build}" ] && omg "${build}: directory exists; purging" && cleanup
36 mount | grep -q "${build}" && wtf "Stuff is mounted under ${build}; cannot continue"
37 ls -1 "${seed}"/base.?? >/dev/null 2>&1 || wtf "Populate seed directory ${seed} first"
38 [ -f "${SRCS}/sys/conf/newvers.sh" ] || wtf "Need sources in ${SRCS} to build"
40 # Cleanup trap here, so that an abort during prepare can clean up properly
41 trap "cleanup" exit hup int term kill
43 meh "Preparing build chroot"
44 [ -d "${build}" ] && wtf "${build}: directory exists"
45 mkdir -p "${build}" || wtf
46 cat "${seed}"/base.?? | tar xCf "${build}" - || wtf
47 mkdir -p "${build}/usr/obj" || wtf
49 meh "Mounting chroot filesystems"
50 mkdir -p "${world}/log"
51 mkdir -p "${world}/obj"
52 mkdir -p "${world}/root"
53 mount -t devfs devfs "${build}/dev" || wtf
54 # Mount /usr/src as a union, so that changes to it will not affect the underlying tree
55 # unionfs suffers from deadlocks; don't use it
56 mount -t nullfs -r "${SRCS}" "${build}/usr/src" || wtf
57 mount -t nullfs "${world}/obj" "${build}/usr/obj" || wtf
58 mount -t nullfs "${world}/root" "${build}/mnt" || wtf
60 if [ -d "${world}/config" ]
62 meh "Installing build-time configuration"
63 [ -f "${world}/config/${CONF}" ] && {
64 mkdir -p "${build}/usr/obj/conf" || wtf
65 cp "${world}/config/${CONF}" "${build}/usr/obj/conf" || wtf
67 [ -f "${world}/config/make.conf" ] && cp "${world}/config/make.conf" "${build}/etc/"
68 [ -f "${world}/config/src.conf" ] && cp "${world}/config/src.conf" "${build}/etc/"
75 [ "${BUILD_VERBOSE}" ] || exec 1>&3
76 [ "${CHROOT_DIRTY}" -a ! "${CHROOT_CLEAN}" ] && return 0
78 umount -f "${build}/mnt"
79 umount -f "${build}/usr/obj"
80 umount -f "${build}/usr/src"
81 umount -f "${build}/dev"
82 mount | grep -q "${build}/" && wtf "Stuff is still mounted under ${build}; not removing"
83 chflags -R noschg "${build}"
85 trap "" exit hup int term kill
89 # Root directory of makeworld
90 ROOT="$(realpath "$(dirname "${0}")/..")"
93 WORLDS="${ROOT}/worlds"
95 # Compute make -j<cpus*2>
96 make_cpus="$(sysctl -n hw.ncpu)"
97 make_jobs="$(( ${make_cpus} * 2 ))"
98 make_tgts="buildworld buildkernel distrib-dirs installworld installkernel distribution"
103 MAKEOPTS="-j${make_jobs}"
110 while getopts "m:a:c:hpdqv" opt
113 m) MAKEOPTS="${MAKEOPTS} ${OPTARG}" ;;
114 a) ARCH="${OPTARG}" ;;
115 c) CONF="${OPTARG}" ;;
116 s) SRCS="${OPTARG}" ;;
117 p) CHROOT_PREPARE="TRUE" ;;
118 d) CHROOT_DIRTY="TRUE" ;;
119 q) CHROOT_CLEAN="TRUE" ;;
120 v) BUILD_VERBOSE="TRUE" ;;
122 [?]) pebkac "Unrecognized option ${opt}" ;;
125 shift $(( $OPTIND - 1 ))
127 # Should be root after this point
130 # Build make target sequence
131 sequence="${*:-${make_tgts}}"
133 # Target world directory
134 world="${WORLDS}/${ARCH}/${CONF}"
135 # Source chroot seed directory
136 seed="${ROOT}/seed/base/$(uname -m)"
137 # Root directory for chroot
138 build="${world}/chroot"
142 # Locate a usable source tree
143 # Pick world/src over /usr/src if it exists at all, even if it is not usable, to provide warning of bad configs
145 [ -L "${SRCS}" -o -d "${SRCS}" ] || SRCS=/usr/src
147 SRCS="$(realpath "${SRCS}")"
149 # If NO_KERNEL exists, don't bother building one (jails)
150 if [ -e "${world}/config/NO_KERNEL" ]
156 # If kernel config matching CONF does not exist, assume GENERIC
157 if [ -e "${world}/config/${CONF}" ]
159 KERNCONFDIR=/usr/obj/conf
167 # Environment for chroot build
171 PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
176 date="$(date +%Y%m%d)"
178 # Check if target config exists
179 [ -d "${world}" ] || wtf "${ARCH}/${CONF} doesn't exist"
181 if [ "${CHROOT_PREPARE}" ]
185 meh "Chroot prepared"
189 if [ "${CHROOT_CLEAN}" ]
196 meh "Making world for ${ARCH}/${CONF}"
198 meh "Targets: ${sequence}"
203 meh "Srctree: ${SRCS}"
204 meh "Config: ${ARCH}/${CONF}"
205 [ "${NO_KERNEL}" ] && meh "Kernel config: NO_KERNEL (will not build kernel)"
206 [ "${KERNCONF}" -a "${KERNCONF}" != "${CONF}" ] && meh "Kernel config: ${KERNCONF}"
207 meh "Builddir: ${build}"
208 meh "make ${MAKEOPTS}"
209 meh "DESTDIR=${world}/root"
211 for step in ${sequence}
213 [ "${NO_KERNEL}" -a "${step%%kernel}" != "${step}" ] && {
214 meh "Step: ${step} -> Skipped: NO_KERNEL"
217 build_log="${world}/log/${date}-${step}.log"
218 meh "==> Step: ${step} -> ${build_log}"
219 [ "${BUILD_VERBOSE}" ] || exec 3>&1 > /dev/null
220 script "${build_log}" env -i ${env} chroot "${build}" sh -c \
221 "cd /usr/src; time make ${MAKEOPTS} ${step} DESTDIR=/mnt TARGET=${ARCH} \
222 ${KERNCONFDIR:+KERNCONFDIR=${KERNCONFDIR}} ${KERNCONF:+KERNCONF=${KERNCONF}}"
224 [ "${BUILD_VERBOSE}" ] || exec 1>&3
225 [ "${res}" -gt 0 ] && wtf "chroot-cmd ${step} failed; check log"
228 # Copy the config files into the target, to keep a record of the build options
229 [ -f "${world}/config/${CONF}" ] && cp "${world}/config/${CONF}" "${world}/root/boot/kernel/"
230 [ -f "${world}/config/make.conf" ] && cp "${world}/config/make.conf" "${world}/root/etc/"
231 [ -f "${world}/config/src.conf" ] && cp "${world}/config/src.conf" "${world}/root/etc/"