488 lines
17 KiB
PHP
488 lines
17 KiB
PHP
# ex: sts=4 et sw=4 ts=8
|
|
inherit rust
|
|
require rust-shared-source.inc
|
|
require rust-snapshot-2016-05-24.inc
|
|
|
|
LIC_FILES_CHKSUM ="file://COPYRIGHT;md5=43e1f1fb9c0ee3af66693d8c4fecafa8"
|
|
|
|
SUMMARY = "Rust compiler and runtime libaries"
|
|
HOMEPAGE = "http://www.rust-lang.org"
|
|
SECTION = "devel"
|
|
|
|
B = "${WORKDIR}/build"
|
|
|
|
DEPENDS += "file-native"
|
|
|
|
PACKAGECONFIG ??= ""
|
|
|
|
# Controls whether we use the local rust to build.
|
|
# By default, we use the rust-snapshot. In some cases (non-supported host
|
|
# systems) this may not be possible. In other cases, it might be desirable
|
|
# to have rust-cross built using rust-native.
|
|
PACKAGECONFIG[local-rust] = ""
|
|
|
|
FETCH_STAGE0 = "${@bb.utils.contains('PACKAGECONFIG', 'local-rust', 'false', 'true', d)}"
|
|
|
|
SRC_URI += "${@bb.utils.contains('PACKAGECONFIG', 'local-rust', '', '${RUST_SNAPSHOT_URI};unpack=0;name=rust-snapshot', d)}"
|
|
|
|
# We generate local targets, and need to be able to locate them
|
|
export RUST_TARGET_PATH="${WORKDIR}/targets/"
|
|
|
|
export FORCE_CRATE_HASH="${BB_TASKHASH}"
|
|
|
|
# Right now this is focused on arm-specific tune features.
|
|
# We get away with this for now as one can only use x86-64 as the build host
|
|
# (not arm).
|
|
# Note that TUNE_FEATURES is _always_ refering to the target, so we really
|
|
# don't want to use this for the host/build.
|
|
def llvm_features_from_tune(d):
|
|
f = []
|
|
feat = d.getVar('TUNE_FEATURES', True)
|
|
if not feat:
|
|
return ""
|
|
feat = frozenset(feat.split())
|
|
|
|
if 'vfpv4' in feat:
|
|
f.append("+vfp4")
|
|
if 'vfpv3' in feat:
|
|
f.append("+vfp3")
|
|
if 'vfpv3d16' in feat:
|
|
f.append("+d16")
|
|
|
|
if 'vfpv2' in feat or 'vfp' in feat:
|
|
f.append("+vfp2")
|
|
|
|
if 'neon' in feat:
|
|
f.append("+neon")
|
|
|
|
if 'aarch64' in feat:
|
|
f.append("+v8")
|
|
|
|
v7=frozenset(['armv7a', 'armv7r', 'armv7m', 'armv7ve'])
|
|
if not feat.isdisjoint(v7):
|
|
f.append("+v7")
|
|
if 'armv6' in feat:
|
|
f.append("+v6")
|
|
|
|
if 'dsp' in feat:
|
|
f.append("+dsp")
|
|
|
|
if d.getVar('ARM_THUMB_OPT', True) is "thumb":
|
|
if not feat.isdisjoint(v7):
|
|
f.append("+thumb2")
|
|
f.append("+thumb-mode")
|
|
|
|
if 'cortexa5' in feat:
|
|
f.append("+a5")
|
|
if 'cortexa7' in feat:
|
|
f.append("+a7")
|
|
if 'cortexa9' in feat:
|
|
f.append("+a9")
|
|
if 'cortexa15' in feat:
|
|
f.append("+a15")
|
|
if 'cortexa17' in feat:
|
|
f.append("+a17")
|
|
|
|
# Seems like it could be infered by the lack of vfp options, but we'll
|
|
# include it anyhow
|
|
if 'soft' in feat:
|
|
f.append("+soft-float")
|
|
|
|
return ','.join(f)
|
|
|
|
# TARGET_CC_ARCH changes from build/cross/target so it'll do the right thing
|
|
# this should go away when https://github.com/rust-lang/rust/pull/31709 is
|
|
# stable (1.9.0?)
|
|
def llvm_features_from_cc_arch(d):
|
|
f = []
|
|
feat = d.getVar('TARGET_CC_ARCH', True)
|
|
if not feat:
|
|
return ""
|
|
feat = frozenset(feat.split())
|
|
|
|
if '-mmmx' in feat:
|
|
f.append("+mmx")
|
|
if '-msse' in feat:
|
|
f.append("+sse")
|
|
if '-msse2' in feat:
|
|
f.append("+sse2")
|
|
if '-msse3' in feat:
|
|
f.append("+sse3")
|
|
if '-mssse3' in feat:
|
|
f.append("+ssse3")
|
|
if '-msse4.1' in feat:
|
|
f.append("+sse4.1")
|
|
if '-msse4.2' in feat:
|
|
f.append("+sse4.2")
|
|
if '-msse4a' in feat:
|
|
f.append("+sse4a")
|
|
if '-mavx' in feat:
|
|
f.append("+avx")
|
|
if '-mavx2' in feat:
|
|
f.append("+avx2")
|
|
|
|
return ','.join(f)
|
|
|
|
## 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] = "${RUST_TARGET_SYS}"
|
|
TARGET_ENDIAN[arm] = "little"
|
|
TARGET_POINTER_WIDTH[arm] = "32"
|
|
FEATURES[arm] = "+v6,+vfp2"
|
|
PRE_LINK_ARGS[arm] = "-Wl,--as-needed"
|
|
|
|
DATA_LAYOUT[aarch64] = "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-n32:64-S128"
|
|
LLVM_TARGET[aarch64] = "aarch64-unknown-linux-gnu"
|
|
TARGET_ENDIAN[aarch64] = "little"
|
|
TARGET_POINTER_WIDTH[aarch64] = "64"
|
|
PRE_LINK_ARGS[aarch64] = "-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_POINTER_WIDTH[x86_64] = "64"
|
|
PRE_LINK_ARGS[x86_64] = "-Wl,--as-needed -m64"
|
|
|
|
## i686-unknown-linux-gnu
|
|
DATA_LAYOUT[i686] = "e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32"
|
|
LLVM_TARGET[i686] = "i686-unknown-linux-gnu"
|
|
TARGET_ENDIAN[i686] = "little"
|
|
TARGET_POINTER_WIDTH[i686] = "32"
|
|
PRE_LINK_ARGS[i686] = "-Wl,--as-needed -m32"
|
|
|
|
## XXX: a bit of a hack so qemux86 builds, clone of i686-unknown-linux-gnu above
|
|
DATA_LAYOUT[i586] = "e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32"
|
|
LLVM_TARGET[i586] = "i586-unknown-linux-gnu"
|
|
TARGET_ENDIAN[i586] = "little"
|
|
TARGET_POINTER_WIDTH[i586] = "32"
|
|
PRE_LINK_ARGS[i586] = "-Wl,--as-needed -m32"
|
|
|
|
TARGET_PRE_LINK_ARGS = "${TARGET_CC_ARCH} ${TOOLCHAIN_OPTIONS}"
|
|
BUILD_PRE_LINK_ARGS = "${BUILD_CC_ARCH} ${TOOLCHAIN_OPTIONS}"
|
|
HOST_PRE_LINK_ARGS = "${HOST_CC_ARCH} ${TOOLCHAIN_OPTIONS}"
|
|
|
|
# These LDFLAGS have '-L' options in them. We need these to come last so they
|
|
# don't screw up the link order and pull in the wrong rust build/version.
|
|
# TODO: may want to strip out all the '-L' flags entirely here
|
|
TARGET_POST_LINK_ARGS = "${TARGET_LDFLAGS}"
|
|
BUILD_POST_LINK_ARGS = "${BUILD_LDFLAGS}"
|
|
HOST_POST_LINK_ARGS = "${HOST_LDFLAGS}"
|
|
|
|
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)
|
|
|
|
## Note: 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).
|
|
## We workaround this in internal-rust-cross.bbclass.
|
|
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])
|
|
|
|
# Convert a normal arch (HOST_ARCH, TARGET_ARCH, BUILD_ARCH, etc) to something
|
|
# rust's internals won't choke on.
|
|
def arch_to_rust_target_arch(arch):
|
|
if arch == "i586" or arch == "i686":
|
|
return "x86"
|
|
else:
|
|
return arch
|
|
|
|
# generates our target CPU value
|
|
def llvm_cpu(d):
|
|
cpu = d.getVar('TUNE_PKGARCH', True)
|
|
target = d.getVar('TRANSLATED_TARGET_ARCH', True)
|
|
|
|
trans = {}
|
|
trans['corei7-64'] = "corei7"
|
|
trans['core2-32'] = "core2"
|
|
trans['x86-64'] = "x86-64"
|
|
trans['i686'] = "i686"
|
|
trans['i586'] = "i586"
|
|
|
|
try:
|
|
return trans[cpu]
|
|
except:
|
|
return trans.get(target, "generic")
|
|
|
|
def post_link_args_for(d, thing, arch):
|
|
post_link_args = (d.getVar('{}_POST_LINK_ARGS'.format(thing), True) or "").split()
|
|
post_link_args.extend((d.getVarFlag('POST_LINK_ARGS', arch, True) or "").split())
|
|
return post_link_args
|
|
|
|
def pre_link_args_for(d, thing, arch):
|
|
ldflags = (d.getVar('{}_PRE_LINK_ARGS'.format(thing), True) or "").split()
|
|
ldflags.extend((d.getVarFlag('PRE_LINK_ARGS', arch, True) or "").split())
|
|
return ldflags
|
|
|
|
def ldflags_for(d, thing, arch):
|
|
a = pre_link_args_for(d, thing, arch)
|
|
a.extend(post_link_args_for(d, thing, arch))
|
|
return a
|
|
|
|
TARGET_LLVM_CPU="${@llvm_cpu(d)}"
|
|
TARGET_LLVM_FEATURES = "${@llvm_features_from_tune(d)} ${@llvm_features_from_cc_arch(d)}"
|
|
|
|
# class-native implies TARGET=HOST, and TUNE_FEATURES only describes the real
|
|
# (original) target.
|
|
TARGET_LLVM_FEATURES_class-native = "${@llvm_features_from_cc_arch(d)}"
|
|
|
|
def rust_gen_target(d, thing, wd):
|
|
import json
|
|
arch = arch_for(d, thing)
|
|
sys = sys_for(d, thing)
|
|
prefix = prefix_for(d, thing)
|
|
|
|
features = ""
|
|
cpu = "generic"
|
|
if thing is "TARGET":
|
|
features = d.getVar('TARGET_LLVM_FEATURES', True) or ""
|
|
cpu = d.getVar('TARGET_LLVM_CPU', True)
|
|
features = features or d.getVarFlag('FEATURES', arch, True) or ""
|
|
|
|
# build tspec
|
|
tspec = {}
|
|
tspec['llvm-target'] = d.getVarFlag('LLVM_TARGET', arch, True)
|
|
tspec['data-layout'] = d.getVarFlag('DATA_LAYOUT', arch, True)
|
|
tspec['target-pointer-width'] = d.getVarFlag('TARGET_POINTER_WIDTH', arch, True)
|
|
tspec['target-word-size'] = tspec['target-pointer-width']
|
|
tspec['target-endian'] = d.getVarFlag('TARGET_ENDIAN', arch, True)
|
|
tspec['arch'] = arch_to_rust_target_arch(arch)
|
|
tspec['os'] = "linux"
|
|
tspec['env'] = "gnu"
|
|
tspec['linker'] = "{}{}gcc".format(d.getVar('CCACHE', True), prefix)
|
|
tspec['objcopy'] = "{}objcopy".format(prefix)
|
|
tspec['ar'] = "{}ar".format(prefix)
|
|
tspec['cpu'] = cpu
|
|
if features is not "":
|
|
tspec['features'] = features
|
|
tspec['dynamic-linking'] = True
|
|
tspec['executables'] = True
|
|
tspec['morestack'] = True
|
|
tspec['linker-is-gnu'] = True
|
|
tspec['has-rpath'] = True
|
|
tspec['has-elf-tls'] = True
|
|
tspec['position-independent-executables'] = True
|
|
tspec['pre-link-args'] = pre_link_args_for(d, thing, arch)
|
|
tspec['post-link-args'] = post_link_args_for(d, thing, arch)
|
|
|
|
# write out the target spec json file
|
|
with open(wd + sys + '.json', 'w') as f:
|
|
json.dump(tspec, f)
|
|
|
|
|
|
python do_rust_gen_targets () {
|
|
wd = d.getVar('WORKDIR', True) + '/targets/'
|
|
# It is important 'TARGET' is last here so that it overrides our less
|
|
# informed choices for BUILD & HOST if TARGET happens to be the same as
|
|
# either of them.
|
|
for thing in ['BUILD', 'HOST', 'TARGET']:
|
|
bb.debug(1, "rust_gen_target for " + thing)
|
|
rust_gen_target(d, thing, wd)
|
|
}
|
|
addtask rust_gen_targets after do_patch before do_compile
|
|
do_rust_gen_targets[dirs] += "${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
|
|
|
|
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.
|
|
|
|
Note that the configure process also depends on the existence of #1, so we
|
|
have to run this before do_configure
|
|
'''
|
|
import subprocess
|
|
|
|
rust_base_sys = rust_base_triple(d, thing)
|
|
arch = arch_for(d, thing)
|
|
sys = sys_for(d, thing)
|
|
prefix = prefix_for(d, thing)
|
|
llvm_target = d.getVarFlag('LLVM_TARGET', arch, True)
|
|
ldflags = ' '.join(ldflags_for(d, thing, arch))
|
|
|
|
b = d.getVar('WORKDIR', True) + '/mk-cfg/'
|
|
o = open(b + sys_for(d, thing) + '.mk', 'w')
|
|
i = open(d.getVar('S', True) + '/mk/cfg/' + rust_base_sys + '.mk', 'r')
|
|
|
|
r = subprocess.call(['sed',
|
|
# 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
|
|
# be inappropriate, avoid having random targets try to use them, we'll
|
|
# add as needed.
|
|
'-e', 's/$(CFLAGS)//',
|
|
'-e', 's/$(CXXFLAGS)//',
|
|
'-e', 's/$(CPPFLAGS)//',
|
|
'-e', 's/$(LDFLAGS)//',
|
|
|
|
# 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). We delete and then insert this because not
|
|
# all targets define it.
|
|
'-e', 's/^CROSS_PREFIX_{}.*$//'.format(sys),
|
|
'-e', '2 a CROSS_PREFIX_{} := {}'.format(sys, prefix),
|
|
'-e', 's/^CFG_LLVM_TARGET_.*$//',
|
|
'-e', '2 a CFG_LLVM_TARGET_{} := {}'.format(sys, llvm_target),
|
|
'-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),
|
|
|
|
# Some targets don't have LINK even though it is required to build.
|
|
'-e', 's/^LINK_{}.*$//'.format(sys),
|
|
'-e', '2 a LINK_{} := gcc'.format(sys),
|
|
|
|
# Append our flags to the existing ones
|
|
'-e', '/^CFG_JEMALLOC_CFLAGS/ s;$; {};'.format(cflags_for(d, thing)),
|
|
'-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(ldflags),
|
|
|
|
# May need to add: CFG_LLC_FLAGS_{}
|
|
], stdout=o, stdin=i)
|
|
if r:
|
|
raise Exception
|
|
o.write("OBJCOPY_{} := {}objcopy\n".format(sys, prefix))
|
|
# Note: this isn't how this variable is supposed to be used, but for
|
|
# non-msvc platforms nothing else touches it.
|
|
# These are the only extra flags passed to the rustllvm (c++ code) build.
|
|
# These are only used for host (even though we emit them for all targets)
|
|
# Without this, there are link failures due to GLIBC_CXX11_ABI issues in
|
|
# certain setups.
|
|
o.write("EXTRA_RUSTLLVM_CXXFLAGS_{} := {}\n".format(sys, cxxflags_for(d, thing)))
|
|
o.close()
|
|
i.close()
|
|
|
|
python do_rust_arch_fixup () {
|
|
for thing in ['BUILD', 'HOST', 'TARGET']:
|
|
bb.debug(1, "rust_gen_mk_cfg for " + thing)
|
|
rust_gen_mk_cfg(d, thing)
|
|
}
|
|
addtask rust_arch_fixup before do_configure after do_patch
|
|
do_rust_arch_fixup[dirs] += "${WORKDIR}/mk-cfg"
|
|
|
|
llvmdir = "${STAGING_DIR_NATIVE}/${prefix_native}"
|
|
|
|
# prevent the rust-installer scripts from calling ldconfig
|
|
export CFG_DISABLE_LDCONFIG="notempty"
|
|
|
|
do_configure () {
|
|
# Note: when we adjust the generated targets, rust doesn't rebuild (even
|
|
# when it should), so for now we need to remove the build dir to keep
|
|
# things in sync.
|
|
cd "${WORKDIR}"
|
|
rm -rf "${B}/"
|
|
mkdir -p "${B}/"
|
|
cd "${B}"
|
|
|
|
# FIXME: target_prefix vs prefix, see cross.bbclass
|
|
|
|
# FIXME: this path to rustc (via `which rustc`) may not be quite right in the case
|
|
# where we're reinstalling the compiler. May want to try for a real
|
|
# path based on bitbake vars
|
|
# Also will be wrong when relative libdir and/or bindir aren't 'bin' and 'lib'.
|
|
local_rust_root=/not/set/do/not/use
|
|
if ${FETCH_STAGE0}; then
|
|
mkdir -p dl
|
|
tar -xf ${WORKDIR}/${RUST_SNAPSHOT} -C dl
|
|
./dl/rustc-${RS_VERSION}-${RS_ARCH}/install.sh --prefix=$PWD/dl
|
|
local_rust_root="$PWD/dl"
|
|
elif which rustc >/dev/null 2>&1; then
|
|
local_rustc=$(which rustc)
|
|
if [ -n "$local_rustc" ]; then
|
|
local_rust_root=$(dirname $(dirname $local_rustc))
|
|
fi
|
|
fi
|
|
|
|
# - rpath is required otherwise rustc fails to resolve symbols
|
|
# - submodule management is done by bitbake's fetching
|
|
${S}/configure \
|
|
"--enable-rpath" \
|
|
"--disable-docs" \
|
|
"--disable-manage-submodules" \
|
|
"--disable-debug" \
|
|
"--enable-optimize" \
|
|
"--enable-optimize-cxx" \
|
|
"--disable-llvm-version-check" \
|
|
"--llvm-root=${llvmdir}" \
|
|
"--enable-optimize-tests" \
|
|
"--release-channel=stable" \
|
|
"--prefix=${prefix}" \
|
|
"--target=${TARGET_SYS}" \
|
|
"--host=${HOST_SYS}" \
|
|
"--build=${BUILD_SYS}" \
|
|
"--localstatedir=${localstatedir}" \
|
|
"--sysconfdir=${sysconfdir}" \
|
|
"--datadir=${datadir}" \
|
|
"--infodir=${infodir}" \
|
|
"--mandir=${mandir}" \
|
|
"--libdir=${libdir}" \
|
|
"--bindir=${bindir}" \
|
|
"--platform-cfg=${WORKDIR}/mk-cfg/" \
|
|
"--enable-local-rust --local-rust-root=$local_rust_root" \
|
|
${EXTRA_OECONF}
|
|
}
|
|
|
|
rust_runmake () {
|
|
echo "COMPILE ${PN}" "$@"
|
|
env
|
|
|
|
# CFLAGS, LDFLAGS, CXXFLAGS, CPPFLAGS are used by rust's build for a
|
|
# wide range of targets (not just TARGET). Yocto's settings for them will
|
|
# be inappropriate, avoid using.
|
|
unset CFLAGS
|
|
unset LDFLAGS
|
|
unset CXXFLAGS
|
|
unset CPPFLAGS
|
|
|
|
oe_runmake "VERBOSE=1" "$@"
|
|
}
|
|
|
|
do_compile () {
|
|
rust_runmake
|
|
}
|
|
|
|
rust_do_install () {
|
|
rust_runmake DESTDIR="${D}" install
|
|
|
|
# Rust's install.sh doesn't mark executables as executable because
|
|
# we're using a custom bindir, do it ourselves.
|
|
chmod +x "${D}/${bindir}/rustc"
|
|
chmod +x "${D}/${bindir}/rustdoc"
|
|
chmod +x "${D}/${bindir}/rust-gdb"
|
|
|
|
# Install our custom target.json files
|
|
local td="${D}${libdir}/rustlib/"
|
|
install -d "$td"
|
|
for tgt in "${WORKDIR}/targets/"* ; do
|
|
install -m 0644 "$tgt" "$td"
|
|
done
|
|
|
|
# Remove any files directly installed into libdir to avoid
|
|
# conflicts between cross and native
|
|
rm -f ${D}${libdir}/lib*.so
|
|
}
|
|
|
|
do_install () {
|
|
rust_do_install
|
|
}
|
|
|