#!/bin/bash # Copyright 1999-2008 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # $Header: $ cd / umask 0022 #159111 if [[ ${ROOT:-/} != "/" ]] ; then echo "Sorry, but crossdev does not support ROOT." exit 2 fi source /etc/init.d/functions.sh || exit 1 esyslog() { :; } die() { echo eerror $* eerror If you file a bug, please attach the following logfiles: eerror ${PORT_LOGDIR}/cross-${CTARGET}-info.log eerror ${logfile} exit 1 } usage() { local exit_status=${1:-0} shift cat << EOF Usage: ${HILITE}crossdev${NORMAL} ${GOOD}[options]${NORMAL} ${BRACKET}--target TARGET${NORMAL} Options: ${GOOD}--b, --binutils${NORMAL} ver Specify version of binutils to use ${GOOD}--g, --gcc${NORMAL} ver Specify version of gcc to use ${GOOD}--k, --kernel${NORMAL} ver Specify version of kernel headers to use ${GOOD}--l, --libc${NORMAL} ver Specify version of libc to use ${GOOD}-S, --stable${NORMAL} Use latest stable versions as default ${GOOD}-C, --clean${NORMAL} target Uninstall specified target ${GOOD}-P, --portage${NORMAL} opts Options to pass to emerge (see emerge(1)) ${GOOD}--with[out]-headers${NORMAL} Build C library headers before C compiler? Stage Options: ${GOOD}-s0, --stage0${NORMAL} Build just binutils ${GOOD}-s1, --stage1${NORMAL} Also build a C compiler (no libc/C++) ${GOOD}-s2, --stage2${NORMAL} Also build kernel headers ${GOOD}-s3, --stage3${NORMAL} Also build the C library (no C++) ${GOOD}-s4, --stage4${NORMAL} Also build a C++ compiler [default] Extra Fun (must be run after above stages): ${GOOD}--ex-only${NORMAL} Skip the stage steps above ${GOOD}--ex-gcc${NORMAL} Build extra gcc targets (gcj/ada/etc...) ${GOOD}--ex-gdb${NORMAL} Build a cross gdb ${GOOD}--ex-insight${NORMAL} Build a cross insight ${BRACKET}Target (-t)${NORMAL} takes a tuple ${BRACKET}ARCH-VENDOR-OS-LIBC${NORMAL}; see 'crossdev -t help' EOF [[ -n $* ]] && echo && eerror "Error: $*" exit ${exit_status} } STAGE_BINUTILS=0 STAGE_C_ONLY=1 STAGE_C_KERNEL=2 STAGE_LIBC=3 STAGE_C_CPP=4 STAGE_DEFAULT=${STAGE_C_CPP} STAGE_DISP=( "binutils" "C compiler only" "kernel headers" "C compiler & libc" "C/C++ compiler" ) parse_target() { CTARGET=${1#cross-} [[ -z ${CTARGET} ]] && usage 1 if [[ ${CTARGET} == "help" ]] ; then cat <<-EOF Supported Architectures: - alpha - arm / armeb - hppa (parisc) - ia64 - i386 / i486 / i586 / i686 (x86) - m68k - mips / mipsel / mips64 / mips64el - powerpc (ppc) / powerpc64 (ppc64) - sparc / sparc64 - s390 / s390x - sh / sh[1-5] / sh64 - x86_64 (amd64) Supported C Libraries: - glibc (gnu) - klibc [prob wont work] - newlib [bare metal/no operating system] - uclibc [not all arches are ported] Special Targets: - avr http://www.nongnu.org/avr-libc/ - bfin http://blackfin.uclinux.org/ - h8300 http://h8300-hms.sourceforge.net/ - mingw32 http://www.mingw.org/ - msp430 http://mspgcc.sourceforge.net/ - nios2 http://www.altera.com/products/ip/processors/nios2/ni2-index.html - xc16x http://www.infineon.com/ - ee / iop / dvp (ps2) [Playstation 2 targets] - ppu / spu (cell) [Cell/Playstation 3 targets] Softfloat toolchains: Include 'softfloat' in the 'vendor' field e.g. armeb-softfloat-linux-uclibc powerpc-booya_softfloat-linux-gnu EOF exit 0 fi # Allow for laziness if [[ ${CTARGET} != *-* ]] ; then # First translate portage ARCH to actual tuple case ${CTARGET} in amd64) CTARGET="x86_64";; parisc*) CTARGET=${CTARGET/parisc/hppa};; ppc|ppc64) CTARGET=${CTARGET/ppc/powerpc};; x86) CTARGET="i686";; esac # Then add common suffixes case ${CTARGET} in i?86|x86_64) CTARGET="${CTARGET}-pc-linux-gnu";; s390*) CTARGET="${CTARGET}-ibm-linux-gnu";; alpha*|arm*|cris*|hppa*|ia64*|m68*|mips*|powerpc*|sparc*|sh*) CTARGET="${CTARGET}-unknown-linux-gnu";; bfin*|h8300*|nios2*|spu*|xc16x*) CTARGET="${CTARGET}-elf";; esac fi # Figure out an acceptable portage ARCH for this target case ${CTARGET} in alpha*) TARCH=alpha;; arm*) TARCH=arm;; hppa*) TARCH=hppa;; ia64*) TARCH=ia64 WITH_DEF_HEADERS="yes";; i?86*) TARCH=x86;; m68*) TARCH=m68k;; mips*) TARCH=mips;; powerpc64*) TARCH=ppc64;; powerpc*) TARCH=ppc;; sparc*) TARCH=sparc;; s390*) TARCH=s390;; sh*) TARCH=sh;; x86_64*) TARCH=amd64;; *) TARCH="*";; esac case ${CTARGET} in *-freebsd*) TARCH="${TARCH}-fbsd";; esac # Now account for all the "special" architectures out there case ${CTARGET} in avr*) KPKG="[none]"; STAGE_DEFAULT=${STAGE_LIBC}; LCAT="dev-embedded"; LPKG="avr-libc"; GUSE=${GUSE_DISABLE};; # due to upstream lameness, build C/C++ at first glance *-cygwin) GUSE_DISABLE=${GUSE_DISABLE/nocxx};; mingw*|*-mingw*) WITH_DEF_HEADERS="yes"; KCAT="dev-util"; KPKG="w32api"; LCAT="dev-util"; LPKG="mingw-runtime";; msp430) STAGE_DEFAULT=${STAGE_BINUTILS};; nios2*) BPKG="binutils-nios2"; GPKG="gcc-nios2";; cell) einfo "The cell target is really an alias for the spu/ppu targets" ${CROSSDEV} -t ppu || exit 1 ${CROSSDEV} -t spu-elf || exit 1 exit 0;; spu*) TARCH=ppc64; KPKG="[none]"; LPKG="newlib";; ppu*) TARCH=ppc64;; ps2) einfo "The ps2 target is really an alias for the ee/iop/dvp targets" ${CROSSDEV} -t ee || exit 1 ${CROSSDEV} -t iop || exit 1 ${CROSSDEV} -t dvp || exit 1 exit 0;; ee*) TARCH=mips; KPKG="[none]" GVER="3.2.2"; BVER="2.14"; STAGE_DEFAULT=${STAGE_C_ONLY}; GUSE=${GUSE_DISABLE};; iop*) TARCH=mips; GVER="3.2.2"; BVER="2.14"; STAGE_DEFAULT=${STAGE_C_ONLY}; GUSE=${GUSE_DISABLE};; dvp*) TARCH=mips; GVER="3.2.2"; BVER="2.14"; STAGE_DEFAULT=${STAGE_BINUTILS};; esac # Tweak packages based upon CTARGET case ${CTARGET} in # Normal Linux host, just diff libc *-dietlibc) LPKG="dietlibc"; LCAT="dev-libs";; *-gnu*) LPKG="glibc";; *-klibc) LPKG="klibc";; *-uclibc*) LPKG="uclibc";; *-uclinux) LPKG="uclibc";; # Windows targets *-cygwin) LCAT="dev-libs"; LPKG="cygwin"; KPKG="[none]"; ;; # Bare metal targets *-newlib|*-elf) LPKG="newlib" KPKG="[none]" STAGE_DEFAULT=${STAGE_LIBC} ;; # Now for the BSDs ... *-freebsd*) LCAT="sys-freebsd" LPKG="freebsd-lib" KPKG="[none]" ;; esac : ${LPKG=[none]} } setup_portage_vars() { PORTDIR_OVERLAYS=$(portageq envvar PORTDIR_OVERLAY) PORTDIR_OVERLAY=${PORTDIR_OVERLAYS%% *} PORTDIR=$(portageq envvar PORTDIR) PORT_LOGDIR=$(portageq envvar PORT_LOGDIR) PORT_LOGDIR=${PORT_LOGDIR:-/var/log/portage} export PKGDIR=$(portageq envvar PKGDIR)/cross/${CTARGET} export PORTAGE_TMPDIR=$(portageq envvar PORTAGE_TMPDIR)/cross/${CTARGET} [[ ! -d ${PORT_LOGDIR} ]] && mkdir -p ${PORT_LOGDIR} [[ ! -d ${PORTAGE_TMPDIR} ]] && mkdir -p ${PORTAGE_TMPDIR} } uninstall() { setup_portage_vars ewarn "Uninstalling target '${CTARGET}' ..." [[ -d ${PORTDIR_OVERLAY}/cross-${CTARGET} ]] \ && rm -r ${PORTDIR_OVERLAY}/cross-${CTARGET} sed -i -e "/^cross-${CTARGET}$/d" /etc/portage/categories for f in package.{mask,keywords,use} ; do f="/etc/portage/${f}" if [[ -d ${f} ]] ; then rm -f "${f}"/cross-${CTARGET} elif [[ -f ${f} ]] ; then sed -i -e "/cross-${CTARGET}\//d" "${f}" fi done if [[ ! -d /var/db/pkg/cross-${CTARGET} ]] ; then eerror "${CTARGET} is not installed." exit 1 fi export CLEAN_DELAY=0 cd /var/db/pkg for p in cross-${CTARGET}/* ; do emerge -C =${p} || exit 1 done for b in addr2line ar as c++filt ld nm objcopy objdump ranlib readelf size strings strip ; do rm -f /usr/bin/${CTARGET}-${b} /usr/${CTARGET}/bin/${b} done rm -f /usr/${CTARGET}/{sys-include,usr} rm -f /usr/bin/${CTARGET}-{gcc,{c,g}++,cpp,gfortran,gcov} rmdir /usr/${CTARGET}/{include/asm,include} &> /dev/null for d in /usr/${CTARGET} /usr/lib/gcc{,-lib}/${CTARGET} ; do if [[ ! -d ${d} ]] ; then rm -f "${d}" &> /dev/null else rmdir "${d}" &> /dev/null && continue rm -ri "${d}" fi done rm -f /etc/env.d/{binutils,gcc}/config-${CTARGET} rmdir /var/db/pkg/cross-${CTARGET} exit 0 } set_withval() { local withval varname varname=${*#--with-} varname=${varname#--without-} varname=${varname%%=*} if [[ $* == *=* ]] ; then withval=${*#*=} else [[ $* == --with-* ]] && withval="yes" || withval="no" fi echo WITH_`echo ${varname} | tr '[:lower:]' '[:upper:]'`=\"${withval}\" } is_stage() { [[ ${STAGE} -ge $1 ]] ; } is_s0() { is_stage 0 ; } is_s1() { is_stage 1 ; } is_s2() { is_stage 2 ; } is_s3() { is_stage 3 ; } is_s4() { is_stage 4 ; } is_s5() { is_stage 5 ; } with_headers() { [[ ${WITH_HEADERS} == "yes" ]] ; } ex_fast() { [[ ${EX_FAST} == "yes" ]] ; } ex_gcc() { [[ ${EX_GCC} == "yes" ]] ; } ex_gdb() { [[ ${EX_GDB} == "yes" ]] ; } ex_insight() { [[ ${EX_INSIGHT} == "yes" ]] ; } hr() { local c=${COLUMNS:-0} if [[ ${c} -eq 0 ]] ; then c=$(stty size 2> /dev/null) [[ -z ${c} ]] \ && c=50 \ || c=${c##* } fi local ext=${1:- _ - ~ -} local sext=${ext//?/ } local br=$(printf "%$((c + ${#ext}))s") local banner=${br//${sext}/${ext}} echo "${banner:0:${c}}" } ################## ### setup vars ### CROSSDEV=$0 EOPTS= UOPTS= TARCH= HARCH=$(unset ARCH ; portageq envvar ARCH) CTARGET= STAGE="" BCAT="sys-devel" ; BPKG="binutils" ; BVER="" ; BUSE="" GCAT="sys-devel" ; GPKG="gcc" ; GVER="" ; GUSE="" KCAT="sys-kernel" ; KPKG="linux-headers" ; KVER="" ; KUSE="" LCAT="sys-libs" ; LPKG="" ; LVER="" ; LUSE="" DEFAULT_VER="[latest]" GUSE_DISABLE="-boundschecking -d -fortran -gtk -gcj -libffi -mudflap nocxx -objc -objc++ -objc-gc -openmp" GUSE_DISABLE_STAGE_2=${GUSE_DISABLE/-fortran} GUSE_DISABLE_STAGE_2=${GUSE_DISABLE_STAGE_2/nocxx} WITH_HEADERS="COW" WITH_DEF_HEADERS="yes" #227065 gcc-4.3+ is a pita w/out headers EX_FAST="no" EX_GCC="no" EX_GDB="no" SET_X="no" while [[ $# -gt 0 ]] ; do case $1 in -V|--version) echo "crossdev-@CDEVPV@"; exit 0;; -t|--target) shift; parse_target $1;; --b|--binutils) shift; BVER=$1;; --g|--gcc) shift; GVER=$1;; --k|--kernel) shift; KVER=$1;; --l|--libc) shift; LVER=$1;; -S|--stable) DEFAULT_VER="[stable]";; -C|--clean) shift; parse_target $1; uninstall;; -s?|--stage?) STAGE=${1:0-1};; --ex-only) EX_FAST="yes";; --ex-gcc) EX_GCC="yes";; --ex-gdb) EX_GDB="yes";; --ex-insight) EX_INSIGHT="yes";; --with-*) eval $(set_withval $1);; --without-*) eval $(set_withval $1);; -x) SET_X="yes";; -P|--portage) UOPTS="${UOPTS} $2"; shift;; -b|-d|-p|-v|-q) UOPTS="${UOPTS} $1";; -pv|-vp) UOPTS="${UOPTS} -p -v";; -h|--help) usage;; -*) eerror "UNKNOWN OPTION: '$1'" ; usage 1;; *) parse_target $1;; esac shift done [[ ${SET_X} == "yes" ]] && set -x BVER=${BVER:-${DEFAULT_VER}} GVER=${GVER:-${DEFAULT_VER}} KVER=${KVER:-${DEFAULT_VER}} LVER=${LVER:-${DEFAULT_VER}} STAGE=${STAGE:-${STAGE_DEFAULT}} [[ -z ${CTARGET} ]] && usage 1 for with in HEADERS ; do var=WITH_${with} defvar=WITH_DEF_${with} [[ ${!var} == "COW" ]] && eval ${var}=${!defvar} done ##################### ### sanity checks ### if ! binutils-config --version &> /dev/null ; then eerror "Sorry, but your host system needs to have binutils-config" eerror "in order to keep from screwing things up." eerror "That means you must be running unstable versions of" eerror "both binutils and binutils-config." exit 1 fi if ! egrep -qs 'inherit.*toolchain( |$)' /var/db/pkg/sys-devel/gcc-*/*.ebuild ; then eerror "Sorry, but your host system needs to have" eerror "an unstable version of gcc in order to" eerror "keep from screwing things up." exit 1 fi setup_portage_vars if [[ -z ${PORTDIR_OVERLAY} ]] ; then eerror "You need to set PORTDIR_OVERLAY in your make.conf." eerror "A standard setting is /usr/local/portage" exit 1 fi if [[ $(unset CHOST ; portageq envvar CHOST) == ${CTARGET} ]] ; then eerror "Refusing to create a cross-compiler using the same" eerror "target name as your host utils." exit 1 fi # grab user settings for v in ABI UCLIBC_CPU USE BVER GVER KVER LVER STAGE CFLAGS LDFLAGS ASFLAGS ; do if [[ -e /etc/portage/crossdev/${CTARGET}/${v} ]] ; then # yes, quotes are needed in this instance (export $var="...") export ${v}="$(& ${PORT_LOGDIR}/cross-${CTARGET}-info.log || exit 1 cat ${PORT_LOGDIR}/cross-${CTARGET}-info.log emerge -v --info >> ${PORT_LOGDIR}/cross-${CTARGET}-info.log #################################### ### Fix up portage files / paths ### set_keywords() { local pkg=$1 ver=$2 output [[ -z ${pkg} ]] && return 0 if [[ -f package.keywords ]] ; then output="package.keywords" sed -i -e "/^cross-${CTARGET}\/${pkg} /d" ${output} else output="package.keywords/cross-${CTARGET}" fi if [[ ${ver} == "["*"]" ]] || [[ -z ${ver} ]] ; then local keywords="" case ${ver} in "[stable]") keywords="${TARCH}";; *) keywords="${TARCH} ~${TARCH}";; esac [[ "${TARCH}" != "${HARCH}" ]] && keywords="${keywords} -${HARCH} -~${HARCH}" echo "cross-${CTARGET}/${pkg} ${keywords}" >> ${output} else echo "cross-${CTARGET}/${pkg} * ~* **" >> ${output} if [[ -f package.mask ]] ; then output="package.mask" sed -i -e "/cross-${CTARGET}\/${pkg}/d" ${output} else output="package.mask/cross-${CTARGET}" fi echo ">cross-${CTARGET}/${pkg}-${ver}" >> ${output} fi } set_use() { local pkg=$1 output shift local use=$@ [[ -z ${use} ]] && return 0 if [[ -f package.use ]] ; then output="package.use" else output="package.use/cross-${CTARGET}" fi [[ -e ${output} ]] && sed -i -e "/cross-${CTARGET}\/${pkg}/d" ${output} echo "cross-${CTARGET}/${pkg} ${use}" >> ${output} } set_links() { local cat=$1 pkg=$2 local s srcdir=${PORTDIR} rm -f "${PORTDIR_OVERLAY}"/cross-${CTARGET}/${pkg} for s in ${PORTDIR_OVERLAYS} ; do if [[ -d ${s}/${cat}/${pkg} ]] ; then einfo "Using ${cat}/${pkg} from ${s} instead of ${PORTDIR}" srcdir=${s} break fi done ln -s "${srcdir}"/${cat}/${pkg} "${PORTDIR_OVERLAY}"/cross-${CTARGET}/${pkg} } set_portage() { local cat=$1 pkg=$2 ver=$3 shift ; shift ; shift local use=$@ [[ ${pkg} == "[none]" ]] && return 0 set_keywords ${pkg} ${ver} set_use ${pkg} ${use} set_links ${cat} ${pkg} } mkdir -p /etc/portage grep -qs "^cross-${CTARGET}$" /etc/portage/categories \ || echo cross-${CTARGET} >> /etc/portage/categories mkdir -p "${PORTDIR_OVERLAY}"/cross-${CTARGET} cd /etc/portage for f in package.{keywords,mask,use} ; do [[ -f ${f} ]] && continue mkdir -p ${f} rm -f ${f}/cross-${CTARGET} done set_portage ${BCAT} ${BPKG} ${BVER} set_portage ${GCAT} ${GPKG} ${GVER} set_portage ${KCAT} ${KPKG} ${KVER} set_portage ${LCAT} ${LPKG} ${LVER} set_portage sys-devel gdb set_portage dev-util insight ################# emerged_with_use() { local pkg=$1 use=$2 grep -qs ${use} /var/db/pkg/cross-${CTARGET}/${pkg}-*/USE } set_eopts_on_pkg_status() { emerged_with_use "$@" \ && EOPTS=${EOPTS_DEF} \ || EOPTS=${EOPTS_UP} } doemerge() { [[ $1 == "[none]" ]] && return 0 local logfile=${PORT_LOGDIR}/cross-${CTARGET} [[ -z $2 ]] \ && logfile=${logfile}-$1.log \ || logfile=${logfile}-$2.log einfo "Log: ${logfile}" ebegin "Emerging cross-${2:-$1}" set_use $1 ${USE} if [[ ${UOPTS/-v} != ${UOPTS} || ${UOPTS/-p} != ${UOPTS} ]] ; then emerge cross-${CTARGET}/$1 ${EOPTS} \ 2>&1 | tee ${logfile} else emerge cross-${CTARGET}/$1 ${EOPTS} \ >& ${logfile} fi local _pipestatus=${PIPESTATUS[*]} [[ "${_pipestatus// /}" -eq 0 ]] || die "$1 failed :(" eend 0 } # we include the '-u' so that we don't re-emerge packages EOPTS_DEF="${UOPTS} --nodeps --oneshot" EOPTS_UP="${EOPTS_DEF} -u" EOPTS=${EOPTS_UP} # keep things like --ask from screwing us up export EMERGE_DEFAULT_OPTS="" # maybe someday this work, but that day != today USE="${USE} -selinux" # make sure multilib crap doesn't screw us over export ABI=${ABI:-pos} LIBDIR_pos="lib" CFLAGS_pos="" LDFLAGS_pos="" # only allow UCLIBC_CPU from env, not from make.conf/profile export UCLIBC_CPU=${UCLIBC_CPU} ex_fast || { ebegin "Forcing the latest versions of {binutils,gcc}-config/gnuconfig" emerge {binutils,gcc}-config gnuconfig -qu --ignore-default-opts &> /dev/null eend $? || exit 1 doemerge ${BPKG} is_s1 || exit 0 if with_headers ; then USE="${KUSE} ${USE}" CROSSCOMPILE_OPTS="headers-only" \ doemerge ${KPKG} ${KPKG}-quick [[ -n ${LPKG} ]] && \ USE="${LUSE} ${USE}" CROSSCOMPILE_OPTS="headers-only" \ doemerge ${LPKG} ${LPKG}-headers fi USE="${GUSE} ${USE} ${GUSE_DISABLE}" CROSSCOMPILE_OPTS="bootstrap" \ doemerge ${GPKG} ${GPKG}-stage1 is_s2 || exit 0 set_eopts_on_pkg_status ${KPKG} crosscompile_opts_headers-only USE="${KUSE} ${USE}" CROSSCOMPILE_OPTS="" \ doemerge ${KPKG} is_s3 || exit 0 [[ -z ${LPKG} ]] && die "Invalid target '${CTARGET}': unknown libc" set_eopts_on_pkg_status ${LPKG} crosscompile_opts_headers-only USE="${LUSE} ${USE}" CROSSCOMPILE_OPTS="" \ doemerge ${LPKG} is_s4 || exit 0 set_eopts_on_pkg_status ${GPKG} crosscompile_opts_bootstrap EOPTS="${EOPTS_UP} --newuse" USE="${GUSE} ${USE} ${GUSE_DISABLE_STAGE_2}" \ doemerge ${GPKG} ${GPKG}-stage2 } EOPTS="${EOPTS_UP} --newuse" ex_gcc && USE="${GUSE} ${USE}" doemerge ${GPKG} ${GPKG}-extra ex_gdb && doemerge gdb ex_insight && doemerge insight exit 0