#!/bin/sh # Load shlib and modules _root="$(dirname "${0}")"; . "${_root}/lib/env.sh" want log pebkac() { [ "${*}" ] && printf "%s\n\n" "${*}" echo "Usage: $(basename "${0}") -m -a -c " echo " -m Provide additional flags to make" echo " -a World architecture (i386, amd64)" echo " -c World configuration (in worlds//)" echo " -s Override source tree selection" echo " -h Help!" echo " -v Verbose (show build log in real time)" echo "" echo "If, for some reason, you wish to spread out builds across multiple" echo "invocations, these might come in handy:" echo " -p Prepare chroot environment" echo " -d Don't prepare or clean up chroot during run" echo " -q Clean up chroot environment" echo "" echo "Available make targets:" for make_tgt in ${make_tgts} do echo " ${make_tgt}" done exit 1 } # Prepare chroot for build prepare() { [ "${CHROOT_DIRTY}" -a ! "${CHROOT_PREPARE}" ] && return 0 # Verify environment sanity [ -d "${build}" ] && omg "${build}: directory exists; purging" && cleanup mount | grep -q "${build}" && wtf "Stuff is mounted under ${build}; cannot continue" ls -1 "${seed}"/base.?? >/dev/null 2>&1 || wtf "Populate seed directory ${seed} first" [ -f "${SRCS}/sys/conf/newvers.sh" ] || wtf "Need sources in ${SRCS} to build" # Cleanup trap here, so that an abort during prepare can clean up properly trap "cleanup" exit hup int term kill meh "Preparing build chroot" [ -d "${build}" ] && wtf "${build}: directory exists" mkdir -p "${build}" || wtf cat "${seed}"/base.?? | tar xCf "${build}" - || wtf mkdir -p "${build}/usr/obj" || wtf meh "Mounting chroot filesystems" mkdir -p "${world}/log" mkdir -p "${world}/obj" mkdir -p "${world}/root" mount -t devfs devfs "${build}/dev" || wtf # Mount /usr/src as a union, so that changes to it will not affect the underlying tree # unionfs suffers from deadlocks; don't use it mount -t nullfs -r "${SRCS}" "${build}/usr/src" || wtf mount -t nullfs "${world}/obj" "${build}/usr/obj" || wtf mount -t nullfs "${world}/root" "${build}/mnt" || wtf if [ -d "${world}/config" ] then meh "Installing build-time configuration" [ -f "${world}/config/${CONF}" ] && cp "${world}/config/${CONF}" "${SRCS}/sys/${ARCH}/conf/" [ -f "${world}/config/make.conf" ] && cp "${world}/config/make.conf" "${build}/etc/" [ -f "${world}/config/src.conf" ] && cp "${world}/config/src.conf" "${build}/etc/" fi return 0 } # Cleanup chroot cleanup() { [ "${BUILD_VERBOSE}" ] || exec 1>&3 [ "${CHROOT_DIRTY}" -a ! "${CHROOT_CLEAN}" ] && return 0 meh "Cleaning up" umount -f "${build}/mnt" umount -f "${build}/usr/obj" umount -f "${build}/usr/src" umount -f "${build}/dev" mount | grep -q "${build}/" && wtf "Stuff is still mounted under ${build}; not removing" chflags -R noschg "${build}" rm -Rf "${build}" trap "" exit hup int term kill return 0 } # Root directory of makeworld ROOT="$(realpath "$(dirname "${0}")/..")" # Location of worlds WORLDS="${ROOT}/worlds" # Compute make -j make_cpus="$(sysctl -n hw.ncpu)" make_jobs="$(( ${make_cpus} * 2 ))" make_tgts="buildworld buildkernel distrib-dirs installworld installkernel distribution" # Defaults ARCH="$(uname -m)" CONF="GENERIC" MAKEOPTS="-j${make_jobs}" SRCS="" CHROOT_PREPARE="" CHROOT_DIRTY="" CHROOT_CLEAN="" BUILD_VERBOSE="" while getopts "m:a:c:hpdq" opt do case "${opt}" in m) MAKEOPTS="${MAKEOPTS} ${OPTARG}" ;; a) ARCH="${OPTARG}" ;; c) CONF="${OPTARG}" ;; s) SRCS="${OPTARG}" ;; p) CHROOT_PREPARE="TRUE" ;; d) CHROOT_DIRTY="TRUE" ;; q) CHROOT_CLEAN="TRUE" ;; v) BUILD_VERBOSE="TRUE" ;; h) pebkac ;; [?]) pebkac "Unrecognized option ${opt}" ;; esac done shift $(( $OPTIND - 1 )) # Should be root after this point want root # Build make target sequence sequence="${*:-${make_tgts}}" # Target world directory world="${WORLDS}/${ARCH}/${CONF}" # Source chroot seed directory seed="${ROOT}/seed/base/$(uname -m)" # Root directory for chroot build="${world}/chroot" if [ -z "${SRCS}" ] then # Locate a usable source tree # Pick world/src over /usr/src if it exists at all, even if it is not usable, to provide warning of bad configs SRCS="${world}/src" [ -L "${SRCS}" -o -d "${SRCS}" ] || SRCS=/usr/src fi SRCS="$(realpath "${SRCS}")" # Environment for chroot build env=" USER=root HOME=/root PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin SHELL=/bin/sh " date="$(date +%Y%m%d)" # Check if target config exists [ -d "${world}" ] || wtf "${ARCH}/${CONF} doesn't exist" if [ "${CHROOT_PREPARE}" ] then prepare trap "" exit meh "Chroot prepared" exit fi if [ "${CHROOT_CLEAN}" ] then cleanup meh "Chroot cleaned" exit fi meh "Making world for ${ARCH}/${CONF}" prepare meh "Seed: ${seed}" meh "Srctree: ${SRCS}" meh "Config: ${ARCH}/${CONF}" meh "Builddir: ${build}" meh "make ${MAKEOPTS}" meh "DESTDIR=${world}/root" for step in ${sequence} do build_log="${world}/log/${date}-${step}.log" meh "==> Step: ${step} -> ${build_log}" [ "${BUILD_VERBOSE}" ] || exec 3>&1 > /dev/null script "${build_log}" env -i ${env} chroot "${build}" sh -c \ "cd /usr/src; time make ${MAKEOPTS} ${step} TARGET=${ARCH} KERNCONF=${CONF} DESTDIR=/mnt" || wtf "chroot-cmd ${step}" [ "${BUILD_VERBOSE}" ] || exec 1>&3 done # Copy the config files into the target, to keep a record of the build options [ -f "${world}/config/${CONF}" ] && cp "${world}/config/${CONF}" "${build}/boot/kernel/" [ -f "${world}/config/make.conf" ] && cp "${world}/config/make.conf" "${build}/etc/" [ -f "${world}/config/src.conf" ] && cp "${world}/config/src.conf" "${build}/etc/"