Auto merge of #94916 - matthiaskrgr:rollup-s6zedfl, r=matthiaskrgr

Rollup of 5 pull requests

Successful merges:

 - #93292 (Implement `BITS` constant for non-zero integers)
 - #94777 (Update armv7-unknown-linux-uclibceabi platform support page.)
 - #94816 (Add `Atomic*::get_mut_slice`)
 - #94844 (Reduce rustbuild bloat caused by serde_derive)
 - #94907 (Omit stdarch test crates from the rust-src component)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2022-03-13 20:59:29 +00:00
commit e95b10ba4a
5 changed files with 397 additions and 176 deletions

View File

@ -465,7 +465,7 @@ macro_rules! nonzero_unsigned_operations {
without modifying the original"]
#[inline]
pub const fn log2(self) -> u32 {
<$Int>::BITS - 1 - self.leading_zeros()
Self::BITS - 1 - self.leading_zeros()
}
/// Returns the base 10 logarithm of the number, rounded down.
@ -1090,3 +1090,41 @@ nonzero_min_max_signed! {
NonZeroI128(i128);
NonZeroIsize(isize);
}
macro_rules! nonzero_bits {
( $( $Ty: ident($Int: ty); )+ ) => {
$(
impl $Ty {
/// The size of this non-zero integer type in bits.
///
#[doc = concat!("This value is equal to [`", stringify!($Int), "::BITS`].")]
///
/// # Examples
///
/// ```
/// #![feature(nonzero_bits)]
#[doc = concat!("# use std::num::", stringify!($Ty), ";")]
///
#[doc = concat!("assert_eq!(", stringify!($Ty), "::BITS, ", stringify!($Int), "::BITS);")]
/// ```
#[unstable(feature = "nonzero_bits", issue = "94881")]
pub const BITS: u32 = <$Int>::BITS;
}
)+
}
}
nonzero_bits! {
NonZeroU8(u8);
NonZeroI8(i8);
NonZeroU16(u16);
NonZeroI16(i16);
NonZeroU32(u32);
NonZeroI32(i32);
NonZeroU64(u64);
NonZeroI64(i64);
NonZeroU128(u128);
NonZeroI128(i128);
NonZeroUsize(usize);
NonZeroIsize(isize);
}

View File

@ -340,6 +340,40 @@ impl AtomicBool {
unsafe { &mut *(v as *mut bool as *mut Self) }
}
/// Get non-atomic access to a `&mut [AtomicBool]` slice.
///
/// This is safe because the mutable reference guarantees that no other threads are
/// concurrently accessing the atomic data.
///
/// # Examples
///
/// ```
/// #![feature(atomic_from_mut, inline_const, scoped_threads)]
/// use std::sync::atomic::{AtomicBool, Ordering};
///
/// let mut some_bools = [const { AtomicBool::new(false) }; 10];
///
/// let view: &mut [bool] = AtomicBool::get_mut_slice(&mut some_bools);
/// assert_eq!(view, [false; 10]);
/// view[..5].copy_from_slice(&[true; 5]);
///
/// std::thread::scope(|s| {
/// for t in &some_bools[..5] {
/// s.spawn(move || assert_eq!(t.load(Ordering::Relaxed), true));
/// }
///
/// for f in &some_bools[5..] {
/// s.spawn(move || assert_eq!(f.load(Ordering::Relaxed), false));
/// }
/// });
/// ```
#[inline]
#[unstable(feature = "atomic_from_mut", issue = "76314")]
pub fn get_mut_slice(this: &mut [Self]) -> &mut [bool] {
// SAFETY: the mutable reference guarantees unique ownership.
unsafe { &mut *(this as *mut [Self] as *mut [bool]) }
}
/// Get atomic access to a `&mut [bool]` slice.
///
/// # Examples
@ -971,6 +1005,46 @@ impl<T> AtomicPtr<T> {
unsafe { &mut *(v as *mut *mut T as *mut Self) }
}
/// Get non-atomic access to a `&mut [AtomicPtr]` slice.
///
/// This is safe because the mutable reference guarantees that no other threads are
/// concurrently accessing the atomic data.
///
/// # Examples
///
/// ```
/// #![feature(atomic_from_mut, inline_const, scoped_threads)]
/// use std::ptr::null_mut;
/// use std::sync::atomic::{AtomicPtr, Ordering};
///
/// let mut some_ptrs = [const { AtomicPtr::new(null_mut::<String>()) }; 10];
///
/// let view: &mut [*mut String] = AtomicPtr::get_mut_slice(&mut some_ptrs);
/// assert_eq!(view, [null_mut::<String>(); 10]);
/// view
/// .iter_mut()
/// .enumerate()
/// .for_each(|(i, ptr)| *ptr = Box::into_raw(Box::new(format!("iteration#{i}"))));
///
/// std::thread::scope(|s| {
/// for ptr in &some_ptrs {
/// s.spawn(move || {
/// let ptr = ptr.load(Ordering::Relaxed);
/// assert!(!ptr.is_null());
///
/// let name = unsafe { Box::from_raw(ptr) };
/// println!("Hello, {name}!");
/// });
/// }
/// });
/// ```
#[inline]
#[unstable(feature = "atomic_from_mut", issue = "76314")]
pub fn get_mut_slice(this: &mut [Self]) -> &mut [*mut T] {
// SAFETY: the mutable reference guarantees unique ownership.
unsafe { &mut *(this as *mut [Self] as *mut [*mut T]) }
}
/// Get atomic access to a slice of pointers.
///
/// # Examples
@ -1521,6 +1595,42 @@ macro_rules! atomic_int {
unsafe { &mut *(v as *mut $int_type as *mut Self) }
}
#[doc = concat!("Get non-atomic access to a `&mut [", stringify!($atomic_type), "]` slice")]
///
/// This is safe because the mutable reference guarantees that no other threads are
/// concurrently accessing the atomic data.
///
/// # Examples
///
/// ```
/// #![feature(atomic_from_mut, inline_const, scoped_threads)]
#[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
///
#[doc = concat!("let mut some_ints = [const { ", stringify!($atomic_type), "::new(0) }; 10];")]
///
#[doc = concat!("let view: &mut [", stringify!($int_type), "] = ", stringify!($atomic_type), "::get_mut_slice(&mut some_ints);")]
/// assert_eq!(view, [0; 10]);
/// view
/// .iter_mut()
/// .enumerate()
/// .for_each(|(idx, int)| *int = idx as _);
///
/// std::thread::scope(|s| {
/// some_ints
/// .iter()
/// .enumerate()
/// .for_each(|(idx, int)| {
/// s.spawn(move || assert_eq!(int.load(Ordering::Relaxed), idx as _));
/// })
/// });
/// ```
#[inline]
#[unstable(feature = "atomic_from_mut", issue = "76314")]
pub fn get_mut_slice(this: &mut [Self]) -> &mut [$int_type] {
// SAFETY: the mutable reference guarantees unique ownership.
unsafe { &mut *(this as *mut [Self] as *mut [$int_type]) }
}
#[doc = concat!("Get atomic access to a `&mut [", stringify!($int_type), "]` slice.")]
///
/// # Examples

View File

@ -17,7 +17,7 @@ use crate::channel::GitInfo;
pub use crate::flags::Subcommand;
use crate::flags::{Color, Flags};
use crate::util::{exe, t};
use serde::Deserialize;
use serde::{Deserialize, Deserializer};
macro_rules! check_ci_llvm {
($name:expr) => {
@ -362,13 +362,13 @@ impl Merge for TomlConfig {
// We are using a decl macro instead of a derive proc macro here to reduce the compile time of
// rustbuild.
macro_rules! derive_merge {
macro_rules! define_config {
($(#[$attr:meta])* struct $name:ident {
$($field:ident: $field_ty:ty,)*
$($field:ident: Option<$field_ty:ty> = $field_key:literal,)*
}) => {
$(#[$attr])*
struct $name {
$($field: $field_ty,)*
$($field: Option<$field_ty>,)*
}
impl Merge for $name {
@ -380,115 +380,173 @@ macro_rules! derive_merge {
)*
}
}
// The following is a trimmed version of what serde_derive generates. All parts not relevant
// for toml deserialization have been removed. This reduces the binary size and improves
// compile time of rustbuild.
impl<'de> Deserialize<'de> for $name {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct Field;
impl<'de> serde::de::Visitor<'de> for Field {
type Value = $name;
fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(concat!("struct ", stringify!($name)))
}
#[inline]
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: serde::de::MapAccess<'de>,
{
$(let mut $field: Option<$field_ty> = None;)*
while let Some(key) =
match serde::de::MapAccess::next_key::<String>(&mut map) {
Ok(val) => val,
Err(err) => {
return Err(err);
}
}
{
match &*key {
$($field_key => {
if $field.is_some() {
return Err(<A::Error as serde::de::Error>::duplicate_field(
$field_key,
));
}
$field = match serde::de::MapAccess::next_value::<$field_ty>(
&mut map,
) {
Ok(val) => Some(val),
Err(err) => {
return Err(err);
}
};
})*
key => {
return Err(serde::de::Error::unknown_field(key, FIELDS));
}
}
}
Ok($name { $($field),* })
}
}
const FIELDS: &'static [&'static str] = &[
$($field_key,)*
];
Deserializer::deserialize_struct(
deserializer,
stringify!($name),
FIELDS,
Field,
)
}
}
}
}
derive_merge! {
define_config! {
/// TOML representation of various global build decisions.
#[derive(Deserialize, Default)]
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
#[derive(Default)]
struct Build {
build: Option<String>,
host: Option<Vec<String>>,
target: Option<Vec<String>>,
build_dir: Option<String>,
cargo: Option<String>,
rustc: Option<String>,
rustfmt: Option<PathBuf>,
docs: Option<bool>,
compiler_docs: Option<bool>,
docs_minification: Option<bool>,
submodules: Option<bool>,
fast_submodules: Option<bool>,
gdb: Option<String>,
nodejs: Option<String>,
npm: Option<String>,
python: Option<String>,
locked_deps: Option<bool>,
vendor: Option<bool>,
full_bootstrap: Option<bool>,
extended: Option<bool>,
tools: Option<HashSet<String>>,
verbose: Option<usize>,
sanitizers: Option<bool>,
profiler: Option<bool>,
cargo_native_static: Option<bool>,
low_priority: Option<bool>,
configure_args: Option<Vec<String>>,
local_rebuild: Option<bool>,
print_step_timings: Option<bool>,
print_step_rusage: Option<bool>,
check_stage: Option<u32>,
doc_stage: Option<u32>,
build_stage: Option<u32>,
test_stage: Option<u32>,
install_stage: Option<u32>,
dist_stage: Option<u32>,
bench_stage: Option<u32>,
patch_binaries_for_nix: Option<bool>,
build: Option<String> = "build",
host: Option<Vec<String>> = "host",
target: Option<Vec<String>> = "target",
build_dir: Option<String> = "build-dir",
cargo: Option<String> = "cargo",
rustc: Option<String> = "rustc",
rustfmt: Option<PathBuf> = "rustfmt",
docs: Option<bool> = "docs",
compiler_docs: Option<bool> = "compiler-docs",
docs_minification: Option<bool> = "docs-minification",
submodules: Option<bool> = "submodules",
fast_submodules: Option<bool> = "fast-submodules",
gdb: Option<String> = "gdb",
nodejs: Option<String> = "nodejs",
npm: Option<String> = "npm",
python: Option<String> = "python",
locked_deps: Option<bool> = "locked-deps",
vendor: Option<bool> = "vendor",
full_bootstrap: Option<bool> = "full-bootstrap",
extended: Option<bool> = "extended",
tools: Option<HashSet<String>> = "tools",
verbose: Option<usize> = "verbose",
sanitizers: Option<bool> = "sanitizers",
profiler: Option<bool> = "profiler",
cargo_native_static: Option<bool> = "cargo-native-static",
low_priority: Option<bool> = "low-priority",
configure_args: Option<Vec<String>> = "configure-args",
local_rebuild: Option<bool> = "local-rebuild",
print_step_timings: Option<bool> = "print-step-timings",
print_step_rusage: Option<bool> = "print-step-rusage",
check_stage: Option<u32> = "check-stage",
doc_stage: Option<u32> = "doc-stage",
build_stage: Option<u32> = "build-stage",
test_stage: Option<u32> = "test-stage",
install_stage: Option<u32> = "install-stage",
dist_stage: Option<u32> = "dist-stage",
bench_stage: Option<u32> = "bench-stage",
patch_binaries_for_nix: Option<bool> = "patch-binaries-for-nix",
}
}
derive_merge! {
define_config! {
/// TOML representation of various global install decisions.
#[derive(Deserialize)]
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
struct Install {
prefix: Option<String>,
sysconfdir: Option<String>,
docdir: Option<String>,
bindir: Option<String>,
libdir: Option<String>,
mandir: Option<String>,
datadir: Option<String>,
prefix: Option<String> = "prefix",
sysconfdir: Option<String> = "sysconfdir",
docdir: Option<String> = "docdir",
bindir: Option<String> = "bindir",
libdir: Option<String> = "libdir",
mandir: Option<String> = "mandir",
datadir: Option<String> = "datadir",
}
}
derive_merge! {
define_config! {
/// TOML representation of how the LLVM build is configured.
#[derive(Deserialize)]
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
struct Llvm {
skip_rebuild: Option<bool>,
optimize: Option<bool>,
thin_lto: Option<bool>,
release_debuginfo: Option<bool>,
assertions: Option<bool>,
tests: Option<bool>,
plugins: Option<bool>,
ccache: Option<StringOrBool>,
version_check: Option<bool>,
static_libstdcpp: Option<bool>,
ninja: Option<bool>,
targets: Option<String>,
experimental_targets: Option<String>,
link_jobs: Option<u32>,
link_shared: Option<bool>,
version_suffix: Option<String>,
clang_cl: Option<String>,
cflags: Option<String>,
cxxflags: Option<String>,
ldflags: Option<String>,
use_libcxx: Option<bool>,
use_linker: Option<String>,
allow_old_toolchain: Option<bool>,
polly: Option<bool>,
clang: Option<bool>,
download_ci_llvm: Option<StringOrBool>,
build_config: Option<HashMap<String, String>>,
skip_rebuild: Option<bool> = "skip-rebuild",
optimize: Option<bool> = "optimize",
thin_lto: Option<bool> = "thin-lto",
release_debuginfo: Option<bool> = "release-debuginfo",
assertions: Option<bool> = "assertions",
tests: Option<bool> = "tests",
plugins: Option<bool> = "plugins",
ccache: Option<StringOrBool> = "ccache",
version_check: Option<bool> = "version-check",
static_libstdcpp: Option<bool> = "static-libstdcpp",
ninja: Option<bool> = "ninja",
targets: Option<String> = "targets",
experimental_targets: Option<String> = "experimental-targets",
link_jobs: Option<u32> = "link-jobs",
link_shared: Option<bool> = "link-shared",
version_suffix: Option<String> = "version-suffix",
clang_cl: Option<String> = "clang-cl",
cflags: Option<String> = "cflags",
cxxflags: Option<String> = "cxxflags",
ldflags: Option<String> = "ldflags",
use_libcxx: Option<bool> = "use-libcxx",
use_linker: Option<String> = "use-linker",
allow_old_toolchain: Option<bool> = "allow-old-toolchain",
polly: Option<bool> = "polly",
clang: Option<bool> = "clang",
download_ci_llvm: Option<StringOrBool> = "download-ci-llvm",
build_config: Option<HashMap<String, String>> = "build-config",
}
}
derive_merge! {
#[derive(Deserialize)]
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
define_config! {
struct Dist {
sign_folder: Option<String>,
gpg_password_file: Option<String>,
upload_addr: Option<String>,
src_tarball: Option<bool>,
missing_tools: Option<bool>,
compression_formats: Option<Vec<String>>,
sign_folder: Option<String> = "sign-folder",
gpg_password_file: Option<String> = "gpg-password-file",
upload_addr: Option<String> = "upload-addr",
src_tarball: Option<bool> = "src-tarball",
missing_tools: Option<bool> = "missing-tools",
compression_formats: Option<Vec<String>> = "compression-formats",
}
}
@ -505,83 +563,79 @@ impl Default for StringOrBool {
}
}
derive_merge! {
define_config! {
/// TOML representation of how the Rust build is configured.
#[derive(Deserialize)]
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
struct Rust {
optimize: Option<bool>,
debug: Option<bool>,
codegen_units: Option<u32>,
codegen_units_std: Option<u32>,
debug_assertions: Option<bool>,
debug_assertions_std: Option<bool>,
overflow_checks: Option<bool>,
overflow_checks_std: Option<bool>,
debug_logging: Option<bool>,
debuginfo_level: Option<u32>,
debuginfo_level_rustc: Option<u32>,
debuginfo_level_std: Option<u32>,
debuginfo_level_tools: Option<u32>,
debuginfo_level_tests: Option<u32>,
run_dsymutil: Option<bool>,
backtrace: Option<bool>,
incremental: Option<bool>,
parallel_compiler: Option<bool>,
default_linker: Option<String>,
channel: Option<String>,
description: Option<String>,
musl_root: Option<String>,
rpath: Option<bool>,
verbose_tests: Option<bool>,
optimize_tests: Option<bool>,
codegen_tests: Option<bool>,
ignore_git: Option<bool>,
dist_src: Option<bool>,
save_toolstates: Option<String>,
codegen_backends: Option<Vec<String>>,
lld: Option<bool>,
use_lld: Option<bool>,
llvm_tools: Option<bool>,
deny_warnings: Option<bool>,
backtrace_on_ice: Option<bool>,
verify_llvm_ir: Option<bool>,
thin_lto_import_instr_limit: Option<u32>,
remap_debuginfo: Option<bool>,
jemalloc: Option<bool>,
test_compare_mode: Option<bool>,
llvm_libunwind: Option<String>,
control_flow_guard: Option<bool>,
new_symbol_mangling: Option<bool>,
profile_generate: Option<String>,
profile_use: Option<String>,
optimize: Option<bool> = "optimize",
debug: Option<bool> = "debug",
codegen_units: Option<u32> = "codegen-units",
codegen_units_std: Option<u32> = "codegen-units-std",
debug_assertions: Option<bool> = "debug-assertions",
debug_assertions_std: Option<bool> = "debug-assertions-std",
overflow_checks: Option<bool> = "overflow-checks",
overflow_checks_std: Option<bool> = "overflow-checks-std",
debug_logging: Option<bool> = "debug-logging",
debuginfo_level: Option<u32> = "debuginfo-level",
debuginfo_level_rustc: Option<u32> = "debuginfo-level-rustc",
debuginfo_level_std: Option<u32> = "debuginfo-level-std",
debuginfo_level_tools: Option<u32> = "debuginfo-level-tools",
debuginfo_level_tests: Option<u32> = "debuginfo-level-tests",
run_dsymutil: Option<bool> = "run-dsymutil",
backtrace: Option<bool> = "backtrace",
incremental: Option<bool> = "incremental",
parallel_compiler: Option<bool> = "parallel-compiler",
default_linker: Option<String> = "default-linker",
channel: Option<String> = "channel",
description: Option<String> = "description",
musl_root: Option<String> = "musl-root",
rpath: Option<bool> = "rpath",
verbose_tests: Option<bool> = "verbose-tests",
optimize_tests: Option<bool> = "optimize-tests",
codegen_tests: Option<bool> = "codegen-tests",
ignore_git: Option<bool> = "ignore-git",
dist_src: Option<bool> = "dist-src",
save_toolstates: Option<String> = "save-toolstates",
codegen_backends: Option<Vec<String>> = "codegen-backends",
lld: Option<bool> = "lld",
use_lld: Option<bool> = "use-lld",
llvm_tools: Option<bool> = "llvm-tools",
deny_warnings: Option<bool> = "deny-warnings",
backtrace_on_ice: Option<bool> = "backtrace-on-ice",
verify_llvm_ir: Option<bool> = "verify-llvm-ir",
thin_lto_import_instr_limit: Option<u32> = "thin-lto-import-instr-limit",
remap_debuginfo: Option<bool> = "remap-debuginfo",
jemalloc: Option<bool> = "jemalloc",
test_compare_mode: Option<bool> = "test-compare-mode",
llvm_libunwind: Option<String> = "llvm-libunwind",
control_flow_guard: Option<bool> = "control-flow-guard",
new_symbol_mangling: Option<bool> = "new-symbol-mangling",
profile_generate: Option<String> = "profile-generate",
profile_use: Option<String> = "profile-use",
// ignored; this is set from an env var set by bootstrap.py
download_rustc: Option<StringOrBool>,
download_rustc: Option<StringOrBool> = "download-rustc",
}
}
derive_merge! {
define_config! {
/// TOML representation of how each build target is configured.
#[derive(Deserialize)]
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
struct TomlTarget {
cc: Option<String>,
cxx: Option<String>,
ar: Option<String>,
ranlib: Option<String>,
default_linker: Option<PathBuf>,
linker: Option<String>,
llvm_config: Option<String>,
llvm_filecheck: Option<String>,
android_ndk: Option<String>,
sanitizers: Option<bool>,
profiler: Option<bool>,
crt_static: Option<bool>,
musl_root: Option<String>,
musl_libdir: Option<String>,
wasi_root: Option<String>,
qemu_rootfs: Option<String>,
no_std: Option<bool>,
cc: Option<String> = "cc",
cxx: Option<String> = "cxx",
ar: Option<String> = "ar",
ranlib: Option<String> = "ranlib",
default_linker: Option<PathBuf> = "default-linker",
linker: Option<String> = "linker",
llvm_config: Option<String> = "llvm-config",
llvm_filecheck: Option<String> = "llvm-filecheck",
android_ndk: Option<String> = "android-ndk",
sanitizers: Option<bool> = "sanitizers",
profiler: Option<bool> = "profiler",
crt_static: Option<bool> = "crt-static",
musl_root: Option<String> = "musl-root",
musl_libdir: Option<String> = "musl-libdir",
wasi_root: Option<String> = "wasi-root",
qemu_rootfs: Option<String> = "qemu-rootfs",
no_std: Option<bool> = "no-std",
}
}
@ -649,7 +703,11 @@ impl Config {
let contents =
t!(fs::read_to_string(file), format!("config file {} not found", file.display()));
match toml::from_str(&contents) {
// Deserialize to Value and then TomlConfig to prevent the Deserialize impl of
// TomlConfig and sub types to be monomorphized 5x by toml.
match toml::from_str(&contents)
.and_then(|table: toml::Value| TomlConfig::deserialize(table))
{
Ok(table) => table,
Err(err) => {
println!("failed to parse TOML configuration '{}': {}", file.display(), err);

View File

@ -821,6 +821,11 @@ impl Step for Src {
// not needed and contains symlinks which rustup currently
// chokes on when unpacking.
"library/backtrace/crates",
// these are 30MB combined and aren't necessary for building
// the standard library.
"library/stdarch/crates/Cargo.toml",
"library/stdarch/crates/stdarch-verify",
"library/stdarch/crates/intrinsic-test",
],
&dst_src,
);

View File

@ -36,8 +36,8 @@ target = ["armv7-unknown-linux-uclibceabi"]
cc = "/path/to/arm-unknown-linux-uclibcgnueabi-gcc"
cxx = "/path/to/arm-unknown-linux-uclibcgnueabi-g++"
ar = "path/to/arm-unknown-linux-uclibcgnueabi-ar"
ranlib = "path/to/arm-unknown-linux-uclibcgnueabi-"
linker = "/path/to/arm-unknown-linux-uclibcgnueabi-"
ranlib = "path/to/arm-unknown-linux-uclibcgnueabi-ranlib"
linker = "/path/to/arm-unknown-linux-uclibcgnueabi-gcc"
```
## Building Rust programs
@ -75,27 +75,37 @@ To cross compile, you'll need to:
```
* Build with:
```text
CC=/opt/tomatoware/arm-soft-mmc/bin/arm-linux-gcc \
CXX=/opt/tomatoware/arm-soft-mmc/bin/arm-linux-g++ \
AR=/opt/tomatoware/arm-soft-mmc/bin/arm-linux-ar \
CC_armv7_unknown_linux_uclibceabi=/opt/tomatoware/arm-soft-mmc/bin/arm-linux-gcc \
CXX_armv7_unknown_linux_uclibceabi=/opt/tomatoware/arm-soft-mmc/bin/arm-linux-g++ \
AR_armv7_unknown_linux_uclibceabi=/opt/tomatoware/arm-soft-mmc/bin/arm-linux-ar \
CFLAGS_armv7_unknown_linux_uclibceabi="-march=armv7-a -mtune=cortex-a9" \
CXXFLAGS_armv7_unknown_linux_uclibceabi="-march=armv7-a -mtune=cortex-a9" \
CARGO_TARGET_ARMV7_UNKNOWN_LINUX_UCLIBCEABI_LINKER=/opt/tomatoware/arm-soft-mmc/bin/arm-linux-gcc \
CARGO_TARGET_ARMV7_UNKNOWN_LINUX_UCLIBCEABI_RUSTFLAGS='-Clink-arg=-s -Clink-arg=-Wl,--dynamic-linker=/mmc/lib/ld-uClibc.so.1 -Clink-arg=-Wl,-rpath,/mmc/lib' \
cargo +stage2 build --target armv7-unknown-linux-uclibceabi --release
cargo +stage2 \
build \
--target armv7-unknown-linux-uclibceabi \
--release
```
* Copy the binary to your target device and run.
We specify `CC`, `CXX`, and `AR` because somtimes a project or a subproject requires the use of your `'C'` cross toolchain. Since Tomatoware has a modified sysroot we also pass via RUSTFLAGS the location of the dynamic-linker and rpath.
We specify `CC`, `CXX`, `AR`, `CFLAGS`, and `CXXFLAGS` environment variables because somtimes a project or a subproject requires the use of your `'C'` cross toolchain. Since Tomatoware has a modified sysroot we also pass via RUSTFLAGS the location of the dynamic-linker and rpath.
### Test with QEMU
To test a cross-compiled binary on your build system follow the instructions for `Cross Compilation`, install `qemu-arm-static`, and run with the following.
```text
CC=/opt/tomatoware/arm-soft-mmc/bin/arm-linux-gcc \
CXX=/opt/tomatoware/arm-soft-mmc/bin/arm-linux-g++ \
AR=/opt/tomatoware/arm-soft-mmc/bin/arm-linux-ar \
CC_armv7_unknown_linux_uclibceabi=/opt/tomatoware/arm-soft-mmc/bin/arm-linux-gcc \
CXX_armv7_unknown_linux_uclibceabi=/opt/tomatoware/arm-soft-mmc/bin/arm-linux-g++ \
AR_armv7_unknown_linux_uclibceabi=/opt/tomatoware/arm-soft-mmc/bin/arm-linux-ar \
CFLAGS_armv7_unknown_linux_uclibceabi="-march=armv7-a -mtune=cortex-a9" \
CXXFLAGS_armv7_unknown_linux_uclibceabi="-march=armv7-a -mtune=cortex-a9" \
CARGO_TARGET_ARMV7_UNKNOWN_LINUX_UCLIBCEABI_LINKER=/opt/tomatoware/arm-soft-mmc/bin/arm-linux-gcc \
CARGO_TARGET_ARMV7_UNKNOWN_LINUX_UCLIBCEABI_RUNNER="qemu-arm-static -L /opt/tomatoware/arm-soft-mmc/arm-tomatoware-linux-uclibcgnueabi/sysroot/" \
cargo +stage2 run --target armv7-unknown-linux-uclibceabi --release
cargo +stage2 \
run \
--target armv7-unknown-linux-uclibceabi \
--release
```
### Run in a chroot