#!/bin/bash # # This file is part of the coreboot project. # # Copyright (C) 2007-2010 coresystems GmbH # Copyright (C) 2012 Google Inc # # 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. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc. # TMPFILE="" XGCCPATH=${1:-"`pwd`/util/crossgcc/xgcc/bin/"} 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.XXXX 2>/dev/null || echo /tmp/temp.78gOIUGz)" 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 else die "no iasl found" fi if program_exists gcc; then HOSTCC=gcc elif program_exists cc; then HOSTCC=cc else die "no host compiler found" fi cat <"$tmp_c" "$1" -nostdlib -Werror $2 "$tmp_c" -o "$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="$(${gccprefix}objdump -p $obj_file)" local obj_arch="$(expr "$obj_type" : '.*format \(.[a-z0-9-]*\)')" [ "$obj_arch" = "$full_arch" ] || return 1 # Architecture matched. GCCPREFIX="$gccprefix" 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" # GCC 4.6 is much more picky about unused variables. # Turn off it's warnings for now: testcc "$GCC" "$CFLAGS_GCC -Wno-unused-but-set-variable " && CFLAGS_GCC="$CFLAGS_GCC -Wno-unused-but-set-variable " # 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) testcc "$GCC" "$CFLAGS_GCC -Wa,--divide" && CFLAGS_GCC="$CFLAGS_GCC -Wa,--divide" testcc "$CLANG" "$CFLAGS_CLANG -Wa,--divide" && CFLAGS_CLANG="$CFLAGS_CLANG -Wa,--divide" # Always 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. CFLAGS_GCC="$CFLAGS_GCC -march=i686" ;; x64) testcc "$GCC" "$CFLAGS_GCC -Wa,--divide" && CFLAGS_GCC="$CFLAGS_GCC -Wa,--divide" testcc "$CLANG" "$CFLAGS_CLANG -Wa,--divide" && CFLAGS_CLANG="$CFLAGS_CLANG -Wa,--divide" ;; 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} -print-librt-file-name 2>/dev/null`" test -z "$GCC" || \ CC_RT_GCC="`${GCC} ${CFLAGS} -print-libgcc-file-name`" } report_arch_toolchain() { cat < /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-" done echo "# $architecture 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" && break 3 testas "$gccprefix" "$TWIDTH" "$TBFDARCH" \ "TRUE" "$endian" && break 3 done done done if [ "invalid" != "$GCCPREFIX" ]; then GCC="${GCCPREFIX}gcc" fi for clang_arch in $TCLIST invalid; do testcc "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="clang -target ${clang_arch}-${TABI} -ccc-gcc-name ${GCC}" fi if [ -z "$GCC" -a -z "$CLANG" ]; then echo "Warning: no suitable compiler for $architecture." >&2 return 1 fi } # This loops over all supported architectures. for architecture in $SUPPORTED_ARCHITECTURES; do if test_architecture $architecture; then detect_special_flags "$architecture" detect_compiler_runtime "$architecture" report_arch_toolchain fi done