#!/bin/bash # Copyright 1999-2015 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 CROSSDEV_VER="@CDEVPV@" cd / umask 0022 #159111 : ${ROOT:=/} if [[ ${ROOT} != "/" ]] ; then echo "Sorry, but crossdev does not support ROOT." 1>&2 exit 2 fi EPREFIX="@GENTOO_PORTAGE_EPREFIX@" if [[ ${EPREFIX} == "@"GENTOO_PORTAGE_EPREFIX"@" ]] ; then EPREFIX="" fi EROOT=${ROOT%/}"${EPREFIX}"/ : ${PORTAGE_CONFIGROOT:=${EROOT}} CONFIGROOT="${PORTAGE_CONFIGROOT}/etc/portage" source "${EPREFIX}"/lib/gentoo/functions.sh || exit 1 esyslog() { :; } die_logs() { echo eerror "error: $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 "* ]]; } xmkdir() { mkdir "$@" || die "could not mkdir $*"; } 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${NORMAL} 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: \`portageq repositories_configuration\`] ${GOOD}-oO, --ov-output${NORMAL} path Parent directory of overlay to write crossdev package links [default: uses repo with name 'crossdev', or 'cross-\${CTARGET}', or falls back to 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] ${GOOD}-ox, --ov-extra${NORMAL} path Overlay for extra packages [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 ${GOOD}--ex-pkg${NORMAL} pkg Build extra packages (may be used multiple times) ${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) - riscv32 / riscv64 - sparc / sparc64 - s390 / s390x - sh / sh[1-5] / sh64 - x86_64 (amd64) Supported C Libraries: - glibc (gnu) - klibc [prob wont work] - musl - 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/ - mingw64 http://mingw-w64.sourceforge.net/ - mmix http://www-cs-faculty.stanford.edu/~knuth/mmix.html - msp430 http://www.ti.com/msp430 - nds32 http://github.com/nds32 - nios2 http://www.altera.com/products/ip/processors/nios2/ni2-index.html - xc16x http://www.infineon.com/ - 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 # Handle aliases local aliases=() case ${CTARGET} in cell) aliases=( ppu spu-elf );; mingw64) aliases=( x86_64-w64-mingw32 );; esac if [[ ${#aliases[@]} -eq 1 ]] ; then CTARGET=${aliases[0]} elif [[ ${#aliases[@]} -gt 1 ]] ; then einfo "The '${CTARGET}' target is really an alias for the '${aliases}' target(s)" local alias for alias in ${aliases} ; do ${CROSSDEV} -t ${alias} || exit 1 done exit 0 fi # 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";; arm64*) CTARGET="aarch${CTARGET#arm}-unknown-linux-gnu";; armv[67]*) CTARGET="${CTARGET}-unknown-linux-gnueabihf";; arm*) CTARGET="${CTARGET}-unknown-linux-gnueabi";; aarch64*|alpha*|cris*|hppa*|ia64*|m68*|mips*|powerpc*|riscv*|sparc*|sh*|tile*) CTARGET="${CTARGET}-unknown-linux-gnu";; bfin*|h8300*|msp430*|nds32*|nios2*|spu*|xc16x*) CTARGET="${CTARGET}-elf";; esac fi # Figure out an acceptable portage ARCH for this target case ${CTARGET} in aarch64*) TARCH=arm64;; 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 -go" # doesn't work MULTILIB_USE="yes" #377039 BUSE+=" cxx" STAGE_DEFAULT=${STAGE_LIBC} WITH_DEF_HEADERS="no";; # Has no glibc support yet (or even ABI defined). Can # only compile linux kernel: # https://parisc.wiki.kernel.org/index.php/Userspace64 hppa64*) STAGE_DEFAULT=${STAGE_C_ONLY} WITH_DEF_HEADERS="no";; # added in bug #609602 mmix*) KPKG="[none]" LPKG="newlib" STAGE_DEFAULT=${STAGE_LIBC} 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" WITH_DEF_HEADERS="yes" # gcc can't boot without headers: bug #693770 ;; mingw*|*-mingw*) # bug #584858 die "'${CTARGET}' target is not supported anymore, use i686-w64-mingw32" ;; spu*) TARCH=ppc64; KPKG="[none]"; LPKG="newlib";; ppu*) TARCH=ppc64;; mips64*-gnuabin32|mipsisa64*-gnuabin32) [[ ${MULTILIB_ABIS} == "default" ]] && MULTILIB_ABIS="n32";; mips64*-gnuabi64|mipsisa64*-gnuabi64|\ mips64*-gnuabin64|mipsisa64*-gnuabin64) [[ ${MULTILIB_ABIS} == "default" ]] && MULTILIB_ABIS="n64";; mips64*-gnuabi32|mipsisa64*-gnuabi32|\ mips64*-gnuabio32|mipsisa64*-gnuabio32) [[ ${MULTILIB_ABIS} == "default" ]] && MULTILIB_ABIS="o32";; 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-ng";; *-uclinux) LPKG="uclibc-ng";; *-musl*) LPKG="musl";; # Windows targets *-cygwin) LCAT="dev-libs"; LPKG="cygwin"; KPKG="[none]"; ;; # Bare metal targets *-newlib|*-elf|*-eabi) LPKG="newlib" KPKG="[none]" STAGE_DEFAULT=${STAGE_LIBC} GUSE+=" cxx -openmp" #489798 GUSE+=" -fortran" #589672, needs syscalls GUSE+=" -hardened" #687598, needs -fstack-check=specific support MULTILIB_USE="yes" #407275 WITH_DEF_HEADERS="no" ;; # Now for the BSDs ... *-freebsd*) LCAT="sys-freebsd" LPKG="freebsd-lib" KPKG="[none]" ;; esac # Target-specific defaults (workarounds for upstream bugs). User # can override them by passing 'USE=foo crossdev ...'. Useful when # one wants to fix upstream bugs. local sanitizer_support=no # Whitelist asan on explicitly supported arches for linux. # Broken examples: # - musl libc # - bare metal targets # Untested examples: # - *BSD case ${CTARGET} in # glibc targets *-gnu*) case ${CTARGET} in mips64*|mipsisa64*) # has some support code, fails to build ;; x86_64*|i?86*|arm*|aarch64*|powerpc*) sanitizer_support=yes ;; esac ;; esac if [[ $sanitizer_support = "no" ]]; then GUSE+=" -sanitize" fi local vtv_support=no # Whitelist vtv on explicitly supported arches for linux. # Broken examples: # - musl libc # - bare metal targets # - powerpc # Untested examples: # - *BSD case ${CTARGET} in # glibc targets *-gnu*) case ${CTARGET} in x86_64*|i?86*|arm*|aarch64) vtv_support=yes ;; esac ;; esac if [[ $vtv_support = "no" ]]; then GUSE+=" -vtv" fi local pie_support=yes # Blacklist rare targets that: # 1. don't support -fPIC in compiler # 2. have -fPIE broken case ${CTARGET} in # [1.]: no -fPIC flag support: # check as '$CC -fPIC -c -x c - =gcc-6, nopie is =gcc-6, nossp is /dev/null done rm -rf "${CONFIGROOT}"/env/cross-${CTARGET} rmdir "${CONFIGROOT}"/env 2>/dev/null rm -f "${EPREFIX}"/etc/revdep-rebuild/05cross-${CTARGET} rmdir "${EPREFIX}"/etc/revdep-rebuild 2>/dev/null # Unmerge all toolchain packages for this target. qmerge -Uqy $(qlist -IC "cross-${CTARGET}/") # clean out known toolchain files (binutils/gcc) for f in \ addr2line ar as c++filt dlltool dllwrap dwp embedspu \ gcc-{ar,nm,ranlib} gccbug gcov-{dump,tool} gprof ld nm \ objcopy objdump ranlib readelf size strings strip windmc windres do rm -f "${EPREFIX}"/usr/bin/${CTARGET}-${f} done rm -f "${EPREFIX}"/usr/${CTARGET}/{sys-include,usr} rmdir "${EPREFIX}"/usr/${CTARGET}/{include/asm,include} 2>/dev/null rm -f "${EPREFIX}"/usr/bin/${CTARGET}-{gcc,{c,g}++,cpp,gfortran,gcov} rm -f "${EPREFIX}"/etc/env.d/{binutils,gcc}/config-${CTARGET} # clean out files from crossdev itself [[ -e ${EPREFIX}/var/db/pkg/cross-${CTARGET} ]] && rmdir "${EPREFIX}"/var/db/pkg/cross-${CTARGET} rm -f "${EPREFIX}"/usr/bin/${CTARGET}-{emerge,fix-root,pkg-config} "${EPREFIX}"/usr/bin/emerge-${CTARGET} for f in make.{conf,globals,profile} ; do f="${EPREFIX}/usr/${CTARGET}/etc/${f}" [[ -L ${f} ]] && rm -f ${f} f="${EPREFIX}/usr/${CTARGET}/etc/portage/${f##*/}" [[ -L ${f} ]] && rm -f ${f} done find "${EPREFIX}"/usr/share/crossdev/etc/ -type f | \ while read f ; do f1=${f} [[ ! -e ${f1} ]] && continue m1=$(set -- `md5sum ${f1}`; echo $1) f2=${EPREFIX}/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 "${EPREFIX}"/usr/lib/gcc{,-lib}/${CTARGET} "${EPREFIX}"/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" ]] ; } ex_pkgs() { [[ ${#XPKGS[@]} -gt 0 ]] ; } # For each extra package, call $@ with the X* vars set up properly. for_each_extra_pkg() { local pkg i for (( i = 0; i < ${#XPKGS[@]}; ++i )) ; do # Since the user gave us full atoms, pull them apart here. pkg=${XPKGS[i]} if [[ ${pkg} != */* ]]; then usage 1 "arguments to --ex-pkg must be CATEGORY/PN" fi XCAT=${pkg%/*} \ XPKG=${pkg#*/} \ XVER=${XVERS[i]} \ XUSE=${XUSES[i]} \ XENV=${XENVS[i]} \ XOVL=${XOVLS[i]} \ "$@" done } 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= HCHOST= HCHOSTS=() 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="" XPKGS=() XVERS=() XUSES=() XENVS=() XOVLS=() DEFAULT_VER="[latest]" SEARCH_OVERLAYS="" CROSSDEV_OVERLAY="" CROSSDEV_OVERLAY_NAME="" CROSSDEV_OVERLAY_CREATE_REPOS_CONF="" AUTOGEN_TAG="# Autogenerated and managed by crossdev" # 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 -gcj -gtk -libffi -mudflap -objc -objc++ -objc-gc" # These are disabled only for stage1 gcc. Normally need libc present. GUSE_DISABLE_STAGE_1="${GUSE_DISABLE} -fortran -go -jit -cxx -mpx -openmp -sanitize -vtv" GUSE_DISABLE_STAGE_2="${GUSE_DISABLE}" # Past history of WITH_DEF_HEADERS: # - ????-2005: "no" # - 2005-2019: "yes": #227065 gcc-4.3+ is a pita w/out headers # - 2019-????: "no" again: glibc does not really support headers install # at least on riscv-*: #686248 WITH_HEADERS="COW" WITH_DEF_HEADERS="no" 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;; -ox|--ov-extra) shift; XOVLS+=( "$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";; --ex-pkg) shift; XPKGS+=( "$1" );; --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";; --show-repo-cfg) show_repo_cfg "$2";; -P|--portage) UOPTS="${UOPTS} $2"; shift;; -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 ) if ex_pkgs ; then show_extra_pkg() { echo "ex_${XPKG}_category=${XCAT}" echo "ex_${XPKG}_pn=${XPKG}" crosspkgs+=( "ex_${XPKG}" ) } for_each_extra_pkg show_extra_pkg echo "extrapkgs='${crosspkgs[*]}'" fi 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 consult" eerror "https://wiki.gentoo.org/wiki/Custom_repository for more details." 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 for hchost in "${HCHOSTS[@]}"; do if [[ ${hchost} == "${CTARGET}" ]] ; then eerror "Refusing to create a cross-compiler using the same" eerror "target name as your host utils." eerror "Consider using sys-devel/multilib-gcc-wrapper package." exit 1 fi done # grab user settings d="${CONFIGROOT}/crossdev/${CTARGET}" for v in MULTILIB_ABIS USE BVER GVER KVER LVER STAGE CFLAGS LDFLAGS ASFLAGS ; do 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 done if [[ -e ${d}/env ]] ; then einfo "Restoring generic user env settings" source "${d}"/env fi # parse multilib settings until profiles are sane load_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} ${MAIN_REPO_PATH} ; 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 if ! multilib_env ; then echo "die 'could not load multilib settings for ${var}'" exit 1 fi ${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} load_multilib_env HCHOST HOST_ABI=${_MULTILIB_ABIS} # Load settings for the target. load_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 "Host Portage System: ${HCHOST} (${HCHOSTS[*]})" einfo "Target Portage ARCH: ${TARCH}" einfo "Target System: ${CTARGET}" einfo "Stage: ${STAGE} (${STAGE_DISP[${STAGE}]})" einfo "USE=multilib: ${MULTILIB_USE}" [[ ${DEFAULT_ABI} != "${MULTILIB_ABIS}" ]] && def_out=" (default: ${DEFAULT_ABI})" || def_out= einfo "Target 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" } ex_pkgs && { einfo "Extra: ${XPKGS[*]}" } 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.accept_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} if [[ ${ver} != "9999" ]] ; then # Disable live versions unless exactly requested. output=$(_set_portage_file ${pkg} package.mask) echo ">=cross-${CTARGET}/${pkg}-9999" >> ${output} fi 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=${MAIN_REPO_PATH} 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 case ${CTARGET} in # avr requires multilib, that provides # libgcc for all sub-architectures #378387 avr*) set_use_force ${pkg} multilib set_use_mask ${pkg} -multilib;; *-newlib|*-elf|*-eabi) set_use_force ${pkg} multilib; set_use_mask ${pkg} -multilib;; *) set_use_force ${pkg} -multilib;; esac set_keywords ${pkg} ${ver} set_use ${pkg} ${use} 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 meta=${CROSSDEV_OVERLAY}/metadata local repo_name local layout=${meta}/layout.conf local f d name masters thin_manifests="false" # See if this repo is already named. f="${CROSSDEV_OVERLAY}/profiles/repo_name" repo_name=$(cat "${f}" 2>/dev/null) : ${repo_name:="${CROSSDEV_OVERLAY_NAME}"} xmkdir -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} "${MAIN_REPO_PATH}" ; do [[ -z ${d} ]] && continue name= if [[ -e ${d}/metadata/layout.conf ]] ; then name=$(awk '$1 == "repo-name" { print $3 }' "${d}/metadata/layout.conf") fi if [[ -z ${name} && -e ${d}/profiles/repo_name ]] ; then name=$(<"${d}"/profiles/repo_name) fi [[ -z ${name} ]] && continue # Don't list ourselves as a master. [[ ${name} == "${repo_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}" || die "could not write ${layout}" ${AUTOGEN_TAG} # Delete the above line if you want to manage this file yourself masters = ${masters% } repo-name = ${repo_name} $(printf '%b' "${this_manifests}") EOF # If there is no repos.conf entry for the output overlay, create one here if [[ -n ${CROSSDEV_OVERLAY_CREATE_REPOS_CONF} ]]; then cat <<-EOF > "${CROSSDEV_OVERLAY_CREATE_REPOS_CONF}" || die "could not create the repo conf" ${AUTOGEN_TAG} [${repo_name}] location = ${CROSSDEV_OVERLAY} masters = ${masters% } auto-sync = no EOF fi } xmkdir -p "${CONFIGROOT}" "${CROSSDEV_OVERLAY}"/{cross-${CTARGET},profiles} for f in "${CONFIGROOT}" "${CROSSDEV_OVERLAY}"/profiles ; do f+="/categories" check_trailing_newline "${f}" grep -qs "^cross-${CTARGET}$" "${f}" \ || echo cross-${CTARGET} >> "${f}" done cd "${CONFIGROOT}" || die "wtf!?" for f in package.{accept_keywords,env,mask,use} env/cross-${CTARGET} profile/package.use.{force,mask} ; do [[ -f ${f} ]] && die "please convert ${CONFIGROOT}/${f} to a directory" xmkdir -p "${f}" rm -f "${f}/cross-${CTARGET}" done for v in B G K L D ; do set_portage ${v} done for_each_extra_pkg set_portage X set_metadata xmkdir -p "${EPREFIX}"/etc/revdep-rebuild cat > "${EPREFIX}"/etc/revdep-rebuild/05cross-${CTARGET} << EOF # Generated by crossdev-${CROSSDEV_VER} # Ignore ${CTARGET} root, https://bugs.gentoo.org/182601. SEARCH_DIRS_MASK="${EPREFIX}/usr/${CTARGET}" EOF hr ####################################### ### Create links for helper scripts ### xmkdir -p "${EPREFIX}"/usr/${CTARGET} emerge-wrapper --target ${CTARGET} --init || exit 1 ############################################################# ### Create directories usually created by sys-apps/baselayout ### ### Why we do that at all: ### For multilib-aware targets (ppc64, s390x, sparc64, x86_64) Gentoo ### normally uses libdir=lib64. ### For crossdev it means /lib and /usr/lib does not get created at all ### but gcc relies on their presence by refering to =/lib64 as ### =/usr/lib/../lib64 when builds itself (see https://bugs.gentoo.org/652724) ### ### Thus we create non-symlinked layout early. xmkdir -p "${EPREFIX}"/usr/${CTARGET}/lib xmkdir -p "${EPREFIX}"/usr/${CTARGET}/usr/lib ################# emerged_with_use() { local pkg=$1 use=$2 grep -qs ${use} "${EPREFIX}"/var/db/pkg/cross-${CTARGET}/${pkg}-*/USE } # Force package rebuild if any of passed USE-flag is set otherwise install package only if flag is missing. # $1 - pkg # $2... - USE flags to check set_eopts_on_pkg_status() { local pkg=$1 flag shift for flag in "$@"; do if emerged_with_use "${pkg}" "${flag}"; then # Force rebuild EOPTS=${EOPTS_DEF} return fi done # Install if missing 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 >/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 } # 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" if ! ex_fast ; then # stage 0: binutils USE="${BUSE}" 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} headers-only" \ 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} headers-only" \ 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="" \ doemerge ${GPKG} ${GPKG}-stage1 fi # stage2: kernel headers if is_s2 ; then set_eopts_on_pkg_status ${KPKG} crosscompile_opts_headers-only 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 headers-only USE="${LUSE} ${USE}" \ CROSSCOMPILE_OPTS="" \ doemerge ${LPKG} fi # stage4: full compiler (C/C++/etc...) if is_s4 ; then 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} if ex_pkgs ; then for pkg in "${XPKGS[@]}" ; do doemerge "${pkg#*/}" done fi exit 0