#!/bin/sh set -e ## true # avoid the shell overhead of fork/exec'ing just to call /bin/true # returns true true() { : ; } ## false # avoid the shell overhead of fork/exec'ing just to call /bin/false # returns false false() { ! : ; } ## error # displays the supplied on stderr error() { echo "error: $*" >&2; } ## die # display the supplied and exit with an error die() { error "$*"; exit 1; } ## simple_usage # A simplified usage interface for commands with no option arguments. simple_usage() { cmd="${1}" summary="${2}" shift 2 if test "$#" -eq '0'; then error "no arguments to command" echo "try 'build ${cmd} --help'" >&2 exit 1 fi while test "$#" -gt '0'; do case "${1}" in (-h|-help|--help) echo "usage: build ${cmd} ${summary}" 2>&1 exit 0;; (--) shift; break;; (-*) error "unknown option '${1}'" echo "try 'build ${cmd} --help'" >&2 exit 1;; (*) break;; esac done } ## mkenv # prepare the environment structure for the current package mkenv() { for dir in "${W}" "${L}" "${E}" "${D}" "${T}"; do if [ ! -d "${dir}" ]; then mkdir -p "${dir}" fi done unset dir if [ "$#" -gt "0" ]; then cat /dev/null > "${L}/${1}.log" set > "${E}/${1}.env" fi } ## import # import a builder library. # During import a library can check 'BUILDER_CALL_STACK' to see if it equals # '__main__'. If it does, then the library is being executed directly. # Further more, builder-libraries can do load-time tests in order to perform # various one-time optimizations. # # Note: this is borrowed from 'shlib' almost verbatim w/ the only change being # the variable names. import() { set -- "${1}" "`echo "${1}" | tr '-' '_'`" test -f "${BUILDER_LIBDIR}/${1}" || die "library does not exist '${1}'" eval "test -z \"\${BUILDER_IMPORT_${2}}\"" || return BUILDER_CALL_STASH="${BUILDER_CALL_STACK}" BUILDER_CALL_STACK="${BUILDER_CALL_STACK} ${1}" . "${BUILDER_LIBDIR}/${1}" eval "BUILDER_IMPORT_${2}='${BUILDER_LIBDIR}/${1}'" if [ -z "${BUILDER_IMPORTED}" ]; then BUILDER_IMPORTED="${1}" else BUILDER_IMPORTED="${BUILDER_IMPORTED} ${1}" fi BUILDER_CALL_STACK="${BUILDER_CALL_STASH}" } ## include # include a builder config. # This command simply sources the named config found in TOPDIR/.builder/ include() { set -- "${1}" "`echo "${1}" | tr '-' '_'`" if ! test -f "${BUILDER_CFGDIR}/${1}"; then die "config not found '${1}'" fi eval "test -z \"\${BUILDER_INCLUDE_${2}}\"" || return 0 . "${BUILDER_CFGDIR}/${1}" eval "BUILDER_INCLUDE_${2}='${BUILDER_CFGDIR}/${1}'" if [ -z "${BUILDER_INCLUDED}" ]; then BUILDER_INCLUDED="${1}" else BUILDER_INCLUDED="${BUILDER_INCLUDED} ${1}" fi } # FIXME we need a build-resolv subcmd for resolving package names parse_pkg_name() { # Only allow a single '/' in the name if [ "1${1##*/}" != "1${1#*/}" ]; then return 1 fi if [ "2${1#*/}" != "2${1}" ]; then printf '%s' "${1}" else printf '%s' "${1}/all" fi } parse_name() { if ! parse_pkg_name "${1}" > /dev/null 2>&1; then return "$?" fi set -- "$(parse_pkg_name "${1}")" printf '%s' "${1#*/}" } parse_category() { if ! parse_pkg_name "${1}" > /dev/null 2>&1; then return "$?" fi set -- "$(parse_pkg_name "${1}")" printf '%s' "${1%/*}" } ## load_rules # load the Buildrules of a package into the current program space load_rules() { # We can aquire this data before we bother loading anything NAME="$(parse_name "${1}")" CATEGORY="$(parse_category "${1}")" PKG_NAME="${CATEGORY}/${NAME}" if [ ! -d "${BUILDER_PKGDIR}/${PKG_NAME}" ]; then die "no such package '${1}'" fi RULESFILE="${BUILDER_PKGDIR}/${CATEGORY}/${NAME}/Buildrules" if [ ! -f "${RULESFILE}" ]; then die "no rulesfile for package '${1}'" fi export NAME CATEGORY PKG_NAME RULESFILE # These variables are used by the Buildrules and fundmentally make up # the majority of their environ data F="${BUILDER_PKGDIR}/${CATEGORY}/${NAME}/files" W="${BUILDER_TMPDIR}/${CATEGORY}/${NAME}/work" L="${BUILDER_TMPDIR}/${CATEGORY}/${NAME}/log" E="${BUILDER_TMPDIR}/${CATEGORY}/${NAME}/env" T="${BUILDER_TMPDIR}/${CATEGORY}/${NAME}/tmp" D="${BUILDER_TMPDIR}/${CATEGORY}/${NAME}/install" export F W L E T D # Source in the toplevel Buildrules if [ -f "${BUILDER_PKGDIR}/.buildrules" ]; then . "${BUILDER_PKGDIR}/.buildrules" fi # Source in the category Buildrules if [ -f "${BUILDER_PKGDIR}/${CATEGORY}/.buildrules" ]; then . "${BUILDER_PKGDIR}/${CATEGORY}/.buildrules" fi # These variables are only set within a Rulesfile and thus need to be # cleared before sourcing it in. VERSION= RELEASE= DESCRIPTION= LICENSE= SOURCE_URI= PATCHES= RDEPENDS= BDEPENDS= EXTRA_SOURCES= # Source in the package Buildrules . "${RULESFILE}" if [ "${CATEGORY}/${NAME}" != "${1}" ]; then die "Buildrules can not set the package name" fi if [ -z "${VERSION}" ]; then die "missing version in '${NAME}'" fi if [ -z "${DESCRIPTION}" ]; then die "missing description in '${NAME}'" fi if test -z "${RELEASE}"; then RELEASE="${VERSION#*-}" if ! test -z "${RELEASE}" && test "${RELEASE}" != "${VERSION}"; then VERSION="${VERSION%-${RELEASE}}" if test -z "${S}"; then S="${W}/${NAME}-${VERSION}-${RELEASE}" fi else RELEASE='0' fi fi if test -z "${S}"; then S="${W}/${NAME}-${VERSION}" fi export VERSION RELEASE DESCRIPTION LICENSE SOURCE_URI PATCHES BDEPENDS RDEPENDS } if [ "${BUILDER_DEBUG:-0}" != '0' ]; then set -x fi ## # Check to see if we are wrapping a sub-command BUILDER_COMMAND= if [ -f "${1}" ]; then case "${1##*/}" in (build-*) BUILDER_COMMAND="${1}" shift . "${BUILDER_COMMAND}" # exit with the exit status of the last command from within the # sub-script. This is normal shell behavior, we are just # making it explicit. exit $? ;; esac fi ## # We are being called as 'build [options] '. Setup the environment # for execution of a sub-command. BUILDER_DEBUG=0 while [ "$#" -gt "0" ]; do case "$1" in (-d|-debug|--debug) BUILDER_DEBUG=1 set -x ;; (-h|-help|--help) shift 1 set -- help "$@" break ;; (-*) echo "error: unknown option '${1}'" >&2 echo "try '${0} help'" >&2 exit 1 ;; (*) break ;; esac shift 1 done export BUILDER_DEBUG ## # Done with arguments, time for setting up the enviroment for the build TOPDIR="${PWD}" while [ ! -z "${TOPDIR}" ]; do [ -d "${TOPDIR}/.builder" ] && break TOPDIR="${TOPDIR%/*}" done if [ -z "${TOPDIR}" ]; then echo "error: current path not in a build-tree" >&2 exit 1 fi # We are being executed as 'build ' BUILDER_CALL_STACK='__main__' export BUILDER_CALL_STACK # set the builtin defaults based on TOPDIR. We export TOPDIR as BUILDER_TOPDIR # to avoid stepping on the potential usage of TOPDIR within package Makefiles BUILDER_TOPDIR="${TOPDIR}" BUILDER_CFGDIR="${TOPDIR}/.builder" BUILDER_PKGDIR="${TOPDIR}/packages" BUILDER_SRCDIR="${TOPDIR}/sources" BUILDER_ATFDIR="${TOPDIR}/artifacts" BUILDER_SYSDIR="${TOPDIR}/sysroot" BUILDER_LIBDIR="${TOPDIR}/scripts/libexec" BUILDER_TMPDIR="${TOPDIR}/tmp" export BUILDER_CFGDIR BUILDER_PKGDIR BUILDER_SRCDIR export BUILDER_ATFDIR BUILDER_SYSDIR BUILDER_LIBDIR export BUILDER_TMPDIR BUILDER_TOPDIR # The default SYSROOT .. Much of the toolchain already obeys SYSROOT .. we # aren't setting a policy so much as obeying one. SYSROOT="${SYSROOT:-${BUILDER_TOPDIR}/sysroot}" export SYSROOT # We save the pre-config PATH as BUILDER_PATH to be used by downstream tools. # FIXME detect prefixing BUILDER_LIBDIR onto PATH multiple times? BUILDER_PATH="${BUILDER_LIBDIR}:${PATH}" PATH="${BUILDER_PATH}" export BUILDER_PATH PATH # include our default config test -f "${BUILDER_CFGDIR}/config" && include config test -f "${BUILDER_CFGDIR}/${ARCH}" && include "${ARCH}" # Default build target # FIXME this should default to all/all TARGET="${TARGET:-all/all}" export TARGET # If unspecified go ahead and ask gcc CBUILD="${CBUILD:-$(build-dumpmachine)}" export CBUILD ARCHIVE_FORMAT="${ARCHIVE_FORMAT:-tar.bz2}" export ARCHIVE_FORMAT # FIXME this stuff needs to be detected in a more reliable fashion ARCH="${ARCH:-$(uname -m)}" export ARCH CHOST="${CHOST:-${CBUILD}}" export CHOST MAKE_OPTS= if test -z "${MAKE_OPTS}"; then num_cpus="$(build-num-cpus)" MAKE_OPTS="-j$((${num_cpus} + 1))" unset num_cpus fi export MAKE_OPTS # if we aren't given an action then we do everything ACTION="install" if [ "$#" -gt "0" ]; then ACTION="${1}" shift 1 fi if command -v "build-make-${ACTION}" 2>&1 > /dev/null; then BUILDER_COMMAND="$(command -v 'build-make')" set -- "${ACTION}" "${@}" elif command -v "build-${ACTION}" 2>&1 > /dev/null; then BUILDER_COMMAND="$(command -v "build-${ACTION}")" else error "unknown action '${ACTION}'" echo "try '${0} help'" >&2 exit 1 fi export BUILDER_COMMAND exec "${BUILDER_COMMAND}" "${@}"