Skip to content

Rollup of 5 pull requests #94916

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Mar 13, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 39 additions & 1 deletion library/core/src/num/nonzero.rs
Original file line number Diff line number Diff line change
@@ -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);
}
110 changes: 110 additions & 0 deletions library/core/src/sync/atomic.rs
Original file line number Diff line number Diff line change
@@ -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
386 changes: 222 additions & 164 deletions src/bootstrap/config.rs
Original file line number Diff line number Diff line change
@@ -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);
5 changes: 5 additions & 0 deletions src/bootstrap/dist.rs
Original file line number Diff line number Diff line change
@@ -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,
);
Original file line number Diff line number Diff line change
@@ -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