#!/bin/bash # Copyright 1999-2012 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 CROSSDEV_VER="@CDEVPV@" cd / umask 0022 #159111 if [[ ${ROOT:-/} != "/" ]] ; then echo "Sorry, but crossdev does not support ROOT." 1>&2 exit 2 fi CONFIGROOT="${PORTAGE_CONFIGROOT}/etc/portage" source /etc/init.d/functions.sh || exit 1 esyslog() { :; } die_logs() { echo eerror "$1" shift local log eerror eerror "If you file a bug, please attach the following logfiles:" eerror "${PORT_LOGDIR}/cross-${CTARGET}-info.log" for log in "$@" ; do eerror "${log}" done exit 1 } die() { die_logs "$*"; } has() { [[ " ${@:2} " == *" $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 Note: versions support depend atom syntaxes: e.g. ">=2.20" "~4.6.1" "=2.13.1-r3" ${GOOD}-A, --abis${NORMAL} abis Specify ABIs to build, first one is the default ${GOOD}--host-abi abi Specify the ABI of the compiler itself ${GOOD}--env${NORMAL} env Specify env settings for all packages (see below) ${GOOD}--[bdgkl]env${NORMAL} env Specify env settings for binutils/gdb/gcc/kernel/libc Note: make sure to quote: 'VAR="some value"\nFOO="cow"' ${GOOD}-f, --force${NORMAL} I don't need a seat belt! ${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? ${GOOD}--show-fail-log${NORMAL} If the build fails, dump the failing log Overlay Options: ${GOOD}-oS, --overlays${NORMAL} list Space delimited list of overlays to search [default: \${PORTDIR_OVERLAY}] ${GOOD}-oO, --ov-output${NORMAL} path Overlay to write crossdev package links [default: first from --overlays list] ${GOOD}-ob, --ov-binutils${NORMAL} path Overlay for binutils ebuilds [default: search] ${GOOD}-od, --ov-gdb${NORMAL} path Overlay for gdb ebuilds [default: search] ${GOOD}-og, --ov-gcc${NORMAL} path Overlay for gcc ebuilds [default: search] ${GOOD}-ok, --ov-kernel${NORMAL} path Overlay for kernel ebuilds [default: search] ${GOOD}-ol, --ov-libc${NORMAL} path Overlay for C library ebuilds [default: search] Stage Options: ${GOOD}-s0, --stage0${NORMAL} Build just binutils ${GOOD}-s1, --stage1${NORMAL} Also build a bare C compiler (no C library/ C++/shared GCC libs/C++ exceptions/etc...) ${GOOD}-s2, --stage2${NORMAL} Also build kernel headers ${GOOD}-s3, --stage3${NORMAL} Also build the C library ${GOOD}-s4, --stage4${NORMAL} Also build a full compiler [default] (shared libs GCC/various lang frontends/etc...) External Tooling Options: ${GOOD}--show-target-cfg${NORMAL} Display target settings that crossdev will use ${GOOD}--init-target${NORMAL} Setup config/overlay/etc... files only 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 ${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 / aarch64 - 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";; arm*) CTARGET="${CTARGET}-unknown-linux-gnueabi";; alpha*|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 aarch64*) TARCH=arm;; alpha*) TARCH=alpha;; arm*) TARCH=arm;; hppa*) TARCH=hppa;; ia64*) TARCH=ia64;; 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 # this is a linux+ target, not microcontroller (below) avr32*) :;; avr*) KPKG="[none]"; LCAT="dev-embedded"; LPKG="avr-libc"; GUSE="-fortran" # doesn't work MULTILIB_USE="yes" #377039 WITH_DEF_HEADERS="no";; # due to upstream lameness, build C/C++ at first glance *-cygwin) GUSE_DISABLE_STAGE_1+=" -nocxx cxx";; # these are the mingw64 targets that binutils seems to use x86_64-*-mingw*|*-w64-mingw*) KPKG="[none]"; LCAT="dev-util"; LPKG="mingw64-runtime";; mingw*|*-mingw*) KCAT="dev-util"; KPKG="w32api"; LCAT="dev-util"; LPKG="mingw-runtime";; msp430) KCAT="dev-embedded"; KPKG="msp430mcu"; BCAT="dev-embedded"; BPKG="msp430-binutils"; GCAT="dev-embedded"; GPKG="msp430-gcc"; LCAT="dev-embedded"; LPKG="msp430-libc"; DCAT="dev-embedded"; DPKG="msp430-gdb"; GUSE="-fortran -openmp"; MULTILIB_USE="yes" WITH_DEF_HEADERS="no";; 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_STAGE_1};; iop*) TARCH=mips; GVER="3.2.2"; BVER="2.14"; STAGE_DEFAULT=${STAGE_C_ONLY}; GUSE=${GUSE_DISABLE_STAGE_1};; 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|*-eabi) LPKG="newlib" KPKG="[none]" STAGE_DEFAULT=${STAGE_LIBC} MULTILIB_USE="yes" #407275 WITH_DEF_HEADERS="no" ;; # Now for the BSDs ... *-freebsd*) LCAT="sys-freebsd" LPKG="freebsd-lib" KPKG="[none]" ;; esac } setup_portage_vars() { local arch=${ARCH} arch_set=${ARCH+set} local chost=${CHOST} chost_set=${CHOST+set} unset arch chost eval $(portageq envvar -v PORTDIR_OVERLAY PORTDIR PORT_LOGDIR PORTAGE_TMPDIR ARCH CHOST) # keep the original values, but be aware of the native ones HARCH=${ARCH} [[ ${arch_set} == "set" ]] && ARCH=${arch} || unset ARCH HCHOST=${CHOST} [[ ${chost_set} == "set" ]] && CHOST=${chost} || unset CHOST # see if user gave us an overlay search list, otherwise # default to whatever is configured in portage : ${SEARCH_OVERLAYS:=${PORTDIR_OVERLAY}} # see if user told us where to write things, otherwise # install our stuff to the first overlay in the list : ${CROSSDEV_OVERLAY:=${SEARCH_OVERLAYS}} CROSSDEV_OVERLAY=${CROSSDEV_OVERLAY%% *} # make sure we have a valid logdir : ${PORT_LOGDIR:=/var/log/portage} mkdir -p "${PORT_LOGDIR}" } uninstall() { local d f setup_portage_vars ewarn "Uninstalling target '${CTARGET}' ..." # clean out portage config files [[ -d ${CROSSDEV_OVERLAY}/cross-${CTARGET} ]] \ && rm -r ${CROSSDEV_OVERLAY}/cross-${CTARGET} for f in categories package.{env,mask,keywords,use} profile/package.use.{force,mask} ; do f="${CONFIGROOT}/${f}" rm -f "${f}"/cross-${CTARGET} rmdir "${f}" 2>/dev/null done rm -rf "${CONFIGROOT}"/env/cross-${CTARGET} rmdir "${CONFIGROOT}"/env 2>/dev/null rm -f /etc/revdep-rebuild/05cross-${CTARGET} rmdir /etc/revdep-rebuild 2>/dev/null rmdir /var/db/pkg/cross-${CTARGET} 2>/dev/null if [[ -d /var/db/pkg/cross-${CTARGET} ]] ; then export CLEAN_DELAY=0 cd /var/db/pkg local pkgs=( cross-${CTARGET}/* ) emerge -qC ${pkgs[@]/#/=} || exit 1 else ewarn "${CTARGET}: no packages installed; will clean out known files" fi # clean out known toolchain files (binutils/gcc) for f in \ addr2line ar as c++filt dlltool dllwrap embedspu \ gprof ld nm objcopy objdump ranlib readelf \ size strings strip windmc windres do rm -f /usr/bin/${CTARGET}-${f} /usr/${CTARGET}/bin/${f} done rm -f /usr/${CTARGET}/{sys-include,usr} rmdir /usr/${CTARGET}/{include/asm,include} 2>/dev/null rm -f /usr/bin/${CTARGET}-{gcc,{c,g}++,cpp,gfortran,gcov} rm -f /etc/env.d/{binutils,gcc}/config-${CTARGET} # clean out files from crossdev itself [[ -e /var/db/pkg/cross-${CTARGET} ]] && rmdir /var/db/pkg/cross-${CTARGET} rm -f /usr/bin/${CTARGET}-{emerge,fix-root,pkg-config} /usr/bin/emerge-${CTARGET} for f in make.{conf,globals,profile} ; do f="/usr/${CTARGET}/etc/${f}" [[ -L ${f} ]] && rm -f ${f} f="/usr/${CTARGET}/etc/portage/${f##*/}" [[ -L ${f} ]] && rm -f ${f} done find /usr/share/crossdev/etc/ -type f | \ while read f ; do f1=${f} [[ ! -e ${f1} ]] && continue m1=$(set -- `md5sum ${f1}`; echo $1) f2=/usr/${CTARGET}${f#/usr/share/crossdev} [[ ! -e ${f2} ]] && continue m2=$(set -- `md5sum ${f2}`; echo $1) if [[ ${m1} == ${m2} ]] ; then rm -f ${f2} fi done # clean out the sysroot, prompting the user if need be for d in /usr/lib/gcc{,-lib}/${CTARGET} /usr/${CTARGET} ; do if [[ ! -d ${d} ]] ; then rm -f "${d}" else if [[ ${FORCE} == "no" ]] ; then find "${d}" -type d -depth -exec rmdir {} + 2>/dev/null && continue printf "${d}: directory still exists; remove recursively? [y/N] " local ans read ans [[ ${ans} == [Yy]* ]] && rm -rf "${d}" else rm -rf "${d}" fi fi done } 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" ]] ; } 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}}" } ver_get_op() { local op ver=$1 [[ ${ver} == "["* ]] && return op=${ver%%[0-9]*} [[ -n ${op} ]] && echo "${op}" } ver_chop_op() { local op ver=$1 op=$(ver_get_op "${ver}") echo "${ver##${op}}" } pretty_atom() { local mid=$1 ver=$2 printf '%s%s%s' "$(ver_get_op "${ver}")" "${mid}" "$(ver_chop_op "${ver}")" } ################## ### setup vars ### CROSSDEV=$0 EOPTS= UOPTS= TARCH= HARCH= CTARGET= MULTILIB_ABIS="default" MULTILIB_USE="" HOST_ABI="default" STAGE="" AENV="" BCAT="sys-devel" ; BPKG="binutils" ; BVER="" BUSE="" BENV="" BOVL="" GCAT="sys-devel" ; GPKG="gcc" ; GVER="" GUSE="" GENV="" GOVL="" KCAT="sys-kernel" ; KPKG="linux-headers" ; KVER="" KUSE="" KENV="" KOVL="" LCAT="sys-libs" ; LPKG="[none]" ; LVER="" LUSE="" LENV="" LOVL="" DCAT="sys-devel" ; DPKG="gdb" ; DVER="" DUSE="" DENV="" DOVL="" DEFAULT_VER="[latest]" SEARCH_OVERLAYS="" CROSSDEV_OVERLAY="" # These flags are always disabled for cross-gcc; either usually/always broken, or # not tested, or doesn't make sense, or no one simply cares about them GUSE_DISABLE="-boundschecking -d -gtk -gcj -libffi -mudflap -objc -objc++ -objc-gc" # These are disabled only for stage1 gcc GUSE_DISABLE_STAGE_1="${GUSE_DISABLE} -fortran nocxx -cxx -openmp" GUSE_DISABLE_STAGE_2="${GUSE_DISABLE}" 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" FORCE="no" SET_X="no" ACTION="install" SHOW_FAIL_LOG="no" SHOW_TARGET_CFG="no" INIT_TARGET_ONLY="no" while [[ $# -gt 0 ]] ; do case $1 in -V|--version) echo "crossdev-${CROSSDEV_VER}"; exit 0;; -t|--target) shift; parse_target $1;; --b|--binutils) shift; BVER=$1;; --benv) shift; BENV=$1;; -ob|--ov-binutils) shift; BOVL=$1;; --d|--gdb) shift; DVER=$1;; --denv) shift; DENV=$1;; -od|--ov-gdb) shift; DOVL=$1;; --g|--gcc) shift; GVER=$1;; --genv) shift; GENV=$1;; -og|--ov-gcc) shift; GOVL=$1;; --k|--kernel) shift; KVER=$1;; --kenv) shift; KENV=$1;; -ok|--ov-kernel) shift; KOVL=$1;; --l|--libc) shift; LVER=$1;; --lenv) shift; LENV=$1;; -ol|--ov-libc) shift; LOVL=$1;; --env) shift; AENV=$1;; -A|--abis) shift; MULTILIB_ABIS=$1;; --host-abi) shift; HOST_ABI=$1;; -S|--stable) DEFAULT_VER="[stable]";; -C|--clean) shift; parse_target $1; ACTION="uninstall";; -s?|--stage?) STAGE=${1:0-1};; -oS|--overlays) shift; SEARCH_OVERLAYS=$1;; -oO|--ov-output) shift; CROSSDEV_OVERLAY=$1;; --ex-only) EX_FAST="yes";; --ex-gcc) EX_GCC="yes";; --ex-gdb) EX_GDB="yes";; --with-*) eval $(set_withval $1);; --without-*) eval $(set_withval $1);; -f|--force) FORCE="yes";; -x) SET_X="yes";; --show-target-cfg) SHOW_TARGET_CFG="yes";; --init-target) INIT_TARGET_ONLY="yes";; --show-fail-log) SHOW_FAIL_LOG="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 case ${ACTION} in uninstall) uninstall; exit 0;; esac 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 show_target_cfg() { local pkgs crosspkgs=() pkgs=( binutils B gcc G kernel K libc L ) ex_gdb && pkgs+=( gdb D ) echo "arch=${TARCH}" echo "target=${CTARGET}" echo "category=cross-${CTARGET}" while [[ ${#pkgs[@]} -gt 0 ]] ; do local pkg=${pkgs[0]} local v=${pkgs[1]} local vcat="${v}CAT" local vpkg="${v}PKG" local ocat="${pkg}_category" local opkg="${pkg}_pn" if [[ ${!vpkg} != "[none]" ]] ; then echo "${ocat}=${!vcat}" echo "${opkg}=${!vpkg}" else printf '%s=\n' "${ocat}" "${opkg}" fi crosspkgs+=( ${pkg} ) pkgs=( ${pkgs[@]:2} ) done echo "crosspkgs='${crosspkgs[*]}'" exit 0 } [[ ${SHOW_TARGET_CFG} == "yes" ]] && show_target_cfg setup_portage_vars if [[ -z ${CROSSDEV_OVERLAY} ]] ; then eerror "You need to specify an output overlay. Please use --ov-output or set" eerror "PORTDIR_OVERLAY in your make.conf. A standard setting is: /usr/local/portage" exit 1 fi if [[ ${HCHOST} == "${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 MULTILIB_ABIS UCLIBC_CPU USE BVER GVER KVER LVER STAGE CFLAGS LDFLAGS ASFLAGS ; do d="${CONFIGROOT}/crossdev/${CTARGET}" if [[ -e ${d}/${v} ]] ; then # yes, quotes are needed in this instance (export $var="...") export ${v}="$(<"${d}"/${v})" einfo "Restoring user setting '${v}' to '${!v}'" fi if [[ -e ${d}/env ]] ; then einfo "Restoring generic user env settings" source "${d}"/env fi done # parse multilib settings until profiles are sane multilib_env() { local var=$1 eval $( # see what target to parse CTARGET=${!var} # clean the env in our subshell unset ${!CFLAGS_*} ${!CHOST_*} ${!CTARGET_*} ${!LDFLAGS_*} ${!LIBDIR_*} # ask multilib.eclass to tell us how things work inherit() { :; } for p in ${SEARCH_OVERLAYS} ${PORTDIR} ; do p+="/eclass/multilib.eclass" if [[ -e ${p} ]] ; then . "${p}" break fi done unset DEFAULT_ABI if [[ ${MULTILIB_ABIS} == "default" ]] ; then unset MULTILIB_ABIS single_abi=true else single_abi=false fi multilib_env ${single_abi} && MULTILIB_ABIS=${DEFAULT_ABI} # output the desired env for v in ${!CFLAGS_*} ${!CHOST_*} ${!CTARGET_*} ${!LDFLAGS_*} ${!LIBDIR_*} ; do echo ${v}=\'${!v}\' done # output the variables that are not uniquely named [[ ${var} == "CTARGET" ]] && d='' || d='_' for v in MULTILIB_ABIS DEFAULT_ABI ; do echo ${d}${v}=\'${!v}\' done # make sure all ABIs have valid vars def_CFLAGS= def_LIBDIR="lib" def_LDFLAGS= for v in CFLAGS LIBDIR LDFLAGS ; do d="def_${v}" for a in ${MULTILIB_ABIS} ; do _v="${v}_${a}" [[ ${!_v+set} == "set" ]] && continue echo ${_v}=\'${!d}\' done done ) } # Load settings for the host. MULTILIB_ABIS=${HOST_ABI} multilib_env HCHOST HOST_ABI=${_MULTILIB_ABIS} # Load settings for the target. multilib_env CTARGET DEFAULT_ABI=${MULTILIB_ABIS%% *} if [[ -z ${MULTILIB_USE} ]] ; then if [[ $(set -- ${MULTILIB_ABIS}; echo $#) -eq 1 ]] ; then MULTILIB_USE="no" else MULTILIB_USE="yes" fi fi ##################### ### do the emerge ### info() { hr - einfo "crossdev version: ${CROSSDEV_VER}" einfo "Host Portage ARCH: ${HARCH}" einfo "Target Portage ARCH: ${TARCH}" einfo "Target System: ${CTARGET}" einfo "Stage: ${STAGE} (${STAGE_DISP[${STAGE}]})" [[ ${DEFAULT_ABI} != "${MULTILIB_ABIS}" ]] && def_out=" (default: ${DEFAULT_ABI})" || def_out= einfo "ABIs: ${MULTILIB_ABIS}${def_out}" echo ex_fast || { is_s0 && { einfo "binutils: `pretty_atom ${BPKG}- ${BVER}`" } is_s1 && { einfo "gcc: `pretty_atom ${GPKG}- ${GVER}`" } is_s2 && { [[ ${KPKG} != "[none]" ]] && \ einfo "headers: `pretty_atom ${KPKG}- ${KVER}`" } is_s3 && { einfo "libc: `pretty_atom ${LPKG}- ${LVER}`" } } ex_gcc && { einfo "Extra: gcc pass: DO IT" } ex_gdb && { einfo "Extra: gdb: DO IT" } echo einfo "CROSSDEV_OVERLAY: ${CROSSDEV_OVERLAY}" einfo "PORT_LOGDIR: ${PORT_LOGDIR}" einfo "PORTAGE_CONFIGROOT: ${PORTAGE_CONFIGROOT}" einfo "Portage flags: ${UOPTS}" hr } # avoid pipe since `einfo` will not use color :( info if [[ ${INIT_TARGET_ONLY} != "yes" ]] ; then ( info emerge -v --info ) >& "${PORT_LOGDIR}"/cross-${CTARGET}-info.log || exit 1 fi #################################### ### Fix up portage files / paths ### check_trailing_newline() { #267132 [[ -e $1 ]] || return 0 if [[ `tail -c 1 "$1" | wc -l` == *0* ]] ; then ewarn "Autofixing mangled file: $1" echo >> "$1" fi } _set_portage_file() { local pkg=$1 output=$2 [[ ! -f ${output} ]] && output+="/cross-${CTARGET}" [[ -e ${output} ]] && sed -i -e "/^cross-${CTARGET}\/${pkg}/d" ${output} check_trailing_newline ${output} echo ${output} } set_keywords() { local pkg=$1 ver=$2 output [[ -z ${pkg} ]] && return 0 output=$(_set_portage_file ${pkg} package.keywords) 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 local op=$(ver_get_op "${ver}") if [[ -n ${op} ]] ; then # user has been explicit in the version they desire ver=$(ver_chop_op "${ver}") echo "cross-${CTARGET}/${pkg} -*" >> ${output} echo "${op}cross-${CTARGET}/${pkg}-${ver} * ~* **" >> ${output} else echo "cross-${CTARGET}/${pkg} * ~* **" >> ${output} output=$(_set_portage_file ${pkg} package.mask) echo ">cross-${CTARGET}/${pkg}-${ver}" >> ${output} fi fi } set_use() { local pkg=$1 output use=${@:2} [[ -z ${use} ]] && return 0 output=$(_set_portage_file ${pkg} package.use) echo "cross-${CTARGET}/${pkg} ${use}" >> ${output} } set_use_force() { local pkg=$1 output use=${@:2} [[ -z ${use} ]] && return 0 output=$(_set_portage_file ${pkg} profile/package.use.force) echo "cross-${CTARGET}/${pkg} ${use}" >> ${output} } set_use_mask() { local pkg=$1 output use=${@:2} [[ -z ${use} ]] && return 0 output=$(_set_portage_file ${pkg} profile/package.use.mask) echo "cross-${CTARGET}/${pkg} ${use}" >> ${output} } set_links() { local cat=$1 pkg=$2 ovl=$3 local s srcdir=${PORTDIR} d d="${CROSSDEV_OVERLAY}"/cross-${CTARGET}/${pkg} # if auto searching and something is already set, leave it be if [[ -z ${ovl} ]] && [[ -e ${d} ]] ; then #211386 #347389 einfo "leaving ${cat}/${pkg} in ${CROSSDEV_OVERLAY}" return fi rm -f "${d}" if [[ -e ${d} ]] ; then eerror "${d} still exists and isn't a symlink !?" exit 1 fi for s in ${ovl} ${SEARCH_OVERLAYS} ; do if [[ -d ${s}/${cat}/${pkg} ]] ; then srcdir=${s} einfo "getting ${cat}/${pkg} from ${srcdir}" break fi done ln -s "${srcdir}"/${cat}/${pkg} "${d}" } set_env() { local l=$1 pkg=$2 env=$3 output shift ; shift # We have to ignore collisions in the build-id tree because it's # easy to create a cross-program that is the same. For example, # if we try to build gdb for both arm-eabi and cross-arm-linux-gnueabi, # then these gdb's might have the same build-id and try to install # into the same paths. Ignoring the collisions isn't great since # updating one can drop the symlink for another, but for now, it's # the best we've got without implementing reference counting on # installed paths in the PM. output="env/cross-${CTARGET}/${pkg}.conf" cat <<-EOF > "${output}" SYMLINK_LIB=no COLLISION_IGNORE="\${COLLISION_IGNORE} /usr/lib/debug/.build-id" $(printf '%b' "${env}") $(printf '%b' "${AENV}") EOF # We need to differentiate between the host and target ABI just like # we have to handle the difference between CHOST and CTARGET. For # the headers and library packages, we want the ABI to be the target. # For the compiler tools (as/ld/cc/gdb/etc...), we want the ABI to be # the host. local TARGET_ABI=$(set -- ${MULTILIB_ABIS}; echo $1) case ${l} in K|L) # Target packages. local ABI=${TARGET_ABI} # Use MULTILIB_ABIS & DEFAULT_ABI from env. ;; *) # Host packages. cat <<-EOF >> "${output}" TARGET_ABI='${TARGET_ABI}' TARGET_MULTILIB_ABIS='${MULTILIB_ABIS}' TARGET_DEFAULT_ABI='${DEFAULT_ABI}' EOF local ABI=${HOST_ABI} local MULTILIB_ABIS=${ABI} local DEFAULT_ABI=${ABI} ;; esac local v for v in ${!CFLAGS_*} ${!CHOST_*} ${!CTARGET_*} ${!LDFLAGS_*} ${!LIBDIR_*} ABI MULTILIB_ABIS DEFAULT_ABI ; do echo "${v}='${!v}'" done >> "${output}" output=$(_set_portage_file ${pkg} package.env) echo "cross-${CTARGET}/${pkg} cross-${CTARGET}/${pkg}.conf" >> ${output} } set_portage() { local l=$1 eval set -- \${${l}CAT} \${${l}PKG} \"\${${l}VER}\" \"\${${l}ENV}\" \"\${${l}OVL}\" local cat=$1 pkg=$2 ver=$3 env=$4 ovl=$5 shift 5 local use=$* [[ ${pkg} == "[none]" ]] && return 0 set_keywords ${pkg} ${ver} set_use ${pkg} ${use} set_use_force ${pkg} -multilib set_use_mask ${pkg} -multilib set_links ${cat} ${pkg} "${ovl}" set_env ${l} ${pkg} "${env}" } set_metadata() { # for people who have eclasses spread over their overlays, generate # a layout.conf file so portage can find them. this is a crapshoot # when diff overlay sources have conflicting eclasses, but nothing # we really can do about that. local autogen_tag="# Autogenerated and managed by crossdev" local meta=${CROSSDEV_OVERLAY}/metadata local layout=${meta}/layout.conf local d name masters thin_manifests="false" mkdir -p "${meta}" if [[ -e ${layout} ]] ; then if ! grep -qs "^${autogen_tag}" "${layout}" ; then einfo "leaving metadata/layout.conf alone in ${CROSSDEV_OVERLAY}" return fi # We are managing it, so blow it away rm -f "${layout}" fi # build up a list of possible repos where we can pull from for d in "${BOVL}" "${GOVL}" "${KOVL}" "${LOVL}" ${SEARCH_OVERLAYS} "${PORTDIR}" ; do [[ -z ${d} ]] && continue name= if [[ -e ${d}/profiles/repo_name ]] ; then name=$(<"${d}"/profiles/repo_name) fi [[ -z ${name} ]] && continue # If this repo has an eclass dir, mark it as a master. # Note: portage reads the masters list in reverse order, # so we have to prepare it the same way. if [[ -d ${d}/eclass ]] ; then has ${name} ${masters} || masters="${name} ${masters}" fi # If one of the overlays uses thin manifests, then turn it on if [[ -z ${this_manifests} ]] && has ${name} ${masters} && \ sed \ -e 's:#.*::' \ -e 's:^[[:space:]]*::' \ -e 's:[[:space:]]*$::' \ -e 's:[[:space:]]*=[[:space:]]*:=:' \ "${d}/metadata/layout.conf" 2>/dev/null | \ gawk -F= '{ if ($1 == "use-manifests") um = $2 if ($1 == "thin-manifests") tm = $2 } END { exit !(um != "false" && tm == "true") }' then einfo "enabling thin-manifests due to ${d}" this_manifests="use-manifests = true\nthin-manifests = true" fi done # write out that layout.conf! cat <<-EOF > "${layout}" ${autogen_tag} # Delete the above line if you want to manage this file yourself masters = ${masters% } $(printf '%b' "${this_manifests}") EOF } mkdir -p "${CONFIGROOT}" check_trailing_newline "${CONFIGROOT}"/categories grep -qs "^cross-${CTARGET}$" "${CONFIGROOT}"/categories \ || echo cross-${CTARGET} >> "${CONFIGROOT}"/categories mkdir -p "${CROSSDEV_OVERLAY}"/cross-${CTARGET} || exit 1 cd "${CONFIGROOT}" for f in package.{env,keywords,mask,use} env/cross-${CTARGET} profile/package.use.{force,mask} ; do [[ -f ${f} ]] && die "please convert ${CONFIGROOT}/${f} to a directory" mkdir -p ${f} || die "wtf!?" rm -f ${f}/cross-${CTARGET} done for v in B G K L D ; do set_portage ${v} done set_metadata # filter out revdep rebuild stuff #182601 mkdir -p /etc/revdep-rebuild echo "SEARCH_DIRS_MASK=/usr/${CTARGET}" > /etc/revdep-rebuild/05cross-${CTARGET} hr ####################################### ### Create links for helper scripts ### mkdir -p /usr/${CTARGET} emerge-wrapper --target ${CTARGET} --init || exit 1 ################# 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() { local category="cross-${CTARGET}" local pn=$1 local atom="${category}/${pn}" [[ ${pn} == "[none]" ]] && return 0 set_use ${pn} ${USE} $( [[ ${MULTILIB_USE} == "no" ]] && echo - )multilib [[ ${INIT_TARGET_ONLY} == "yes" ]] && return 0 local logfile=${PORT_LOGDIR}/${category} [[ -z $2 ]] \ && logfile=${logfile}-${pn}.log \ || logfile=${logfile}-$2.log einfo "Log: ${logfile}" ebegin "Emerging cross-${2:-${pn}}" if has -v ${UOPTS} || has -p ${UOPTS} || has -vp ${UOPTS} || has -pv ${UOPTS} ; then SHOW_FAIL_LOG="no" emerge ${atom} ${EOPTS} 2>&1 | tee "${logfile}" else emerge ${atom} ${EOPTS} >& "${logfile}" fi local _pipestatus=${PIPESTATUS[*]} if [[ "${_pipestatus// /}" -ne 0 ]] ; then [[ ${SHOW_FAIL_LOG} == "yes" ]] && cat "${logfile}" local d for d in "${PORTAGE_TMPDIR}"/portage/${atom}*/work/ ; do [[ -d ${d} ]] || continue pushd "${d}" >/dev/null mkdir -p ../temp # sanity! find -name config.log | \ tar cf - --files-from=- | \ xz > ../temp/${pn}-config.logs.tar.xz popd "${d}" >/dev/null done xz -zkf "${logfile}" die_logs "${pn} failed :(" \ "${logfile}.xz" \ "${PORTAGE_TMPDIR}/portage/${atom}*/temp/${pn}-config.logs.tar.xz" fi eend 0 } # Make this "just work" rather than worrying about user not putting # this overlay path into their system settings already. if [[ -n ${CROSSDEV_OVERLAY} ]] ; then export PORTDIR_OVERLAY="${CROSSDEV_OVERLAY} ${PORTDIR_OVERLAY}" fi # We include the '-u' so that we don't re-emerge packages. Avoid # using --nodeps as packages have more host depends nowadays (like # gcc wanting updated mpfr/gmp). Don't use --oneshot anymore to # follow normal emerge behavior; people can pass the -1 to portage # themselves if they want that. EOPTS_DEF="${UOPTS}" EOPTS_UP="${EOPTS_DEF} -u" EOPTS=${EOPTS_UP} # keep things like --ask from screwing us up export EMERGE_DEFAULT_OPTS="--quiet-build=n" # screw random strictness in cross-compilers export FEATURES="${FEATURES} -stricter" # maybe someday this work, but that day != today USE="${USE} -selinux" # only allow UCLIBC_CPU from env, not from make.conf/profile export UCLIBC_CPU=${UCLIBC_CPU} if ! ex_fast ; then # stage 0: binutils doemerge ${BPKG} # stage1: bare C compiler if is_s1 ; then # first install headers if requested if with_headers ; then # install kernel headers (since the C library often uses them) USE="${KUSE} ${USE}" \ CROSSCOMPILE_OPTS="headers-only" \ doemerge ${KPKG} ${KPKG}-quick if [[ -n ${LPKG} ]] ; then # install C library headers # we have to use --nodeps as glibc itself might have # a dependency on newer gcc versions that we don't # care about at this point -- we aren't compiling yet USE="${LUSE} ${USE}" \ CROSSCOMPILE_OPTS="headers-only" \ EOPTS="${EOPTS} --nodeps" \ doemerge ${LPKG} ${LPKG}-headers fi fi # then finally get around to the C compiler USE="${GUSE} ${USE} ${GUSE_DISABLE_STAGE_1}" \ CROSSCOMPILE_OPTS="bootstrap" \ doemerge ${GPKG} ${GPKG}-stage1 fi # stage2: kernel headers if is_s2 ; then set_eopts_on_pkg_status ${KPKG} crosscompile_opts_headers-only USE="${KUSE} ${USE}" \ CROSSCOMPILE_OPTS="" \ doemerge ${KPKG} fi # stage3: full C library (headers/libs/etc...) if is_s3 ; then [[ -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} fi # stage4: full compiler (C/C++/etc...) if is_s4 ; then set_eopts_on_pkg_status ${GPKG} crosscompile_opts_bootstrap EOPTS="${EOPTS_UP} --newuse" USE="${GUSE} ${USE} ${GUSE_DISABLE_STAGE_2}" \ doemerge ${GPKG} ${GPKG}-stage2 fi fi # all the extra things (like debuggers) EOPTS="${EOPTS_UP} --newuse" ex_gcc && USE="${GUSE} ${USE}" doemerge ${GPKG} ${GPKG}-extra ex_gdb && USE="${DUSE} ${USE}" doemerge ${DPKG} exit 0