#!/bin/sh # Copyright (c) 2015-2020 Solo5 Contributors # Copyright (c) 2024 Romain Calascibetta # # This file is part of Gilbraltar, a bare-metal OS for Raspberry Pi. # # Permission to use, copy, modify, and/or distribute this software # for any purpose with or without fee is hereby granted, provided # that the above copyright notice and this permission notice appear # in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL # WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE # AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR # CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS # OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. TARGET_CC="${TARGET_CC:-aarch64-linux-gnu-gcc}" TARGET_LD="${TARGET_LD:-aarch64-linux-gnu-ld}" TARGET_AR="${TARGET_AR:-aarch64-linux-gnu-ar}" TARGET_NM="${TARGET_NM:-aarch64-linux-gnu-nm}" TARGET_RANLIB="${TARGET_NM:-aarch64-linux-gnu-ranlib}" TARGET_OBJCOPY="${TARGET_OBJCOPY:-aarch64-linux-gnu-objcopy}" TARGET_OBJDUMP="${TARGET_OBJDUMP:-aarch64-linux-gnu-objdump}" TARGET_READELF="${TARGET_OBJDUMP:-aarch64-linux-gnu-readelf}" TARGET_STRIP="${TARGET_STRIP:-aarch64-linux-gnu-strip}" prog_NAME="$(basename $0)" cleanup() { rm -f conftmp.c conftmp.d conftmp*.o } err() { echo "${prog_NAME}: ERROR: $@" 1>&2 } die() { echo "${prog_NAME}: ERROR: $@" 1>&2 cleanup exit 1 } warn() { echo "${prog_NAME}: WARNING: $@" 1>&2 } usage() { cat <&2 usage: ${prog_NAME} [ OPTIONS ] Configures the Gilbraltar build system. Options: --prefix=DIR Installation prefix (default: /usr/local). Environment variables affecting the build system configuration: HOST_CC C compiler used for host tools. TARGET_CC (= $TARGET_CC) TARGET_LD (= $TARGET_LD) TARGET_OBJCOPY (= $TARGET_OBJCOPY) C compiler, linker and objcopy used for target toolchain. Experimental: If a cross-toolchain is specified here, the resulting target toolchain and bindings will be cross-compiled to its architecture. EOM exit 1 } cc_maybe_gcc() { ${CC} -dM -E - /dev/null 2>&1 int main(int argc, char *argv[]) { return 0; } EOM } cc_check_header() { ${CC} ${PKG_CFLAGS} -x c -o /dev/null - </dev/null 2>&1 #include <$@> int main(int argc, char *argv[]) { return 0; } EOM } cc_check_lib() { ${CC} -x c -o /dev/null - "$@" ${PKG_LIBS} </dev/null 2>&1 int main(int argc, char *argv[]) { return 0; } EOM } ld_is_lld() { ${LD} --version 2>&1 | grep -q '^LLD' } # Check that the linker ${LD} is available and suitable for our purposes. check_ld() { echo -n "${prog_NAME}: Checking if ${LD} is available: " if [ -x "$(command -v ${LD})" ]; then echo "yes" else echo "no" return 1 fi echo -n "${prog_NAME}: Checking if ${LD} is LLD: " if ld_is_lld; then echo "yes" # LLD < 8 chokes on the Xen ldscript, so refuse to use it. echo -n "${prog_NAME}: Checking if LLD ${LD} is LLVM 8 or newer: " if ${LD} --version 2>&1 | grep -q '^LLD [1-7]\.'; then echo "no" return 1 else echo "yes" fi else echo "no" fi cat >conftmp.c </dev/null 2>&1; then echo "no" return 1 else echo "yes" fi return 0 } # Check that the objcopy ${OBJCOPY} is available and suitable for our purposes. check_objcopy() { echo -n "${prog_NAME}: Checking if ${OBJCOPY} is available: " if [ -x "$(command -v ${OBJCOPY})" ]; then echo "yes" else echo "no" return 1 fi cat >conftmp.c </dev/null 2>&1; then echo "no" return 1 else echo "yes" fi # [Clang] For LLVM objcopy, -w was introduced in # https://reviews.llvm.org/D66613 (release/12.x) and -G was introduced in # https://reviews.llvm.org/D50589 (release/8.x). echo -n "${prog_NAME}: Checking if ${OBJCOPY} understands -w -G: " if ! ${OBJCOPY} -w -G KEEP\* conftmp.o conftmp.o >/dev/null 2>&1; then echo "no" return 1 else echo "yes" fi return 0 } OPT_PREFIX=/usr/local while [ $# -gt 0 ]; do OPT="$1" case "${OPT}" in --prefix=*) OPT_PREFIX="${OPT##*=}" ;; --help) usage ;; *) err "Unknown option: '${OPT}'" usage ;; esac shift done # # Configure host tools based on HOST_CC. # HOST_CC=${HOST_CC:-cc} HOST_CC_MACHINE=$(${HOST_CC} -dumpmachine) [ $? -ne 0 ] && die "Could not run '${HOST_CC} -dumpmachine', is your compiler working?" echo "${prog_NAME}: Using ${HOST_CC} for host compiler (${HOST_CC_MACHINE})" case ${HOST_CC_MACHINE} in x86_64-*linux*) CONFIG_HOST_ARCH=x86_64 CONFIG_HOST=Linux ;; aarch64-*linux*) CONFIG_HOST_ARCH=aarch64 CONFIG_HOST=Linux ;; powerpc64le-*linux*|ppc64le-*linux*) CONFIG_HOST_ARCH=ppc64le CONFIG_HOST=Linux ;; x86_64-*freebsd*) CONFIG_HOST_ARCH=x86_64 CONFIG_HOST=FreeBSD ;; amd64-*openbsd*) CONFIG_HOST_ARCH=x86_64 CONFIG_HOST=OpenBSD ;; *) die "Unsupported host toolchain: ${HOST_CC_MACHINE}" ;; esac # If no toolchain was requested, stop here. # XXX De-duplicate the generation of Makeconf*? if [ -n "${OPT_DISABLE_TOOLCHAIN}" ]; then cat <Makeconf # Generated by configure.sh CONFIG_PREFIX=${OPT_PREFIX} CONFIG_HOST_ARCH=${CONFIG_HOST_ARCH} CONFIG_HOST=${CONFIG_HOST} CONFIG_HOST_CC=${HOST_CC} EOM sed -Ee 's/^([A-Z_]+)=(.*)$/\1="\2"/' Makeconf >Makeconf.sh cleanup exit 0 fi # # Configure target toolchain and bindings based on TARGET_{CC,LD,OBJCOPY}. # TARGET_CC="${TARGET_CC:-cc}" echo -n "${prog_NAME}: Checking that ${TARGET_CC} works: " cat >conftmp.c </dev/null 2>&1; then echo "no" die "Could not find a working compiler for target toolchain" else echo "yes" fi TARGET_CC_MACHINE=$(${TARGET_CC} -dumpmachine) CONFIG_HVT= CONFIG_SPT= CONFIG_VIRTIO= CONFIG_MUEN= CONFIG_XEN= case ${TARGET_CC_MACHINE} in x86_64-*|amd64-*) TARGET_ARCH=x86_64 TARGET_LD_MAX_PAGE_SIZE=0x1000 ;; aarch64-*) TARGET_ARCH=aarch64 TARGET_LD_MAX_PAGE_SIZE=0x1000 ;; powerpc64le-*|ppc64le-*) TARGET_ARCH=ppc64le TARGET_LD_MAX_PAGE_SIZE=0x10000 ;; *) die "Unsupported target toolchain: ${TARGET_CC_MACHINE}" ;; esac TARGET_CC_CFLAGS= TARGET_CC_IS_OPENBSD= if CC="${TARGET_CC}" cc_is_clang; then TARGET_CC_CFLAGS=-nostdlibinc # XXX Clang warns for no good reason if -nostdlibinc is used and no # compliation is performed. We could work around this by using --config # which "claims" all command line arguments as "used", but this is easier # for now. TARGET_CC_CFLAGS="${TARGET_CC_CFLAGS} -Wno-unused-command-line-argument" else TARGET_CC_CFLAGS=-nostdinc fi case ${TARGET_CC_MACHINE} in x86_64-*linux*|powerpc64le-*linux*|ppc64le-*linux*) # On x86_64 and PPC we need to ensure that TLS is not used for the # stack protector: # [GCC] -mstack-protector-guard=global is available from GCC 4.9.0. # [Clang] -mstack-protector-guard=global was introduced in # https://reviews.llvm.org/D88631 (release/12.x). CC="${TARGET_CC}" cc_check_option -mstack-protector-guard=global || \ die "${TARGET_CC} does not support -mstack-protector-guard=" TARGET_CC_CFLAGS="${TARGET_CC_CFLAGS} -mstack-protector-guard=global" ;; *openbsd*) # [Clang] OpenBSD's Clang needs to be told to switch off mitigations. TARGET_CC_CFLAGS="${TARGET_CC_CFLAGS} -mno-retpoline -fno-ret-protector" # [Clang] OpenBSD's LLVM/Clang uses a global stack protector guard, but # different symbols; see bindings/GNUmakefile. TARGET_CC_IS_OPENBSD=1 ;; esac echo "${prog_NAME}:" \ "Using ${TARGET_CC} for target compiler (${TARGET_CC_MACHINE})" # TARGET_CC_LDFLAGS are used by "cc as linker"; TARGET_LD_LDFLAGS are used by # the plain "ld" wrapper. # TODO: Are there Linux distributions with toolchains configured to force PIE # even if -static is used? If yes, these will need treatment similar to OpenBSD # below, and/or disabling PIE in "cc". TARGET_CC_LDFLAGS= TARGET_LD_LDFLAGS= case ${CONFIG_HOST} in Linux) # The "--build-id=none" nonsense is needed for "cc as a linker" to suppress any # generation of a .note.gnu.build-id, since our linker scripts don't # support it and Linux "cc" toolchains insist on adding it by default # which leads to linkers warning if it is enabled but the input section # is subsequently discarded. TARGET_LD="${TARGET_LD:-ld}" TARGET_OBJCOPY="${TARGET_OBJCOPY:-objcopy}" TARGET_CC_LDFLAGS="--build-id=none" ;; FreeBSD) TARGET_LD="${TARGET_LD:-ld.lld}" TARGET_OBJCOPY="${TARGET_OBJCOPY:-objcopy}" # FreeBSD's GNU ld is old and broken, refuse to use it. if ! LD="${TARGET_LD}" ld_is_lld; then err "${TARGET_LD} is not LLVM LLD" die "Using GNU LD is not supported on FreeBSD" fi ;; OpenBSD) TARGET_LD="${TARGET_LD:-ld.lld}" TARGET_OBJCOPY="${TARGET_OBJCOPY:-objcopy}" # OpenBSD's GNU ld is old and broken, refuse to use it. if ! LD="${TARGET_LD}" ld_is_lld; then err "${TARGET_LD} is not LLVM LLD" die "Using GNU LD is not supported on OpenBSD" fi # [LLD] OpenBSD's LLD needs to be explicitly told not to produce PIE # executables. TARGET_CC_LDFLAGS="-nopie" TARGET_LD_LDFLAGS="-nopie" ;; *) die "Unsupported host system: ${CONFIG_HOST}" ;; esac # [Clang] Force Clang to use the right TARGET_LD when run as "cc as linker". # -fuse-ld= is braindead and accepts either a "flavour" (e.g. "lld") or an # absolute path; we try with the latter. # TODO XXX: This is fragile, but works for the default cases for now. # TODO document: This won't work with clang "bare metal" targets. if CC="${TARGET_CC}" cc_is_clang; then REAL_TARGET_LD="$(command -v ${TARGET_LD})" [ ! -x "${REAL_TARGET_LD}" ] && \ die "Cannot determine absolute path for ${TARGET_LD}" TARGET_CC_LDFLAGS="${TARGET_CC_LDFLAGS} -fuse-ld=${REAL_TARGET_LD}" fi if ! CC="${TARGET_CC}" LD="${TARGET_LD}" check_ld; then die "Could not find a working target linker" fi if ! CC="${TARGET_CC}" OBJCOPY="${TARGET_OBJCOPY}" check_objcopy; then die "Could not find a working target objcopy" fi if CC="${TARGET_CC}" cc_is_gcc; then LIBGCC=$(${TARGET_CC} -print-libgcc-file-name) TARGET_CC_LDFLAGS="${TARGET_CC_LDFLAGS} -L $(dirname ${LIBGCC})" fi echo "${prog_NAME}: Using ${TARGET_LD} for target linker" echo "${prog_NAME}: Using ${TARGET_OBJCOPY} for target objcopy" TARGET_TRIPLE="${TARGET_ARCH}-gilbraltar-ocaml" echo "${prog_NAME}: Target toolchain triple is ${TARGET_TRIPLE}" # # Generate Makeconf, to be included by Makefiles. # cat <Makeconf # Generated by configure.sh CONFIG_PREFIX=${OPT_PREFIX} CONFIG_HOST_ARCH=${CONFIG_HOST_ARCH} CONFIG_HOST=${CONFIG_HOST} CONFIG_HOST_CC=${HOST_CC} CONFIG_TARGET_ARCH=${TARGET_ARCH} CONFIG_TARGET_TRIPLE=${TARGET_TRIPLE} CONFIG_TARGET_CC=${TARGET_CC} CONFIG_TARGET_CC_CFLAGS=${TARGET_CC_CFLAGS} CONFIG_TARGET_CC_LDFLAGS=${TARGET_CC_LDFLAGS} CONFIG_TARGET_CC_IS_OPENBSD=${TARGET_CC_IS_OPENBSD} CONFIG_TARGET_LD=${TARGET_LD} CONFIG_TARGET_LD_LDFLAGS=${TARGET_LD_LDFLAGS} CONFIG_TARGET_LD_MAX_PAGE_SIZE=${TARGET_LD_MAX_PAGE_SIZE} CONFIG_TARGET_NM=${TARGET_NM} CONFIG_TARGET_AR=${TARGET_AR} CONFIG_TARGET_RANLIB=${TARGET_RANLIB} CONFIG_TARGET_OBJCOPY=${TARGET_OBJCOPY} CONFIG_TARGET_OBJDUMP=${TARGET_OBJDUMP} CONFIG_TARGET_READELF=${TARGET_READELF} CONFIG_TARGET_STRIP=${TARGET_STRIP} EOM # # Generate Makeconf.sh, to be included by shell scripts. # sed -Ee 's/^([A-Z_]+)=(.*)$/\1="\2"/' Makeconf >Makeconf.sh cleanup