diff --git a/recipes/rust/rust.inc b/recipes/rust/rust.inc index fa6c44d..dd2e346 100644 --- a/recipes/rust/rust.inc +++ b/recipes/rust/rust.inc @@ -11,7 +11,132 @@ LIC_FILES_CHKSUM ="\ file://COPYRIGHT;md5=0e8e4a3b5d8e1c90eb243d406369763a \ " -def rust_triple(arch, vendor, os, d): +export RUST_TARGET_PATH="${WORKDIR}/targets/" + +## arm-unknown-linux-gnueabihf +DATA_LAYOUT[arm] = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:64:128-a0:0:64-n32" +LLVM_TARGET[arm] = "arm-unknown-linux-gnueabihf" +TARGET_ENDIAN[arm] = "little" +TARGET_WORD_SIZE[arm] = "32" +FEATURES[arm] = "+v6,+vfp2" +PRE_LINK_ARGS[arm] = "-Wl,--as-needed" + +## x86_64-unknown-linux-gnu +DATA_LAYOUT[x86_64] = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" +LLVM_TARGET[x86_64] = "x86_64-unknown-linux-gnu" +TARGET_ENDIAN[x86_64] = "little" +TARGET_WORD_SIZE[x86_64] = "64" +PRE_LINK_ARGS[x86_64] = "-m64 -Wl,--as-needed" + +def ldflags_for(d, thing): + cc_arch = d.getVar('{}_CC_ARCH'.format(thing), True) or "" + tc = d.getVar('TOOLCHAIN_OPTIONS', True) or "" + ldflags = d.getVar('{}_LDFLAGS'.format(thing), True) or "" + return tc.split() + ldflags.split() + cc_arch.split() + +def arch_for(d, thing): + return d.getVar('{}_ARCH'.format(thing), True) + +def sys_for(d, thing): + return d.getVar('{}_SYS'.format(thing), True) + +def prefix_for(d, thing): + return d.getVar('{}_PREFIX'.format(thing), True) + +## FIXME: TOOLCHAIN_OPTIONS is set to "" by native.bbclass and cross.bbclass, +## which prevents us from grabbing them when building a cross compiler (native doesn't matter). +def cflags_for(d, thing): + cc_arch = d.getVar('{}_CC_ARCH'.format(thing), True) or "" + flags = d.getVar('{}_CFLAGS'.format(thing), True) or "" + tc = d.getVar('TOOLCHAIN_OPTIONS', True) or "" + return ' '.join([cc_arch, flags, tc]) + +def cxxflags_for(d, thing): + cc_arch = d.getVar('{}_CC_ARCH'.format(thing), True) or "" + flags = d.getVar('{}_CXXFLAGS'.format(thing), True) or "" + tc = d.getVar('TOOLCHAIN_OPTIONS', True) or "" + return ' '.join([cc_arch, flags, tc]) + +def as_json(list_): + a = '[' + for e in list_: + if type(e) == str: + a += '"{}",'.format(e) + else: + raise Exception + if len(e): + a = a[:-1] + a += ']' + return a + +def rust_gen_target(d, thing, wd): + arch = arch_for(d, thing) + ldflags = ldflags_for(d, thing) + sys = sys_for(d, thing) + prefix = prefix_for(d, thing) + o = open(wd + sys + '.json', 'w') + + data_layout = d.getVarFlag('DATA_LAYOUT', arch, True) + llvm_target = d.getVarFlag('LLVM_TARGET', arch, True) + target_word_size = d.getVarFlag('TARGET_WORD_SIZE', arch, True) + prefix = d.getVar('{}_PREFIX'.format(thing), True) + ccache = d.getVar('CCACHE', True) + linker = "{}{}gcc".format(ccache, prefix) + features = d.getVarFlag('FEATURES', arch, True) or "" + + pre_link_args = (d.getVarFlag('PRE_LINK_ARGS', arch, True) or "").split() + + o.write('''{{ + "data-layout": "{}", + "llvm-target": "{}", + "target-endian": "little", + "target-word-size": "{}", + "arch": "{}", + "os": "linux", + "linker": "{}", + "features": "{}", + "dynamic-linking": true, + "executables": true, + "morestack": true, + "linker-is-gnu": true, + "has-rpath": true, + "position-independent-executables": true, + "pre-link-args": {} + }}'''.format( + data_layout, + llvm_target, + target_word_size, + arch, + linker, + features, + as_json(pre_link_args) + )) + o.close() + +python do_rust_gen_targets () { + import os + wd = d.getVar('WORKDIR', True) + '/targets/' + try: + os.makedirs(wd) + except OSError as e: + if e.errno != 17: + raise e + + for thing in ['HOST', 'BUILD', 'TARGET']: + rust_gen_target(d, thing, wd) +} +addtask do_rust_gen_targets after do_patch before do_compile + +def rust_base_triple(d, thing): + ''' + Mangle bitbake's *_SYS into something that rust might support (see + rust/mk/cfg/* for a list) + ''' + + arch = d.getVar('{}_ARCH'.format(thing), True) + vendor = d.getVar('{}_VENDOR'.format(thing), True) + os = d.getVar('{}_OS'.format(thing), True) + if arch.startswith("arm"): vendor = "-unknown" if os.endswith("gnueabi"): @@ -22,156 +147,56 @@ def rust_triple(arch, vendor, os, d): os = "linux-gnu" return arch + vendor + '-' + os -export RUST_TARGET_PATH="${WORKDIR}/targets/" +def rust_gen_mk_cfg(d, thing): + '''' + Rust's build system adds support for new archs via 2 things: + 1. a file in mk/cfg which defines how the runtime libraries are built + 2. and rustc arch definition either built into the compiler or supplied as a .json file -## arm-unknown-linux-gnueabihf -DATA_LAYOUT[arm] = "e-p:32:32:32\ - -i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\ - -f32:32:32-f64:64:64\ - -v64:64:64-v128:64:128\ - -a0:0:64-n32" -LLVM_TARGET[arm] = "arm-unknown-linux-gnueabihf" -TARGET_ENDIAN[arm] = "little" -TARGET_WORD_SIZE[arm] = "32" -FEATURES[arm] = "+v6,+vfp2" + This generates a new #1 for the given 'thing' (one of HOST, TARGET, BUILD) + using a "similar" config that rust already supplies as a template. -## x86_64-unknown-linux-gnu -DATA_LAYOUT[x86_64] = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-\ - f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-\ - s0:64:64-f80:128:128-n8:16:32:64-S128" -LLVM_TARGET[x86_64] = "x86_64-unknown-linux-gnu" -TARGET_ENDIAN[x86_64] = "little" -TARGET_WORD_SIZE[x86_64] = "64" -PRE_LINK_ARGS[x86_64] = "-m64" + Note that the configure process also depends on the existence of #1, so we + have to run this before do_configure + ''' -python rust_gen_targets () { + import shutil, subprocess + rust_base_sys = rust_base_triple(d, thing) + arch = arch_for(d, thing) + sys = sys_for(d, thing) + prefix = prefix_for(d, thing) + p = d.getVar('S', True) + '/mk/cfg/' + o = open(p + sys_for(d, thing), 'w') + + r = subprocess.call(['sed', + # update all triplets to the new one + '-e', 's/{}/{}/g'.format(rust_base_sys, sys), + + # Replace tools with our own (CROSS_PREFIX is appended to all tools + # by rust's build system) + '-e', 's/^CROSS_PREFIX_{}.*$/CROSS_PREFIX_{} := {}/'.format(sys, sys, prefix), + '-e', 's/^CC_{}=.*$/CC_{} := gcc/'.format(sys, sys), + '-e', 's/^CXX_{}.*$/CXX_{} := g++/'.format(sys, sys), + '-e', 's/^CPP_{}.*$/CPP_{} := gcc -E/'.format(sys, sys), + '-e', 's/^AR_{}.*$/AR_{} := ar/'.format(sys, sys), + + # Append our flags to the existing ones + '-e', '/^CFG_GCCISH_CFLAGS/ s;$; {};'.format(cflags_for(d, thing)), + '-e', '/^CFG_GCCISH_CXXFLAGS/ s;$; {};'.format(cxxflags_for(d, thing)), + '-e', '/^CFG_GCCISH_LINK_FLAGS/ s;$; {};'.format(" ".join(ldflags_for(d, thing))), + + p + rust_base_sys + ], stdout=o) + if r: + raise Exception + +python do_rust_arch_fixup () { + for thing in ['HOST', 'BUILD', 'TARGET']: + rust_gen_mk_cfg(d, thing) } - -# Generates a config file suitable for use as a compiler-and-runtime-build-time -# target specification (distinct from those target specifications used by -# `rustc --target`) -# -# Designed to operate where $1={host,target,build}, and creates targets for -# these using our triples in *_SYS. -rust_gen_mk_cfg () { - - deref() { - eval echo "\$$1" - } - - ARCH="$(deref $u_ARCH)" - - local u=`echo $1 | tr '[:lower:]' '[:upper:]'` - local sys=$(deref ${u}_SYS) - local rust_base_sys=$(deref RUST_BASE_${u}_SYS) - local p="${S}/mk/cfg/" - - if [ -z "$sys" ]; then - bbnote "Rust: no SYS for $u" - return - fi - if [ -z "$rust_base_sys" ]; then - bbfatal "Rust: no RUST_BUILD_SYS for $u (sys=$sys)" - fi - - if ! [ -e "$p$rust_base_sys" ]; then - bberror "Could not find RUST_BASE_${u}_SYS = ${rust_base_sys}" - bbfatal "file '$p/$rust_base_sys'" - fi - - # Use one of the existing configs as our base - cp -f "$p$rust_base_sys" "$p$sys" - - # FIXME: right now we assume our targets lack regex special characters - # and assumes flags lack regex special chars and ';' - - # 1. Fixup the target name for all variables - # 2. Blank CROSS_PREFIX (XXX: should we set it to "${CCACHE}${$u_PREFIX}" - # and adjust other vars as needed?) - # 3. Edit in our: - local bare_cc="$(deref ${u}_PREFIX)gcc" - local cc="${CCACHE}${bare_cc} $(deref ${u}_CC_ARCH)" - local cxx="${CCACHE}$(deref ${u}_PREFIX)g++ $(deref ${u}_CC_ARCH)" - local cpp="$(deref ${u}_PREFIX)gcc $(deref ${u}_CC_ARCH) -E" - local ar="$(deref ${u}_PREFIX)ar" - - # 4. Append our: - # FIXME: TOOLCHAIN_OPTIONS are only for TARGET (which is sometimes HOST) - local c_flags="$(deref ${u}_CC_ARCH)${TOOLCHAIN_OPTIONS} $(deref ${u}_CFLAGS)" - local cxx_flags="$(deref ${u}_CC_ARCH)${TOOLCHAIN_OPTIONS} $(deref ${u}_CXXFLAGS)" - local link_flags="${TOOLCHAIN_OPTIONS} $(deref ${u}_LD_ARCH)" - - sed -i \ - -e "s/${rust_base_sys}/$sys/g" \ - \ - -e "s/^CROSS_PREFIX_${sys}.*\$//" \ - -e "s/^CC_$sys=.\*\$/CC_$sys := ${cc}/" \ - -e "s/^CXX_$sys=.\*\$/CXX_$sys := ${cxx}/" \ - -e "s/^CPP_$sys=.\*\$/CPP_$sys := ${cpp}/" \ - -e "s/^AR_$sys=.\*\$/AR_$sys := ${ar}/" \ - \ - -e "/^CFG_GCCISH_CFLAGS/ s;\$; ${c_flags};" \ - -e "/^CFG_GCCISH_CXXFLAGS/ s;\$; ${cxx_flags};" \ - -e "/^CFG_GCCISH_LINK_FLAGS/ s;\$; ${link_flags};" \ - \ - "$p/$sys" - - local t="${WORKDIR}/targets/" - mkdir -p "$t" - - local link_flags_vec='[ "-fPIC" ]' - - cat >"$t$sys" <<-EOF - { - "data-layout": "$(deref DATA_LAYOUT__$ARCH)", - "llvm_target": "${sys}", - "target_endian": "little", - "target-word-size": "$(deref TARGET_WORD_SIZE__$ARCH)", - "arch": "$ARCH", - "os": "linux", - - "linker": "${bare_cc}", - "pre_link_args": ${link_flags_vec}, - # post_link_args - # cpu - "features": "$(deref FEATURES__$ARCH)", - "dynamic_linking": true, - "executables": true, - "morestack": true, - # relocation_model - # ... - # is_like_windows - "linker_is_gnu": true, - "has_rpath": true, - # no_compiler_rt - "position_independent_executables": true, - } - EOF -} - -do_rust_arch_fixup () { - RUST_BASE_TARGET_SYS="${@rust_triple('${TARGET_ARCH}','${TARGET_VENDOR}','${TARGET_OS}', d)}" - RUST_BASE_BUILD_SYS="${@rust_triple('${BUILD_ARCH}','${BUILD_VENDOR}','${BUILD_OS}', d)}" - RUST_BASE_HOST_SYS="${@rust_triple('${HOST_ARCH}','${HOST_VENDOR}','${HOST_OS}', d)}" - - # XXX: these are all hacks around having the variables be shell vars - # instead of bitbake vars. It probably makes sense to convert this - # entire mess into python so we don't have to do this. - HOST_SYS="${HOST_SYS}" - BUILD_SYS="${BUILD_SYS}" - TARGET_SYS="${TARGET_SYS}" - HOST_ARCH="${HOST_ARCH}" - BUILD_ARCH="${BUILD_ARCH}" - TARGET_ARCH="${TARGET_ARCH}" - - - rust_gen_mk_cfg host - rust_gen_mk_cfg build - rust_gen_mk_cfg target -} -addtask rust_arch_fixup before do_configure after do_patch +addtask do_rust_arch_fixup before do_configure after do_patch do_configure () { # FIXME: allow --enable-local-rust @@ -208,7 +233,7 @@ rust_runmake () { env # CFLAGS, LDFLAGS, CXXFLAGS, CPPFLAGS are used by rust's build for a - # wide range of targets (not just HOST). Yocto's settings for them will + # wide range of targets (not just TARGET). Yocto's settings for them will # be inappropriate, avoid using. unset CFLAGS unset LDFLAGS