| #!/usr/bin/env bash |
| # |
| # This file is part of the coreboot project. |
| # |
| # Copyright (C) 2007-2010 coresystems GmbH |
| # Copyright (C) 2012 Google Inc |
| # Copyright (C) 2016 Raptor Engineering, LLC |
| # |
| # This program is free software; you can redistribute it and/or modify |
| # it under the terms of the GNU General Public License as published by |
| # the Free Software Foundation; version 2 of the License. |
| # |
| # This program is distributed in the hope that it will be useful, |
| # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| # GNU General Public License for more details. |
| # |
| |
| # Usage: [--debug] [path to xgcc/bin directory] |
| |
| # Enable debug output |
| if [ "$1" = "--debug" ]; then |
| shift |
| set -x |
| fi |
| |
| TMPFILE="" |
| XGCCPATH=$1 |
| |
| # payloads under payloads/external crossgcc path |
| if [ -d "$(pwd)/../../../../util/crossgcc/xgcc/bin/" ] |
| then |
| XGCCPATH=${XGCCPATH:-"$(pwd)/../../../../util/crossgcc/xgcc/bin/"} |
| fi |
| |
| # libpayload crossgcc path |
| if [ -d "$(pwd)/../../util/crossgcc/xgcc/bin/" ] |
| then |
| XGCCPATH=${XGCCPATH:-"$(pwd)/../../util/crossgcc/xgcc/bin/"} |
| fi |
| |
| # coreboot crossgcc path |
| if [ -d "$(pwd)/util/crossgcc/xgcc/bin/" ] |
| then |
| XGCCPATH=${XGCCPATH:-"$(pwd)/util/crossgcc/xgcc/bin/"} |
| fi |
| |
| die() { |
| echo "ERROR: $*" >&2 |
| exit 1 |
| } |
| |
| clean_up() { |
| if [ -n "$TMPFILE" ]; then |
| rm -f "$TMPFILE" "$TMPFILE.c" "$TMPFILE.o" |
| fi |
| } |
| |
| # Create temporary file(s). |
| TMPFILE="$(mktemp /tmp/temp.XXXXXX 2>/dev/null || echo /tmp/temp.coreboot.$RANDOM)" |
| touch "$TMPFILE" |
| trap clean_up EXIT |
| |
| |
| program_exists() { |
| type "$1" >/dev/null 2>&1 |
| } |
| |
| |
| if [ "$("${XGCCPATH}/iasl" 2>/dev/null | grep -c ACPI)" -gt 0 ]; then |
| IASL=${XGCCPATH}iasl |
| elif [ "$(iasl 2>/dev/null | grep -c ACPI)" -gt 0 ]; then |
| IASL=iasl |
| fi |
| |
| if program_exists gcc; then |
| HOSTCC=gcc |
| elif program_exists cc; then |
| HOSTCC=cc |
| else |
| die "no host compiler found" |
| fi |
| |
| # try to find the core count using various methods |
| CORES="$(getconf _NPROCESSORS_ONLN 2>/dev/null)" |
| if [ -z "$CORES" ]; then |
| NPROC=$(command -v nproc) |
| if [ -n "$NPROC" ]; then |
| CORES="$($NPROC)" |
| fi |
| fi |
| if [ -z "$CORES" ]; then |
| SYSCTL=$(command -v sysctl) |
| if [ -n "$SYSCTL" ]; then |
| CORES="$(${SYSCTL} -n hw.ncpu 2>/dev/null)" |
| fi |
| fi |
| if [ -z "$CORES" ] && [ -f /proc/cpuinfo ]; then |
| CORES="$(grep 'processor' /proc/cpuinfo 2>/dev/null | wc -l)" |
| fi |
| |
| cat <<EOF |
| # platform agnostic and host tools |
| IASL:=${IASL} |
| HOSTCC?=${HOSTCC} |
| CPUS?=${CORES} |
| |
| EOF |
| |
| testcc() { |
| local cc="$1" |
| local cflags="$2" |
| local tmp_c="$TMPFILE.c" |
| local tmp_o="$TMPFILE.o" |
| rm -f "$tmp_c" "$tmp_o" |
| echo "void _start(void) {}" >"$tmp_c" |
| "$cc" -nostdlib -Werror $cflags -c "$tmp_c" -o "$tmp_o" >/dev/null 2>&1 |
| } |
| |
| testld() { |
| local gcc="$1" |
| local cflags="$2" |
| local ld="$3" |
| local ldflags="$4" |
| local tmp_o="$TMPFILE.o" |
| local tmp_elf="$TMPFILE.elf" |
| rm -f "$tmp_elf" |
| testcc "$gcc" "$cflags" && |
| $ld -nostdlib -static $ldflags -o "$tmp_elf" "$tmp_o" >/dev/null 2>&1 |
| } |
| |
| testas() { |
| local gccprefix="$1" |
| local twidth="$2" |
| local arch="$3" |
| local use_dash_twidth="$4" |
| local endian="$5" |
| local obj_file="$TMPFILE.o" |
| local full_arch="elf$twidth-$arch" |
| |
| rm -f "$obj_file" |
| [ -n "$use_dash_twidth" ] && use_dash_twidth="--$twidth" |
| [ -n "$endian" ] && endian="-$endian" |
| "${gccprefix}as" $use_dash_twidth $endian -o "$obj_file" "$TMPFILE" \ |
| 2>/dev/null || return 1 |
| |
| # Check output content type. |
| local obj_type="$(LANG=C LC_ALL='' "${gccprefix}"objdump -p "$obj_file" 2>/dev/null)" |
| local obj_arch="$(expr "$obj_type" : '.*format \(.[a-z0-9-]*\)')" |
| [ "$obj_arch" = "$full_arch" ] || return 1 |
| |
| unset ASFLAGS LDFLAGS |
| unset CFLAGS_GCC CFLAGS_CLANG |
| |
| if [ -n "$use_dash_twidth" ]; then |
| ASFLAGS="--$twidth" |
| CFLAGS_GCC="-m$twidth" |
| CFLAGS_CLANG="-m$twidth" |
| LDFLAGS="-b $full_arch" |
| |
| fi |
| |
| # Special parameters only available in dash_twidth mode. |
| [ -n "$use_dash_twidth" ] && case "$full_arch" in |
| "elf32-i386" ) |
| LDFLAGS="$LDFLAGS -melf_i386" |
| CFLAGS_GCC="$CFLAGS_GCC -Wl,-b,elf32-i386 -Wl,-melf_i386" |
| CFLAGS_CLANG="$CFLAGS_GCC -Wl,-b,elf32-i386 -Wl,-melf_i386" |
| ;; |
| esac |
| |
| return 0 |
| } |
| |
| detect_special_flags() { |
| local architecture="$1" |
| # Check for an operational -m32/-m64 |
| testcc "$GCC" "$CFLAGS_GCC -m$TWIDTH " && |
| CFLAGS_GCC="$CFLAGS_GCC -m$TWIDTH " |
| |
| # Use bfd linker instead of gold if available: |
| testcc "$GCC" "$CFLAGS_GCC -fuse-ld=bfd" && |
| CFLAGS_GCC="$CFLAGS_GCC -fuse-ld=bfd" && LINKER_SUFFIX='.bfd' |
| |
| testcc "$GCC" "$CFLAGS_GCC -fno-stack-protector"&& |
| CFLAGS_GCC="$CFLAGS_GCC -fno-stack-protector" |
| testcc "$GCC" "$CFLAGS_GCC -Wl,--build-id=none" && |
| CFLAGS_GCC="$CFLAGS_GCC -Wl,--build-id=none" |
| |
| case "$architecture" in |
| x86) |
| ;; |
| x64) |
| ;; |
| arm64) |
| testld "$GCC" "$CFLAGS_GCC" "${GCCPREFIX}ld${LINKER_SUFFIX}" \ |
| "$LDFLAGS --fix-cortex-a53-843419" && \ |
| LDFLAGS_ARM64_A53_ERRATUM_843419+=" --fix-cortex-a53-843419" |
| ;; |
| mipsel) |
| testcc "$GCC" "$CFLAGS_GCC -mno-abicalls -fno-pic" && \ |
| CFLAGS_GCC+=" -mno-abicalls -fno-pic" |
| |
| # Enforce little endian mode. |
| testcc "$GCC" "$CFLAGS_GCC -EL" && \ |
| CFLAGS_GCC+=" -EL" |
| ;; |
| esac |
| } |
| |
| detect_compiler_runtime() { |
| test -z "$CLANG" || \ |
| CC_RT_CLANG="$(${CLANG} ${CFLAGS_CLANG} -print-librt-file-name 2>/dev/null)" |
| test -z "$GCC" || \ |
| CC_RT_GCC="$(${GCC} ${CFLAGS_GCC} -print-libgcc-file-name)" |
| } |
| |
| report_arch_toolchain() { |
| cat <<EOF |
| # elf${TWIDTH}-${TBFDARCH} toolchain (${GCC}) |
| ARCH_SUPPORTED+=${TARCH} |
| SUBARCH_SUPPORTED+=${TSUPP-${TARCH}} |
| |
| # GCC |
| GCC_CC_${TARCH}:=${GCC} |
| GCC_CFLAGS_${TARCH}:=${CFLAGS_GCC} |
| GCC_COMPILER_RT_${TARCH}:=${CC_RT_GCC} |
| GCC_COMPILER_RT_FLAGS_${TARCH}:=${CC_RT_EXTRA_GCC} |
| EOF |
| |
| # Generally the x86 should build for i686 -- no sse/mmx |
| # instructions since SMM modules are compiled using these |
| # flags. Note that this doesn't prevent a project using |
| # xcompile to explicitly specify -mmsse, etc flags. |
| # The Quark processor doesn't support the instructions |
| # introduced with the Pentium 6 architecture, so allow it |
| # to use i586 instead. |
| if [ "${TARCH}" = "x86_64" ] || [ "${TARCH}" = "x86_32" ]; then |
| cat <<EOF |
| |
| ifeq (\$(CONFIG_USE_MARCH_586),y) |
| GCC_CFLAGS_${TARCH} += -march=i586 |
| else |
| GCC_CFLAGS_${TARCH} += -march=i686 |
| endif |
| EOF |
| fi |
| |
| cat <<EOF |
| |
| # Clang |
| CLANG_CC_${TARCH}:=${CLANG} |
| CLANG_CFLAGS_${TARCH}:=${CFLAGS_CLANG} |
| CLANG_CFLAGS_${TARCH}+=-no-integrated-as -Qunused-arguments -m${TWIDTH} |
| # tone down clang compiler warnings |
| CLANG_CFLAGS_${TARCH}+=-Wno-unused-variable -Wno-unused-function -Wno-tautological-compare -Wno-shift-overflow |
| CLANG_COMPILER_RT_${TARCH}:=${CC_RT_CLANG} |
| CLANG_COMPILER_RT_FLAGS_${TARCH}:=${CC_RT_EXTRA_CLANG} |
| |
| ifeq (\$(CONFIG_COMPILER_GCC)\$(CONFIG_LP_COMPILER_GCC),y) |
| CC_${TARCH}:=\$(GCC_CC_${TARCH}) |
| CFLAGS_${TARCH}:=\$(GCC_CFLAGS_${TARCH}) |
| COMPILER_RT_${TARCH}:=\$(GCC_COMPILER_RT_${TARCH}) |
| COMPILER_RT_FLAGS_${TARCH}:=\$(GCC_COMPILER_RT_FLAGS_${TARCH}) |
| else |
| CC_${TARCH}:=\$(CLANG_CC_${TARCH}) |
| CFLAGS_${TARCH}:=\$(CLANG_CFLAGS_${TARCH}) |
| COMPILER_RT_${TARCH}:=\$(CLANG_COMPILER_RT_${TARCH}) |
| COMPILER_RT_FLAGS_${TARCH}:=\$(CLANG_COMPILER_RT_FLAGS_${TARCH}) |
| endif |
| |
| CPP_${TARCH}:=${GCCPREFIX}cpp |
| AS_${TARCH}:=${GCCPREFIX}as ${ASFLAGS} |
| LD_${TARCH}:=${GCCPREFIX}ld${LINKER_SUFFIX} ${LDFLAGS} |
| EOF |
| |
| if [ "${TARCH}" = "arm64" ] && \ |
| [ -n "${LDFLAGS_ARM64_A53_ERRATUM_843419}" ]; then |
| cat <<EOF |
| |
| ifeq (\$(CONFIG_ARM64_A53_ERRATUM_843419),y) |
| LD_${TARCH}+=${LDFLAGS_ARM64_A53_ERRATUM_843419} |
| endif |
| |
| EOF |
| fi # if [ "${TARCH}" = "arm64" ]... |
| |
| cat <<EOF |
| NM_${TARCH}:=${GCCPREFIX}nm |
| OBJCOPY_${TARCH}:=${GCCPREFIX}objcopy |
| OBJDUMP_${TARCH}:=${GCCPREFIX}objdump |
| READELF_${TARCH}:=${GCCPREFIX}readelf |
| STRIP_${TARCH}:=${GCCPREFIX}strip |
| AR_${TARCH}:=${GCCPREFIX}ar |
| GNATBIND_${TARCH}:=${GCCPREFIX}gnatbind |
| CROSS_COMPILE_${TARCH}:=${GCCPREFIX} |
| |
| |
| EOF |
| #The two blank lines above are intentional separators |
| } |
| |
| # Architecture definitions |
| SUPPORTED_ARCHITECTURES="arm arm64 mipsel riscv x64 x86 power8" |
| |
| # TARCH: local name for the architecture |
| # (used as CC_${TARCH} in the build system) |
| # TBFDARCHS: architecture name in binutils (eg elf32-${TBFDARCH}) |
| # TCLIST: first part of the compiler triplet (eg i386 in i386-elf) |
| # TWIDTH: numerical argument for cpu mode: gcc -m${TWIDTH} |
| # TSUPP: supported subarchs (for -mcpu=...) |
| # TABI: typically elf, eabi or linux |
| |
| arch_config_arm() { |
| TARCH="arm" |
| TBFDARCHS="littlearm" |
| TCLIST="armv7-a armv7a arm" |
| TWIDTH="32" |
| TSUPP="arm armv4 armv7 armv7_m" |
| TABI="eabi" |
| } |
| |
| arch_config_arm64() { |
| TARCH="arm64" |
| TBFDARCHS="littleaarch64" |
| TCLIST="aarch64" |
| TWIDTH="64" |
| TSUPP="arm64 armv8_64" |
| TABI="elf" |
| } |
| |
| arch_config_riscv() { |
| TARCH="riscv" |
| TBFDARCHS="littleriscv" |
| TCLIST="riscv riscv64" |
| TWIDTH="64" |
| TABI="elf" |
| } |
| |
| arch_config_x64() { |
| TARCH="x86_64" |
| TBFDARCHS="x86-64" |
| TCLIST="x86_64" |
| TWIDTH="64" |
| TABI="elf" |
| } |
| |
| arch_config_x86() { |
| TARCH="x86_32" |
| TBFDARCHS="i386" |
| TCLIST="i386 x86_64" |
| TWIDTH="32" |
| TABI="elf" |
| CC_RT_EXTRA_GCC="--wrap __divdi3 --wrap __udivdi3 --wrap __moddi3 --wrap __umoddi3" |
| } |
| |
| arch_config_mipsel() { |
| TARCH="mips" |
| TBFDARCHS="tradlittlemips littlemips" |
| TCLIST="mipsel" |
| TWIDTH="32" |
| TSUPP="mips mipsel" |
| TABI="elf" |
| TENDIAN="EL" |
| } |
| |
| arch_config_power8() { |
| TARCH="power8" |
| TBFDARCHS="powerpc" |
| TCLIST="powerpc64" |
| TWIDTH="64" |
| TSUPP="power8" |
| TABI="linux-gnu" # there is no generic ABI on ppc64 |
| CC_RT_EXTRA_GCC="-mcpu=power8 -mbig-endian" |
| } |
| |
| test_architecture() { |
| local architecture=$1 |
| local endian gccprefix search |
| |
| GCCPREFIX="invalid" |
| unset TABI TARCH TBFDARCH TCLIST TENDIAN TSUPP TWIDTH |
| unset CC_RT_EXTRA_GCC CC_RT_EXTRA_CLANG |
| unset GCC CLANG |
| if type "arch_config_$architecture" > /dev/null; then |
| "arch_config_$architecture" |
| else |
| die "no architecture definition for $architecture" |
| fi |
| |
| # To override toolchain, define CROSS_COMPILE_$arch or CROSS_COMPILE as |
| # environment variable. |
| # Ex: CROSS_COMPILE_arm="armv7a-cros-linux-gnueabi-" |
| # CROSS_COMPILE_x86="i686-pc-linux-gnu-" |
| search="$(eval echo "\$CROSS_COMPILE_$architecture" 2>/dev/null)" |
| search="$search $CROSS_COMPILE" |
| for toolchain in $TCLIST; do |
| search="$search $XGCCPATH$toolchain-$TABI-" |
| search="$search $toolchain-$TABI-" |
| search="$search $toolchain-linux-gnu-" |
| search="$search $toolchain-linux-" |
| search="$search $toolchain-" |
| search="$search $toolchain-linux-gnueabi-" |
| done |
| echo "###########################################################################" |
| echo "# $architecture" |
| echo "# TARCH_SEARCH=$search" |
| |
| # Search toolchain by checking assembler capability. |
| for TBFDARCH in $TBFDARCHS; do |
| for gccprefix in $search ""; do |
| program_exists "${gccprefix}as" || continue |
| for endian in $TENDIAN ""; do |
| { testas "$gccprefix" "$TWIDTH" "$TBFDARCH" \ |
| "" "$endian" || |
| testas "$gccprefix" "$TWIDTH" "$TBFDARCH" \ |
| "TRUE" "$endian" ; } && \ |
| testcc "${gccprefix}gcc" "$CFLAGS_GCC" && \ |
| GCCPREFIX="$gccprefix" && \ |
| break 3 |
| done |
| done |
| done |
| if [ "invalid" != "$GCCPREFIX" ]; then |
| GCC="${GCCPREFIX}gcc" |
| fi |
| |
| for clang_arch in $TCLIST invalid; do |
| testcc "${XGCCPATH}clang" "-target ${clang_arch}-$TABI -c" && break |
| done |
| |
| if [ "invalid" != "$clang_arch" ]; then |
| # FIXME: this may break in a clang && !gcc configuration, |
| # but that's more of a clang limitation. Let's be optimistic |
| # that this will change in the future. |
| CLANG="${XGCCPATH}clang" |
| CFLAGS_CLANG="-target ${clang_arch}-${TABI} $CFLAGS_CLANG -ccc-gcc-name ${GCC}" |
| fi |
| } |
| |
| # This loops over all supported architectures. |
| for architecture in $SUPPORTED_ARCHITECTURES; do |
| test_architecture "$architecture" |
| detect_special_flags "$architecture" |
| detect_compiler_runtime "$architecture" |
| report_arch_toolchain |
| done |
| echo XCOMPILE_COMPLETE:=1 |