rust/compiler/rustc_target/src/spec/mod.rs

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

3515 lines
142 KiB
Rust
Raw Normal View History

//! [Flexible target specification.](https://github.com/rust-lang/rfcs/pull/131)
//!
//! Rust targets a wide variety of usecases, and in the interest of flexibility,
//! allows new target triples to be defined in configuration files. Most users
//! will not need to care about these, but this is invaluable when porting Rust
//! to a new platform, and allows for an unprecedented level of control over how
//! the compiler works.
//!
//! # Using custom targets
//!
//! A target triple, as passed via `rustc --target=TRIPLE`, will first be
//! compared against the list of built-in targets. This is to ease distributing
//! rustc (no need for configuration files) and also to hold these built-in
//! targets as immutable and sacred. If `TRIPLE` is not one of the built-in
//! targets, rustc will check if a file named `TRIPLE` exists. If it does, it
//! will be loaded as the target configuration. If the file does not exist,
//! rustc will search each directory in the environment variable
//! `RUST_TARGET_PATH` for a file named `TRIPLE.json`. The first one found will
//! be loaded. If no file is found in any of those directories, a fatal error
//! will be given.
//!
//! Projects defining their own targets should use
//! `--target=path/to/my-awesome-platform.json` instead of adding to
//! `RUST_TARGET_PATH`.
//!
//! # Defining a new target
//!
2021-06-23 16:26:46 -04:00
//! Targets are defined using [JSON](https://json.org/). The `Target` struct in
//! this module defines the format the JSON file should take, though each
//! underscore in the field names should be replaced with a hyphen (`-`) in the
//! JSON file. Some fields are required in every target specification, such as
//! `llvm-target`, `target-endian`, `target-pointer-width`, `data-layout`,
//! `arch`, and `os`. In general, options passed to rustc with `-C` override
//! the target's settings, though `target-feature` and `link-args` will *add*
//! to the list specified by the target, rather than replace.
use crate::abi::call::Conv;
use crate::abi::{Endian, Integer, Size, TargetDataLayout, TargetDataLayoutErrors};
2021-06-03 17:45:09 +02:00
use crate::json::{Json, ToJson};
2019-02-08 21:00:07 +09:00
use crate::spec::abi::{lookup as lookup_abi, Abi};
use crate::spec::crt_objects::CrtObjects;
use rustc_fs_util::try_canonicalize;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use rustc_span::symbol::{kw, sym, Symbol};
2021-06-03 17:45:09 +02:00
use serde_json::Value;
use std::borrow::Cow;
use std::collections::BTreeMap;
use std::hash::{Hash, Hasher};
use std::ops::{Deref, DerefMut};
use std::path::{Path, PathBuf};
use std::str::FromStr;
2019-02-08 21:00:07 +09:00
use std::{fmt, io};
2019-11-09 23:32:17 +01:00
use rustc_macros::HashStable_Generic;
pub mod abi;
pub mod crt_objects;
mod base;
pub use base::apple::deployment_target as current_apple_deployment_target;
pub use base::apple::platform as current_apple_platform;
pub use base::apple::sdk_version as current_apple_sdk_version;
pub use base::avr_gnu::ef_avr_arch;
/// Linker is called through a C/C++ compiler.
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub enum Cc {
Yes,
No,
}
/// Linker is LLD.
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub enum Lld {
Yes,
No,
}
/// All linkers have some kinds of command line interfaces and rustc needs to know which commands
/// to use with each of them. So we cluster all such interfaces into a (somewhat arbitrary) number
/// of classes that we call "linker flavors".
///
/// Technically, it's not even necessary, we can nearly always infer the flavor from linker name
/// and target properties like `is_like_windows`/`is_like_osx`/etc. However, the PRs originally
/// introducing `-Clinker-flavor` (#40018 and friends) were aiming to reduce this kind of inference
/// and provide something certain and explicitly specified instead, and that design goal is still
/// relevant now.
///
/// The second goal is to keep the number of flavors to the minimum if possible.
/// LLD somewhat forces our hand here because that linker is self-sufficient only if its executable
/// (`argv[0]`) is named in specific way, otherwise it doesn't work and requires a
/// `-flavor LLD_FLAVOR` argument to choose which logic to use. Our shipped `rust-lld` in
/// particular is not named in such specific way, so it needs the flavor option, so we make our
/// linker flavors sufficiently fine-grained to satisfy LLD without inferring its flavor from other
/// target properties, in accordance with the first design goal.
///
/// The first component of the flavor is tightly coupled with the compilation target,
2023-04-10 22:02:52 +02:00
/// while the `Cc` and `Lld` flags can vary within the same target.
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub enum LinkerFlavor {
/// Unix-like linker with GNU extensions (both naked and compiler-wrapped forms).
/// Besides similar "default" Linux/BSD linkers this also includes Windows/GNU linker,
/// which is somewhat different because it doesn't produce ELFs.
Gnu(Cc, Lld),
/// Unix-like linker for Apple targets (both naked and compiler-wrapped forms).
/// Extracted from the "umbrella" `Unix` flavor due to its corresponding LLD flavor.
Darwin(Cc, Lld),
/// Unix-like linker for Wasm targets (both naked and compiler-wrapped forms).
/// Extracted from the "umbrella" `Unix` flavor due to its corresponding LLD flavor.
/// Non-LLD version does not exist, so the lld flag is currently hardcoded here.
WasmLld(Cc),
/// Basic Unix-like linker for "any other Unix" targets (Solaris/illumos, L4Re, MSP430, etc),
/// possibly with non-GNU extensions (both naked and compiler-wrapped forms).
/// LLD doesn't support any of these.
Unix(Cc),
/// MSVC-style linker for Windows and UEFI, LLD supports it.
Msvc(Lld),
/// Emscripten Compiler Frontend, a wrapper around `WasmLld(Cc::Yes)` that has a different
/// interface and produces some additional JavaScript output.
EmCc,
// Below: other linker-like tools with unique interfaces for exotic targets.
/// Linker tool for BPF.
Bpf,
/// Linker tool for Nvidia PTX.
Ptx,
}
/// Linker flavors available externally through command line (`-Clinker-flavor`)
/// or json target specifications.
/// This set has accumulated historically, and contains both (stable and unstable) legacy values, as
/// well as modern ones matching the internal linker flavors (`LinkerFlavor`).
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub enum LinkerFlavorCli {
// Modern (unstable) flavors, with direct counterparts in `LinkerFlavor`.
Gnu(Cc, Lld),
Darwin(Cc, Lld),
WasmLld(Cc),
Unix(Cc),
// Note: `Msvc(Lld::No)` is also a stable value.
Msvc(Lld),
EmCc,
Bpf,
Ptx,
// Legacy stable values
Gcc,
Ld,
Lld(LldFlavor),
Em,
}
impl LinkerFlavorCli {
/// Returns whether this `-C linker-flavor` option is one of the unstable values.
pub fn is_unstable(&self) -> bool {
match self {
LinkerFlavorCli::Gnu(..)
| LinkerFlavorCli::Darwin(..)
| LinkerFlavorCli::WasmLld(..)
| LinkerFlavorCli::Unix(..)
| LinkerFlavorCli::Msvc(Lld::Yes)
| LinkerFlavorCli::EmCc
| LinkerFlavorCli::Bpf
| LinkerFlavorCli::Ptx => true,
LinkerFlavorCli::Gcc
| LinkerFlavorCli::Ld
| LinkerFlavorCli::Lld(..)
| LinkerFlavorCli::Msvc(Lld::No)
| LinkerFlavorCli::Em => false,
}
}
}
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub enum LldFlavor {
Wasm,
Ld64,
Ld,
Link,
}
2018-08-18 20:16:04 +02:00
impl LldFlavor {
pub fn as_str(&self) -> &'static str {
match self {
LldFlavor::Wasm => "wasm",
LldFlavor::Ld64 => "darwin",
LldFlavor::Ld => "gnu",
LldFlavor::Link => "link",
}
}
2018-08-18 20:16:04 +02:00
fn from_str(s: &str) -> Option<Self> {
Some(match s {
"darwin" => LldFlavor::Ld64,
"gnu" => LldFlavor::Ld,
"link" => LldFlavor::Link,
"wasm" => LldFlavor::Wasm,
_ => return None,
})
}
}
impl ToJson for LldFlavor {
fn to_json(&self) -> Json {
self.as_str().to_json()
2018-08-18 20:16:04 +02:00
}
}
impl LinkerFlavor {
/// At this point the target's reference linker flavor doesn't yet exist and we need to infer
/// it. The inference always succeds and gives some result, and we don't report any flavor
/// incompatibility errors for json target specs. The CLI flavor is used as the main source
/// of truth, other flags are used in case of ambiguities.
fn from_cli_json(cli: LinkerFlavorCli, lld_flavor: LldFlavor, is_gnu: bool) -> LinkerFlavor {
match cli {
LinkerFlavorCli::Gnu(cc, lld) => LinkerFlavor::Gnu(cc, lld),
LinkerFlavorCli::Darwin(cc, lld) => LinkerFlavor::Darwin(cc, lld),
LinkerFlavorCli::WasmLld(cc) => LinkerFlavor::WasmLld(cc),
LinkerFlavorCli::Unix(cc) => LinkerFlavor::Unix(cc),
LinkerFlavorCli::Msvc(lld) => LinkerFlavor::Msvc(lld),
LinkerFlavorCli::EmCc => LinkerFlavor::EmCc,
LinkerFlavorCli::Bpf => LinkerFlavor::Bpf,
LinkerFlavorCli::Ptx => LinkerFlavor::Ptx,
// Below: legacy stable values
LinkerFlavorCli::Gcc => match lld_flavor {
LldFlavor::Ld if is_gnu => LinkerFlavor::Gnu(Cc::Yes, Lld::No),
LldFlavor::Ld64 => LinkerFlavor::Darwin(Cc::Yes, Lld::No),
LldFlavor::Wasm => LinkerFlavor::WasmLld(Cc::Yes),
LldFlavor::Ld | LldFlavor::Link => LinkerFlavor::Unix(Cc::Yes),
},
LinkerFlavorCli::Ld => match lld_flavor {
LldFlavor::Ld if is_gnu => LinkerFlavor::Gnu(Cc::No, Lld::No),
LldFlavor::Ld64 => LinkerFlavor::Darwin(Cc::No, Lld::No),
LldFlavor::Ld | LldFlavor::Wasm | LldFlavor::Link => LinkerFlavor::Unix(Cc::No),
},
LinkerFlavorCli::Lld(LldFlavor::Ld) => LinkerFlavor::Gnu(Cc::No, Lld::Yes),
LinkerFlavorCli::Lld(LldFlavor::Ld64) => LinkerFlavor::Darwin(Cc::No, Lld::Yes),
LinkerFlavorCli::Lld(LldFlavor::Wasm) => LinkerFlavor::WasmLld(Cc::No),
LinkerFlavorCli::Lld(LldFlavor::Link) => LinkerFlavor::Msvc(Lld::Yes),
LinkerFlavorCli::Em => LinkerFlavor::EmCc,
}
}
/// Returns the corresponding backwards-compatible CLI flavor.
fn to_cli(self) -> LinkerFlavorCli {
match self {
LinkerFlavor::Gnu(Cc::Yes, _)
| LinkerFlavor::Darwin(Cc::Yes, _)
| LinkerFlavor::WasmLld(Cc::Yes)
| LinkerFlavor::Unix(Cc::Yes) => LinkerFlavorCli::Gcc,
LinkerFlavor::Gnu(_, Lld::Yes) => LinkerFlavorCli::Lld(LldFlavor::Ld),
LinkerFlavor::Darwin(_, Lld::Yes) => LinkerFlavorCli::Lld(LldFlavor::Ld64),
LinkerFlavor::WasmLld(..) => LinkerFlavorCli::Lld(LldFlavor::Wasm),
LinkerFlavor::Gnu(..) | LinkerFlavor::Darwin(..) | LinkerFlavor::Unix(..) => {
LinkerFlavorCli::Ld
}
LinkerFlavor::Msvc(Lld::Yes) => LinkerFlavorCli::Lld(LldFlavor::Link),
LinkerFlavor::Msvc(..) => LinkerFlavorCli::Msvc(Lld::No),
LinkerFlavor::EmCc => LinkerFlavorCli::Em,
LinkerFlavor::Bpf => LinkerFlavorCli::Bpf,
LinkerFlavor::Ptx => LinkerFlavorCli::Ptx,
}
}
/// Returns the modern CLI flavor that is the counterpart of this flavor.
fn to_cli_counterpart(self) -> LinkerFlavorCli {
match self {
LinkerFlavor::Gnu(cc, lld) => LinkerFlavorCli::Gnu(cc, lld),
LinkerFlavor::Darwin(cc, lld) => LinkerFlavorCli::Darwin(cc, lld),
LinkerFlavor::WasmLld(cc) => LinkerFlavorCli::WasmLld(cc),
LinkerFlavor::Unix(cc) => LinkerFlavorCli::Unix(cc),
LinkerFlavor::Msvc(lld) => LinkerFlavorCli::Msvc(lld),
LinkerFlavor::EmCc => LinkerFlavorCli::EmCc,
LinkerFlavor::Bpf => LinkerFlavorCli::Bpf,
LinkerFlavor::Ptx => LinkerFlavorCli::Ptx,
}
}
fn infer_cli_hints(cli: LinkerFlavorCli) -> (Option<Cc>, Option<Lld>) {
match cli {
LinkerFlavorCli::Gnu(cc, lld) | LinkerFlavorCli::Darwin(cc, lld) => {
(Some(cc), Some(lld))
}
LinkerFlavorCli::WasmLld(cc) => (Some(cc), Some(Lld::Yes)),
LinkerFlavorCli::Unix(cc) => (Some(cc), None),
LinkerFlavorCli::Msvc(lld) => (Some(Cc::No), Some(lld)),
LinkerFlavorCli::EmCc => (Some(Cc::Yes), Some(Lld::Yes)),
LinkerFlavorCli::Bpf | LinkerFlavorCli::Ptx => (None, None),
// Below: legacy stable values
LinkerFlavorCli::Gcc => (Some(Cc::Yes), None),
LinkerFlavorCli::Ld => (Some(Cc::No), Some(Lld::No)),
LinkerFlavorCli::Lld(_) => (Some(Cc::No), Some(Lld::Yes)),
LinkerFlavorCli::Em => (Some(Cc::Yes), Some(Lld::Yes)),
}
}
fn infer_linker_hints(linker_stem: &str) -> (Option<Cc>, Option<Lld>) {
// Remove any version postfix.
let stem = linker_stem
.rsplit_once('-')
.and_then(|(lhs, rhs)| rhs.chars().all(char::is_numeric).then_some(lhs))
.unwrap_or(linker_stem);
// GCC/Clang can have an optional target prefix.
if stem == "emcc"
|| stem == "gcc"
|| stem.ends_with("-gcc")
|| stem == "g++"
|| stem.ends_with("-g++")
|| stem == "clang"
|| stem.ends_with("-clang")
|| stem == "clang++"
|| stem.ends_with("-clang++")
{
(Some(Cc::Yes), Some(Lld::No))
} else if stem == "wasm-ld"
|| stem.ends_with("-wasm-ld")
|| stem == "ld.lld"
|| stem == "lld"
|| stem == "rust-lld"
|| stem == "lld-link"
{
(Some(Cc::No), Some(Lld::Yes))
} else if stem == "ld" || stem.ends_with("-ld") || stem == "link" {
(Some(Cc::No), Some(Lld::No))
} else {
(None, None)
}
}
fn with_hints(self, (cc_hint, lld_hint): (Option<Cc>, Option<Lld>)) -> LinkerFlavor {
match self {
LinkerFlavor::Gnu(cc, lld) => {
LinkerFlavor::Gnu(cc_hint.unwrap_or(cc), lld_hint.unwrap_or(lld))
}
LinkerFlavor::Darwin(cc, lld) => {
LinkerFlavor::Darwin(cc_hint.unwrap_or(cc), lld_hint.unwrap_or(lld))
}
LinkerFlavor::WasmLld(cc) => LinkerFlavor::WasmLld(cc_hint.unwrap_or(cc)),
LinkerFlavor::Unix(cc) => LinkerFlavor::Unix(cc_hint.unwrap_or(cc)),
LinkerFlavor::Msvc(lld) => LinkerFlavor::Msvc(lld_hint.unwrap_or(lld)),
LinkerFlavor::EmCc | LinkerFlavor::Bpf | LinkerFlavor::Ptx => self,
}
}
pub fn with_cli_hints(self, cli: LinkerFlavorCli) -> LinkerFlavor {
self.with_hints(LinkerFlavor::infer_cli_hints(cli))
}
pub fn with_linker_hints(self, linker_stem: &str) -> LinkerFlavor {
self.with_hints(LinkerFlavor::infer_linker_hints(linker_stem))
}
pub fn check_compatibility(self, cli: LinkerFlavorCli) -> Option<String> {
let compatible = |cli| {
// The CLI flavor should be compatible with the target if:
// 1. they are counterparts: they have the same principal flavor.
match (self, cli) {
(LinkerFlavor::Gnu(..), LinkerFlavorCli::Gnu(..))
| (LinkerFlavor::Darwin(..), LinkerFlavorCli::Darwin(..))
| (LinkerFlavor::WasmLld(..), LinkerFlavorCli::WasmLld(..))
| (LinkerFlavor::Unix(..), LinkerFlavorCli::Unix(..))
| (LinkerFlavor::Msvc(..), LinkerFlavorCli::Msvc(..))
| (LinkerFlavor::EmCc, LinkerFlavorCli::EmCc)
| (LinkerFlavor::Bpf, LinkerFlavorCli::Bpf)
| (LinkerFlavor::Ptx, LinkerFlavorCli::Ptx) => return true,
_ => {}
}
// 2. or, the flavor is legacy and survives this roundtrip.
cli == self.with_cli_hints(cli).to_cli()
};
(!compatible(cli)).then(|| {
LinkerFlavorCli::all()
.iter()
.filter(|cli| compatible(**cli))
.map(|cli| cli.desc())
.intersperse(", ")
.collect()
})
}
pub fn lld_flavor(self) -> LldFlavor {
match self {
LinkerFlavor::Gnu(..)
| LinkerFlavor::Unix(..)
| LinkerFlavor::EmCc
| LinkerFlavor::Bpf
| LinkerFlavor::Ptx => LldFlavor::Ld,
LinkerFlavor::Darwin(..) => LldFlavor::Ld64,
LinkerFlavor::WasmLld(..) => LldFlavor::Wasm,
LinkerFlavor::Msvc(..) => LldFlavor::Link,
}
}
pub fn is_gnu(self) -> bool {
matches!(self, LinkerFlavor::Gnu(..))
}
2023-06-21 15:46:50 +00:00
/// Returns whether the flavor uses the `lld` linker.
pub fn uses_lld(self) -> bool {
// Exhaustive match in case new flavors are added in the future.
match self {
LinkerFlavor::Gnu(_, Lld::Yes)
| LinkerFlavor::Darwin(_, Lld::Yes)
| LinkerFlavor::WasmLld(..)
| LinkerFlavor::EmCc
| LinkerFlavor::Msvc(Lld::Yes) => true,
LinkerFlavor::Gnu(..)
| LinkerFlavor::Darwin(..)
| LinkerFlavor::Msvc(_)
| LinkerFlavor::Unix(_)
| LinkerFlavor::Bpf
| LinkerFlavor::Ptx => false,
}
}
/// Returns whether the flavor calls the linker via a C/C++ compiler.
pub fn uses_cc(self) -> bool {
// Exhaustive match in case new flavors are added in the future.
match self {
LinkerFlavor::Gnu(Cc::Yes, _)
| LinkerFlavor::Darwin(Cc::Yes, _)
| LinkerFlavor::WasmLld(Cc::Yes)
| LinkerFlavor::Unix(Cc::Yes)
| LinkerFlavor::EmCc => true,
LinkerFlavor::Gnu(..)
| LinkerFlavor::Darwin(..)
| LinkerFlavor::WasmLld(_)
| LinkerFlavor::Msvc(_)
| LinkerFlavor::Unix(_)
| LinkerFlavor::Bpf
| LinkerFlavor::Ptx => false,
2023-06-21 15:46:50 +00:00
}
}
}
macro_rules! linker_flavor_cli_impls {
($(($($flavor:tt)*) $string:literal)*) => (
impl LinkerFlavorCli {
const fn all() -> &'static [LinkerFlavorCli] {
&[$($($flavor)*,)*]
}
pub const fn one_of() -> &'static str {
concat!("one of: ", $($string, " ",)*)
}
pub fn from_str(s: &str) -> Option<LinkerFlavorCli> {
Some(match s {
$($string => $($flavor)*,)*
_ => return None,
})
}
pub fn desc(self) -> &'static str {
match self {
$($($flavor)* => $string,)*
}
}
}
)
}
linker_flavor_cli_impls! {
(LinkerFlavorCli::Gnu(Cc::No, Lld::No)) "gnu"
(LinkerFlavorCli::Gnu(Cc::No, Lld::Yes)) "gnu-lld"
(LinkerFlavorCli::Gnu(Cc::Yes, Lld::No)) "gnu-cc"
(LinkerFlavorCli::Gnu(Cc::Yes, Lld::Yes)) "gnu-lld-cc"
(LinkerFlavorCli::Darwin(Cc::No, Lld::No)) "darwin"
(LinkerFlavorCli::Darwin(Cc::No, Lld::Yes)) "darwin-lld"
(LinkerFlavorCli::Darwin(Cc::Yes, Lld::No)) "darwin-cc"
(LinkerFlavorCli::Darwin(Cc::Yes, Lld::Yes)) "darwin-lld-cc"
(LinkerFlavorCli::WasmLld(Cc::No)) "wasm-lld"
(LinkerFlavorCli::WasmLld(Cc::Yes)) "wasm-lld-cc"
(LinkerFlavorCli::Unix(Cc::No)) "unix"
(LinkerFlavorCli::Unix(Cc::Yes)) "unix-cc"
(LinkerFlavorCli::Msvc(Lld::Yes)) "msvc-lld"
(LinkerFlavorCli::Msvc(Lld::No)) "msvc"
(LinkerFlavorCli::EmCc) "em-cc"
(LinkerFlavorCli::Bpf) "bpf"
(LinkerFlavorCli::Ptx) "ptx"
// Legacy stable flavors
(LinkerFlavorCli::Gcc) "gcc"
(LinkerFlavorCli::Ld) "ld"
(LinkerFlavorCli::Lld(LldFlavor::Ld)) "ld.lld"
(LinkerFlavorCli::Lld(LldFlavor::Ld64)) "ld64.lld"
(LinkerFlavorCli::Lld(LldFlavor::Link)) "lld-link"
(LinkerFlavorCli::Lld(LldFlavor::Wasm)) "wasm-ld"
(LinkerFlavorCli::Em) "em"
}
impl ToJson for LinkerFlavorCli {
fn to_json(&self) -> Json {
self.desc().to_json()
}
}
/// The different `-Clink-self-contained` options that can be specified in a target spec:
/// - enabling or disabling in bulk
/// - some target-specific pieces of inference to determine whether to use self-contained linking
/// if `-Clink-self-contained` is not specified explicitly (e.g. on musl/mingw)
/// - explicitly enabling some of the self-contained linking components, e.g. the linker component
/// to use `rust-lld`
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum LinkSelfContainedDefault {
/// The target spec explicitly enables self-contained linking.
True,
/// The target spec explicitly disables self-contained linking.
False,
/// The target spec requests that the self-contained mode is inferred, in the context of musl.
InferredForMusl,
/// The target spec requests that the self-contained mode is inferred, in the context of mingw.
InferredForMingw,
/// The target spec explicitly enables a list of self-contained linking components: e.g. for
/// targets opting into a subset of components like the CLI's `-C link-self-contained=+linker`.
WithComponents(LinkSelfContainedComponents),
}
/// Parses a backwards-compatible `-Clink-self-contained` option string, without components.
impl FromStr for LinkSelfContainedDefault {
type Err = ();
fn from_str(s: &str) -> Result<LinkSelfContainedDefault, ()> {
Ok(match s {
"false" => LinkSelfContainedDefault::False,
"true" | "wasm" => LinkSelfContainedDefault::True,
"musl" => LinkSelfContainedDefault::InferredForMusl,
"mingw" => LinkSelfContainedDefault::InferredForMingw,
_ => return Err(()),
})
}
}
impl ToJson for LinkSelfContainedDefault {
fn to_json(&self) -> Json {
match *self {
LinkSelfContainedDefault::WithComponents(components) => {
// Serialize the components in a json object's `components` field, to prepare for a
// future where `crt-objects-fallback` is removed from the json specs and
// incorporated as a field here.
let mut map = BTreeMap::new();
map.insert("components", components);
map.to_json()
}
// Stable backwards-compatible values
LinkSelfContainedDefault::True => "true".to_json(),
LinkSelfContainedDefault::False => "false".to_json(),
LinkSelfContainedDefault::InferredForMusl => "musl".to_json(),
LinkSelfContainedDefault::InferredForMingw => "mingw".to_json(),
}
}
}
impl LinkSelfContainedDefault {
/// Returns whether the target spec has self-contained linking explicitly disabled. Used to emit
/// errors if the user then enables it on the CLI.
pub fn is_disabled(self) -> bool {
self == LinkSelfContainedDefault::False
}
/// Returns whether the target spec explictly requests self-contained linking, i.e. not via
/// inference.
pub fn is_linker_enabled(self) -> bool {
match self {
LinkSelfContainedDefault::True => true,
LinkSelfContainedDefault::False => false,
LinkSelfContainedDefault::WithComponents(c) => {
c.contains(LinkSelfContainedComponents::LINKER)
}
_ => false,
}
}
/// Returns the key to use when serializing the setting to json:
/// - individual components in a `link-self-contained` object value
/// - the other variants as a backwards-compatible `crt-objects-fallback` string
fn json_key(self) -> &'static str {
match self {
LinkSelfContainedDefault::WithComponents(_) => "link-self-contained",
_ => "crt-objects-fallback",
}
}
}
bitflags::bitflags! {
#[derive(Clone, Copy, PartialEq, Eq, Default)]
/// The `-C link-self-contained` components that can individually be enabled or disabled.
pub struct LinkSelfContainedComponents: u8 {
/// CRT objects (e.g. on `windows-gnu`, `musl`, `wasi` targets)
const CRT_OBJECTS = 1 << 0;
/// libc static library (e.g. on `musl`, `wasi` targets)
const LIBC = 1 << 1;
/// libgcc/libunwind (e.g. on `windows-gnu`, `fuchsia`, `fortanix`, `gnullvm` targets)
const UNWIND = 1 << 2;
/// Linker, dlltool, and their necessary libraries (e.g. on `windows-gnu` and for `rust-lld`)
const LINKER = 1 << 3;
/// Sanitizer runtime libraries
const SANITIZERS = 1 << 4;
/// Other MinGW libs and Windows import libs
const MINGW = 1 << 5;
}
}
rustc_data_structures::external_bitflags_debug! { LinkSelfContainedComponents }
impl LinkSelfContainedComponents {
/// Parses a single `-Clink-self-contained` well-known component, not a set of flags.
pub fn from_str(s: &str) -> Option<LinkSelfContainedComponents> {
Some(match s {
"crto" => LinkSelfContainedComponents::CRT_OBJECTS,
"libc" => LinkSelfContainedComponents::LIBC,
"unwind" => LinkSelfContainedComponents::UNWIND,
"linker" => LinkSelfContainedComponents::LINKER,
"sanitizers" => LinkSelfContainedComponents::SANITIZERS,
"mingw" => LinkSelfContainedComponents::MINGW,
_ => return None,
})
}
/// Return the component's name.
///
/// Returns `None` if the bitflags aren't a singular component (but a mix of multiple flags).
pub fn as_str(self) -> Option<&'static str> {
Some(match self {
LinkSelfContainedComponents::CRT_OBJECTS => "crto",
LinkSelfContainedComponents::LIBC => "libc",
LinkSelfContainedComponents::UNWIND => "unwind",
LinkSelfContainedComponents::LINKER => "linker",
LinkSelfContainedComponents::SANITIZERS => "sanitizers",
LinkSelfContainedComponents::MINGW => "mingw",
_ => return None,
})
}
/// Returns an array of all the components.
fn all_components() -> [LinkSelfContainedComponents; 6] {
[
LinkSelfContainedComponents::CRT_OBJECTS,
LinkSelfContainedComponents::LIBC,
LinkSelfContainedComponents::UNWIND,
LinkSelfContainedComponents::LINKER,
LinkSelfContainedComponents::SANITIZERS,
LinkSelfContainedComponents::MINGW,
]
}
/// Returns whether at least a component is enabled.
pub fn are_any_components_enabled(self) -> bool {
!self.is_empty()
}
/// Returns whether `LinkSelfContainedComponents::LINKER` is enabled.
pub fn is_linker_enabled(self) -> bool {
self.contains(LinkSelfContainedComponents::LINKER)
}
/// Returns whether `LinkSelfContainedComponents::CRT_OBJECTS` is enabled.
pub fn is_crt_objects_enabled(self) -> bool {
self.contains(LinkSelfContainedComponents::CRT_OBJECTS)
}
}
impl ToJson for LinkSelfContainedComponents {
fn to_json(&self) -> Json {
let components: Vec<_> = Self::all_components()
.into_iter()
.filter(|c| self.contains(*c))
.map(|c| {
// We can unwrap because we're iterating over all the known singular components,
// not an actual set of flags where `as_str` can fail.
c.as_str().unwrap().to_owned()
})
.collect();
components.to_json()
}
}
#[derive(Clone, Copy, Debug, PartialEq, Hash, Encodable, Decodable, HashStable_Generic)]
pub enum PanicStrategy {
Unwind,
Abort,
}
impl PanicStrategy {
pub fn desc(&self) -> &str {
match *self {
PanicStrategy::Unwind => "unwind",
PanicStrategy::Abort => "abort",
}
}
2020-07-25 19:02:49 +01:00
pub const fn desc_symbol(&self) -> Symbol {
2020-07-25 19:02:49 +01:00
match *self {
PanicStrategy::Unwind => sym::unwind,
PanicStrategy::Abort => sym::abort,
}
}
pub const fn all() -> [Symbol; 2] {
[Self::Abort.desc_symbol(), Self::Unwind.desc_symbol()]
}
}
impl ToJson for PanicStrategy {
fn to_json(&self) -> Json {
match *self {
PanicStrategy::Abort => "abort".to_json(),
PanicStrategy::Unwind => "unwind".to_json(),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Hash)]
pub enum RelroLevel {
Full,
Partial,
Off,
None,
}
impl RelroLevel {
pub fn desc(&self) -> &str {
match *self {
RelroLevel::Full => "full",
RelroLevel::Partial => "partial",
RelroLevel::Off => "off",
RelroLevel::None => "none",
}
}
}
impl FromStr for RelroLevel {
type Err = ();
fn from_str(s: &str) -> Result<RelroLevel, ()> {
match s {
"full" => Ok(RelroLevel::Full),
"partial" => Ok(RelroLevel::Partial),
"off" => Ok(RelroLevel::Off),
"none" => Ok(RelroLevel::None),
_ => Err(()),
}
}
}
impl ToJson for RelroLevel {
fn to_json(&self) -> Json {
match *self {
RelroLevel::Full => "full".to_json(),
RelroLevel::Partial => "partial".to_json(),
RelroLevel::Off => "off".to_json(),
RelroLevel::None => "None".to_json(),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Hash)]
pub enum MergeFunctions {
Disabled,
Trampolines,
Aliases,
}
impl MergeFunctions {
pub fn desc(&self) -> &str {
match *self {
MergeFunctions::Disabled => "disabled",
MergeFunctions::Trampolines => "trampolines",
MergeFunctions::Aliases => "aliases",
}
}
}
impl FromStr for MergeFunctions {
type Err = ();
fn from_str(s: &str) -> Result<MergeFunctions, ()> {
match s {
"disabled" => Ok(MergeFunctions::Disabled),
"trampolines" => Ok(MergeFunctions::Trampolines),
"aliases" => Ok(MergeFunctions::Aliases),
_ => Err(()),
}
}
}
impl ToJson for MergeFunctions {
fn to_json(&self) -> Json {
match *self {
MergeFunctions::Disabled => "disabled".to_json(),
MergeFunctions::Trampolines => "trampolines".to_json(),
MergeFunctions::Aliases => "aliases".to_json(),
}
}
}
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
pub enum RelocModel {
Static,
Pic,
Pie,
DynamicNoPic,
Ropi,
Rwpi,
RopiRwpi,
}
impl RelocModel {
pub fn desc(&self) -> &str {
match *self {
RelocModel::Static => "static",
RelocModel::Pic => "pic",
RelocModel::Pie => "pie",
RelocModel::DynamicNoPic => "dynamic-no-pic",
RelocModel::Ropi => "ropi",
RelocModel::Rwpi => "rwpi",
RelocModel::RopiRwpi => "ropi-rwpi",
}
}
pub const fn desc_symbol(&self) -> Symbol {
match *self {
RelocModel::Static => kw::Static,
RelocModel::Pic => sym::pic,
RelocModel::Pie => sym::pie,
RelocModel::DynamicNoPic => sym::dynamic_no_pic,
RelocModel::Ropi => sym::ropi,
RelocModel::Rwpi => sym::rwpi,
RelocModel::RopiRwpi => sym::ropi_rwpi,
}
}
pub const fn all() -> [Symbol; 7] {
[
RelocModel::Static.desc_symbol(),
RelocModel::Pic.desc_symbol(),
RelocModel::Pie.desc_symbol(),
RelocModel::DynamicNoPic.desc_symbol(),
RelocModel::Ropi.desc_symbol(),
RelocModel::Rwpi.desc_symbol(),
RelocModel::RopiRwpi.desc_symbol(),
]
}
}
impl FromStr for RelocModel {
type Err = ();
fn from_str(s: &str) -> Result<RelocModel, ()> {
Ok(match s {
"static" => RelocModel::Static,
"pic" => RelocModel::Pic,
"pie" => RelocModel::Pie,
"dynamic-no-pic" => RelocModel::DynamicNoPic,
"ropi" => RelocModel::Ropi,
"rwpi" => RelocModel::Rwpi,
"ropi-rwpi" => RelocModel::RopiRwpi,
_ => return Err(()),
})
}
}
impl ToJson for RelocModel {
fn to_json(&self) -> Json {
self.desc().to_json()
}
}
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
pub enum CodeModel {
Tiny,
Small,
Kernel,
Medium,
Large,
}
impl FromStr for CodeModel {
type Err = ();
fn from_str(s: &str) -> Result<CodeModel, ()> {
Ok(match s {
2020-05-20 23:09:19 +03:00
"tiny" => CodeModel::Tiny,
"small" => CodeModel::Small,
"kernel" => CodeModel::Kernel,
"medium" => CodeModel::Medium,
"large" => CodeModel::Large,
_ => return Err(()),
})
}
}
impl ToJson for CodeModel {
fn to_json(&self) -> Json {
match *self {
CodeModel::Tiny => "tiny",
CodeModel::Small => "small",
CodeModel::Kernel => "kernel",
CodeModel::Medium => "medium",
CodeModel::Large => "large",
}
.to_json()
}
}
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
pub enum TlsModel {
GeneralDynamic,
LocalDynamic,
InitialExec,
LocalExec,
Emulated,
}
impl FromStr for TlsModel {
type Err = ();
fn from_str(s: &str) -> Result<TlsModel, ()> {
Ok(match s {
// Note the difference "general" vs "global" difference. The model name is "general",
// but the user-facing option name is "global" for consistency with other compilers.
"global-dynamic" => TlsModel::GeneralDynamic,
"local-dynamic" => TlsModel::LocalDynamic,
"initial-exec" => TlsModel::InitialExec,
"local-exec" => TlsModel::LocalExec,
"emulated" => TlsModel::Emulated,
_ => return Err(()),
})
}
}
impl ToJson for TlsModel {
fn to_json(&self) -> Json {
match *self {
TlsModel::GeneralDynamic => "global-dynamic",
TlsModel::LocalDynamic => "local-dynamic",
TlsModel::InitialExec => "initial-exec",
TlsModel::LocalExec => "local-exec",
TlsModel::Emulated => "emulated",
}
.to_json()
}
}
/// Everything is flattened to a single enum to make the json encoding/decoding less annoying.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub enum LinkOutputKind {
/// Dynamically linked non position-independent executable.
DynamicNoPicExe,
/// Dynamically linked position-independent executable.
DynamicPicExe,
/// Statically linked non position-independent executable.
StaticNoPicExe,
/// Statically linked position-independent executable.
StaticPicExe,
/// Regular dynamic library ("dynamically linked").
DynamicDylib,
/// Dynamic library with bundled libc ("statically linked").
StaticDylib,
/// WASI module with a lifetime past the _initialize entry point
WasiReactorExe,
}
impl LinkOutputKind {
fn as_str(&self) -> &'static str {
match self {
LinkOutputKind::DynamicNoPicExe => "dynamic-nopic-exe",
LinkOutputKind::DynamicPicExe => "dynamic-pic-exe",
LinkOutputKind::StaticNoPicExe => "static-nopic-exe",
LinkOutputKind::StaticPicExe => "static-pic-exe",
LinkOutputKind::DynamicDylib => "dynamic-dylib",
LinkOutputKind::StaticDylib => "static-dylib",
LinkOutputKind::WasiReactorExe => "wasi-reactor-exe",
}
}
pub(super) fn from_str(s: &str) -> Option<LinkOutputKind> {
Some(match s {
"dynamic-nopic-exe" => LinkOutputKind::DynamicNoPicExe,
"dynamic-pic-exe" => LinkOutputKind::DynamicPicExe,
"static-nopic-exe" => LinkOutputKind::StaticNoPicExe,
"static-pic-exe" => LinkOutputKind::StaticPicExe,
"dynamic-dylib" => LinkOutputKind::DynamicDylib,
"static-dylib" => LinkOutputKind::StaticDylib,
"wasi-reactor-exe" => LinkOutputKind::WasiReactorExe,
_ => return None,
})
}
pub fn can_link_dylib(self) -> bool {
match self {
LinkOutputKind::StaticNoPicExe | LinkOutputKind::StaticPicExe => false,
LinkOutputKind::DynamicNoPicExe
| LinkOutputKind::DynamicPicExe
| LinkOutputKind::DynamicDylib
| LinkOutputKind::StaticDylib
| LinkOutputKind::WasiReactorExe => true,
}
}
}
impl fmt::Display for LinkOutputKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
pub type LinkArgs = BTreeMap<LinkerFlavor, Vec<StaticCow<str>>>;
pub type LinkArgsCli = BTreeMap<LinkerFlavorCli, Vec<StaticCow<str>>>;
/// Which kind of debuginfo does the target use?
///
/// Useful in determining whether a target supports Split DWARF (a target with
/// `DebuginfoKind::Dwarf` and supporting `SplitDebuginfo::Unpacked` for example).
#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
pub enum DebuginfoKind {
/// DWARF debuginfo (such as that used on `x86_64_unknown_linux_gnu`).
#[default]
Dwarf,
/// DWARF debuginfo in dSYM files (such as on Apple platforms).
DwarfDsym,
/// Program database files (such as on Windows).
Pdb,
}
impl DebuginfoKind {
fn as_str(&self) -> &'static str {
match self {
DebuginfoKind::Dwarf => "dwarf",
DebuginfoKind::DwarfDsym => "dwarf-dsym",
DebuginfoKind::Pdb => "pdb",
}
}
}
impl FromStr for DebuginfoKind {
type Err = ();
fn from_str(s: &str) -> Result<Self, ()> {
Ok(match s {
"dwarf" => DebuginfoKind::Dwarf,
"dwarf-dsym" => DebuginfoKind::DwarfDsym,
"pdb" => DebuginfoKind::Pdb,
_ => return Err(()),
})
}
}
impl ToJson for DebuginfoKind {
fn to_json(&self) -> Json {
self.as_str().to_json()
}
}
impl fmt::Display for DebuginfoKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
rustc: Stabilize `-Zrun-dsymutil` as `-Csplit-debuginfo` This commit adds a new stable codegen option to rustc, `-Csplit-debuginfo`. The old `-Zrun-dsymutil` flag is deleted and now subsumed by this stable flag. Additionally `-Zsplit-dwarf` is also subsumed by this flag but still requires `-Zunstable-options` to actually activate. The `-Csplit-debuginfo` flag takes one of three values: * `off` - This indicates that split-debuginfo from the final artifact is not desired. This is not supported on Windows and is the default on Unix platforms except macOS. On macOS this means that `dsymutil` is not executed. * `packed` - This means that debuginfo is desired in one location separate from the main executable. This is the default on Windows (`*.pdb`) and macOS (`*.dSYM`). On other Unix platforms this subsumes `-Zsplit-dwarf=single` and produces a `*.dwp` file. * `unpacked` - This means that debuginfo will be roughly equivalent to object files, meaning that it's throughout the build directory rather than in one location (often the fastest for local development). This is not the default on any platform and is not supported on Windows. Each target can indicate its own default preference for how debuginfo is handled. Almost all platforms default to `off` except for Windows and macOS which default to `packed` for historical reasons. Some equivalencies for previous unstable flags with the new flags are: * `-Zrun-dsymutil=yes` -> `-Csplit-debuginfo=packed` * `-Zrun-dsymutil=no` -> `-Csplit-debuginfo=unpacked` * `-Zsplit-dwarf=single` -> `-Csplit-debuginfo=packed` * `-Zsplit-dwarf=split` -> `-Csplit-debuginfo=unpacked` Note that `-Csplit-debuginfo` still requires `-Zunstable-options` for non-macOS platforms since split-dwarf support was *just* implemented in rustc. There's some more rationale listed on #79361, but the main gist of the motivation for this commit is that `dsymutil` can take quite a long time to execute in debug builds and provides little benefit. This means that incremental compile times appear that much worse on macOS because the compiler is constantly running `dsymutil` over every single binary it produces during `cargo build` (even build scripts!). Ideally rustc would switch to not running `dsymutil` by default, but that's a problem left to get tackled another day. Closes #79361
2020-11-30 08:39:08 -08:00
pub enum SplitDebuginfo {
/// Split debug-information is disabled, meaning that on supported platforms
/// you can find all debug information in the executable itself. This is
/// only supported for ELF effectively.
///
/// * Windows - not supported
/// * macOS - don't run `dsymutil`
/// * ELF - `.debug_*` sections
#[default]
rustc: Stabilize `-Zrun-dsymutil` as `-Csplit-debuginfo` This commit adds a new stable codegen option to rustc, `-Csplit-debuginfo`. The old `-Zrun-dsymutil` flag is deleted and now subsumed by this stable flag. Additionally `-Zsplit-dwarf` is also subsumed by this flag but still requires `-Zunstable-options` to actually activate. The `-Csplit-debuginfo` flag takes one of three values: * `off` - This indicates that split-debuginfo from the final artifact is not desired. This is not supported on Windows and is the default on Unix platforms except macOS. On macOS this means that `dsymutil` is not executed. * `packed` - This means that debuginfo is desired in one location separate from the main executable. This is the default on Windows (`*.pdb`) and macOS (`*.dSYM`). On other Unix platforms this subsumes `-Zsplit-dwarf=single` and produces a `*.dwp` file. * `unpacked` - This means that debuginfo will be roughly equivalent to object files, meaning that it's throughout the build directory rather than in one location (often the fastest for local development). This is not the default on any platform and is not supported on Windows. Each target can indicate its own default preference for how debuginfo is handled. Almost all platforms default to `off` except for Windows and macOS which default to `packed` for historical reasons. Some equivalencies for previous unstable flags with the new flags are: * `-Zrun-dsymutil=yes` -> `-Csplit-debuginfo=packed` * `-Zrun-dsymutil=no` -> `-Csplit-debuginfo=unpacked` * `-Zsplit-dwarf=single` -> `-Csplit-debuginfo=packed` * `-Zsplit-dwarf=split` -> `-Csplit-debuginfo=unpacked` Note that `-Csplit-debuginfo` still requires `-Zunstable-options` for non-macOS platforms since split-dwarf support was *just* implemented in rustc. There's some more rationale listed on #79361, but the main gist of the motivation for this commit is that `dsymutil` can take quite a long time to execute in debug builds and provides little benefit. This means that incremental compile times appear that much worse on macOS because the compiler is constantly running `dsymutil` over every single binary it produces during `cargo build` (even build scripts!). Ideally rustc would switch to not running `dsymutil` by default, but that's a problem left to get tackled another day. Closes #79361
2020-11-30 08:39:08 -08:00
Off,
/// Split debug-information can be found in a "packed" location separate
/// from the final artifact. This is supported on all platforms.
///
/// * Windows - `*.pdb`
/// * macOS - `*.dSYM` (run `dsymutil`)
/// * ELF - `*.dwp` (run `thorin`)
rustc: Stabilize `-Zrun-dsymutil` as `-Csplit-debuginfo` This commit adds a new stable codegen option to rustc, `-Csplit-debuginfo`. The old `-Zrun-dsymutil` flag is deleted and now subsumed by this stable flag. Additionally `-Zsplit-dwarf` is also subsumed by this flag but still requires `-Zunstable-options` to actually activate. The `-Csplit-debuginfo` flag takes one of three values: * `off` - This indicates that split-debuginfo from the final artifact is not desired. This is not supported on Windows and is the default on Unix platforms except macOS. On macOS this means that `dsymutil` is not executed. * `packed` - This means that debuginfo is desired in one location separate from the main executable. This is the default on Windows (`*.pdb`) and macOS (`*.dSYM`). On other Unix platforms this subsumes `-Zsplit-dwarf=single` and produces a `*.dwp` file. * `unpacked` - This means that debuginfo will be roughly equivalent to object files, meaning that it's throughout the build directory rather than in one location (often the fastest for local development). This is not the default on any platform and is not supported on Windows. Each target can indicate its own default preference for how debuginfo is handled. Almost all platforms default to `off` except for Windows and macOS which default to `packed` for historical reasons. Some equivalencies for previous unstable flags with the new flags are: * `-Zrun-dsymutil=yes` -> `-Csplit-debuginfo=packed` * `-Zrun-dsymutil=no` -> `-Csplit-debuginfo=unpacked` * `-Zsplit-dwarf=single` -> `-Csplit-debuginfo=packed` * `-Zsplit-dwarf=split` -> `-Csplit-debuginfo=unpacked` Note that `-Csplit-debuginfo` still requires `-Zunstable-options` for non-macOS platforms since split-dwarf support was *just* implemented in rustc. There's some more rationale listed on #79361, but the main gist of the motivation for this commit is that `dsymutil` can take quite a long time to execute in debug builds and provides little benefit. This means that incremental compile times appear that much worse on macOS because the compiler is constantly running `dsymutil` over every single binary it produces during `cargo build` (even build scripts!). Ideally rustc would switch to not running `dsymutil` by default, but that's a problem left to get tackled another day. Closes #79361
2020-11-30 08:39:08 -08:00
Packed,
/// Split debug-information can be found in individual object files on the
/// filesystem. The main executable may point to the object files.
///
/// * Windows - not supported
/// * macOS - supported, scattered object files
/// * ELF - supported, scattered `*.dwo` or `*.o` files (see `SplitDwarfKind`)
rustc: Stabilize `-Zrun-dsymutil` as `-Csplit-debuginfo` This commit adds a new stable codegen option to rustc, `-Csplit-debuginfo`. The old `-Zrun-dsymutil` flag is deleted and now subsumed by this stable flag. Additionally `-Zsplit-dwarf` is also subsumed by this flag but still requires `-Zunstable-options` to actually activate. The `-Csplit-debuginfo` flag takes one of three values: * `off` - This indicates that split-debuginfo from the final artifact is not desired. This is not supported on Windows and is the default on Unix platforms except macOS. On macOS this means that `dsymutil` is not executed. * `packed` - This means that debuginfo is desired in one location separate from the main executable. This is the default on Windows (`*.pdb`) and macOS (`*.dSYM`). On other Unix platforms this subsumes `-Zsplit-dwarf=single` and produces a `*.dwp` file. * `unpacked` - This means that debuginfo will be roughly equivalent to object files, meaning that it's throughout the build directory rather than in one location (often the fastest for local development). This is not the default on any platform and is not supported on Windows. Each target can indicate its own default preference for how debuginfo is handled. Almost all platforms default to `off` except for Windows and macOS which default to `packed` for historical reasons. Some equivalencies for previous unstable flags with the new flags are: * `-Zrun-dsymutil=yes` -> `-Csplit-debuginfo=packed` * `-Zrun-dsymutil=no` -> `-Csplit-debuginfo=unpacked` * `-Zsplit-dwarf=single` -> `-Csplit-debuginfo=packed` * `-Zsplit-dwarf=split` -> `-Csplit-debuginfo=unpacked` Note that `-Csplit-debuginfo` still requires `-Zunstable-options` for non-macOS platforms since split-dwarf support was *just* implemented in rustc. There's some more rationale listed on #79361, but the main gist of the motivation for this commit is that `dsymutil` can take quite a long time to execute in debug builds and provides little benefit. This means that incremental compile times appear that much worse on macOS because the compiler is constantly running `dsymutil` over every single binary it produces during `cargo build` (even build scripts!). Ideally rustc would switch to not running `dsymutil` by default, but that's a problem left to get tackled another day. Closes #79361
2020-11-30 08:39:08 -08:00
Unpacked,
}
impl SplitDebuginfo {
fn as_str(&self) -> &'static str {
match self {
SplitDebuginfo::Off => "off",
SplitDebuginfo::Packed => "packed",
SplitDebuginfo::Unpacked => "unpacked",
}
}
}
impl FromStr for SplitDebuginfo {
type Err = ();
fn from_str(s: &str) -> Result<Self, ()> {
rustc: Stabilize `-Zrun-dsymutil` as `-Csplit-debuginfo` This commit adds a new stable codegen option to rustc, `-Csplit-debuginfo`. The old `-Zrun-dsymutil` flag is deleted and now subsumed by this stable flag. Additionally `-Zsplit-dwarf` is also subsumed by this flag but still requires `-Zunstable-options` to actually activate. The `-Csplit-debuginfo` flag takes one of three values: * `off` - This indicates that split-debuginfo from the final artifact is not desired. This is not supported on Windows and is the default on Unix platforms except macOS. On macOS this means that `dsymutil` is not executed. * `packed` - This means that debuginfo is desired in one location separate from the main executable. This is the default on Windows (`*.pdb`) and macOS (`*.dSYM`). On other Unix platforms this subsumes `-Zsplit-dwarf=single` and produces a `*.dwp` file. * `unpacked` - This means that debuginfo will be roughly equivalent to object files, meaning that it's throughout the build directory rather than in one location (often the fastest for local development). This is not the default on any platform and is not supported on Windows. Each target can indicate its own default preference for how debuginfo is handled. Almost all platforms default to `off` except for Windows and macOS which default to `packed` for historical reasons. Some equivalencies for previous unstable flags with the new flags are: * `-Zrun-dsymutil=yes` -> `-Csplit-debuginfo=packed` * `-Zrun-dsymutil=no` -> `-Csplit-debuginfo=unpacked` * `-Zsplit-dwarf=single` -> `-Csplit-debuginfo=packed` * `-Zsplit-dwarf=split` -> `-Csplit-debuginfo=unpacked` Note that `-Csplit-debuginfo` still requires `-Zunstable-options` for non-macOS platforms since split-dwarf support was *just* implemented in rustc. There's some more rationale listed on #79361, but the main gist of the motivation for this commit is that `dsymutil` can take quite a long time to execute in debug builds and provides little benefit. This means that incremental compile times appear that much worse on macOS because the compiler is constantly running `dsymutil` over every single binary it produces during `cargo build` (even build scripts!). Ideally rustc would switch to not running `dsymutil` by default, but that's a problem left to get tackled another day. Closes #79361
2020-11-30 08:39:08 -08:00
Ok(match s {
"off" => SplitDebuginfo::Off,
"unpacked" => SplitDebuginfo::Unpacked,
"packed" => SplitDebuginfo::Packed,
_ => return Err(()),
})
}
}
impl ToJson for SplitDebuginfo {
fn to_json(&self) -> Json {
self.as_str().to_json()
}
}
impl fmt::Display for SplitDebuginfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum StackProbeType {
/// Don't emit any stack probes.
None,
/// It is harmless to use this option even on targets that do not have backend support for
/// stack probes as the failure mode is the same as if no stack-probe option was specified in
/// the first place.
Inline,
/// Call `__rust_probestack` whenever stack needs to be probed.
Call,
/// Use inline option for LLVM versions later than specified in `min_llvm_version_for_inline`
/// and call `__rust_probestack` otherwise.
InlineOrCall { min_llvm_version_for_inline: (u32, u32, u32) },
}
impl StackProbeType {
fn from_json(json: &Json) -> Result<Self, String> {
let object = json.as_object().ok_or_else(|| "expected a JSON object")?;
let kind = object
.get("kind")
2021-06-03 17:45:09 +02:00
.and_then(|o| o.as_str())
.ok_or_else(|| "expected `kind` to be a string")?;
match kind {
"none" => Ok(StackProbeType::None),
"inline" => Ok(StackProbeType::Inline),
"call" => Ok(StackProbeType::Call),
"inline-or-call" => {
let min_version = object
.get("min-llvm-version-for-inline")
.and_then(|o| o.as_array())
.ok_or_else(|| "expected `min-llvm-version-for-inline` to be an array")?;
let mut iter = min_version.into_iter().map(|v| {
let int = v.as_u64().ok_or_else(
|| "expected `min-llvm-version-for-inline` values to be integers",
)?;
u32::try_from(int)
.map_err(|_| "`min-llvm-version-for-inline` values don't convert to u32")
});
let min_llvm_version_for_inline = (
iter.next().unwrap_or(Ok(11))?,
iter.next().unwrap_or(Ok(0))?,
iter.next().unwrap_or(Ok(0))?,
);
Ok(StackProbeType::InlineOrCall { min_llvm_version_for_inline })
}
_ => Err(String::from(
"`kind` expected to be one of `none`, `inline`, `call` or `inline-or-call`",
)),
}
}
}
impl ToJson for StackProbeType {
fn to_json(&self) -> Json {
Json::Object(match self {
StackProbeType::None => {
[(String::from("kind"), "none".to_json())].into_iter().collect()
}
StackProbeType::Inline => {
[(String::from("kind"), "inline".to_json())].into_iter().collect()
}
StackProbeType::Call => {
[(String::from("kind"), "call".to_json())].into_iter().collect()
}
2021-06-03 17:45:09 +02:00
StackProbeType::InlineOrCall { min_llvm_version_for_inline: (maj, min, patch) } => [
(String::from("kind"), "inline-or-call".to_json()),
(
String::from("min-llvm-version-for-inline"),
2021-06-03 17:45:09 +02:00
Json::Array(vec![maj.to_json(), min.to_json(), patch.to_json()]),
),
]
.into_iter()
.collect(),
})
}
}
#[derive(Default, Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, HashStable_Generic)]
pub struct SanitizerSet(u16);
2021-02-07 23:47:03 +02:00
bitflags::bitflags! {
impl SanitizerSet: u16 {
2021-02-07 23:47:03 +02:00
const ADDRESS = 1 << 0;
const LEAK = 1 << 1;
const MEMORY = 1 << 2;
const THREAD = 1 << 3;
const HWADDRESS = 1 << 4;
const CFI = 1 << 5;
const MEMTAG = 1 << 6;
const SHADOWCALLSTACK = 1 << 7;
const KCFI = 1 << 8;
const KERNELADDRESS = 1 << 9;
const SAFESTACK = 1 << 10;
const DATAFLOW = 1 << 11;
2021-02-07 23:47:03 +02:00
}
}
rustc_data_structures::external_bitflags_debug! { SanitizerSet }
2021-02-07 23:47:03 +02:00
impl SanitizerSet {
/// Return sanitizer's name
///
/// Returns none if the flags is a set of sanitizers numbering not exactly one.
pub fn as_str(self) -> Option<&'static str> {
Some(match self {
SanitizerSet::ADDRESS => "address",
SanitizerSet::CFI => "cfi",
SanitizerSet::DATAFLOW => "dataflow",
SanitizerSet::KCFI => "kcfi",
SanitizerSet::KERNELADDRESS => "kernel-address",
SanitizerSet::LEAK => "leak",
SanitizerSet::MEMORY => "memory",
SanitizerSet::MEMTAG => "memtag",
SanitizerSet::SAFESTACK => "safestack",
SanitizerSet::SHADOWCALLSTACK => "shadow-call-stack",
SanitizerSet::THREAD => "thread",
SanitizerSet::HWADDRESS => "hwaddress",
_ => return None,
})
}
}
2021-02-07 23:47:03 +02:00
/// Formats a sanitizer set as a comma separated list of sanitizers' names.
impl fmt::Display for SanitizerSet {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut first = true;
for s in *self {
let name = s.as_str().unwrap_or_else(|| panic!("unrecognized sanitizer {s:?}"));
2021-02-07 23:47:03 +02:00
if !first {
f.write_str(", ")?;
2021-02-07 23:47:03 +02:00
}
f.write_str(name)?;
first = false;
}
Ok(())
}
}
impl ToJson for SanitizerSet {
fn to_json(&self) -> Json {
self.into_iter()
.map(|v| Some(v.as_str()?.to_json()))
.collect::<Option<Vec<_>>>()
2021-08-31 00:54:48 +02:00
.unwrap_or_default()
.to_json()
}
}
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
pub enum FramePointer {
/// Forces the machine code generator to always preserve the frame pointers.
Always,
/// Forces the machine code generator to preserve the frame pointers except for the leaf
/// functions (i.e. those that don't call other functions).
NonLeaf,
/// Allows the machine code generator to omit the frame pointers.
///
/// This option does not guarantee that the frame pointers will be omitted.
MayOmit,
}
impl FromStr for FramePointer {
type Err = ();
fn from_str(s: &str) -> Result<Self, ()> {
Ok(match s {
"always" => Self::Always,
"non-leaf" => Self::NonLeaf,
"may-omit" => Self::MayOmit,
_ => return Err(()),
})
}
}
impl ToJson for FramePointer {
fn to_json(&self) -> Json {
match *self {
Self::Always => "always",
Self::NonLeaf => "non-leaf",
Self::MayOmit => "may-omit",
}
.to_json()
}
}
add rustc option for using LLVM stack smash protection LLVM has built-in heuristics for adding stack canaries to functions. These heuristics can be selected with LLVM function attributes. This patch adds a rustc option `-Z stack-protector={none,basic,strong,all}` which controls the use of these attributes. This gives rustc the same stack smash protection support as clang offers through options `-fno-stack-protector`, `-fstack-protector`, `-fstack-protector-strong`, and `-fstack-protector-all`. The protection this can offer is demonstrated in test/ui/abi/stack-protector.rs. This fills a gap in the current list of rustc exploit mitigations (https://doc.rust-lang.org/rustc/exploit-mitigations.html), originally discussed in #15179. Stack smash protection adds runtime overhead and is therefore still off by default, but now users have the option to trade performance for security as they see fit. An example use case is adding Rust code in an existing C/C++ code base compiled with stack smash protection. Without the ability to add stack smash protection to the Rust code, the code base artifacts could be exploitable in ways not possible if the code base remained pure C/C++. Stack smash protection support is present in LLVM for almost all the current tier 1/tier 2 targets: see test/assembly/stack-protector/stack-protector-target-support.rs. The one exception is nvptx64-nvidia-cuda. This patch follows clang's example, and adds a warning message printed if stack smash protection is used with this target (see test/ui/stack-protector/warn-stack-protector-unsupported.rs). Support for tier 3 targets has not been checked. Since the heuristics are applied at the LLVM level, the heuristics are expected to add stack smash protection to a fraction of functions comparable to C/C++. Some experiments demonstrating how Rust code is affected by the different heuristics can be found in test/assembly/stack-protector/stack-protector-heuristics-effect.rs. There is potential for better heuristics using Rust-specific safety information. For example it might be reasonable to skip stack smash protection in functions which transitively only use safe Rust code, or which uses only a subset of functions the user declares safe (such as anything under `std.*`). Such alternative heuristics could be added at a later point. LLVM also offers a "safestack" sanitizer as an alternative way to guard against stack smashing (see #26612). This could possibly also be included as a stack-protection heuristic. An alternative is to add it as a sanitizer (#39699). This is what clang does: safestack is exposed with option `-fsanitize=safe-stack`. The options are only supported by the LLVM backend, but as with other codegen options it is visible in the main codegen option help menu. The heuristic names "basic", "strong", and "all" are hopefully sufficiently generic to be usable in other backends as well. Reviewed-by: Nikita Popov <nikic@php.net> Extra commits during review: - [address-review] make the stack-protector option unstable - [address-review] reduce detail level of stack-protector option help text - [address-review] correct grammar in comment - [address-review] use compiler flag to avoid merging functions in test - [address-review] specify min LLVM version in fortanix stack-protector test Only for Fortanix test, since this target specifically requests the `--x86-experimental-lvi-inline-asm-hardening` flag. - [address-review] specify required LLVM components in stack-protector tests - move stack protector option enum closer to other similar option enums - rustc_interface/tests: sort debug option list in tracking hash test - add an explicit `none` stack-protector option Revert "set LLVM requirements for all stack protector support test revisions" This reverts commit a49b74f92a4e7d701d6f6cf63d207a8aff2e0f68.
2021-04-06 21:37:49 +02:00
/// Controls use of stack canaries.
#[derive(Clone, Copy, Debug, PartialEq, Hash, Eq)]
pub enum StackProtector {
/// Disable stack canary generation.
None,
/// On LLVM, mark all generated LLVM functions with the `ssp` attribute (see
/// llvm/docs/LangRef.rst). This triggers stack canary generation in
/// functions which contain an array of a byte-sized type with more than
/// eight elements.
Basic,
/// On LLVM, mark all generated LLVM functions with the `sspstrong`
/// attribute (see llvm/docs/LangRef.rst). This triggers stack canary
/// generation in functions which either contain an array, or which take
/// the address of a local variable.
Strong,
/// Generate stack canaries in all functions.
All,
}
impl StackProtector {
fn as_str(&self) -> &'static str {
match self {
StackProtector::None => "none",
StackProtector::Basic => "basic",
StackProtector::Strong => "strong",
StackProtector::All => "all",
}
}
}
impl FromStr for StackProtector {
type Err = ();
fn from_str(s: &str) -> Result<StackProtector, ()> {
Ok(match s {
"none" => StackProtector::None,
"basic" => StackProtector::Basic,
"strong" => StackProtector::Strong,
"all" => StackProtector::All,
_ => return Err(()),
})
}
}
impl fmt::Display for StackProtector {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
2021-02-07 23:47:03 +02:00
macro_rules! supported_targets {
( $(($triple:literal, $module:ident),)+ ) => {
mod targets {
$(pub(crate) mod $module;)+
}
2021-02-07 23:47:03 +02:00
/// List of supported targets
pub const TARGETS: &[&str] = &[$($triple),+];
2021-02-07 23:47:03 +02:00
fn load_builtin(target: &str) -> Option<Target> {
let mut t = match target {
$( $triple => targets::$module::target(), )+
2021-02-07 23:47:03 +02:00
_ => return None,
};
t.is_builtin = true;
debug!("got builtin target: {:?}", t);
Some(t)
}
#[cfg(test)]
mod tests {
mod tests_impl;
// Cannot put this into a separate file without duplication, make an exception.
$(
#[test] // `#[test]`
fn $module() {
tests_impl::test_target(crate::spec::targets::$module::target());
2021-02-07 23:47:03 +02:00
}
)+
}
};
}
supported_targets! {
("x86_64-unknown-linux-gnu", x86_64_unknown_linux_gnu),
2017-10-11 16:15:42 -03:00
("x86_64-unknown-linux-gnux32", x86_64_unknown_linux_gnux32),
("i686-unknown-linux-gnu", i686_unknown_linux_gnu),
2016-02-13 17:03:00 +01:00
("i586-unknown-linux-gnu", i586_unknown_linux_gnu),
("loongarch64-unknown-linux-gnu", loongarch64_unknown_linux_gnu),
("loongarch64-unknown-linux-musl", loongarch64_unknown_linux_musl),
("m68k-unknown-linux-gnu", m68k_unknown_linux_gnu),
("csky-unknown-linux-gnuabiv2", csky_unknown_linux_gnuabiv2),
("csky-unknown-linux-gnuabiv2hf", csky_unknown_linux_gnuabiv2hf),
("mips-unknown-linux-gnu", mips_unknown_linux_gnu),
("mips64-unknown-linux-gnuabi64", mips64_unknown_linux_gnuabi64),
("mips64el-unknown-linux-gnuabi64", mips64el_unknown_linux_gnuabi64),
("mipsisa32r6-unknown-linux-gnu", mipsisa32r6_unknown_linux_gnu),
("mipsisa32r6el-unknown-linux-gnu", mipsisa32r6el_unknown_linux_gnu),
("mipsisa64r6-unknown-linux-gnuabi64", mipsisa64r6_unknown_linux_gnuabi64),
("mipsisa64r6el-unknown-linux-gnuabi64", mipsisa64r6el_unknown_linux_gnuabi64),
("mipsel-unknown-linux-gnu", mipsel_unknown_linux_gnu),
("powerpc-unknown-linux-gnu", powerpc_unknown_linux_gnu),
("powerpc-unknown-linux-gnuspe", powerpc_unknown_linux_gnuspe),
2018-09-10 01:35:35 +00:00
("powerpc-unknown-linux-musl", powerpc_unknown_linux_musl),
2022-08-25 14:37:29 +08:00
("powerpc64-ibm-aix", powerpc64_ibm_aix),
("powerpc64-unknown-linux-gnu", powerpc64_unknown_linux_gnu),
("powerpc64-unknown-linux-musl", powerpc64_unknown_linux_musl),
("powerpc64le-unknown-linux-gnu", powerpc64le_unknown_linux_gnu),
("powerpc64le-unknown-linux-musl", powerpc64le_unknown_linux_musl),
("s390x-unknown-linux-gnu", s390x_unknown_linux_gnu),
2021-02-16 00:46:14 +00:00
("s390x-unknown-linux-musl", s390x_unknown_linux_musl),
("sparc-unknown-linux-gnu", sparc_unknown_linux_gnu),
2018-01-04 14:55:04 -02:00
("sparc64-unknown-linux-gnu", sparc64_unknown_linux_gnu),
("arm-unknown-linux-gnueabi", arm_unknown_linux_gnueabi),
("arm-unknown-linux-gnueabihf", arm_unknown_linux_gnueabihf),
("armeb-unknown-linux-gnueabi", armeb_unknown_linux_gnueabi),
2016-04-27 18:02:31 -07:00
("arm-unknown-linux-musleabi", arm_unknown_linux_musleabi),
("arm-unknown-linux-musleabihf", arm_unknown_linux_musleabihf),
("armv4t-unknown-linux-gnueabi", armv4t_unknown_linux_gnueabi),
2016-11-06 13:06:01 +01:00
("armv5te-unknown-linux-gnueabi", armv5te_unknown_linux_gnueabi),
2018-05-04 08:47:24 +02:00
("armv5te-unknown-linux-musleabi", armv5te_unknown_linux_musleabi),
("armv5te-unknown-linux-uclibceabi", armv5te_unknown_linux_uclibceabi),
("armv7-unknown-linux-gnueabi", armv7_unknown_linux_gnueabi),
("armv7-unknown-linux-gnueabihf", armv7_unknown_linux_gnueabihf),
("thumbv7neon-unknown-linux-gnueabihf", thumbv7neon_unknown_linux_gnueabihf),
("thumbv7neon-unknown-linux-musleabihf", thumbv7neon_unknown_linux_musleabihf),
("armv7-unknown-linux-musleabi", armv7_unknown_linux_musleabi),
2016-04-27 18:02:31 -07:00
("armv7-unknown-linux-musleabihf", armv7_unknown_linux_musleabihf),
("aarch64-unknown-linux-gnu", aarch64_unknown_linux_gnu),
("aarch64-unknown-linux-musl", aarch64_unknown_linux_musl),
("x86_64-unknown-linux-musl", x86_64_unknown_linux_musl),
("i686-unknown-linux-musl", i686_unknown_linux_musl),
2018-01-04 14:55:04 -02:00
("i586-unknown-linux-musl", i586_unknown_linux_musl),
("mips-unknown-linux-musl", mips_unknown_linux_musl),
("mipsel-unknown-linux-musl", mipsel_unknown_linux_musl),
("mips64-unknown-linux-muslabi64", mips64_unknown_linux_muslabi64),
("mips64el-unknown-linux-muslabi64", mips64el_unknown_linux_muslabi64),
("hexagon-unknown-linux-musl", hexagon_unknown_linux_musl),
("hexagon-unknown-none-elf", hexagon_unknown_none_elf),
2018-01-04 14:55:04 -02:00
("mips-unknown-linux-uclibc", mips_unknown_linux_uclibc),
("mipsel-unknown-linux-uclibc", mipsel_unknown_linux_uclibc),
("i686-linux-android", i686_linux_android),
2017-04-20 14:02:42 -03:00
("x86_64-linux-android", x86_64_linux_android),
("arm-linux-androideabi", arm_linux_androideabi),
2016-05-05 01:08:14 +03:00
("armv7-linux-androideabi", armv7_linux_androideabi),
("thumbv7neon-linux-androideabi", thumbv7neon_linux_androideabi),
("aarch64-linux-android", aarch64_linux_android),
("riscv64-linux-android", riscv64_linux_android),
("aarch64-unknown-freebsd", aarch64_unknown_freebsd),
2019-02-02 16:41:38 +01:00
("armv6-unknown-freebsd", armv6_unknown_freebsd),
("armv7-unknown-freebsd", armv7_unknown_freebsd),
("i686-unknown-freebsd", i686_unknown_freebsd),
("powerpc-unknown-freebsd", powerpc_unknown_freebsd),
2019-01-21 18:50:54 +01:00
("powerpc64-unknown-freebsd", powerpc64_unknown_freebsd),
("powerpc64le-unknown-freebsd", powerpc64le_unknown_freebsd),
2021-11-27 07:23:55 +01:00
("riscv64gc-unknown-freebsd", riscv64gc_unknown_freebsd),
("x86_64-unknown-freebsd", x86_64_unknown_freebsd),
("x86_64-unknown-dragonfly", x86_64_unknown_dragonfly),
2018-05-12 09:45:35 +02:00
("aarch64-unknown-openbsd", aarch64_unknown_openbsd),
2016-11-29 18:49:09 +01:00
("i686-unknown-openbsd", i686_unknown_openbsd),
("powerpc-unknown-openbsd", powerpc_unknown_openbsd),
2022-08-28 05:16:02 +00:00
("powerpc64-unknown-openbsd", powerpc64_unknown_openbsd),
("riscv64gc-unknown-openbsd", riscv64gc_unknown_openbsd),
("sparc64-unknown-openbsd", sparc64_unknown_openbsd),
("x86_64-unknown-openbsd", x86_64_unknown_openbsd),
2016-11-29 18:49:09 +01:00
2018-08-04 16:53:52 -05:00
("aarch64-unknown-netbsd", aarch64_unknown_netbsd),
("aarch64_be-unknown-netbsd", aarch64_be_unknown_netbsd),
2018-05-18 09:26:53 -05:00
("armv6-unknown-netbsd-eabihf", armv6_unknown_netbsd_eabihf),
2018-05-18 09:26:53 -05:00
("armv7-unknown-netbsd-eabihf", armv7_unknown_netbsd_eabihf),
("i586-unknown-netbsd", i586_unknown_netbsd),
("i686-unknown-netbsd", i686_unknown_netbsd),
("mipsel-unknown-netbsd", mipsel_unknown_netbsd),
2018-02-16 14:29:24 -06:00
("powerpc-unknown-netbsd", powerpc_unknown_netbsd),
("riscv64gc-unknown-netbsd", riscv64gc_unknown_netbsd),
2016-12-03 08:53:13 -06:00
("sparc64-unknown-netbsd", sparc64_unknown_netbsd),
("x86_64-unknown-netbsd", x86_64_unknown_netbsd),
2016-09-30 13:17:22 -05:00
("i686-unknown-haiku", i686_unknown_haiku),
("x86_64-unknown-haiku", x86_64_unknown_haiku),
2023-09-19 12:41:30 +02:00
("i686-unknown-hurd-gnu", i686_unknown_hurd_gnu),
("aarch64-apple-darwin", aarch64_apple_darwin),
2023-11-15 14:56:27 +04:00
("arm64e-apple-darwin", arm64e_apple_darwin),
("x86_64-apple-darwin", x86_64_apple_darwin),
("x86_64h-apple-darwin", x86_64h_apple_darwin),
("i686-apple-darwin", i686_apple_darwin),
2023-01-09 13:23:50 -05:00
// FIXME(#106649): Remove aarch64-fuchsia in favor of aarch64-unknown-fuchsia
("aarch64-fuchsia", aarch64_fuchsia),
("aarch64-unknown-fuchsia", aarch64_unknown_fuchsia),
("riscv64gc-unknown-fuchsia", riscv64gc_unknown_fuchsia),
2023-01-09 13:23:50 -05:00
// FIXME(#106649): Remove x86_64-fuchsia in favor of x86_64-unknown-fuchsia
("x86_64-fuchsia", x86_64_fuchsia),
("x86_64-unknown-fuchsia", x86_64_unknown_fuchsia),
("avr-unknown-gnu-atmega328", avr_unknown_gnu_atmega328),
2016-05-06 09:32:10 -04:00
("x86_64-unknown-l4re-uclibc", x86_64_unknown_l4re_uclibc),
2019-04-07 08:39:54 -06:00
("aarch64-unknown-redox", aarch64_unknown_redox),
2016-12-12 19:53:51 -07:00
("x86_64-unknown-redox", x86_64_unknown_redox),
("i386-apple-ios", i386_apple_ios),
("x86_64-apple-ios", x86_64_apple_ios),
("aarch64-apple-ios", aarch64_apple_ios),
2023-11-15 14:55:18 +04:00
("arm64e-apple-ios", arm64e_apple_ios),
("armv7s-apple-ios", armv7s_apple_ios),
("x86_64-apple-ios-macabi", x86_64_apple_ios_macabi),
("aarch64-apple-ios-macabi", aarch64_apple_ios_macabi),
("aarch64-apple-ios-sim", aarch64_apple_ios_sim),
2020-01-10 18:48:37 -08:00
("aarch64-apple-tvos", aarch64_apple_tvos),
("aarch64-apple-tvos-sim", aarch64_apple_tvos_sim),
2020-01-10 18:48:37 -08:00
("x86_64-apple-tvos", x86_64_apple_tvos),
2022-03-23 14:54:58 +00:00
("armv7k-apple-watchos", armv7k_apple_watchos),
("arm64_32-apple-watchos", arm64_32_apple_watchos),
("x86_64-apple-watchos-sim", x86_64_apple_watchos_sim),
("aarch64-apple-watchos", aarch64_apple_watchos),
2022-03-23 14:54:58 +00:00
("aarch64-apple-watchos-sim", aarch64_apple_watchos_sim),
2018-08-24 19:32:49 +02:00
("armebv7r-none-eabi", armebv7r_none_eabi),
("armebv7r-none-eabihf", armebv7r_none_eabihf),
2018-08-24 19:16:20 +02:00
("armv7r-none-eabi", armv7r_none_eabi),
2018-08-24 19:32:49 +02:00
("armv7r-none-eabihf", armv7r_none_eabihf),
("armv8r-none-eabihf", armv8r_none_eabihf),
("x86_64-pc-solaris", x86_64_pc_solaris),
("sparcv9-sun-solaris", sparcv9_sun_solaris),
("x86_64-unknown-illumos", x86_64_unknown_illumos),
("aarch64-unknown-illumos", aarch64_unknown_illumos),
("x86_64-pc-windows-gnu", x86_64_pc_windows_gnu),
("i686-pc-windows-gnu", i686_pc_windows_gnu),
2019-05-27 17:18:14 +02:00
("i686-uwp-windows-gnu", i686_uwp_windows_gnu),
("x86_64-uwp-windows-gnu", x86_64_uwp_windows_gnu),
2022-03-06 15:12:50 +01:00
("aarch64-pc-windows-gnullvm", aarch64_pc_windows_gnullvm),
2023-09-08 22:37:06 +02:00
("i686-pc-windows-gnullvm", i686_pc_windows_gnullvm),
2022-03-06 15:12:50 +01:00
("x86_64-pc-windows-gnullvm", x86_64_pc_windows_gnullvm),
("aarch64-pc-windows-msvc", aarch64_pc_windows_msvc),
2019-07-31 15:00:34 +07:00
("aarch64-uwp-windows-msvc", aarch64_uwp_windows_msvc),
Add arm64ec-pc-windows-msvc target Introduces the `arm64ec-pc-windows-msvc` target for building Arm64EC ("Emulation Compatible") binaries for Windows. For more information about Arm64EC see <https://learn.microsoft.com/en-us/windows/arm/arm64ec>. Tier 3 policy: > A tier 3 target must have a designated developer or developers (the "target maintainers") on record to be CCed when issues arise regarding the target. (The mechanism to track and CC such developers may evolve over time.) I will be the maintainer for this target. > Targets must use naming consistent with any existing targets; for instance, a target for the same CPU or OS as an existing Rust target should use the same name for that CPU or OS. Targets should normally use the same names and naming conventions as used elsewhere in the broader ecosystem beyond Rust (such as in other toolchains), unless they have a very good reason to diverge. Changing the name of a target can be highly disruptive, especially once the target reaches a higher tier, so getting the name right is important even for a tier 3 target. Target uses the `arm64ec` architecture to match LLVM and MSVC, and the `-pc-windows-msvc` suffix to indicate that it targets Windows via the MSVC environment. > Target names should not introduce undue confusion or ambiguity unless absolutely necessary to maintain ecosystem compatibility. For example, if the name of the target makes people extremely likely to form incorrect beliefs about what it targets, the name should be changed or augmented to disambiguate it. Target name exactly specifies the type of code that will be produced. > If possible, use only letters, numbers, dashes and underscores for the name. Periods (.) are known to cause issues in Cargo. Done. > Tier 3 targets may have unusual requirements to build or use, but must not create legal issues or impose onerous legal terms for the Rust project or for Rust developers or users. > The target must not introduce license incompatibilities. Uses the same dependencies, requirements and licensing as the other `*-pc-windows-msvc` targets. > Anything added to the Rust repository must be under the standard Rust license (MIT OR Apache-2.0). Understood. > The target must not cause the Rust tools or libraries built for any other host (even when supporting cross-compilation to the target) to depend on any new dependency less permissive than the Rust licensing policy. This applies whether the dependency is a Rust crate that would require adding new license exceptions (as specified by the tidy tool in the rust-lang/rust repository), or whether the dependency is a native library or binary. In other words, the introduction of the target must not cause a user installing or running a version of Rust or the Rust tools to be subject to any new license requirements. > Compiling, linking, and emitting functional binaries, libraries, or other code for the target (whether hosted on the target itself or cross-compiling from another target) must not depend on proprietary (non-FOSS) libraries. Host tools built for the target itself may depend on the ordinary runtime libraries supplied by the platform and commonly used by other applications built for the target, but those libraries must not be required for code generation for the target; cross-compilation to the target must not require such libraries at all. For instance, rustc built for the target may depend on a common proprietary C runtime library or console output library, but must not depend on a proprietary code generation library or code optimization library. Rust's license permits such combinations, but the Rust project has no interest in maintaining such combinations within the scope of Rust itself, even at tier 3. > "onerous" here is an intentionally subjective term. At a minimum, "onerous" legal/licensing terms include but are not limited to: non-disclosure requirements, non-compete requirements, contributor license agreements (CLAs) or equivalent, "non-commercial"/"research-only"/etc terms, requirements conditional on the employer or employment of any particular Rust developers, revocable terms, any requirements that create liability for the Rust project or its developers or users, or any requirements that adversely affect the livelihood or prospects of the Rust project or its developers or users. Uses the same dependencies, requirements and licensing as the other `*-pc-windows-msvc` targets. > Neither this policy nor any decisions made regarding targets shall create any binding agreement or estoppel by any party. If any member of an approving Rust team serves as one of the maintainers of a target, or has any legal or employment requirement (explicit or implicit) that might affect their decisions regarding a target, they must recuse themselves from any approval decisions regarding the target's tier status, though they may otherwise participate in discussions. > This requirement does not prevent part or all of this policy from being cited in an explicit contract or work agreement (e.g. to implement or maintain support for a target). This requirement exists to ensure that a developer or team responsible for reviewing and approving a target does not face any legal threats or obligations that would prevent them from freely exercising their judgment in such approval, even if such judgment involves subjective matters or goes beyond the letter of these requirements. Understood, I am not a member of the Rust team. > Tier 3 targets should attempt to implement as much of the standard libraries as possible and appropriate (core for most targets, alloc for targets that can support dynamic memory allocation, std for targets with an operating system or equivalent layer of system-provided functionality), but may leave some code unimplemented (either unavailable or stubbed out as appropriate), whether because the target makes it impossible to implement or challenging to implement. The authors of pull requests are not obligated to avoid calling any portions of the standard library on the basis of a tier 3 target not implementing those portions. Both `core` and `alloc` are supported. Support for `std` dependends on making changes to the standard library, `stdarch` and `backtrace` which cannot be done yet as the bootstrapping compiler raises a warning ("unexpected `cfg` condition value") for `target_arch = "arm64ec"`. > The target must provide documentation for the Rust community explaining how to build for the target, using cross-compilation if possible. If the target supports running binaries, or running tests (even if they do not pass), the documentation must explain how to run such binaries or tests for the target, using emulation if possible or dedicated hardware if necessary. Documentation is provided in src/doc/rustc/src/platform-support/arm64ec-pc-windows-msvc.md > Tier 3 targets must not impose burden on the authors of pull requests, or other developers in the community, to maintain the target. In particular, do not post comments (automated or manual) on a PR that derail or suggest a block on the PR based on a tier 3 target. Do not send automated messages or notifications (via any medium, including via @) to a PR author or others involved with a PR regarding a tier 3 target, unless they have opted into such messages. > Backlinks such as those generated by the issue/PR tracker when linking to an issue or PR are not considered a violation of this policy, within reason. However, such messages (even on a separate repository) must not generate notifications to anyone involved with a PR who has not requested such notifications. > Patches adding or updating tier 3 targets must not break any existing tier 2 or tier 1 target, and must not knowingly break another tier 3 target without approval of either the compiler team or the maintainers of the other tier 3 target. > In particular, this may come up when working on closely related targets, such as variations of the same architecture with different features. Avoid introducing unconditional uses of features that another variation of the target may not have; use conditional compilation or runtime detection, as appropriate, to let each target run code supported by that target. Understood.
2023-12-15 16:46:34 -08:00
("arm64ec-pc-windows-msvc", arm64ec_pc_windows_msvc),
("x86_64-pc-windows-msvc", x86_64_pc_windows_msvc),
2019-07-31 15:00:34 +07:00
("x86_64-uwp-windows-msvc", x86_64_uwp_windows_msvc),
("x86_64-win7-windows-msvc", x86_64_win7_windows_msvc),
("i686-pc-windows-msvc", i686_pc_windows_msvc),
2019-07-31 15:00:34 +07:00
("i686-uwp-windows-msvc", i686_uwp_windows_msvc),
2023-11-14 17:44:03 +01:00
("i686-win7-windows-msvc", i686_win7_windows_msvc),
("i586-pc-windows-msvc", i586_pc_windows_msvc),
2018-06-26 09:44:19 -07:00
("thumbv7a-pc-windows-msvc", thumbv7a_pc_windows_msvc),
2020-05-12 16:33:41 +08:00
("thumbv7a-uwp-windows-msvc", thumbv7a_uwp_windows_msvc),
("wasm32-unknown-emscripten", wasm32_unknown_emscripten),
std: Add a new wasm32-unknown-unknown target This commit adds a new target to the compiler: wasm32-unknown-unknown. This target is a reimagining of what it looks like to generate WebAssembly code from Rust. Instead of using Emscripten which can bring with it a weighty runtime this instead is a target which uses only the LLVM backend for WebAssembly and a "custom linker" for now which will hopefully one day be direct calls to lld. Notable features of this target include: * There is zero runtime footprint. The target assumes nothing exists other than the wasm32 instruction set. * There is zero toolchain footprint beyond adding the target. No custom linker is needed, rustc contains everything. * Very small wasm modules can be generated directly from Rust code using this target. * Most of the standard library is stubbed out to return an error, but anything related to allocation works (aka `HashMap`, `Vec`, etc). * Naturally, any `#[no_std]` crate should be 100% compatible with this new target. This target is currently somewhat janky due to how linking works. The "linking" is currently unconditional whole program LTO (aka LLVM is being used as a linker). Naturally that means compiling programs is pretty slow! Eventually though this target should have a linker. This target is also intended to be quite experimental. I'm hoping that this can act as a catalyst for further experimentation in Rust with WebAssembly. Breaking changes are very likely to land to this target, so it's not recommended to rely on it in any critical capacity yet. We'll let you know when it's "production ready". --- Currently testing-wise this target is looking pretty good but isn't complete. I've got almost the entire `run-pass` test suite working with this target (lots of tests ignored, but many passing as well). The `core` test suite is still getting LLVM bugs fixed to get that working and will take some time. Relatively simple programs all seem to work though! --- It's worth nothing that you may not immediately see the "smallest possible wasm module" for the input you feed to rustc. For various reasons it's very difficult to get rid of the final "bloat" in vanilla rustc (again, a real linker should fix all this). For now what you'll have to do is: cargo install --git https://github.com/alexcrichton/wasm-gc wasm-gc foo.wasm bar.wasm And then `bar.wasm` should be the smallest we can get it! --- In any case for now I'd love feedback on this, particularly on the various integration points if you've got better ideas of how to approach them!
2017-10-22 20:01:00 -07:00
("wasm32-unknown-unknown", wasm32_unknown_unknown),
("wasm32-wasi", wasm32_wasi),
("wasm32-wasip1", wasm32_wasip1),
("wasm32-wasip2", wasm32_wasip2),
("wasm32-wasi-preview1-threads", wasm32_wasi_preview1_threads),
2020-12-30 12:52:21 -06:00
("wasm64-unknown-unknown", wasm64_unknown_unknown),
("thumbv6m-none-eabi", thumbv6m_none_eabi),
("thumbv7m-none-eabi", thumbv7m_none_eabi),
("thumbv7em-none-eabi", thumbv7em_none_eabi),
("thumbv7em-none-eabihf", thumbv7em_none_eabihf),
("thumbv8m.base-none-eabi", thumbv8m_base_none_eabi),
("thumbv8m.main-none-eabi", thumbv8m_main_none_eabi),
("thumbv8m.main-none-eabihf", thumbv8m_main_none_eabihf),
2017-07-06 15:15:44 -05:00
("armv7a-none-eabi", armv7a_none_eabi),
("armv7a-none-eabihf", armv7a_none_eabihf),
2017-07-06 15:15:44 -05:00
("msp430-none-elf", msp430_none_elf),
("aarch64-unknown-hermit", aarch64_unknown_hermit),
("riscv64gc-unknown-hermit", riscv64gc_unknown_hermit),
("x86_64-unknown-hermit", x86_64_unknown_hermit),
("x86_64-unikraft-linux-musl", x86_64_unikraft_linux_musl),
2019-07-18 18:37:23 +03:00
("riscv32i-unknown-none-elf", riscv32i_unknown_none_elf),
("riscv32im-risc0-zkvm-elf", riscv32im_risc0_zkvm_elf),
("riscv32im-unknown-none-elf", riscv32im_unknown_none_elf),
("riscv32imc-unknown-none-elf", riscv32imc_unknown_none_elf),
2021-07-29 20:18:22 +03:00
("riscv32imc-esp-espidf", riscv32imc_esp_espidf),
("riscv32imac-esp-espidf", riscv32imac_esp_espidf),
("riscv32imafc-esp-espidf", riscv32imafc_esp_espidf),
("riscv32imac-unknown-none-elf", riscv32imac_unknown_none_elf),
("riscv32imafc-unknown-none-elf", riscv32imafc_unknown_none_elf),
("riscv32imac-unknown-xous-elf", riscv32imac_unknown_xous_elf),
("riscv32gc-unknown-linux-gnu", riscv32gc_unknown_linux_gnu),
("riscv32gc-unknown-linux-musl", riscv32gc_unknown_linux_musl),
("riscv64imac-unknown-none-elf", riscv64imac_unknown_none_elf),
2019-02-12 19:15:00 +03:00
("riscv64gc-unknown-none-elf", riscv64gc_unknown_none_elf),
2019-11-23 14:15:27 +07:00
("riscv64gc-unknown-linux-gnu", riscv64gc_unknown_linux_gnu),
("riscv64gc-unknown-linux-musl", riscv64gc_unknown_linux_musl),
("sparc-unknown-none-elf", sparc_unknown_none_elf),
("loongarch64-unknown-none", loongarch64_unknown_none),
("loongarch64-unknown-none-softfloat", loongarch64_unknown_none_softfloat),
("aarch64-unknown-none", aarch64_unknown_none),
("aarch64-unknown-none-softfloat", aarch64_unknown_none_softfloat),
("x86_64-fortanix-unknown-sgx", x86_64_fortanix_unknown_sgx),
Add x86_64-unknown-uefi target This adds a new rustc target-configuration called 'x86_64-unknown_uefi'. Furthermore, it adds a UEFI base-configuration to be used with other targets supported by UEFI (e.g., i386, armv7hl, aarch64, itanium, ...). UEFI systems provide a very basic operating-system environment, meant to unify how systems are booted. It is tailored for simplicity and fast setup, as it is only meant to bootstrap other systems. For instance, it copies most of the ABI from Microsoft Windows, rather than inventing anything on its own. Furthermore, any complex CPU features are disabled. Only one CPU is allowed to be up, no interrupts other than the timer-interrupt are allowed, no process-separation is performed, page-tables are identity-mapped, ... Nevertheless, UEFI has an application model. Its main purpose is to allow operating-system vendors to write small UEFI applications that load their kernel and terminate the UEFI system. However, many other UEFI applications have emerged in the past, including network-boot, debug-consoles, and more. This UEFI target allows to compile rust code natively as UEFI applications. No standard library support is added, but libcore can be used out-of-the-box if a panic-handler is provided. Furthermore, liballoc works as well, if a `GlobalAlloc` handler is provided. Both have been tested with this target-configuration. Note that full libstd support is unlikely to happen. While UEFI does have standardized interfaces for networking and alike, none of these are mandatory and they are unlikely to be shipped in common consumer firmwares. Furthermore, several features like process-separation are not available (or only in very limited fashion). Those parts of libstd would have to be masked.
2018-12-13 10:08:20 +01:00
("x86_64-unknown-uefi", x86_64_unknown_uefi),
("i686-unknown-uefi", i686_unknown_uefi),
("aarch64-unknown-uefi", aarch64_unknown_uefi),
("nvptx64-nvidia-cuda", nvptx64_nvidia_cuda),
("i686-wrs-vxworks", i686_wrs_vxworks),
("x86_64-wrs-vxworks", x86_64_wrs_vxworks),
("armv7-wrs-vxworks-eabihf", armv7_wrs_vxworks_eabihf),
("aarch64-wrs-vxworks", aarch64_wrs_vxworks),
("powerpc-wrs-vxworks", powerpc_wrs_vxworks),
("powerpc-wrs-vxworks-spe", powerpc_wrs_vxworks_spe),
("powerpc64-wrs-vxworks", powerpc64_wrs_vxworks),
2020-05-09 15:41:49 -04:00
Add SOLID targets SOLID[1] is an embedded development platform provided by Kyoto Microcomputer Co., Ltd. This commit introduces a basic Tier 3 support for SOLID. # New Targets The following targets are added: - `aarch64-kmc-solid_asp3` - `armv7a-kmc-solid_asp3-eabi` - `armv7a-kmc-solid_asp3-eabihf` SOLID's target software system can be divided into two parts: an RTOS kernel, which is responsible for threading and synchronization, and Core Services, which provides filesystems, networking, and other things. The RTOS kernel is a μITRON4.0[2][3]-derived kernel based on the open-source TOPPERS RTOS kernels[4]. For uniprocessor systems (more precisely, systems where only one processor core is allocated for SOLID), this will be the TOPPERS/ASP3 kernel. As μITRON is traditionally only specified at the source-code level, the ABI is unique to each implementation, which is why `asp3` is included in the target names. More targets could be added later, as we support other base kernels (there are at least three at the point of writing) and are interested in supporting other processor architectures in the future. # C Compiler Although SOLID provides its own supported C/C++ build toolchain, GNU Arm Embedded Toolchain seems to work for the purpose of building Rust. # Unresolved Questions A μITRON4 kernel can support `Thread::unpark` natively, but it's not used by this commit's implementation because the underlying kernel feature is also used to implement `Condvar`, and it's unclear whether `std` should guarantee that parking tokens are not clobbered by other synchronization primitives. # Unsupported or Unimplemented Features Most features are implemented. The following features are not implemented due to the lack of native support: - `fs::File::{file_attr, truncate, duplicate, set_permissions}` - `fs::{symlink, link, canonicalize}` - Process creation - Command-line arguments Backtrace generation is not really a good fit for embedded targets, so it's intentionally left unimplemented. Unwinding is functional, however. ## Dynamic Linking Dynamic linking is not supported. The target platform supports dynamic linking, but enabling this in Rust causes several problems. - The linker invocation used to build the shared object of `std` is too long for the platform-provided linker to handle. - A linker script with specific requirements is required for the compiled shared object to be actually loadable. As such, we decided to disable dynamic linking for now. Regardless, the users can try to create shared objects by manually invoking the linker. ## Executable Building an executable is not supported as the notion of "executable files" isn't well-defined for these targets. [1] https://solid.kmckk.com/SOLID/ [2] http://ertl.jp/ITRON/SPEC/mitron4-e.html [3] https://en.wikipedia.org/wiki/ITRON_project [4] https://toppers.jp/
2021-09-28 11:20:46 +09:00
("aarch64-kmc-solid_asp3", aarch64_kmc_solid_asp3),
("armv7a-kmc-solid_asp3-eabi", armv7a_kmc_solid_asp3_eabi),
("armv7a-kmc-solid_asp3-eabihf", armv7a_kmc_solid_asp3_eabihf),
2020-05-09 15:41:49 -04:00
("mipsel-sony-psp", mipsel_sony_psp),
2022-10-04 21:37:30 -04:00
("mipsel-sony-psx", mipsel_sony_psx),
2020-11-02 19:11:24 +01:00
("mipsel-unknown-none", mipsel_unknown_none),
("thumbv4t-none-eabi", thumbv4t_none_eabi),
2022-08-16 20:10:31 +01:00
("armv4t-none-eabi", armv4t_none_eabi),
2022-09-02 14:16:02 +01:00
("thumbv5te-none-eabi", thumbv5te_none_eabi),
("armv5te-none-eabi", armv5te_none_eabi),
("aarch64_be-unknown-linux-gnu", aarch64_be_unknown_linux_gnu),
("aarch64-unknown-linux-gnu_ilp32", aarch64_unknown_linux_gnu_ilp32),
("aarch64_be-unknown-linux-gnu_ilp32", aarch64_be_unknown_linux_gnu_ilp32),
("bpfeb-unknown-none", bpfeb_unknown_none),
("bpfel-unknown-none", bpfel_unknown_none),
("armv6k-nintendo-3ds", armv6k_nintendo_3ds),
("aarch64-nintendo-switch-freestanding", aarch64_nintendo_switch_freestanding),
2021-09-15 13:56:20 -04:00
2022-12-14 19:39:16 +01:00
("armv7-sony-vita-newlibeabihf", armv7_sony_vita_newlibeabihf),
("armv7-unknown-linux-uclibceabi", armv7_unknown_linux_uclibceabi),
("armv7-unknown-linux-uclibceabihf", armv7_unknown_linux_uclibceabihf),
("x86_64-unknown-none", x86_64_unknown_none),
("aarch64-unknown-teeos", aarch64_unknown_teeos),
("mips64-openwrt-linux-musl", mips64_openwrt_linux_musl),
("aarch64-unknown-nto-qnx710", aarch64_unknown_nto_qnx710),
("x86_64-pc-nto-qnx710", x86_64_pc_nto_qnx710),
2023-02-04 20:34:26 -08:00
("i586-pc-nto-qnx700", i586_pc_nto_qnx700),
("aarch64-unknown-linux-ohos", aarch64_unknown_linux_ohos),
("armv7-unknown-linux-ohos", armv7_unknown_linux_ohos),
("x86_64-unknown-linux-ohos", x86_64_unknown_linux_ohos),
}
/// Cow-Vec-Str: Cow<'static, [Cow<'static, str>]>
macro_rules! cvs {
() => {
::std::borrow::Cow::Borrowed(&[])
};
($($x:expr),+ $(,)?) => {
::std::borrow::Cow::Borrowed(&[
$(
::std::borrow::Cow::Borrowed($x),
)*
])
};
}
pub(crate) use cvs;
/// Warnings encountered when parsing the target `json`.
///
/// Includes fields that weren't recognized and fields that don't have the expected type.
#[derive(Debug, PartialEq)]
pub struct TargetWarnings {
unused_fields: Vec<String>,
incorrect_type: Vec<String>,
}
impl TargetWarnings {
pub fn empty() -> Self {
Self { unused_fields: Vec::new(), incorrect_type: Vec::new() }
}
pub fn warning_messages(&self) -> Vec<String> {
let mut warnings = vec![];
if !self.unused_fields.is_empty() {
warnings.push(format!(
"target json file contains unused fields: {}",
self.unused_fields.join(", ")
));
}
if !self.incorrect_type.is_empty() {
warnings.push(format!(
"target json file contains fields whose value doesn't have the correct json type: {}",
self.incorrect_type.join(", ")
));
}
warnings
}
}
/// Everything `rustc` knows about how to compile for a specific target.
///
/// Every field here must be specified, and has no default value.
#[derive(PartialEq, Clone, Debug)]
pub struct Target {
/// Target triple to pass to LLVM.
pub llvm_target: StaticCow<str>,
/// A short description of the target including platform requirements,
/// for example "64-bit Linux (kernel 3.2+, glibc 2.17+)".
/// Optional for now, intended to be required in the future.
/// Part of #120745.
pub description: Option<StaticCow<str>>,
/// Number of bits in a pointer. Influences the `target_pointer_width` `cfg` variable.
pub pointer_width: u32,
/// Architecture to use for ABI considerations. Valid options include: "x86",
/// "x86_64", "arm", "aarch64", "mips", "powerpc", "powerpc64", and others.
pub arch: StaticCow<str>,
2021-06-23 16:26:46 -04:00
/// [Data layout](https://llvm.org/docs/LangRef.html#data-layout) to pass to LLVM.
pub data_layout: StaticCow<str>,
/// Optional settings with defaults.
pub options: TargetOptions,
}
impl Target {
2022-12-20 22:10:40 +01:00
pub fn parse_data_layout(&self) -> Result<TargetDataLayout, TargetDataLayoutErrors<'_>> {
let mut dl = TargetDataLayout::parse_from_llvm_datalayout_string(&self.data_layout)?;
// Perform consistency checks against the Target information.
if dl.endian != self.endian {
return Err(TargetDataLayoutErrors::InconsistentTargetArchitecture {
dl: dl.endian.as_str(),
target: self.endian.as_str(),
});
}
let target_pointer_width: u64 = self.pointer_width.into();
if dl.pointer_size.bits() != target_pointer_width {
return Err(TargetDataLayoutErrors::InconsistentTargetPointerWidth {
pointer_size: dl.pointer_size.bits(),
target: self.pointer_width,
});
}
dl.c_enum_min_size = self
.c_enum_min_bits
.map_or_else(
|| {
self.c_int_width
.parse()
.map_err(|_| String::from("failed to parse c_int_width"))
},
Ok,
)
.and_then(|i| Integer::from_size(Size::from_bits(i)))
.map_err(|err| TargetDataLayoutErrors::InvalidBitsSize { err })?;
Ok(dl)
}
}
pub trait HasTargetSpec {
fn target_spec(&self) -> &Target;
}
impl HasTargetSpec for Target {
2021-06-01 00:00:00 +00:00
#[inline]
fn target_spec(&self) -> &Target {
self
}
}
type StaticCow<T> = Cow<'static, T>;
/// Optional aspects of a target specification.
///
/// This has an implementation of `Default`, see each field for what the default is. In general,
/// these try to take "minimal defaults" that don't assume anything about the runtime they run in.
///
/// `TargetOptions` as a separate structure is mostly an implementation detail of `Target`
/// construction, all its fields logically belong to `Target` and available from `Target`
/// through `Deref` impls.
#[derive(PartialEq, Clone, Debug)]
pub struct TargetOptions {
/// Whether the target is built-in or loaded from a custom target specification.
pub is_builtin: bool,
/// Used as the `target_endian` `cfg` variable. Defaults to little endian.
pub endian: Endian,
/// Width of c_int type. Defaults to "32".
pub c_int_width: StaticCow<str>,
/// OS name to use for conditional compilation (`target_os`). Defaults to "none".
/// "none" implies a bare metal target without `std` library.
/// A couple of targets having `std` also use "unknown" as an `os` value,
/// but they are exceptions.
pub os: StaticCow<str>,
/// Environment name to use for conditional compilation (`target_env`). Defaults to "".
pub env: StaticCow<str>,
/// ABI name to distinguish multiple ABIs on the same OS and architecture. For instance, `"eabi"`
/// or `"eabihf"`. Defaults to "".
pub abi: StaticCow<str>,
/// Vendor name to use for conditional compilation (`target_vendor`). Defaults to "unknown".
pub vendor: StaticCow<str>,
/// Linker to invoke
pub linker: Option<StaticCow<str>>,
/// Default linker flavor used if `-C linker-flavor` or `-C linker` are not passed
/// on the command line. Defaults to `LinkerFlavor::Gnu(Cc::Yes, Lld::No)`.
pub linker_flavor: LinkerFlavor,
linker_flavor_json: LinkerFlavorCli,
lld_flavor_json: LldFlavor,
linker_is_gnu_json: bool,
/// Objects to link before and after all other object code.
pub pre_link_objects: CrtObjects,
pub post_link_objects: CrtObjects,
/// Same as `(pre|post)_link_objects`, but when self-contained linking mode is enabled.
pub pre_link_objects_self_contained: CrtObjects,
pub post_link_objects_self_contained: CrtObjects,
/// Behavior for the self-contained linking mode: inferred for some targets, or explicitly
/// enabled (in bulk, or with individual components).
pub link_self_contained: LinkSelfContainedDefault,
/// Linker arguments that are passed *before* any user-defined libraries.
pub pre_link_args: LinkArgs,
pre_link_args_json: LinkArgsCli,
/// Linker arguments that are unconditionally passed after any
/// user-defined but before post-link objects. Standard platform
/// libraries that should be always be linked to, usually go here.
-Z linker-flavor This patch adds a `-Z linker-flavor` flag to rustc which can be used to invoke the linker using a different interface. For example, by default rustc assumes that all the Linux targets will be linked using GCC. This makes it impossible to use LLD as a linker using just `-C linker=ld.lld` because that will invoke LLD with invalid command line arguments. (e.g. rustc will pass -Wl,--gc-sections to LLD but LLD doesn't understand that; --gc-sections would be the right argument) With this patch one can pass `-Z linker-flavor=ld` to rustc to invoke the linker using a LD-like interface. This way, `rustc -C linker=ld.lld -Z linker-flavor=ld` will invoke LLD with the right arguments. `-Z linker-flavor` accepts 4 different arguments: `em` (emcc), `ld`, `gcc`, `msvc` (link.exe). `em`, `gnu` and `msvc` cover all the existing linker interfaces. `ld` is a new flavor for interfacing GNU's ld and LLD. This patch also changes target specifications. `linker-flavor` is now a mandatory field that specifies the *default* linker flavor that the target will use. This change also makes the linker interface *explicit*; before, it used to be derived from other fields like linker-is-gnu, is-like-msvc, is-like-emscripten, etc. Another change to target specifications is that the fields `pre-link-args`, `post-link-args` and `late-link-args` now expect a map from flavor to linker arguments. ``` diff - "pre-link-args": ["-Wl,--as-needed", "-Wl,-z,-noexecstack"], + "pre-link-args": { + "gcc": ["-Wl,--as-needed", "-Wl,-z,-noexecstack"], + "ld": ["--as-needed", "-z,-noexecstack"], + }, ``` [breaking-change] for users of custom targets specifications
2017-02-21 14:47:15 -05:00
pub late_link_args: LinkArgs,
late_link_args_json: LinkArgsCli,
/// Linker arguments used in addition to `late_link_args` if at least one
/// Rust dependency is dynamically linked.
pub late_link_args_dynamic: LinkArgs,
late_link_args_dynamic_json: LinkArgsCli,
/// Linker arguments used in addition to `late_link_args` if all Rust
/// dependencies are statically linked.
pub late_link_args_static: LinkArgs,
late_link_args_static_json: LinkArgsCli,
/// Linker arguments that are unconditionally passed *after* any
/// user-defined libraries.
-Z linker-flavor This patch adds a `-Z linker-flavor` flag to rustc which can be used to invoke the linker using a different interface. For example, by default rustc assumes that all the Linux targets will be linked using GCC. This makes it impossible to use LLD as a linker using just `-C linker=ld.lld` because that will invoke LLD with invalid command line arguments. (e.g. rustc will pass -Wl,--gc-sections to LLD but LLD doesn't understand that; --gc-sections would be the right argument) With this patch one can pass `-Z linker-flavor=ld` to rustc to invoke the linker using a LD-like interface. This way, `rustc -C linker=ld.lld -Z linker-flavor=ld` will invoke LLD with the right arguments. `-Z linker-flavor` accepts 4 different arguments: `em` (emcc), `ld`, `gcc`, `msvc` (link.exe). `em`, `gnu` and `msvc` cover all the existing linker interfaces. `ld` is a new flavor for interfacing GNU's ld and LLD. This patch also changes target specifications. `linker-flavor` is now a mandatory field that specifies the *default* linker flavor that the target will use. This change also makes the linker interface *explicit*; before, it used to be derived from other fields like linker-is-gnu, is-like-msvc, is-like-emscripten, etc. Another change to target specifications is that the fields `pre-link-args`, `post-link-args` and `late-link-args` now expect a map from flavor to linker arguments. ``` diff - "pre-link-args": ["-Wl,--as-needed", "-Wl,-z,-noexecstack"], + "pre-link-args": { + "gcc": ["-Wl,--as-needed", "-Wl,-z,-noexecstack"], + "ld": ["--as-needed", "-z,-noexecstack"], + }, ``` [breaking-change] for users of custom targets specifications
2017-02-21 14:47:15 -05:00
pub post_link_args: LinkArgs,
post_link_args_json: LinkArgsCli,
/// Optional link script applied to `dylib` and `executable` crate types.
/// This is a string containing the script, not a path. Can only be applied
/// to linkers where linker flavor matches `LinkerFlavor::Gnu(..)`.
pub link_script: Option<StaticCow<str>>,
/// Environment variables to be set for the linker invocation.
pub link_env: StaticCow<[(StaticCow<str>, StaticCow<str>)]>,
/// Environment variables to be removed for the linker invocation.
pub link_env_remove: StaticCow<[StaticCow<str>]>,
/// Extra arguments to pass to the external assembler (when used)
pub asm_args: StaticCow<[StaticCow<str>]>,
/// Default CPU to pass to LLVM. Corresponds to `llc -mcpu=$cpu`. Defaults
/// to "generic".
pub cpu: StaticCow<str>,
/// Default target features to pass to LLVM. These features will *always* be
/// passed, and cannot be disabled even via `-C`. Corresponds to `llc
/// -mattr=$features`.
pub features: StaticCow<str>,
/// Direct or use GOT indirect to reference external data symbols
pub direct_access_external_data: Option<bool>,
/// Whether dynamic linking is available on this target. Defaults to false.
pub dynamic_linking: bool,
/// Whether dynamic linking can export TLS globals. Defaults to true.
pub dll_tls_export: bool,
std: Add a new wasm32-unknown-unknown target This commit adds a new target to the compiler: wasm32-unknown-unknown. This target is a reimagining of what it looks like to generate WebAssembly code from Rust. Instead of using Emscripten which can bring with it a weighty runtime this instead is a target which uses only the LLVM backend for WebAssembly and a "custom linker" for now which will hopefully one day be direct calls to lld. Notable features of this target include: * There is zero runtime footprint. The target assumes nothing exists other than the wasm32 instruction set. * There is zero toolchain footprint beyond adding the target. No custom linker is needed, rustc contains everything. * Very small wasm modules can be generated directly from Rust code using this target. * Most of the standard library is stubbed out to return an error, but anything related to allocation works (aka `HashMap`, `Vec`, etc). * Naturally, any `#[no_std]` crate should be 100% compatible with this new target. This target is currently somewhat janky due to how linking works. The "linking" is currently unconditional whole program LTO (aka LLVM is being used as a linker). Naturally that means compiling programs is pretty slow! Eventually though this target should have a linker. This target is also intended to be quite experimental. I'm hoping that this can act as a catalyst for further experimentation in Rust with WebAssembly. Breaking changes are very likely to land to this target, so it's not recommended to rely on it in any critical capacity yet. We'll let you know when it's "production ready". --- Currently testing-wise this target is looking pretty good but isn't complete. I've got almost the entire `run-pass` test suite working with this target (lots of tests ignored, but many passing as well). The `core` test suite is still getting LLVM bugs fixed to get that working and will take some time. Relatively simple programs all seem to work though! --- It's worth nothing that you may not immediately see the "smallest possible wasm module" for the input you feed to rustc. For various reasons it's very difficult to get rid of the final "bloat" in vanilla rustc (again, a real linker should fix all this). For now what you'll have to do is: cargo install --git https://github.com/alexcrichton/wasm-gc wasm-gc foo.wasm bar.wasm And then `bar.wasm` should be the smallest we can get it! --- In any case for now I'd love feedback on this, particularly on the various integration points if you've got better ideas of how to approach them!
2017-10-22 20:01:00 -07:00
/// If dynamic linking is available, whether only cdylibs are supported.
pub only_cdylib: bool,
/// Whether executables are available on this target. Defaults to true.
pub executables: bool,
/// Relocation model to use in object file. Corresponds to `llc
/// -relocation-model=$relocation_model`. Defaults to `Pic`.
pub relocation_model: RelocModel,
/// Code model to use. Corresponds to `llc -code-model=$code_model`.
/// Defaults to `None` which means "inherited from the base LLVM target".
pub code_model: Option<CodeModel>,
/// TLS model to use. Options are "global-dynamic" (default), "local-dynamic", "initial-exec"
/// and "local-exec". This is similar to the -ftls-model option in GCC/Clang.
pub tls_model: TlsModel,
/// Do not emit code that uses the "red zone", if the ABI has one. Defaults to false.
pub disable_redzone: bool,
/// Frame pointer mode for this target. Defaults to `MayOmit`.
pub frame_pointer: FramePointer,
/// Emit each function in its own section. Defaults to true.
pub function_sections: bool,
/// String to prepend to the name of every dynamic library. Defaults to "lib".
pub dll_prefix: StaticCow<str>,
/// String to append to the name of every dynamic library. Defaults to ".so".
pub dll_suffix: StaticCow<str>,
/// String to append to the name of every executable.
pub exe_suffix: StaticCow<str>,
/// String to prepend to the name of every static library. Defaults to "lib".
pub staticlib_prefix: StaticCow<str>,
/// String to append to the name of every static library. Defaults to ".a".
pub staticlib_suffix: StaticCow<str>,
/// Values of the `target_family` cfg set for this target.
///
/// Common options are: "unix", "windows". Defaults to no families.
///
/// See <https://doc.rust-lang.org/reference/conditional-compilation.html#target_family>.
pub families: StaticCow<[StaticCow<str>]>,
/// Whether the target toolchain's ABI supports returning small structs as an integer.
pub abi_return_struct_as_int: bool,
2022-08-25 14:37:29 +08:00
/// Whether the target toolchain is like AIX's. Linker options on AIX are special and it uses
/// XCOFF as binary format. Defaults to false.
pub is_like_aix: bool,
/// Whether the target toolchain is like macOS's. Only useful for compiling against iOS/macOS,
/// in particular running dsymutil and some other stuff like `-dead_strip`. Defaults to false.
/// Also indiates whether to use Apple-specific ABI changes, such as extending function
/// parameters to 32-bits.
pub is_like_osx: bool,
2016-01-21 19:30:22 +03:00
/// Whether the target toolchain is like Solaris's.
/// Only useful for compiling against Illumos/Solaris,
/// as they have a different set of linker flags. Defaults to false.
2016-01-28 14:02:31 +03:00
pub is_like_solaris: bool,
/// Whether the target is like Windows.
/// This is a combination of several more specific properties represented as a single flag:
/// - The target uses a Windows ABI,
/// - uses PE/COFF as a format for object code,
/// - uses Windows-style dllexport/dllimport for shared libraries,
/// - uses import libraries and .def files for symbol exports,
/// - executables support setting a subsystem.
pub is_like_windows: bool,
/// Whether the target is like MSVC.
/// This is a combination of several more specific properties represented as a single flag:
/// - The target has all the properties from `is_like_windows`
/// (for in-tree targets "is_like_msvc ⇒ is_like_windows" is ensured by a unit test),
/// - has some MSVC-specific Windows ABI properties,
/// - uses a link.exe-like linker,
/// - uses CodeView/PDB for debuginfo and natvis for its visualization,
/// - uses SEH-based unwinding,
/// - supports control flow guard mechanism.
pub is_like_msvc: bool,
2020-12-30 12:52:21 -06:00
/// Whether a target toolchain is like WASM.
pub is_like_wasm: bool,
/// Whether a target toolchain is like Android, implying a Linux kernel and a Bionic libc
pub is_like_android: bool,
/// Default supported version of DWARF on this platform.
/// Useful because some platforms (osx, bsd) only want up to DWARF2.
pub default_dwarf_version: u32,
/// The MinGW toolchain has a known issue that prevents it from correctly
2017-12-31 17:17:01 +01:00
/// handling COFF object files with more than 2<sup>15</sup> sections. Since each weak
/// symbol needs its own COMDAT section, weak linkage implies a large
/// number sections that easily exceeds the given limit for larger
2022-03-30 17:28:19 -04:00
/// codebases. Consequently we want a way to disallow weak linkage on some
/// platforms.
pub allows_weak_linkage: bool,
/// Whether the linker support rpaths or not. Defaults to false.
pub has_rpath: bool,
/// Whether to disable linking to the default libraries, typically corresponds
/// to `-nodefaultlibs`. Defaults to true.
pub no_default_libraries: bool,
/// Dynamically linked executables can be compiled as position independent
/// if the default relocation model of position independent code is not
/// changed. This is a requirement to take advantage of ASLR, as otherwise
/// the functions in the executable are not randomized and can be used
/// during an exploit of a vulnerability in any code.
2014-11-06 00:17:56 -05:00
pub position_independent_executables: bool,
/// Executables that are both statically linked and position-independent are supported.
pub static_position_independent_executables: bool,
/// Determines if the target always requires using the PLT for indirect
/// library calls or not. This controls the default value of the `-Z plt` flag.
pub plt_by_default: bool,
/// Either partial, full, or off. Full RELRO makes the dynamic linker
/// resolve all symbols at startup and marks the GOT read-only before
/// starting the program, preventing overwriting the GOT.
pub relro_level: RelroLevel,
trans: Use LLVM's writeArchive to modify archives We have previously always relied upon an external tool, `ar`, to modify archives that the compiler produces (staticlibs, rlibs, etc). This approach, however, has a number of downsides: * Spawning a process is relatively expensive for small compilations * Encoding arguments across process boundaries often incurs unnecessary overhead or lossiness. For example `ar` has a tough time dealing with files that have the same name in archives, and the compiler copies many files around to ensure they can be passed to `ar` in a reasonable fashion. * Most `ar` programs found do **not** have the ability to target arbitrary platforms, so this is an extra tool which needs to be found/specified when cross compiling. The LLVM project has had a tool called `llvm-ar` for quite some time now, but it wasn't available in the standard LLVM libraries (it was just a standalone program). Recently, however, in LLVM 3.7, this functionality has been moved to a library and is now accessible by consumers of LLVM via the `writeArchive` function. This commit migrates our archive bindings to no longer invoke `ar` by default but instead make a library call to LLVM to do various operations. This solves all of the downsides listed above: * Archive management is now much faster, for example creating a "hello world" staticlib is now 6x faster (50ms => 8ms). Linking dynamic libraries also recently started requiring modification of rlibs, and linking a hello world dynamic library is now 2x faster. * The compiler is now one step closer to "hassle free" cross compilation because no external tool is needed for managing archives, LLVM does the right thing! This commit does not remove support for calling a system `ar` utility currently. We will continue to maintain compatibility with LLVM 3.5 and 3.6 looking forward (so the system LLVM can be used wherever possible), and in these cases we must shell out to a system utility. All nightly builds of Rust, however, will stop needing a system `ar`.
2015-07-09 00:14:20 -07:00
/// Format that archives should be emitted in. This affects whether we use
/// LLVM to assemble an archive or fall back to the system linker, and
/// currently only "gnu" is used to fall into LLVM. Unknown strings cause
/// the system linker to be used.
pub archive_format: StaticCow<str>,
/// Is asm!() allowed? Defaults to true.
pub allow_asm: bool,
/// Whether the runtime startup code requires the `main` function be passed
/// `argc` and `argv` values.
pub main_needs_argc_argv: bool,
/// Flag indicating whether #[thread_local] is available for this target.
pub has_thread_local: bool,
/// This is mainly for easy compatibility with emscripten.
/// If we give emcc .o files that are actually .bc files it
/// will 'just work'.
pub obj_is_bitcode: bool,
/// Whether the target requires that emitted object code includes bitcode.
pub forces_embed_bitcode: bool,
/// Content of the LLVM cmdline section associated with embedded bitcode.
pub bitcode_llvm_cmdline: StaticCow<str>,
/// Don't use this field; instead use the `.min_atomic_width()` method.
pub min_atomic_width: Option<u64>,
/// Don't use this field; instead use the `.max_atomic_width()` method.
pub max_atomic_width: Option<u64>,
/// Whether the target supports atomic CAS operations natively
pub atomic_cas: bool,
/// Panic strategy: "unwind" or "abort"
pub panic_strategy: PanicStrategy,
2016-10-24 11:04:04 +02:00
/// Whether or not linking dylibs to a static CRT is allowed.
pub crt_static_allows_dylibs: bool,
rustc: Implement #[link(cfg(..))] and crt-static This commit is an implementation of [RFC 1721] which adds a new target feature to the compiler, `crt-static`, which can be used to select how the C runtime for a target is linked. Most targets dynamically linke the C runtime by default with the notable exception of some of the musl targets. [RFC 1721]: https://github.com/rust-lang/rfcs/blob/master/text/1721-crt-static.md This commit first adds the new target-feature, `crt-static`. If enabled, then the `cfg(target_feature = "crt-static")` will be available. Targets like musl will have this enabled by default. This feature can be controlled through the standard target-feature interface, `-C target-feature=+crt-static` or `-C target-feature=-crt-static`. Next this adds an gated and unstable `#[link(cfg(..))]` feature to enable the `crt-static` semantics we want with libc. The exact behavior of this attribute is a little squishy, but it's intended to be a forever-unstable implementation detail of the liblibc crate. Specifically the `#[link(cfg(..))]` annotation means that the `#[link]` directive is only active in a compilation unit if that `cfg` value is satisfied. For example when compiling an rlib, these directives are just encoded and ignored for dylibs, and all staticlibs are continued to be put into the rlib as usual. When placing that rlib into a staticlib, executable, or dylib, however, the `cfg` is evaluated *as if it were defined in the final artifact* and the library is decided to be linked or not. Essentially, what'll happen is: * On MSVC with `-C target-feature=-crt-static`, the `msvcrt.lib` library will be linked to. * On MSVC with `-C target-feature=+crt-static`, the `libcmt.lib` library will be linked to. * On musl with `-C target-feature=-crt-static`, the object files in liblibc.rlib are removed and `-lc` is passed instead. * On musl with `-C target-feature=+crt-static`, the object files in liblibc.rlib are used and `-lc` is not passed. This commit does **not** include an update to the liblibc module to implement these changes. I plan to do that just after the 1.14.0 beta release is cut to ensure we get ample time to test this feature. cc #37406
2016-10-31 16:40:13 -07:00
/// Whether or not the CRT is statically linked by default.
pub crt_static_default: bool,
/// Whether or not crt-static is respected by the compiler (or is a no-op).
pub crt_static_respected: bool,
/// The implementation of stack probes to use.
pub stack_probes: StackProbeType,
/// The minimum alignment for global symbols.
pub min_global_align: Option<u64>,
/// Default number of codegen units to use in debug mode
pub default_codegen_units: Option<u64>,
/// Whether to generate trap instructions in places where optimization would
/// otherwise produce control flow that falls through into unrelated memory.
pub trap_unreachable: bool,
std: Add a new wasm32-unknown-unknown target This commit adds a new target to the compiler: wasm32-unknown-unknown. This target is a reimagining of what it looks like to generate WebAssembly code from Rust. Instead of using Emscripten which can bring with it a weighty runtime this instead is a target which uses only the LLVM backend for WebAssembly and a "custom linker" for now which will hopefully one day be direct calls to lld. Notable features of this target include: * There is zero runtime footprint. The target assumes nothing exists other than the wasm32 instruction set. * There is zero toolchain footprint beyond adding the target. No custom linker is needed, rustc contains everything. * Very small wasm modules can be generated directly from Rust code using this target. * Most of the standard library is stubbed out to return an error, but anything related to allocation works (aka `HashMap`, `Vec`, etc). * Naturally, any `#[no_std]` crate should be 100% compatible with this new target. This target is currently somewhat janky due to how linking works. The "linking" is currently unconditional whole program LTO (aka LLVM is being used as a linker). Naturally that means compiling programs is pretty slow! Eventually though this target should have a linker. This target is also intended to be quite experimental. I'm hoping that this can act as a catalyst for further experimentation in Rust with WebAssembly. Breaking changes are very likely to land to this target, so it's not recommended to rely on it in any critical capacity yet. We'll let you know when it's "production ready". --- Currently testing-wise this target is looking pretty good but isn't complete. I've got almost the entire `run-pass` test suite working with this target (lots of tests ignored, but many passing as well). The `core` test suite is still getting LLVM bugs fixed to get that working and will take some time. Relatively simple programs all seem to work though! --- It's worth nothing that you may not immediately see the "smallest possible wasm module" for the input you feed to rustc. For various reasons it's very difficult to get rid of the final "bloat" in vanilla rustc (again, a real linker should fix all this). For now what you'll have to do is: cargo install --git https://github.com/alexcrichton/wasm-gc wasm-gc foo.wasm bar.wasm And then `bar.wasm` should be the smallest we can get it! --- In any case for now I'd love feedback on this, particularly on the various integration points if you've got better ideas of how to approach them!
2017-10-22 20:01:00 -07:00
/// This target requires everything to be compiled with LTO to emit a final
/// executable, aka there is no native linker for this target.
pub requires_lto: bool,
/// This target has no support for threads.
pub singlethread: bool,
/// Whether library functions call lowering/optimization is disabled in LLVM
/// for this target unconditionally.
pub no_builtins: bool,
/// The default visibility for symbols in this target should be "hidden"
/// rather than "default".
///
/// This value typically shouldn't be accessed directly, but through
/// the `rustc_session::Session::default_hidden_visibility` method, which
/// allows `rustc` users to override this setting using cmdline flags.
pub default_hidden_visibility: bool,
/// Whether a .debug_gdb_scripts section will be added to the output object file
pub emit_debug_gdb_scripts: bool,
/// Whether or not to unconditionally `uwtable` attributes on functions,
/// typically because the platform needs to unwind for things like stack
/// unwinders.
pub requires_uwtable: bool,
/// Whether or not to emit `uwtable` attributes on functions if `-C force-unwind-tables`
/// is not specified and `uwtable` is not required on this target.
pub default_uwtable: bool,
/// Whether or not SIMD types are passed by reference in the Rust ABI,
/// typically required if a target can be compiled with a mixed set of
/// target features. This is `true` by default, and `false` for targets like
/// wasm32 where the whole program either has simd or not.
pub simd_types_indirect: bool,
/// Pass a list of symbol which should be exported in the dylib to the linker.
pub limit_rdylib_exports: bool,
/// If set, have the linker export exactly these symbols, instead of using
/// the usual logic to figure this out from the crate itself.
pub override_export_symbols: Option<StaticCow<[StaticCow<str>]>>,
/// Determines how or whether the MergeFunctions LLVM pass should run for
/// this target. Either "disabled", "trampolines", or "aliases".
/// The MergeFunctions pass is generally useful, but some targets may need
/// to opt out. The default is "aliases".
///
2020-10-14 17:35:43 +02:00
/// Workaround for: <https://github.com/rust-lang/rust/issues/57356>
2019-03-30 18:50:19 +09:00
pub merge_functions: MergeFunctions,
/// Use platform dependent mcount function
pub mcount: StaticCow<str>,
/// Use LLVM intrinsic for mcount function name
pub llvm_mcount_intrinsic: Option<StaticCow<str>>,
/// LLVM ABI name, corresponds to the '-mabi' parameter available in multilib C compilers
pub llvm_abiname: StaticCow<str>,
/// Whether or not RelaxElfRelocation flag will be passed to the linker
pub relax_elf_relocations: bool,
/// Additional arguments to pass to LLVM, similar to the `-C llvm-args` codegen option.
pub llvm_args: StaticCow<[StaticCow<str>]>,
/// Whether to use legacy .ctors initialization hooks rather than .init_array. Defaults
/// to false (uses .init_array).
pub use_ctors_section: bool,
/// Whether the linker is instructed to add a `GNU_EH_FRAME` ELF header
/// used to locate unwinding information is passed
/// (only has effect if the linker is `ld`-like).
pub eh_frame_header: bool,
/// Is true if the target is an ARM architecture using thumb v1 which allows for
/// thumb and arm interworking.
pub has_thumb_interworking: bool,
rustc: Stabilize `-Zrun-dsymutil` as `-Csplit-debuginfo` This commit adds a new stable codegen option to rustc, `-Csplit-debuginfo`. The old `-Zrun-dsymutil` flag is deleted and now subsumed by this stable flag. Additionally `-Zsplit-dwarf` is also subsumed by this flag but still requires `-Zunstable-options` to actually activate. The `-Csplit-debuginfo` flag takes one of three values: * `off` - This indicates that split-debuginfo from the final artifact is not desired. This is not supported on Windows and is the default on Unix platforms except macOS. On macOS this means that `dsymutil` is not executed. * `packed` - This means that debuginfo is desired in one location separate from the main executable. This is the default on Windows (`*.pdb`) and macOS (`*.dSYM`). On other Unix platforms this subsumes `-Zsplit-dwarf=single` and produces a `*.dwp` file. * `unpacked` - This means that debuginfo will be roughly equivalent to object files, meaning that it's throughout the build directory rather than in one location (often the fastest for local development). This is not the default on any platform and is not supported on Windows. Each target can indicate its own default preference for how debuginfo is handled. Almost all platforms default to `off` except for Windows and macOS which default to `packed` for historical reasons. Some equivalencies for previous unstable flags with the new flags are: * `-Zrun-dsymutil=yes` -> `-Csplit-debuginfo=packed` * `-Zrun-dsymutil=no` -> `-Csplit-debuginfo=unpacked` * `-Zsplit-dwarf=single` -> `-Csplit-debuginfo=packed` * `-Zsplit-dwarf=split` -> `-Csplit-debuginfo=unpacked` Note that `-Csplit-debuginfo` still requires `-Zunstable-options` for non-macOS platforms since split-dwarf support was *just* implemented in rustc. There's some more rationale listed on #79361, but the main gist of the motivation for this commit is that `dsymutil` can take quite a long time to execute in debug builds and provides little benefit. This means that incremental compile times appear that much worse on macOS because the compiler is constantly running `dsymutil` over every single binary it produces during `cargo build` (even build scripts!). Ideally rustc would switch to not running `dsymutil` by default, but that's a problem left to get tackled another day. Closes #79361
2020-11-30 08:39:08 -08:00
/// Which kind of debuginfo is used by this target?
pub debuginfo_kind: DebuginfoKind,
rustc: Stabilize `-Zrun-dsymutil` as `-Csplit-debuginfo` This commit adds a new stable codegen option to rustc, `-Csplit-debuginfo`. The old `-Zrun-dsymutil` flag is deleted and now subsumed by this stable flag. Additionally `-Zsplit-dwarf` is also subsumed by this flag but still requires `-Zunstable-options` to actually activate. The `-Csplit-debuginfo` flag takes one of three values: * `off` - This indicates that split-debuginfo from the final artifact is not desired. This is not supported on Windows and is the default on Unix platforms except macOS. On macOS this means that `dsymutil` is not executed. * `packed` - This means that debuginfo is desired in one location separate from the main executable. This is the default on Windows (`*.pdb`) and macOS (`*.dSYM`). On other Unix platforms this subsumes `-Zsplit-dwarf=single` and produces a `*.dwp` file. * `unpacked` - This means that debuginfo will be roughly equivalent to object files, meaning that it's throughout the build directory rather than in one location (often the fastest for local development). This is not the default on any platform and is not supported on Windows. Each target can indicate its own default preference for how debuginfo is handled. Almost all platforms default to `off` except for Windows and macOS which default to `packed` for historical reasons. Some equivalencies for previous unstable flags with the new flags are: * `-Zrun-dsymutil=yes` -> `-Csplit-debuginfo=packed` * `-Zrun-dsymutil=no` -> `-Csplit-debuginfo=unpacked` * `-Zsplit-dwarf=single` -> `-Csplit-debuginfo=packed` * `-Zsplit-dwarf=split` -> `-Csplit-debuginfo=unpacked` Note that `-Csplit-debuginfo` still requires `-Zunstable-options` for non-macOS platforms since split-dwarf support was *just* implemented in rustc. There's some more rationale listed on #79361, but the main gist of the motivation for this commit is that `dsymutil` can take quite a long time to execute in debug builds and provides little benefit. This means that incremental compile times appear that much worse on macOS because the compiler is constantly running `dsymutil` over every single binary it produces during `cargo build` (even build scripts!). Ideally rustc would switch to not running `dsymutil` by default, but that's a problem left to get tackled another day. Closes #79361
2020-11-30 08:39:08 -08:00
/// How to handle split debug information, if at all. Specifying `None` has
/// target-specific meaning.
pub split_debuginfo: SplitDebuginfo,
/// Which kinds of split debuginfo are supported by the target?
pub supported_split_debuginfo: StaticCow<[SplitDebuginfo]>,
/// The sanitizers supported by this target
///
/// Note that the support here is at a codegen level. If the machine code with sanitizer
/// enabled can generated on this target, but the necessary supporting libraries are not
/// distributed with the target, the sanitizer should still appear in this list for the target.
pub supported_sanitizers: SanitizerSet,
rustc: Add a new `wasm` ABI This commit implements the idea of a new ABI for the WebAssembly target, one called `"wasm"`. This ABI is entirely of my own invention and has no current precedent, but I think that the addition of this ABI might help solve a number of issues with the WebAssembly targets. When `wasm32-unknown-unknown` was first added to Rust I naively "implemented an abi" for the target. I then went to write `wasm-bindgen` which accidentally relied on details of this ABI. Turns out the ABI definition didn't match C, which is causing issues for C/Rust interop. Currently the compiler has a "wasm32 bindgen compat" ABI which is the original implementation I added, and it's purely there for, well, `wasm-bindgen`. Another issue with the WebAssembly target is that it's not clear to me when and if the default C ABI will change to account for WebAssembly's multi-value feature (a feature that allows functions to return multiple values). Even if this does happen, though, it seems like the C ABI will be guided based on the performance of WebAssembly code and will likely not match even what the current wasm-bindgen-compat ABI is today. This leaves a hole in Rust's expressivity in binding WebAssembly where given a particular import type, Rust may not be able to import that signature with an updated C ABI for multi-value. To fix these issues I had the idea of a new ABI for WebAssembly, one called `wasm`. The definition of this ABI is "what you write maps straight to wasm". The goal here is that whatever you write down in the parameter list or in the return values goes straight into the function's signature in the WebAssembly file. This special ABI is for intentionally matching the ABI of an imported function from the environment or exporting a function with the right signature. With the addition of a new ABI, this enables rustc to: * Eventually remove the "wasm-bindgen compat hack". Once this ABI is stable wasm-bindgen can switch to using it everywhere. Afterwards the wasm32-unknown-unknown target can have its default ABI updated to match C. * Expose the ability to precisely match an ABI signature for a WebAssembly function, regardless of what the C ABI that clang chooses turns out to be. * Continue to evolve the definition of the default C ABI to match what clang does on all targets, since the purpose of that ABI will be explicitly matching C rather than generating particular function imports/exports. Naturally this is implemented as an unstable feature initially, but it would be nice for this to get stabilized (if it works) in the near-ish future to remove the wasm32-unknown-unknown incompatibility with the C ABI. Doing this, however, requires the feature to be on stable because wasm-bindgen works with stable Rust.
2021-04-01 16:08:29 -07:00
/// If present it's a default value to use for adjusting the C ABI.
pub default_adjusted_cabi: Option<Abi>,
2021-08-10 18:34:13 +00:00
/// Minimum number of bits in #[repr(C)] enum. Defaults to the size of c_int
pub c_enum_min_bits: Option<u64>,
/// Whether or not the DWARF `.debug_aranges` section should be generated.
pub generate_arange_section: bool,
add rustc option for using LLVM stack smash protection LLVM has built-in heuristics for adding stack canaries to functions. These heuristics can be selected with LLVM function attributes. This patch adds a rustc option `-Z stack-protector={none,basic,strong,all}` which controls the use of these attributes. This gives rustc the same stack smash protection support as clang offers through options `-fno-stack-protector`, `-fstack-protector`, `-fstack-protector-strong`, and `-fstack-protector-all`. The protection this can offer is demonstrated in test/ui/abi/stack-protector.rs. This fills a gap in the current list of rustc exploit mitigations (https://doc.rust-lang.org/rustc/exploit-mitigations.html), originally discussed in #15179. Stack smash protection adds runtime overhead and is therefore still off by default, but now users have the option to trade performance for security as they see fit. An example use case is adding Rust code in an existing C/C++ code base compiled with stack smash protection. Without the ability to add stack smash protection to the Rust code, the code base artifacts could be exploitable in ways not possible if the code base remained pure C/C++. Stack smash protection support is present in LLVM for almost all the current tier 1/tier 2 targets: see test/assembly/stack-protector/stack-protector-target-support.rs. The one exception is nvptx64-nvidia-cuda. This patch follows clang's example, and adds a warning message printed if stack smash protection is used with this target (see test/ui/stack-protector/warn-stack-protector-unsupported.rs). Support for tier 3 targets has not been checked. Since the heuristics are applied at the LLVM level, the heuristics are expected to add stack smash protection to a fraction of functions comparable to C/C++. Some experiments demonstrating how Rust code is affected by the different heuristics can be found in test/assembly/stack-protector/stack-protector-heuristics-effect.rs. There is potential for better heuristics using Rust-specific safety information. For example it might be reasonable to skip stack smash protection in functions which transitively only use safe Rust code, or which uses only a subset of functions the user declares safe (such as anything under `std.*`). Such alternative heuristics could be added at a later point. LLVM also offers a "safestack" sanitizer as an alternative way to guard against stack smashing (see #26612). This could possibly also be included as a stack-protection heuristic. An alternative is to add it as a sanitizer (#39699). This is what clang does: safestack is exposed with option `-fsanitize=safe-stack`. The options are only supported by the LLVM backend, but as with other codegen options it is visible in the main codegen option help menu. The heuristic names "basic", "strong", and "all" are hopefully sufficiently generic to be usable in other backends as well. Reviewed-by: Nikita Popov <nikic@php.net> Extra commits during review: - [address-review] make the stack-protector option unstable - [address-review] reduce detail level of stack-protector option help text - [address-review] correct grammar in comment - [address-review] use compiler flag to avoid merging functions in test - [address-review] specify min LLVM version in fortanix stack-protector test Only for Fortanix test, since this target specifically requests the `--x86-experimental-lvi-inline-asm-hardening` flag. - [address-review] specify required LLVM components in stack-protector tests - move stack protector option enum closer to other similar option enums - rustc_interface/tests: sort debug option list in tracking hash test - add an explicit `none` stack-protector option Revert "set LLVM requirements for all stack protector support test revisions" This reverts commit a49b74f92a4e7d701d6f6cf63d207a8aff2e0f68.
2021-04-06 21:37:49 +02:00
/// Whether the target supports stack canary checks. `true` by default,
/// since this is most common among tier 1 and tier 2 targets.
pub supports_stack_protector: bool,
/// The name of entry function.
/// Default value is "main"
pub entry_name: StaticCow<str>,
/// The ABI of entry function.
/// Default value is `Conv::C`, i.e. C call convention
pub entry_abi: Conv,
/// Whether the target supports XRay instrumentation.
pub supports_xray: bool,
}
/// Add arguments for the given flavor and also for its "twin" flavors
/// that have a compatible command line interface.
fn add_link_args_iter(
link_args: &mut LinkArgs,
flavor: LinkerFlavor,
args: impl Iterator<Item = StaticCow<str>> + Clone,
) {
let mut insert = |flavor| link_args.entry(flavor).or_default().extend(args.clone());
insert(flavor);
match flavor {
LinkerFlavor::Gnu(cc, lld) => {
assert_eq!(lld, Lld::No);
insert(LinkerFlavor::Gnu(cc, Lld::Yes));
}
LinkerFlavor::Darwin(cc, lld) => {
assert_eq!(lld, Lld::No);
insert(LinkerFlavor::Darwin(cc, Lld::Yes));
}
LinkerFlavor::Msvc(lld) => {
assert_eq!(lld, Lld::No);
insert(LinkerFlavor::Msvc(Lld::Yes));
}
LinkerFlavor::WasmLld(..)
| LinkerFlavor::Unix(..)
| LinkerFlavor::EmCc
| LinkerFlavor::Bpf
| LinkerFlavor::Ptx => {}
}
}
fn add_link_args(link_args: &mut LinkArgs, flavor: LinkerFlavor, args: &[&'static str]) {
add_link_args_iter(link_args, flavor, args.iter().copied().map(Cow::Borrowed))
}
impl TargetOptions {
fn link_args(flavor: LinkerFlavor, args: &[&'static str]) -> LinkArgs {
let mut link_args = LinkArgs::new();
add_link_args(&mut link_args, flavor, args);
link_args
}
fn add_pre_link_args(&mut self, flavor: LinkerFlavor, args: &[&'static str]) {
add_link_args(&mut self.pre_link_args, flavor, args);
}
fn update_from_cli(&mut self) {
self.linker_flavor = LinkerFlavor::from_cli_json(
self.linker_flavor_json,
self.lld_flavor_json,
self.linker_is_gnu_json,
);
for (args, args_json) in [
(&mut self.pre_link_args, &self.pre_link_args_json),
(&mut self.late_link_args, &self.late_link_args_json),
(&mut self.late_link_args_dynamic, &self.late_link_args_dynamic_json),
(&mut self.late_link_args_static, &self.late_link_args_static_json),
(&mut self.post_link_args, &self.post_link_args_json),
] {
args.clear();
for (flavor, args_json) in args_json {
let linker_flavor = self.linker_flavor.with_cli_hints(*flavor);
// Normalize to no lld to avoid asserts.
let linker_flavor = match linker_flavor {
LinkerFlavor::Gnu(cc, _) => LinkerFlavor::Gnu(cc, Lld::No),
LinkerFlavor::Darwin(cc, _) => LinkerFlavor::Darwin(cc, Lld::No),
LinkerFlavor::Msvc(_) => LinkerFlavor::Msvc(Lld::No),
_ => linker_flavor,
};
if !args.contains_key(&linker_flavor) {
add_link_args_iter(args, linker_flavor, args_json.iter().cloned());
}
}
}
}
fn update_to_cli(&mut self) {
self.linker_flavor_json = self.linker_flavor.to_cli_counterpart();
self.lld_flavor_json = self.linker_flavor.lld_flavor();
self.linker_is_gnu_json = self.linker_flavor.is_gnu();
for (args, args_json) in [
(&self.pre_link_args, &mut self.pre_link_args_json),
(&self.late_link_args, &mut self.late_link_args_json),
(&self.late_link_args_dynamic, &mut self.late_link_args_dynamic_json),
(&self.late_link_args_static, &mut self.late_link_args_static_json),
(&self.post_link_args, &mut self.post_link_args_json),
] {
*args_json = args
.iter()
.map(|(flavor, args)| (flavor.to_cli_counterpart(), args.clone()))
.collect();
}
}
}
impl Default for TargetOptions {
2019-02-08 14:53:55 +01:00
/// Creates a set of "sane defaults" for any target. This is still
/// incomplete, and if used for compilation, will certainly not work.
fn default() -> TargetOptions {
TargetOptions {
is_builtin: false,
endian: Endian::Little,
c_int_width: "32".into(),
os: "none".into(),
env: "".into(),
abi: "".into(),
vendor: "unknown".into(),
linker: option_env!("CFG_DEFAULT_LINKER").map(|s| s.into()),
linker_flavor: LinkerFlavor::Gnu(Cc::Yes, Lld::No),
linker_flavor_json: LinkerFlavorCli::Gcc,
lld_flavor_json: LldFlavor::Ld,
linker_is_gnu_json: true,
link_script: None,
asm_args: cvs![],
cpu: "generic".into(),
features: "".into(),
direct_access_external_data: None,
dynamic_linking: false,
dll_tls_export: true,
std: Add a new wasm32-unknown-unknown target This commit adds a new target to the compiler: wasm32-unknown-unknown. This target is a reimagining of what it looks like to generate WebAssembly code from Rust. Instead of using Emscripten which can bring with it a weighty runtime this instead is a target which uses only the LLVM backend for WebAssembly and a "custom linker" for now which will hopefully one day be direct calls to lld. Notable features of this target include: * There is zero runtime footprint. The target assumes nothing exists other than the wasm32 instruction set. * There is zero toolchain footprint beyond adding the target. No custom linker is needed, rustc contains everything. * Very small wasm modules can be generated directly from Rust code using this target. * Most of the standard library is stubbed out to return an error, but anything related to allocation works (aka `HashMap`, `Vec`, etc). * Naturally, any `#[no_std]` crate should be 100% compatible with this new target. This target is currently somewhat janky due to how linking works. The "linking" is currently unconditional whole program LTO (aka LLVM is being used as a linker). Naturally that means compiling programs is pretty slow! Eventually though this target should have a linker. This target is also intended to be quite experimental. I'm hoping that this can act as a catalyst for further experimentation in Rust with WebAssembly. Breaking changes are very likely to land to this target, so it's not recommended to rely on it in any critical capacity yet. We'll let you know when it's "production ready". --- Currently testing-wise this target is looking pretty good but isn't complete. I've got almost the entire `run-pass` test suite working with this target (lots of tests ignored, but many passing as well). The `core` test suite is still getting LLVM bugs fixed to get that working and will take some time. Relatively simple programs all seem to work though! --- It's worth nothing that you may not immediately see the "smallest possible wasm module" for the input you feed to rustc. For various reasons it's very difficult to get rid of the final "bloat" in vanilla rustc (again, a real linker should fix all this). For now what you'll have to do is: cargo install --git https://github.com/alexcrichton/wasm-gc wasm-gc foo.wasm bar.wasm And then `bar.wasm` should be the smallest we can get it! --- In any case for now I'd love feedback on this, particularly on the various integration points if you've got better ideas of how to approach them!
2017-10-22 20:01:00 -07:00
only_cdylib: false,
executables: true,
relocation_model: RelocModel::Pic,
code_model: None,
tls_model: TlsModel::GeneralDynamic,
disable_redzone: false,
frame_pointer: FramePointer::MayOmit,
function_sections: true,
dll_prefix: "lib".into(),
dll_suffix: ".so".into(),
exe_suffix: "".into(),
staticlib_prefix: "lib".into(),
staticlib_suffix: ".a".into(),
families: cvs![],
abi_return_struct_as_int: false,
2022-08-25 14:37:29 +08:00
is_like_aix: false,
is_like_osx: false,
2016-01-28 14:02:31 +03:00
is_like_solaris: false,
is_like_windows: false,
is_like_msvc: false,
2020-12-30 12:52:21 -06:00
is_like_wasm: false,
is_like_android: false,
default_dwarf_version: 4,
allows_weak_linkage: true,
has_rpath: false,
no_default_libraries: true,
2014-11-06 00:17:56 -05:00
position_independent_executables: false,
static_position_independent_executables: false,
plt_by_default: true,
relro_level: RelroLevel::None,
pre_link_objects: Default::default(),
post_link_objects: Default::default(),
pre_link_objects_self_contained: Default::default(),
post_link_objects_self_contained: Default::default(),
link_self_contained: LinkSelfContainedDefault::False,
pre_link_args: LinkArgs::new(),
pre_link_args_json: LinkArgsCli::new(),
-Z linker-flavor This patch adds a `-Z linker-flavor` flag to rustc which can be used to invoke the linker using a different interface. For example, by default rustc assumes that all the Linux targets will be linked using GCC. This makes it impossible to use LLD as a linker using just `-C linker=ld.lld` because that will invoke LLD with invalid command line arguments. (e.g. rustc will pass -Wl,--gc-sections to LLD but LLD doesn't understand that; --gc-sections would be the right argument) With this patch one can pass `-Z linker-flavor=ld` to rustc to invoke the linker using a LD-like interface. This way, `rustc -C linker=ld.lld -Z linker-flavor=ld` will invoke LLD with the right arguments. `-Z linker-flavor` accepts 4 different arguments: `em` (emcc), `ld`, `gcc`, `msvc` (link.exe). `em`, `gnu` and `msvc` cover all the existing linker interfaces. `ld` is a new flavor for interfacing GNU's ld and LLD. This patch also changes target specifications. `linker-flavor` is now a mandatory field that specifies the *default* linker flavor that the target will use. This change also makes the linker interface *explicit*; before, it used to be derived from other fields like linker-is-gnu, is-like-msvc, is-like-emscripten, etc. Another change to target specifications is that the fields `pre-link-args`, `post-link-args` and `late-link-args` now expect a map from flavor to linker arguments. ``` diff - "pre-link-args": ["-Wl,--as-needed", "-Wl,-z,-noexecstack"], + "pre-link-args": { + "gcc": ["-Wl,--as-needed", "-Wl,-z,-noexecstack"], + "ld": ["--as-needed", "-z,-noexecstack"], + }, ``` [breaking-change] for users of custom targets specifications
2017-02-21 14:47:15 -05:00
late_link_args: LinkArgs::new(),
late_link_args_json: LinkArgsCli::new(),
late_link_args_dynamic: LinkArgs::new(),
late_link_args_dynamic_json: LinkArgsCli::new(),
late_link_args_static: LinkArgs::new(),
late_link_args_static_json: LinkArgsCli::new(),
post_link_args: LinkArgs::new(),
post_link_args_json: LinkArgsCli::new(),
link_env: cvs![],
link_env_remove: cvs![],
archive_format: "gnu".into(),
main_needs_argc_argv: true,
allow_asm: true,
has_thread_local: false,
obj_is_bitcode: false,
forces_embed_bitcode: false,
bitcode_llvm_cmdline: "".into(),
min_atomic_width: None,
max_atomic_width: None,
atomic_cas: true,
panic_strategy: PanicStrategy::Unwind,
crt_static_allows_dylibs: false,
rustc: Implement #[link(cfg(..))] and crt-static This commit is an implementation of [RFC 1721] which adds a new target feature to the compiler, `crt-static`, which can be used to select how the C runtime for a target is linked. Most targets dynamically linke the C runtime by default with the notable exception of some of the musl targets. [RFC 1721]: https://github.com/rust-lang/rfcs/blob/master/text/1721-crt-static.md This commit first adds the new target-feature, `crt-static`. If enabled, then the `cfg(target_feature = "crt-static")` will be available. Targets like musl will have this enabled by default. This feature can be controlled through the standard target-feature interface, `-C target-feature=+crt-static` or `-C target-feature=-crt-static`. Next this adds an gated and unstable `#[link(cfg(..))]` feature to enable the `crt-static` semantics we want with libc. The exact behavior of this attribute is a little squishy, but it's intended to be a forever-unstable implementation detail of the liblibc crate. Specifically the `#[link(cfg(..))]` annotation means that the `#[link]` directive is only active in a compilation unit if that `cfg` value is satisfied. For example when compiling an rlib, these directives are just encoded and ignored for dylibs, and all staticlibs are continued to be put into the rlib as usual. When placing that rlib into a staticlib, executable, or dylib, however, the `cfg` is evaluated *as if it were defined in the final artifact* and the library is decided to be linked or not. Essentially, what'll happen is: * On MSVC with `-C target-feature=-crt-static`, the `msvcrt.lib` library will be linked to. * On MSVC with `-C target-feature=+crt-static`, the `libcmt.lib` library will be linked to. * On musl with `-C target-feature=-crt-static`, the object files in liblibc.rlib are removed and `-lc` is passed instead. * On musl with `-C target-feature=+crt-static`, the object files in liblibc.rlib are used and `-lc` is not passed. This commit does **not** include an update to the liblibc module to implement these changes. I plan to do that just after the 1.14.0 beta release is cut to ensure we get ample time to test this feature. cc #37406
2016-10-31 16:40:13 -07:00
crt_static_default: false,
crt_static_respected: false,
stack_probes: StackProbeType::None,
min_global_align: None,
default_codegen_units: None,
trap_unreachable: true,
std: Add a new wasm32-unknown-unknown target This commit adds a new target to the compiler: wasm32-unknown-unknown. This target is a reimagining of what it looks like to generate WebAssembly code from Rust. Instead of using Emscripten which can bring with it a weighty runtime this instead is a target which uses only the LLVM backend for WebAssembly and a "custom linker" for now which will hopefully one day be direct calls to lld. Notable features of this target include: * There is zero runtime footprint. The target assumes nothing exists other than the wasm32 instruction set. * There is zero toolchain footprint beyond adding the target. No custom linker is needed, rustc contains everything. * Very small wasm modules can be generated directly from Rust code using this target. * Most of the standard library is stubbed out to return an error, but anything related to allocation works (aka `HashMap`, `Vec`, etc). * Naturally, any `#[no_std]` crate should be 100% compatible with this new target. This target is currently somewhat janky due to how linking works. The "linking" is currently unconditional whole program LTO (aka LLVM is being used as a linker). Naturally that means compiling programs is pretty slow! Eventually though this target should have a linker. This target is also intended to be quite experimental. I'm hoping that this can act as a catalyst for further experimentation in Rust with WebAssembly. Breaking changes are very likely to land to this target, so it's not recommended to rely on it in any critical capacity yet. We'll let you know when it's "production ready". --- Currently testing-wise this target is looking pretty good but isn't complete. I've got almost the entire `run-pass` test suite working with this target (lots of tests ignored, but many passing as well). The `core` test suite is still getting LLVM bugs fixed to get that working and will take some time. Relatively simple programs all seem to work though! --- It's worth nothing that you may not immediately see the "smallest possible wasm module" for the input you feed to rustc. For various reasons it's very difficult to get rid of the final "bloat" in vanilla rustc (again, a real linker should fix all this). For now what you'll have to do is: cargo install --git https://github.com/alexcrichton/wasm-gc wasm-gc foo.wasm bar.wasm And then `bar.wasm` should be the smallest we can get it! --- In any case for now I'd love feedback on this, particularly on the various integration points if you've got better ideas of how to approach them!
2017-10-22 20:01:00 -07:00
requires_lto: false,
singlethread: false,
no_builtins: false,
default_hidden_visibility: false,
emit_debug_gdb_scripts: true,
requires_uwtable: false,
default_uwtable: false,
simd_types_indirect: true,
limit_rdylib_exports: true,
override_export_symbols: None,
merge_functions: MergeFunctions::Aliases,
mcount: "mcount".into(),
llvm_mcount_intrinsic: None,
llvm_abiname: "".into(),
relax_elf_relocations: false,
llvm_args: cvs![],
use_ctors_section: false,
eh_frame_header: true,
has_thumb_interworking: false,
debuginfo_kind: Default::default(),
split_debuginfo: Default::default(),
// `Off` is supported by default, but targets can remove this manually, e.g. Windows.
supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]),
supported_sanitizers: SanitizerSet::empty(),
rustc: Add a new `wasm` ABI This commit implements the idea of a new ABI for the WebAssembly target, one called `"wasm"`. This ABI is entirely of my own invention and has no current precedent, but I think that the addition of this ABI might help solve a number of issues with the WebAssembly targets. When `wasm32-unknown-unknown` was first added to Rust I naively "implemented an abi" for the target. I then went to write `wasm-bindgen` which accidentally relied on details of this ABI. Turns out the ABI definition didn't match C, which is causing issues for C/Rust interop. Currently the compiler has a "wasm32 bindgen compat" ABI which is the original implementation I added, and it's purely there for, well, `wasm-bindgen`. Another issue with the WebAssembly target is that it's not clear to me when and if the default C ABI will change to account for WebAssembly's multi-value feature (a feature that allows functions to return multiple values). Even if this does happen, though, it seems like the C ABI will be guided based on the performance of WebAssembly code and will likely not match even what the current wasm-bindgen-compat ABI is today. This leaves a hole in Rust's expressivity in binding WebAssembly where given a particular import type, Rust may not be able to import that signature with an updated C ABI for multi-value. To fix these issues I had the idea of a new ABI for WebAssembly, one called `wasm`. The definition of this ABI is "what you write maps straight to wasm". The goal here is that whatever you write down in the parameter list or in the return values goes straight into the function's signature in the WebAssembly file. This special ABI is for intentionally matching the ABI of an imported function from the environment or exporting a function with the right signature. With the addition of a new ABI, this enables rustc to: * Eventually remove the "wasm-bindgen compat hack". Once this ABI is stable wasm-bindgen can switch to using it everywhere. Afterwards the wasm32-unknown-unknown target can have its default ABI updated to match C. * Expose the ability to precisely match an ABI signature for a WebAssembly function, regardless of what the C ABI that clang chooses turns out to be. * Continue to evolve the definition of the default C ABI to match what clang does on all targets, since the purpose of that ABI will be explicitly matching C rather than generating particular function imports/exports. Naturally this is implemented as an unstable feature initially, but it would be nice for this to get stabilized (if it works) in the near-ish future to remove the wasm32-unknown-unknown incompatibility with the C ABI. Doing this, however, requires the feature to be on stable because wasm-bindgen works with stable Rust.
2021-04-01 16:08:29 -07:00
default_adjusted_cabi: None,
c_enum_min_bits: None,
generate_arange_section: true,
add rustc option for using LLVM stack smash protection LLVM has built-in heuristics for adding stack canaries to functions. These heuristics can be selected with LLVM function attributes. This patch adds a rustc option `-Z stack-protector={none,basic,strong,all}` which controls the use of these attributes. This gives rustc the same stack smash protection support as clang offers through options `-fno-stack-protector`, `-fstack-protector`, `-fstack-protector-strong`, and `-fstack-protector-all`. The protection this can offer is demonstrated in test/ui/abi/stack-protector.rs. This fills a gap in the current list of rustc exploit mitigations (https://doc.rust-lang.org/rustc/exploit-mitigations.html), originally discussed in #15179. Stack smash protection adds runtime overhead and is therefore still off by default, but now users have the option to trade performance for security as they see fit. An example use case is adding Rust code in an existing C/C++ code base compiled with stack smash protection. Without the ability to add stack smash protection to the Rust code, the code base artifacts could be exploitable in ways not possible if the code base remained pure C/C++. Stack smash protection support is present in LLVM for almost all the current tier 1/tier 2 targets: see test/assembly/stack-protector/stack-protector-target-support.rs. The one exception is nvptx64-nvidia-cuda. This patch follows clang's example, and adds a warning message printed if stack smash protection is used with this target (see test/ui/stack-protector/warn-stack-protector-unsupported.rs). Support for tier 3 targets has not been checked. Since the heuristics are applied at the LLVM level, the heuristics are expected to add stack smash protection to a fraction of functions comparable to C/C++. Some experiments demonstrating how Rust code is affected by the different heuristics can be found in test/assembly/stack-protector/stack-protector-heuristics-effect.rs. There is potential for better heuristics using Rust-specific safety information. For example it might be reasonable to skip stack smash protection in functions which transitively only use safe Rust code, or which uses only a subset of functions the user declares safe (such as anything under `std.*`). Such alternative heuristics could be added at a later point. LLVM also offers a "safestack" sanitizer as an alternative way to guard against stack smashing (see #26612). This could possibly also be included as a stack-protection heuristic. An alternative is to add it as a sanitizer (#39699). This is what clang does: safestack is exposed with option `-fsanitize=safe-stack`. The options are only supported by the LLVM backend, but as with other codegen options it is visible in the main codegen option help menu. The heuristic names "basic", "strong", and "all" are hopefully sufficiently generic to be usable in other backends as well. Reviewed-by: Nikita Popov <nikic@php.net> Extra commits during review: - [address-review] make the stack-protector option unstable - [address-review] reduce detail level of stack-protector option help text - [address-review] correct grammar in comment - [address-review] use compiler flag to avoid merging functions in test - [address-review] specify min LLVM version in fortanix stack-protector test Only for Fortanix test, since this target specifically requests the `--x86-experimental-lvi-inline-asm-hardening` flag. - [address-review] specify required LLVM components in stack-protector tests - move stack protector option enum closer to other similar option enums - rustc_interface/tests: sort debug option list in tracking hash test - add an explicit `none` stack-protector option Revert "set LLVM requirements for all stack protector support test revisions" This reverts commit a49b74f92a4e7d701d6f6cf63d207a8aff2e0f68.
2021-04-06 21:37:49 +02:00
supports_stack_protector: true,
entry_name: "main".into(),
entry_abi: Conv::C,
supports_xray: false,
}
}
}
/// `TargetOptions` being a separate type is basically an implementation detail of `Target` that is
/// used for providing defaults. Perhaps there's a way to merge `TargetOptions` into `Target` so
/// this `Deref` implementation is no longer necessary.
impl Deref for Target {
type Target = TargetOptions;
2022-02-12 00:00:00 +00:00
#[inline]
fn deref(&self) -> &Self::Target {
&self.options
}
}
impl DerefMut for Target {
2022-02-12 00:00:00 +00:00
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.options
}
}
impl Target {
/// Given a function ABI, turn it into the correct ABI for this target.
2024-01-12 23:05:07 -08:00
pub fn adjust_abi(&self, abi: Abi, c_variadic: bool) -> Abi {
match abi {
Abi::C { .. } => self.default_adjusted_cabi.unwrap_or(abi),
2024-01-12 23:05:07 -08:00
// On Windows, `extern "system"` behaves like msvc's `__stdcall`.
// `__stdcall` only applies on x86 and on non-variadic functions:
// https://learn.microsoft.com/en-us/cpp/cpp/stdcall?view=msvc-170
Abi::System { unwind } if self.is_like_windows && self.arch == "x86" && !c_variadic => {
Abi::Stdcall { unwind }
}
Abi::System { unwind } => Abi::C { unwind },
Abi::EfiApi if self.arch == "arm" => Abi::Aapcs { unwind: false },
Abi::EfiApi if self.arch == "x86_64" => Abi::Win64 { unwind: false },
Abi::EfiApi => Abi::C { unwind: false },
rustc: Add a new `wasm` ABI This commit implements the idea of a new ABI for the WebAssembly target, one called `"wasm"`. This ABI is entirely of my own invention and has no current precedent, but I think that the addition of this ABI might help solve a number of issues with the WebAssembly targets. When `wasm32-unknown-unknown` was first added to Rust I naively "implemented an abi" for the target. I then went to write `wasm-bindgen` which accidentally relied on details of this ABI. Turns out the ABI definition didn't match C, which is causing issues for C/Rust interop. Currently the compiler has a "wasm32 bindgen compat" ABI which is the original implementation I added, and it's purely there for, well, `wasm-bindgen`. Another issue with the WebAssembly target is that it's not clear to me when and if the default C ABI will change to account for WebAssembly's multi-value feature (a feature that allows functions to return multiple values). Even if this does happen, though, it seems like the C ABI will be guided based on the performance of WebAssembly code and will likely not match even what the current wasm-bindgen-compat ABI is today. This leaves a hole in Rust's expressivity in binding WebAssembly where given a particular import type, Rust may not be able to import that signature with an updated C ABI for multi-value. To fix these issues I had the idea of a new ABI for WebAssembly, one called `wasm`. The definition of this ABI is "what you write maps straight to wasm". The goal here is that whatever you write down in the parameter list or in the return values goes straight into the function's signature in the WebAssembly file. This special ABI is for intentionally matching the ABI of an imported function from the environment or exporting a function with the right signature. With the addition of a new ABI, this enables rustc to: * Eventually remove the "wasm-bindgen compat hack". Once this ABI is stable wasm-bindgen can switch to using it everywhere. Afterwards the wasm32-unknown-unknown target can have its default ABI updated to match C. * Expose the ability to precisely match an ABI signature for a WebAssembly function, regardless of what the C ABI that clang chooses turns out to be. * Continue to evolve the definition of the default C ABI to match what clang does on all targets, since the purpose of that ABI will be explicitly matching C rather than generating particular function imports/exports. Naturally this is implemented as an unstable feature initially, but it would be nice for this to get stabilized (if it works) in the near-ish future to remove the wasm32-unknown-unknown incompatibility with the C ABI. Doing this, however, requires the feature to be on stable because wasm-bindgen works with stable Rust.
2021-04-01 16:08:29 -07:00
// See commentary in `is_abi_supported`.
Abi::Stdcall { .. } | Abi::Thiscall { .. } if self.arch == "x86" => abi,
Abi::Stdcall { unwind } | Abi::Thiscall { unwind } => Abi::C { unwind },
Abi::Fastcall { .. } if self.arch == "x86" => abi,
Abi::Vectorcall { .. } if ["x86", "x86_64"].contains(&&self.arch[..]) => abi,
Abi::Fastcall { unwind } | Abi::Vectorcall { unwind } => Abi::C { unwind },
rustc: Add a new `wasm` ABI This commit implements the idea of a new ABI for the WebAssembly target, one called `"wasm"`. This ABI is entirely of my own invention and has no current precedent, but I think that the addition of this ABI might help solve a number of issues with the WebAssembly targets. When `wasm32-unknown-unknown` was first added to Rust I naively "implemented an abi" for the target. I then went to write `wasm-bindgen` which accidentally relied on details of this ABI. Turns out the ABI definition didn't match C, which is causing issues for C/Rust interop. Currently the compiler has a "wasm32 bindgen compat" ABI which is the original implementation I added, and it's purely there for, well, `wasm-bindgen`. Another issue with the WebAssembly target is that it's not clear to me when and if the default C ABI will change to account for WebAssembly's multi-value feature (a feature that allows functions to return multiple values). Even if this does happen, though, it seems like the C ABI will be guided based on the performance of WebAssembly code and will likely not match even what the current wasm-bindgen-compat ABI is today. This leaves a hole in Rust's expressivity in binding WebAssembly where given a particular import type, Rust may not be able to import that signature with an updated C ABI for multi-value. To fix these issues I had the idea of a new ABI for WebAssembly, one called `wasm`. The definition of this ABI is "what you write maps straight to wasm". The goal here is that whatever you write down in the parameter list or in the return values goes straight into the function's signature in the WebAssembly file. This special ABI is for intentionally matching the ABI of an imported function from the environment or exporting a function with the right signature. With the addition of a new ABI, this enables rustc to: * Eventually remove the "wasm-bindgen compat hack". Once this ABI is stable wasm-bindgen can switch to using it everywhere. Afterwards the wasm32-unknown-unknown target can have its default ABI updated to match C. * Expose the ability to precisely match an ABI signature for a WebAssembly function, regardless of what the C ABI that clang chooses turns out to be. * Continue to evolve the definition of the default C ABI to match what clang does on all targets, since the purpose of that ABI will be explicitly matching C rather than generating particular function imports/exports. Naturally this is implemented as an unstable feature initially, but it would be nice for this to get stabilized (if it works) in the near-ish future to remove the wasm32-unknown-unknown incompatibility with the C ABI. Doing this, however, requires the feature to be on stable because wasm-bindgen works with stable Rust.
2021-04-01 16:08:29 -07:00
// The Windows x64 calling convention we use for `extern "Rust"`
// <https://learn.microsoft.com/en-us/cpp/build/x64-software-conventions#register-volatility-and-preservation>
// expects the callee to save `xmm6` through `xmm15`, but `PreserveMost`
// (that we use by default for `extern "rust-cold"`) doesn't save any of those.
// So to avoid bloating callers, just use the Rust convention here.
Abi::RustCold if self.is_like_windows && self.arch == "x86_64" => Abi::Rust,
abi => abi,
}
}
/// Returns a None if the UNSUPPORTED_CALLING_CONVENTIONS lint should be emitted
pub fn is_abi_supported(&self, abi: Abi) -> Option<bool> {
use Abi::*;
Some(match abi {
Rust
| C { .. }
| System { .. }
| RustIntrinsic
| RustCall
| Unadjusted
| Cdecl { .. }
| RustCold => true,
EfiApi => {
["arm", "aarch64", "riscv32", "riscv64", "x86", "x86_64"].contains(&&self.arch[..])
}
X86Interrupt => ["x86", "x86_64"].contains(&&self.arch[..]),
Aapcs { .. } => "arm" == self.arch,
CCmseNonSecureCall => ["arm", "aarch64"].contains(&&self.arch[..]),
Win64 { .. } | SysV64 { .. } => self.arch == "x86_64",
PtxKernel => self.arch == "nvptx64",
Msp430Interrupt => self.arch == "msp430",
feat: `riscv-interrupt-{m,s}` calling conventions Similar to prior support added for the mips430, avr, and x86 targets this change implements the rough equivalent of clang's [`__attribute__((interrupt))`][clang-attr] for riscv targets, enabling e.g. ```rust static mut CNT: usize = 0; pub extern "riscv-interrupt-m" fn isr_m() { unsafe { CNT += 1; } } ``` to produce highly effective assembly like: ```asm pub extern "riscv-interrupt-m" fn isr_m() { 420003a0: 1141 addi sp,sp,-16 unsafe { CNT += 1; 420003a2: c62a sw a0,12(sp) 420003a4: c42e sw a1,8(sp) 420003a6: 3fc80537 lui a0,0x3fc80 420003aa: 63c52583 lw a1,1596(a0) # 3fc8063c <_ZN12esp_riscv_rt3CNT17hcec3e3a214887d53E.0> 420003ae: 0585 addi a1,a1,1 420003b0: 62b52e23 sw a1,1596(a0) } } 420003b4: 4532 lw a0,12(sp) 420003b6: 45a2 lw a1,8(sp) 420003b8: 0141 addi sp,sp,16 420003ba: 30200073 mret ``` (disassembly via `riscv64-unknown-elf-objdump -C -S --disassemble ./esp32c3-hal/target/riscv32imc-unknown-none-elf/release/examples/gpio_interrupt`) This outcome is superior to hand-coded interrupt routines which, lacking visibility into any non-assembly body of the interrupt handler, have to be very conservative and save the [entire CPU state to the stack frame][full-frame-save]. By instead asking LLVM to only save the registers that it uses, we defer the decision to the tool with the best context: it can more accurately account for the cost of spills if it knows that every additional register used is already at the cost of an implicit spill. At the LLVM level, this is apparently [implemented by] marking every register as "[callee-save]," matching the semantics of an interrupt handler nicely (it has to leave the CPU state just as it found it after its `{m|s}ret`). This approach is not suitable for every interrupt handler, as it makes no attempt to e.g. save the state in a user-accessible stack frame. For a full discussion of those challenges and tradeoffs, please refer to [the interrupt calling conventions RFC][rfc]. Inside rustc, this implementation differs from prior art because LLVM does not expose the "all-saved" function flavor as a calling convention directly, instead preferring to use an attribute that allows for differentiating between "machine-mode" and "superivsor-mode" interrupts. Finally, some effort has been made to guide those who may not yet be aware of the differences between machine-mode and supervisor-mode interrupts as to why no `riscv-interrupt` calling convention is exposed through rustc, and similarly for why `riscv-interrupt-u` makes no appearance (as it would complicate future LLVM upgrades). [clang-attr]: https://clang.llvm.org/docs/AttributeReference.html#interrupt-risc-v [full-frame-save]: https://github.com/esp-rs/esp-riscv-rt/blob/9281af2ecffe13e40992917316f36920c26acaf3/src/lib.rs#L440-L469 [implemented by]: https://github.com/llvm/llvm-project/blob/b7fb2a3fec7c187d58a6d338ab512d9173bca987/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp#L61-L67 [callee-save]: https://github.com/llvm/llvm-project/blob/973f1fe7a8591c7af148e573491ab68cc15b6ecf/llvm/lib/Target/RISCV/RISCVCallingConv.td#L30-L37 [rfc]: https://github.com/rust-lang/rfcs/pull/3246
2023-05-23 15:08:23 -07:00
RiscvInterruptM | RiscvInterruptS => ["riscv32", "riscv64"].contains(&&self.arch[..]),
AvrInterrupt | AvrNonBlockingInterrupt => self.arch == "avr",
Wasm => ["wasm32", "wasm64"].contains(&&self.arch[..]),
Thiscall { .. } => self.arch == "x86",
// On windows these fall-back to platform native calling convention (C) when the
// architecture is not supported.
//
// This is I believe a historical accident that has occurred as part of Microsoft
// striving to allow most of the code to "just" compile when support for 64-bit x86
// was added and then later again, when support for ARM architectures was added.
//
// This is well documented across MSDN. Support for this in Rust has been added in
// #54576. This makes much more sense in context of Microsoft's C++ than it does in
// Rust, but there isn't much leeway remaining here to change it back at the time this
// comment has been written.
//
// Following are the relevant excerpts from the MSDN documentation.
//
// > The __vectorcall calling convention is only supported in native code on x86 and
// x64 processors that include Streaming SIMD Extensions 2 (SSE2) and above.
// > ...
// > On ARM machines, __vectorcall is accepted and ignored by the compiler.
//
// -- https://docs.microsoft.com/en-us/cpp/cpp/vectorcall?view=msvc-160
//
// > On ARM and x64 processors, __stdcall is accepted and ignored by the compiler;
//
// -- https://docs.microsoft.com/en-us/cpp/cpp/stdcall?view=msvc-160
//
// > In most cases, keywords or compiler switches that specify an unsupported
// > convention on a particular platform are ignored, and the platform default
// > convention is used.
//
// -- https://docs.microsoft.com/en-us/cpp/cpp/argument-passing-and-naming-conventions
Stdcall { .. } | Fastcall { .. } | Vectorcall { .. } if self.is_like_windows => true,
// Outside of Windows we want to only support these calling conventions for the
// architectures for which these calling conventions are actually well defined.
Stdcall { .. } | Fastcall { .. } if self.arch == "x86" => true,
Vectorcall { .. } if ["x86", "x86_64"].contains(&&self.arch[..]) => true,
// Return a `None` for other cases so that we know to emit a future compat lint.
Stdcall { .. } | Fastcall { .. } | Vectorcall { .. } => return None,
})
}
/// Minimum integer size in bits that this target can perform atomic
/// operations on.
pub fn min_atomic_width(&self) -> u64 {
self.min_atomic_width.unwrap_or(8)
}
/// Maximum integer size in bits that this target can perform atomic
/// operations on.
pub fn max_atomic_width(&self) -> u64 {
self.max_atomic_width.unwrap_or_else(|| self.pointer_width.into())
}
2019-02-08 14:53:55 +01:00
/// Loads a target descriptor from a JSON object.
2021-06-03 17:45:09 +02:00
pub fn from_json(obj: Json) -> Result<(Target, TargetWarnings), String> {
// While ugly, this code must remain this way to retain
// compatibility with existing JSON fields and the internal
// expected naming of the Target and TargetOptions structs.
// To ensure compatibility is retained, the built-in targets
// are round-tripped through this code to catch cases where
// the JSON parser is not updated to match the structs.
2021-06-03 17:45:09 +02:00
let mut obj = match obj {
Value::Object(obj) => obj,
_ => return Err("Expected JSON object for target")?,
};
let mut get_req_field = |name: &str| {
2021-06-03 17:45:09 +02:00
obj.remove(name)
.and_then(|j| j.as_str().map(str::to_string))
.ok_or_else(|| format!("Field {name} in target specification is required"))
};
let mut base = Target {
llvm_target: get_req_field("llvm-target")?.into(),
description: get_req_field("description").ok().map(Into::into),
pointer_width: get_req_field("target-pointer-width")?
.parse::<u32>()
.map_err(|_| "target-pointer-width must be an integer".to_string())?,
data_layout: get_req_field("data-layout")?.into(),
arch: get_req_field("arch")?.into(),
options: Default::default(),
};
let mut incorrect_type = vec![];
macro_rules! key {
($key_name:ident) => ( {
let name = (stringify!($key_name)).replace("_", "-");
2021-06-03 17:45:09 +02:00
if let Some(s) = obj.remove(&name).and_then(|s| s.as_str().map(str::to_string).map(Cow::from)) {
base.$key_name = s;
}
} );
($key_name:ident = $json_name:expr) => ( {
let name = $json_name;
2021-06-03 17:45:09 +02:00
if let Some(s) = obj.remove(name).and_then(|s| s.as_str().map(str::to_string).map(Cow::from)) {
base.$key_name = s;
}
} );
($key_name:ident, bool) => ( {
let name = (stringify!($key_name)).replace("_", "-");
2021-06-03 17:45:09 +02:00
if let Some(s) = obj.remove(&name).and_then(|b| b.as_bool()) {
base.$key_name = s;
}
} );
($key_name:ident = $json_name:expr, bool) => ( {
let name = $json_name;
if let Some(s) = obj.remove(name).and_then(|b| b.as_bool()) {
base.$key_name = s;
}
} );
($key_name:ident, u32) => ( {
let name = (stringify!($key_name)).replace("_", "-");
2021-06-03 17:45:09 +02:00
if let Some(s) = obj.remove(&name).and_then(|b| b.as_u64()) {
if s < 1 || s > 5 {
return Err("Not a valid DWARF version number".into());
}
base.$key_name = s as u32;
}
} );
($key_name:ident, Option<bool>) => ( {
let name = (stringify!($key_name)).replace("_", "-");
if let Some(s) = obj.remove(&name).and_then(|b| b.as_bool()) {
base.$key_name = Some(s);
}
} );
($key_name:ident, Option<u64>) => ( {
let name = (stringify!($key_name)).replace("_", "-");
2021-06-03 17:45:09 +02:00
if let Some(s) = obj.remove(&name).and_then(|b| b.as_u64()) {
base.$key_name = Some(s);
}
} );
($key_name:ident, MergeFunctions) => ( {
let name = (stringify!($key_name)).replace("_", "-");
2021-06-03 17:45:09 +02:00
obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
match s.parse::<MergeFunctions>() {
Ok(mergefunc) => base.$key_name = mergefunc,
_ => return Some(Err(format!("'{}' is not a valid value for \
merge-functions. Use 'disabled', \
'trampolines', or 'aliases'.",
s))),
}
Some(Ok(()))
})).unwrap_or(Ok(()))
} );
($key_name:ident, RelocModel) => ( {
let name = (stringify!($key_name)).replace("_", "-");
2021-06-03 17:45:09 +02:00
obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
match s.parse::<RelocModel>() {
Ok(relocation_model) => base.$key_name = relocation_model,
_ => return Some(Err(format!("'{}' is not a valid relocation model. \
Run `rustc --print relocation-models` to \
see the list of supported values.", s))),
}
Some(Ok(()))
})).unwrap_or(Ok(()))
} );
($key_name:ident, CodeModel) => ( {
let name = (stringify!($key_name)).replace("_", "-");
2021-06-03 17:45:09 +02:00
obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
match s.parse::<CodeModel>() {
Ok(code_model) => base.$key_name = Some(code_model),
_ => return Some(Err(format!("'{}' is not a valid code model. \
Run `rustc --print code-models` to \
see the list of supported values.", s))),
}
Some(Ok(()))
})).unwrap_or(Ok(()))
} );
($key_name:ident, TlsModel) => ( {
let name = (stringify!($key_name)).replace("_", "-");
2021-06-03 17:45:09 +02:00
obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
match s.parse::<TlsModel>() {
Ok(tls_model) => base.$key_name = tls_model,
_ => return Some(Err(format!("'{}' is not a valid TLS model. \
Run `rustc --print tls-models` to \
see the list of supported values.", s))),
}
Some(Ok(()))
})).unwrap_or(Ok(()))
} );
($key_name:ident, PanicStrategy) => ( {
let name = (stringify!($key_name)).replace("_", "-");
2021-06-03 17:45:09 +02:00
obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
match s {
"unwind" => base.$key_name = PanicStrategy::Unwind,
"abort" => base.$key_name = PanicStrategy::Abort,
_ => return Some(Err(format!("'{}' is not a valid value for \
panic-strategy. Use 'unwind' or 'abort'.",
s))),
}
Some(Ok(()))
})).unwrap_or(Ok(()))
} );
($key_name:ident, RelroLevel) => ( {
let name = (stringify!($key_name)).replace("_", "-");
2021-06-03 17:45:09 +02:00
obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
match s.parse::<RelroLevel>() {
Ok(level) => base.$key_name = level,
_ => return Some(Err(format!("'{}' is not a valid value for \
relro-level. Use 'full', 'partial, or 'off'.",
s))),
}
Some(Ok(()))
})).unwrap_or(Ok(()))
} );
($key_name:ident, DebuginfoKind) => ( {
let name = (stringify!($key_name)).replace("_", "-");
obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
match s.parse::<DebuginfoKind>() {
Ok(level) => base.$key_name = level,
_ => return Some(Err(
format!("'{s}' is not a valid value for debuginfo-kind. Use 'dwarf', \
'dwarf-dsym' or 'pdb'.")
)),
}
Some(Ok(()))
})).unwrap_or(Ok(()))
} );
rustc: Stabilize `-Zrun-dsymutil` as `-Csplit-debuginfo` This commit adds a new stable codegen option to rustc, `-Csplit-debuginfo`. The old `-Zrun-dsymutil` flag is deleted and now subsumed by this stable flag. Additionally `-Zsplit-dwarf` is also subsumed by this flag but still requires `-Zunstable-options` to actually activate. The `-Csplit-debuginfo` flag takes one of three values: * `off` - This indicates that split-debuginfo from the final artifact is not desired. This is not supported on Windows and is the default on Unix platforms except macOS. On macOS this means that `dsymutil` is not executed. * `packed` - This means that debuginfo is desired in one location separate from the main executable. This is the default on Windows (`*.pdb`) and macOS (`*.dSYM`). On other Unix platforms this subsumes `-Zsplit-dwarf=single` and produces a `*.dwp` file. * `unpacked` - This means that debuginfo will be roughly equivalent to object files, meaning that it's throughout the build directory rather than in one location (often the fastest for local development). This is not the default on any platform and is not supported on Windows. Each target can indicate its own default preference for how debuginfo is handled. Almost all platforms default to `off` except for Windows and macOS which default to `packed` for historical reasons. Some equivalencies for previous unstable flags with the new flags are: * `-Zrun-dsymutil=yes` -> `-Csplit-debuginfo=packed` * `-Zrun-dsymutil=no` -> `-Csplit-debuginfo=unpacked` * `-Zsplit-dwarf=single` -> `-Csplit-debuginfo=packed` * `-Zsplit-dwarf=split` -> `-Csplit-debuginfo=unpacked` Note that `-Csplit-debuginfo` still requires `-Zunstable-options` for non-macOS platforms since split-dwarf support was *just* implemented in rustc. There's some more rationale listed on #79361, but the main gist of the motivation for this commit is that `dsymutil` can take quite a long time to execute in debug builds and provides little benefit. This means that incremental compile times appear that much worse on macOS because the compiler is constantly running `dsymutil` over every single binary it produces during `cargo build` (even build scripts!). Ideally rustc would switch to not running `dsymutil` by default, but that's a problem left to get tackled another day. Closes #79361
2020-11-30 08:39:08 -08:00
($key_name:ident, SplitDebuginfo) => ( {
let name = (stringify!($key_name)).replace("_", "-");
2021-06-03 17:45:09 +02:00
obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
rustc: Stabilize `-Zrun-dsymutil` as `-Csplit-debuginfo` This commit adds a new stable codegen option to rustc, `-Csplit-debuginfo`. The old `-Zrun-dsymutil` flag is deleted and now subsumed by this stable flag. Additionally `-Zsplit-dwarf` is also subsumed by this flag but still requires `-Zunstable-options` to actually activate. The `-Csplit-debuginfo` flag takes one of three values: * `off` - This indicates that split-debuginfo from the final artifact is not desired. This is not supported on Windows and is the default on Unix platforms except macOS. On macOS this means that `dsymutil` is not executed. * `packed` - This means that debuginfo is desired in one location separate from the main executable. This is the default on Windows (`*.pdb`) and macOS (`*.dSYM`). On other Unix platforms this subsumes `-Zsplit-dwarf=single` and produces a `*.dwp` file. * `unpacked` - This means that debuginfo will be roughly equivalent to object files, meaning that it's throughout the build directory rather than in one location (often the fastest for local development). This is not the default on any platform and is not supported on Windows. Each target can indicate its own default preference for how debuginfo is handled. Almost all platforms default to `off` except for Windows and macOS which default to `packed` for historical reasons. Some equivalencies for previous unstable flags with the new flags are: * `-Zrun-dsymutil=yes` -> `-Csplit-debuginfo=packed` * `-Zrun-dsymutil=no` -> `-Csplit-debuginfo=unpacked` * `-Zsplit-dwarf=single` -> `-Csplit-debuginfo=packed` * `-Zsplit-dwarf=split` -> `-Csplit-debuginfo=unpacked` Note that `-Csplit-debuginfo` still requires `-Zunstable-options` for non-macOS platforms since split-dwarf support was *just* implemented in rustc. There's some more rationale listed on #79361, but the main gist of the motivation for this commit is that `dsymutil` can take quite a long time to execute in debug builds and provides little benefit. This means that incremental compile times appear that much worse on macOS because the compiler is constantly running `dsymutil` over every single binary it produces during `cargo build` (even build scripts!). Ideally rustc would switch to not running `dsymutil` by default, but that's a problem left to get tackled another day. Closes #79361
2020-11-30 08:39:08 -08:00
match s.parse::<SplitDebuginfo>() {
Ok(level) => base.$key_name = level,
_ => return Some(Err(format!("'{}' is not a valid value for \
split-debuginfo. Use 'off' or 'dsymutil'.",
s))),
}
Some(Ok(()))
})).unwrap_or(Ok(()))
} );
($key_name:ident, list) => ( {
let name = (stringify!($key_name)).replace("_", "-");
2021-06-03 17:45:09 +02:00
if let Some(j) = obj.remove(&name) {
if let Some(v) = j.as_array() {
base.$key_name = v.iter()
2021-06-03 17:45:09 +02:00
.map(|a| a.as_str().unwrap().to_string().into())
.collect();
} else {
incorrect_type.push(name)
}
}
} );
($key_name:ident, opt_list) => ( {
let name = (stringify!($key_name)).replace("_", "-");
2021-06-03 17:45:09 +02:00
if let Some(j) = obj.remove(&name) {
if let Some(v) = j.as_array() {
base.$key_name = Some(v.iter()
2021-06-03 17:45:09 +02:00
.map(|a| a.as_str().unwrap().to_string().into())
.collect());
} else {
incorrect_type.push(name)
}
}
} );
($key_name:ident, fallible_list) => ( {
let name = (stringify!($key_name)).replace("_", "-");
obj.remove(&name).and_then(|j| {
if let Some(v) = j.as_array() {
match v.iter().map(|a| FromStr::from_str(a.as_str().unwrap())).collect() {
Ok(l) => { base.$key_name = l },
// FIXME: `fallible_list` can't re-use the `key!` macro for list
// elements and the error messages from that macro, so it has a bad
// generic message instead
Err(_) => return Some(Err(
format!("`{:?}` is not a valid value for `{}`", j, name)
)),
}
} else {
incorrect_type.push(name)
}
Some(Ok(()))
}).unwrap_or(Ok(()))
} );
($key_name:ident, optional) => ( {
let name = (stringify!($key_name)).replace("_", "-");
2021-06-03 17:45:09 +02:00
if let Some(o) = obj.remove(&name) {
base.$key_name = o
2021-06-03 17:45:09 +02:00
.as_str()
.map(|s| s.to_string().into());
}
} );
($key_name:ident = $json_name:expr, LldFlavor) => ( {
let name = $json_name;
obj.remove(name).and_then(|o| o.as_str().and_then(|s| {
2018-08-18 20:16:04 +02:00
if let Some(flavor) = LldFlavor::from_str(&s) {
base.$key_name = flavor;
2018-08-18 20:16:04 +02:00
} else {
return Some(Err(format!(
"'{}' is not a valid value for lld-flavor. \
2022-12-25 00:43:50 +01:00
Use 'darwin', 'gnu', 'link' or 'wasm'.",
2018-08-18 20:16:04 +02:00
s)))
}
Some(Ok(()))
})).unwrap_or(Ok(()))
} );
($key_name:ident = $json_name:expr, LinkerFlavor) => ( {
let name = $json_name;
obj.remove(name).and_then(|o| o.as_str().and_then(|s| {
match LinkerFlavorCli::from_str(s) {
Some(linker_flavor) => base.$key_name = linker_flavor,
_ => return Some(Err(format!("'{}' is not a valid value for linker-flavor. \
Use {}", s, LinkerFlavorCli::one_of()))),
}
Some(Ok(()))
-Z linker-flavor This patch adds a `-Z linker-flavor` flag to rustc which can be used to invoke the linker using a different interface. For example, by default rustc assumes that all the Linux targets will be linked using GCC. This makes it impossible to use LLD as a linker using just `-C linker=ld.lld` because that will invoke LLD with invalid command line arguments. (e.g. rustc will pass -Wl,--gc-sections to LLD but LLD doesn't understand that; --gc-sections would be the right argument) With this patch one can pass `-Z linker-flavor=ld` to rustc to invoke the linker using a LD-like interface. This way, `rustc -C linker=ld.lld -Z linker-flavor=ld` will invoke LLD with the right arguments. `-Z linker-flavor` accepts 4 different arguments: `em` (emcc), `ld`, `gcc`, `msvc` (link.exe). `em`, `gnu` and `msvc` cover all the existing linker interfaces. `ld` is a new flavor for interfacing GNU's ld and LLD. This patch also changes target specifications. `linker-flavor` is now a mandatory field that specifies the *default* linker flavor that the target will use. This change also makes the linker interface *explicit*; before, it used to be derived from other fields like linker-is-gnu, is-like-msvc, is-like-emscripten, etc. Another change to target specifications is that the fields `pre-link-args`, `post-link-args` and `late-link-args` now expect a map from flavor to linker arguments. ``` diff - "pre-link-args": ["-Wl,--as-needed", "-Wl,-z,-noexecstack"], + "pre-link-args": { + "gcc": ["-Wl,--as-needed", "-Wl,-z,-noexecstack"], + "ld": ["--as-needed", "-z,-noexecstack"], + }, ``` [breaking-change] for users of custom targets specifications
2017-02-21 14:47:15 -05:00
})).unwrap_or(Ok(()))
} );
($key_name:ident, StackProbeType) => ( {
let name = (stringify!($key_name)).replace("_", "-");
2021-06-03 17:45:09 +02:00
obj.remove(&name).and_then(|o| match StackProbeType::from_json(&o) {
Ok(v) => {
base.$key_name = v;
Some(Ok(()))
},
Err(s) => Some(Err(
format!("`{:?}` is not a valid value for `{}`: {}", o, name, s)
)),
}).unwrap_or(Ok(()))
} );
($key_name:ident, SanitizerSet) => ( {
let name = (stringify!($key_name)).replace("_", "-");
2021-06-03 17:45:09 +02:00
if let Some(o) = obj.remove(&name) {
if let Some(a) = o.as_array() {
for s in a {
2021-06-03 17:45:09 +02:00
base.$key_name |= match s.as_str() {
Some("address") => SanitizerSet::ADDRESS,
Some("cfi") => SanitizerSet::CFI,
Some("dataflow") => SanitizerSet::DATAFLOW,
Some("kcfi") => SanitizerSet::KCFI,
Some("kernel-address") => SanitizerSet::KERNELADDRESS,
Some("leak") => SanitizerSet::LEAK,
Some("memory") => SanitizerSet::MEMORY,
Some("memtag") => SanitizerSet::MEMTAG,
Some("safestack") => SanitizerSet::SAFESTACK,
Some("shadow-call-stack") => SanitizerSet::SHADOWCALLSTACK,
Some("thread") => SanitizerSet::THREAD,
Some("hwaddress") => SanitizerSet::HWADDRESS,
Some(s) => return Err(format!("unknown sanitizer {}", s)),
_ => return Err(format!("not a string: {:?}", s)),
};
}
} else {
incorrect_type.push(name)
}
}
Ok::<(), String>(())
} );
($key_name:ident, link_self_contained_components) => ( {
// Skeleton of what needs to be parsed:
//
// ```
// $name: {
// "components": [
// <array of strings>
// ]
// }
// ```
let name = (stringify!($key_name)).replace("_", "-");
if let Some(o) = obj.remove(&name) {
if let Some(o) = o.as_object() {
let component_array = o.get("components")
.ok_or_else(|| format!("{name}: expected a \
JSON object with a `components` field."))?;
let component_array = component_array.as_array()
.ok_or_else(|| format!("{name}.components: expected a JSON array"))?;
let mut components = LinkSelfContainedComponents::empty();
for s in component_array {
components |= match s.as_str() {
Some(s) => {
LinkSelfContainedComponents::from_str(s)
.ok_or_else(|| format!("unknown \
`-Clink-self-contained` component: {s}"))?
},
_ => return Err(format!("not a string: {:?}", s)),
};
}
base.$key_name = LinkSelfContainedDefault::WithComponents(components);
} else {
incorrect_type.push(name)
}
}
Ok::<(), String>(())
} );
($key_name:ident = $json_name:expr, link_self_contained_backwards_compatible) => ( {
let name = $json_name;
obj.remove(name).and_then(|o| o.as_str().and_then(|s| {
match s.parse::<LinkSelfContainedDefault>() {
Ok(lsc_default) => base.$key_name = lsc_default,
_ => return Some(Err(format!("'{}' is not a valid `-Clink-self-contained` default. \
Use 'false', 'true', 'musl' or 'mingw'", s))),
}
Some(Ok(()))
})).unwrap_or(Ok(()))
} );
($key_name:ident = $json_name:expr, link_objects) => ( {
let name = $json_name;
if let Some(val) = obj.remove(name) {
let obj = val.as_object().ok_or_else(|| format!("{}: expected a \
JSON object with fields per CRT object kind.", name))?;
let mut args = CrtObjects::new();
for (k, v) in obj {
let kind = LinkOutputKind::from_str(&k).ok_or_else(|| {
format!("{}: '{}' is not a valid value for CRT object kind. \
Use '(dynamic,static)-(nopic,pic)-exe' or \
'(dynamic,static)-dylib' or 'wasi-reactor-exe'", name, k)
})?;
let v = v.as_array().ok_or_else(||
format!("{}.{}: expected a JSON array", name, k)
)?.iter().enumerate()
.map(|(i,s)| {
2021-06-03 17:45:09 +02:00
let s = s.as_str().ok_or_else(||
format!("{}.{}[{}]: expected a JSON string", name, k, i))?;
Ok(s.to_string().into())
})
.collect::<Result<Vec<_>, String>>()?;
args.insert(kind, v);
}
base.$key_name = args;
}
} );
($key_name:ident = $json_name:expr, link_args) => ( {
let name = $json_name;
if let Some(val) = obj.remove(name) {
let obj = val.as_object().ok_or_else(|| format!("{}: expected a \
JSON object with fields per linker-flavor.", name))?;
let mut args = LinkArgsCli::new();
-Z linker-flavor This patch adds a `-Z linker-flavor` flag to rustc which can be used to invoke the linker using a different interface. For example, by default rustc assumes that all the Linux targets will be linked using GCC. This makes it impossible to use LLD as a linker using just `-C linker=ld.lld` because that will invoke LLD with invalid command line arguments. (e.g. rustc will pass -Wl,--gc-sections to LLD but LLD doesn't understand that; --gc-sections would be the right argument) With this patch one can pass `-Z linker-flavor=ld` to rustc to invoke the linker using a LD-like interface. This way, `rustc -C linker=ld.lld -Z linker-flavor=ld` will invoke LLD with the right arguments. `-Z linker-flavor` accepts 4 different arguments: `em` (emcc), `ld`, `gcc`, `msvc` (link.exe). `em`, `gnu` and `msvc` cover all the existing linker interfaces. `ld` is a new flavor for interfacing GNU's ld and LLD. This patch also changes target specifications. `linker-flavor` is now a mandatory field that specifies the *default* linker flavor that the target will use. This change also makes the linker interface *explicit*; before, it used to be derived from other fields like linker-is-gnu, is-like-msvc, is-like-emscripten, etc. Another change to target specifications is that the fields `pre-link-args`, `post-link-args` and `late-link-args` now expect a map from flavor to linker arguments. ``` diff - "pre-link-args": ["-Wl,--as-needed", "-Wl,-z,-noexecstack"], + "pre-link-args": { + "gcc": ["-Wl,--as-needed", "-Wl,-z,-noexecstack"], + "ld": ["--as-needed", "-z,-noexecstack"], + }, ``` [breaking-change] for users of custom targets specifications
2017-02-21 14:47:15 -05:00
for (k, v) in obj {
let flavor = LinkerFlavorCli::from_str(&k).ok_or_else(|| {
-Z linker-flavor This patch adds a `-Z linker-flavor` flag to rustc which can be used to invoke the linker using a different interface. For example, by default rustc assumes that all the Linux targets will be linked using GCC. This makes it impossible to use LLD as a linker using just `-C linker=ld.lld` because that will invoke LLD with invalid command line arguments. (e.g. rustc will pass -Wl,--gc-sections to LLD but LLD doesn't understand that; --gc-sections would be the right argument) With this patch one can pass `-Z linker-flavor=ld` to rustc to invoke the linker using a LD-like interface. This way, `rustc -C linker=ld.lld -Z linker-flavor=ld` will invoke LLD with the right arguments. `-Z linker-flavor` accepts 4 different arguments: `em` (emcc), `ld`, `gcc`, `msvc` (link.exe). `em`, `gnu` and `msvc` cover all the existing linker interfaces. `ld` is a new flavor for interfacing GNU's ld and LLD. This patch also changes target specifications. `linker-flavor` is now a mandatory field that specifies the *default* linker flavor that the target will use. This change also makes the linker interface *explicit*; before, it used to be derived from other fields like linker-is-gnu, is-like-msvc, is-like-emscripten, etc. Another change to target specifications is that the fields `pre-link-args`, `post-link-args` and `late-link-args` now expect a map from flavor to linker arguments. ``` diff - "pre-link-args": ["-Wl,--as-needed", "-Wl,-z,-noexecstack"], + "pre-link-args": { + "gcc": ["-Wl,--as-needed", "-Wl,-z,-noexecstack"], + "ld": ["--as-needed", "-z,-noexecstack"], + }, ``` [breaking-change] for users of custom targets specifications
2017-02-21 14:47:15 -05:00
format!("{}: '{}' is not a valid value for linker-flavor. \
Use 'em', 'gcc', 'ld' or 'msvc'", name, k)
})?;
let v = v.as_array().ok_or_else(||
format!("{}.{}: expected a JSON array", name, k)
)?.iter().enumerate()
.map(|(i,s)| {
2021-06-03 17:45:09 +02:00
let s = s.as_str().ok_or_else(||
format!("{}.{}[{}]: expected a JSON string", name, k, i))?;
Ok(s.to_string().into())
})
.collect::<Result<Vec<_>, String>>()?;
args.insert(flavor, v);
-Z linker-flavor This patch adds a `-Z linker-flavor` flag to rustc which can be used to invoke the linker using a different interface. For example, by default rustc assumes that all the Linux targets will be linked using GCC. This makes it impossible to use LLD as a linker using just `-C linker=ld.lld` because that will invoke LLD with invalid command line arguments. (e.g. rustc will pass -Wl,--gc-sections to LLD but LLD doesn't understand that; --gc-sections would be the right argument) With this patch one can pass `-Z linker-flavor=ld` to rustc to invoke the linker using a LD-like interface. This way, `rustc -C linker=ld.lld -Z linker-flavor=ld` will invoke LLD with the right arguments. `-Z linker-flavor` accepts 4 different arguments: `em` (emcc), `ld`, `gcc`, `msvc` (link.exe). `em`, `gnu` and `msvc` cover all the existing linker interfaces. `ld` is a new flavor for interfacing GNU's ld and LLD. This patch also changes target specifications. `linker-flavor` is now a mandatory field that specifies the *default* linker flavor that the target will use. This change also makes the linker interface *explicit*; before, it used to be derived from other fields like linker-is-gnu, is-like-msvc, is-like-emscripten, etc. Another change to target specifications is that the fields `pre-link-args`, `post-link-args` and `late-link-args` now expect a map from flavor to linker arguments. ``` diff - "pre-link-args": ["-Wl,--as-needed", "-Wl,-z,-noexecstack"], + "pre-link-args": { + "gcc": ["-Wl,--as-needed", "-Wl,-z,-noexecstack"], + "ld": ["--as-needed", "-z,-noexecstack"], + }, ``` [breaking-change] for users of custom targets specifications
2017-02-21 14:47:15 -05:00
}
base.$key_name = args;
-Z linker-flavor This patch adds a `-Z linker-flavor` flag to rustc which can be used to invoke the linker using a different interface. For example, by default rustc assumes that all the Linux targets will be linked using GCC. This makes it impossible to use LLD as a linker using just `-C linker=ld.lld` because that will invoke LLD with invalid command line arguments. (e.g. rustc will pass -Wl,--gc-sections to LLD but LLD doesn't understand that; --gc-sections would be the right argument) With this patch one can pass `-Z linker-flavor=ld` to rustc to invoke the linker using a LD-like interface. This way, `rustc -C linker=ld.lld -Z linker-flavor=ld` will invoke LLD with the right arguments. `-Z linker-flavor` accepts 4 different arguments: `em` (emcc), `ld`, `gcc`, `msvc` (link.exe). `em`, `gnu` and `msvc` cover all the existing linker interfaces. `ld` is a new flavor for interfacing GNU's ld and LLD. This patch also changes target specifications. `linker-flavor` is now a mandatory field that specifies the *default* linker flavor that the target will use. This change also makes the linker interface *explicit*; before, it used to be derived from other fields like linker-is-gnu, is-like-msvc, is-like-emscripten, etc. Another change to target specifications is that the fields `pre-link-args`, `post-link-args` and `late-link-args` now expect a map from flavor to linker arguments. ``` diff - "pre-link-args": ["-Wl,--as-needed", "-Wl,-z,-noexecstack"], + "pre-link-args": { + "gcc": ["-Wl,--as-needed", "-Wl,-z,-noexecstack"], + "ld": ["--as-needed", "-z,-noexecstack"], + }, ``` [breaking-change] for users of custom targets specifications
2017-02-21 14:47:15 -05:00
}
} );
($key_name:ident, env) => ( {
let name = (stringify!($key_name)).replace("_", "-");
2021-06-03 17:45:09 +02:00
if let Some(o) = obj.remove(&name) {
if let Some(a) = o.as_array() {
for o in a {
2021-06-03 17:45:09 +02:00
if let Some(s) = o.as_str() {
let p = s.split('=').collect::<Vec<_>>();
if p.len() == 2 {
let k = p[0].to_string();
let v = p[1].to_string();
base.$key_name.to_mut().push((k.into(), v.into()));
}
}
}
} else {
incorrect_type.push(name)
}
}
} );
rustc: Add a new `wasm` ABI This commit implements the idea of a new ABI for the WebAssembly target, one called `"wasm"`. This ABI is entirely of my own invention and has no current precedent, but I think that the addition of this ABI might help solve a number of issues with the WebAssembly targets. When `wasm32-unknown-unknown` was first added to Rust I naively "implemented an abi" for the target. I then went to write `wasm-bindgen` which accidentally relied on details of this ABI. Turns out the ABI definition didn't match C, which is causing issues for C/Rust interop. Currently the compiler has a "wasm32 bindgen compat" ABI which is the original implementation I added, and it's purely there for, well, `wasm-bindgen`. Another issue with the WebAssembly target is that it's not clear to me when and if the default C ABI will change to account for WebAssembly's multi-value feature (a feature that allows functions to return multiple values). Even if this does happen, though, it seems like the C ABI will be guided based on the performance of WebAssembly code and will likely not match even what the current wasm-bindgen-compat ABI is today. This leaves a hole in Rust's expressivity in binding WebAssembly where given a particular import type, Rust may not be able to import that signature with an updated C ABI for multi-value. To fix these issues I had the idea of a new ABI for WebAssembly, one called `wasm`. The definition of this ABI is "what you write maps straight to wasm". The goal here is that whatever you write down in the parameter list or in the return values goes straight into the function's signature in the WebAssembly file. This special ABI is for intentionally matching the ABI of an imported function from the environment or exporting a function with the right signature. With the addition of a new ABI, this enables rustc to: * Eventually remove the "wasm-bindgen compat hack". Once this ABI is stable wasm-bindgen can switch to using it everywhere. Afterwards the wasm32-unknown-unknown target can have its default ABI updated to match C. * Expose the ability to precisely match an ABI signature for a WebAssembly function, regardless of what the C ABI that clang chooses turns out to be. * Continue to evolve the definition of the default C ABI to match what clang does on all targets, since the purpose of that ABI will be explicitly matching C rather than generating particular function imports/exports. Naturally this is implemented as an unstable feature initially, but it would be nice for this to get stabilized (if it works) in the near-ish future to remove the wasm32-unknown-unknown incompatibility with the C ABI. Doing this, however, requires the feature to be on stable because wasm-bindgen works with stable Rust.
2021-04-01 16:08:29 -07:00
($key_name:ident, Option<Abi>) => ( {
let name = (stringify!($key_name)).replace("_", "-");
2021-06-03 17:45:09 +02:00
obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
rustc: Add a new `wasm` ABI This commit implements the idea of a new ABI for the WebAssembly target, one called `"wasm"`. This ABI is entirely of my own invention and has no current precedent, but I think that the addition of this ABI might help solve a number of issues with the WebAssembly targets. When `wasm32-unknown-unknown` was first added to Rust I naively "implemented an abi" for the target. I then went to write `wasm-bindgen` which accidentally relied on details of this ABI. Turns out the ABI definition didn't match C, which is causing issues for C/Rust interop. Currently the compiler has a "wasm32 bindgen compat" ABI which is the original implementation I added, and it's purely there for, well, `wasm-bindgen`. Another issue with the WebAssembly target is that it's not clear to me when and if the default C ABI will change to account for WebAssembly's multi-value feature (a feature that allows functions to return multiple values). Even if this does happen, though, it seems like the C ABI will be guided based on the performance of WebAssembly code and will likely not match even what the current wasm-bindgen-compat ABI is today. This leaves a hole in Rust's expressivity in binding WebAssembly where given a particular import type, Rust may not be able to import that signature with an updated C ABI for multi-value. To fix these issues I had the idea of a new ABI for WebAssembly, one called `wasm`. The definition of this ABI is "what you write maps straight to wasm". The goal here is that whatever you write down in the parameter list or in the return values goes straight into the function's signature in the WebAssembly file. This special ABI is for intentionally matching the ABI of an imported function from the environment or exporting a function with the right signature. With the addition of a new ABI, this enables rustc to: * Eventually remove the "wasm-bindgen compat hack". Once this ABI is stable wasm-bindgen can switch to using it everywhere. Afterwards the wasm32-unknown-unknown target can have its default ABI updated to match C. * Expose the ability to precisely match an ABI signature for a WebAssembly function, regardless of what the C ABI that clang chooses turns out to be. * Continue to evolve the definition of the default C ABI to match what clang does on all targets, since the purpose of that ABI will be explicitly matching C rather than generating particular function imports/exports. Naturally this is implemented as an unstable feature initially, but it would be nice for this to get stabilized (if it works) in the near-ish future to remove the wasm32-unknown-unknown incompatibility with the C ABI. Doing this, however, requires the feature to be on stable because wasm-bindgen works with stable Rust.
2021-04-01 16:08:29 -07:00
match lookup_abi(s) {
feat: `riscv-interrupt-{m,s}` calling conventions Similar to prior support added for the mips430, avr, and x86 targets this change implements the rough equivalent of clang's [`__attribute__((interrupt))`][clang-attr] for riscv targets, enabling e.g. ```rust static mut CNT: usize = 0; pub extern "riscv-interrupt-m" fn isr_m() { unsafe { CNT += 1; } } ``` to produce highly effective assembly like: ```asm pub extern "riscv-interrupt-m" fn isr_m() { 420003a0: 1141 addi sp,sp,-16 unsafe { CNT += 1; 420003a2: c62a sw a0,12(sp) 420003a4: c42e sw a1,8(sp) 420003a6: 3fc80537 lui a0,0x3fc80 420003aa: 63c52583 lw a1,1596(a0) # 3fc8063c <_ZN12esp_riscv_rt3CNT17hcec3e3a214887d53E.0> 420003ae: 0585 addi a1,a1,1 420003b0: 62b52e23 sw a1,1596(a0) } } 420003b4: 4532 lw a0,12(sp) 420003b6: 45a2 lw a1,8(sp) 420003b8: 0141 addi sp,sp,16 420003ba: 30200073 mret ``` (disassembly via `riscv64-unknown-elf-objdump -C -S --disassemble ./esp32c3-hal/target/riscv32imc-unknown-none-elf/release/examples/gpio_interrupt`) This outcome is superior to hand-coded interrupt routines which, lacking visibility into any non-assembly body of the interrupt handler, have to be very conservative and save the [entire CPU state to the stack frame][full-frame-save]. By instead asking LLVM to only save the registers that it uses, we defer the decision to the tool with the best context: it can more accurately account for the cost of spills if it knows that every additional register used is already at the cost of an implicit spill. At the LLVM level, this is apparently [implemented by] marking every register as "[callee-save]," matching the semantics of an interrupt handler nicely (it has to leave the CPU state just as it found it after its `{m|s}ret`). This approach is not suitable for every interrupt handler, as it makes no attempt to e.g. save the state in a user-accessible stack frame. For a full discussion of those challenges and tradeoffs, please refer to [the interrupt calling conventions RFC][rfc]. Inside rustc, this implementation differs from prior art because LLVM does not expose the "all-saved" function flavor as a calling convention directly, instead preferring to use an attribute that allows for differentiating between "machine-mode" and "superivsor-mode" interrupts. Finally, some effort has been made to guide those who may not yet be aware of the differences between machine-mode and supervisor-mode interrupts as to why no `riscv-interrupt` calling convention is exposed through rustc, and similarly for why `riscv-interrupt-u` makes no appearance (as it would complicate future LLVM upgrades). [clang-attr]: https://clang.llvm.org/docs/AttributeReference.html#interrupt-risc-v [full-frame-save]: https://github.com/esp-rs/esp-riscv-rt/blob/9281af2ecffe13e40992917316f36920c26acaf3/src/lib.rs#L440-L469 [implemented by]: https://github.com/llvm/llvm-project/blob/b7fb2a3fec7c187d58a6d338ab512d9173bca987/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp#L61-L67 [callee-save]: https://github.com/llvm/llvm-project/blob/973f1fe7a8591c7af148e573491ab68cc15b6ecf/llvm/lib/Target/RISCV/RISCVCallingConv.td#L30-L37 [rfc]: https://github.com/rust-lang/rfcs/pull/3246
2023-05-23 15:08:23 -07:00
Ok(abi) => base.$key_name = Some(abi),
rustc: Add a new `wasm` ABI This commit implements the idea of a new ABI for the WebAssembly target, one called `"wasm"`. This ABI is entirely of my own invention and has no current precedent, but I think that the addition of this ABI might help solve a number of issues with the WebAssembly targets. When `wasm32-unknown-unknown` was first added to Rust I naively "implemented an abi" for the target. I then went to write `wasm-bindgen` which accidentally relied on details of this ABI. Turns out the ABI definition didn't match C, which is causing issues for C/Rust interop. Currently the compiler has a "wasm32 bindgen compat" ABI which is the original implementation I added, and it's purely there for, well, `wasm-bindgen`. Another issue with the WebAssembly target is that it's not clear to me when and if the default C ABI will change to account for WebAssembly's multi-value feature (a feature that allows functions to return multiple values). Even if this does happen, though, it seems like the C ABI will be guided based on the performance of WebAssembly code and will likely not match even what the current wasm-bindgen-compat ABI is today. This leaves a hole in Rust's expressivity in binding WebAssembly where given a particular import type, Rust may not be able to import that signature with an updated C ABI for multi-value. To fix these issues I had the idea of a new ABI for WebAssembly, one called `wasm`. The definition of this ABI is "what you write maps straight to wasm". The goal here is that whatever you write down in the parameter list or in the return values goes straight into the function's signature in the WebAssembly file. This special ABI is for intentionally matching the ABI of an imported function from the environment or exporting a function with the right signature. With the addition of a new ABI, this enables rustc to: * Eventually remove the "wasm-bindgen compat hack". Once this ABI is stable wasm-bindgen can switch to using it everywhere. Afterwards the wasm32-unknown-unknown target can have its default ABI updated to match C. * Expose the ability to precisely match an ABI signature for a WebAssembly function, regardless of what the C ABI that clang chooses turns out to be. * Continue to evolve the definition of the default C ABI to match what clang does on all targets, since the purpose of that ABI will be explicitly matching C rather than generating particular function imports/exports. Naturally this is implemented as an unstable feature initially, but it would be nice for this to get stabilized (if it works) in the near-ish future to remove the wasm32-unknown-unknown incompatibility with the C ABI. Doing this, however, requires the feature to be on stable because wasm-bindgen works with stable Rust.
2021-04-01 16:08:29 -07:00
_ => return Some(Err(format!("'{}' is not a valid value for abi", s))),
}
Some(Ok(()))
})).unwrap_or(Ok(()))
} );
($key_name:ident, TargetFamilies) => ( {
2021-06-03 17:45:09 +02:00
if let Some(value) = obj.remove("target-family") {
if let Some(v) = value.as_array() {
base.$key_name = v.iter()
2021-06-03 17:45:09 +02:00
.map(|a| a.as_str().unwrap().to_string().into())
.collect();
2021-06-03 17:45:09 +02:00
} else if let Some(v) = value.as_str() {
base.$key_name = vec![v.to_string().into()].into();
}
}
} );
($key_name:ident, Conv) => ( {
let name = (stringify!($key_name)).replace("_", "-");
obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
match Conv::from_str(s) {
Ok(c) => {
base.$key_name = c;
Some(Ok(()))
}
Err(e) => Some(Err(e))
}
})).unwrap_or(Ok(()))
} );
}
2021-06-03 17:45:09 +02:00
if let Some(j) = obj.remove("target-endian") {
if let Some(s) = j.as_str() {
base.endian = s.parse()?;
} else {
incorrect_type.push("target-endian".into())
}
}
2021-06-03 17:45:09 +02:00
if let Some(fp) = obj.remove("frame-pointer") {
if let Some(s) = fp.as_str() {
base.frame_pointer = s
.parse()
.map_err(|()| format!("'{s}' is not a valid value for frame-pointer"))?;
} else {
incorrect_type.push("frame-pointer".into())
}
}
key!(is_builtin, bool);
key!(c_int_width = "target-c-int-width");
key!(c_enum_min_bits, Option<u64>); // if None, matches c_int_width
key!(os);
key!(env);
key!(abi);
key!(vendor);
key!(linker, optional);
key!(linker_flavor_json = "linker-flavor", LinkerFlavor)?;
key!(lld_flavor_json = "lld-flavor", LldFlavor)?;
key!(linker_is_gnu_json = "linker-is-gnu", bool);
key!(pre_link_objects = "pre-link-objects", link_objects);
key!(post_link_objects = "post-link-objects", link_objects);
key!(pre_link_objects_self_contained = "pre-link-objects-fallback", link_objects);
key!(post_link_objects_self_contained = "post-link-objects-fallback", link_objects);
// Deserializes the backwards-compatible variants of `-Clink-self-contained`
key!(
link_self_contained = "crt-objects-fallback",
link_self_contained_backwards_compatible
)?;
// Deserializes the components variant of `-Clink-self-contained`
key!(link_self_contained, link_self_contained_components)?;
key!(pre_link_args_json = "pre-link-args", link_args);
key!(late_link_args_json = "late-link-args", link_args);
key!(late_link_args_dynamic_json = "late-link-args-dynamic", link_args);
key!(late_link_args_static_json = "late-link-args-static", link_args);
key!(post_link_args_json = "post-link-args", link_args);
key!(link_script, optional);
key!(link_env, env);
key!(link_env_remove, list);
key!(asm_args, list);
key!(cpu);
key!(features);
key!(dynamic_linking, bool);
key!(direct_access_external_data, Option<bool>);
key!(dll_tls_export, bool);
std: Add a new wasm32-unknown-unknown target This commit adds a new target to the compiler: wasm32-unknown-unknown. This target is a reimagining of what it looks like to generate WebAssembly code from Rust. Instead of using Emscripten which can bring with it a weighty runtime this instead is a target which uses only the LLVM backend for WebAssembly and a "custom linker" for now which will hopefully one day be direct calls to lld. Notable features of this target include: * There is zero runtime footprint. The target assumes nothing exists other than the wasm32 instruction set. * There is zero toolchain footprint beyond adding the target. No custom linker is needed, rustc contains everything. * Very small wasm modules can be generated directly from Rust code using this target. * Most of the standard library is stubbed out to return an error, but anything related to allocation works (aka `HashMap`, `Vec`, etc). * Naturally, any `#[no_std]` crate should be 100% compatible with this new target. This target is currently somewhat janky due to how linking works. The "linking" is currently unconditional whole program LTO (aka LLVM is being used as a linker). Naturally that means compiling programs is pretty slow! Eventually though this target should have a linker. This target is also intended to be quite experimental. I'm hoping that this can act as a catalyst for further experimentation in Rust with WebAssembly. Breaking changes are very likely to land to this target, so it's not recommended to rely on it in any critical capacity yet. We'll let you know when it's "production ready". --- Currently testing-wise this target is looking pretty good but isn't complete. I've got almost the entire `run-pass` test suite working with this target (lots of tests ignored, but many passing as well). The `core` test suite is still getting LLVM bugs fixed to get that working and will take some time. Relatively simple programs all seem to work though! --- It's worth nothing that you may not immediately see the "smallest possible wasm module" for the input you feed to rustc. For various reasons it's very difficult to get rid of the final "bloat" in vanilla rustc (again, a real linker should fix all this). For now what you'll have to do is: cargo install --git https://github.com/alexcrichton/wasm-gc wasm-gc foo.wasm bar.wasm And then `bar.wasm` should be the smallest we can get it! --- In any case for now I'd love feedback on this, particularly on the various integration points if you've got better ideas of how to approach them!
2017-10-22 20:01:00 -07:00
key!(only_cdylib, bool);
key!(executables, bool);
key!(relocation_model, RelocModel)?;
key!(code_model, CodeModel)?;
key!(tls_model, TlsModel)?;
key!(disable_redzone, bool);
key!(function_sections, bool);
key!(dll_prefix);
key!(dll_suffix);
key!(exe_suffix);
key!(staticlib_prefix);
key!(staticlib_suffix);
key!(families, TargetFamilies);
key!(abi_return_struct_as_int, bool);
2022-08-25 14:37:29 +08:00
key!(is_like_aix, bool);
key!(is_like_osx, bool);
key!(is_like_solaris, bool);
key!(is_like_windows, bool);
key!(is_like_msvc, bool);
2020-12-30 12:52:21 -06:00
key!(is_like_wasm, bool);
key!(is_like_android, bool);
key!(default_dwarf_version, u32);
key!(allows_weak_linkage, bool);
key!(has_rpath, bool);
key!(no_default_libraries, bool);
key!(position_independent_executables, bool);
key!(static_position_independent_executables, bool);
key!(plt_by_default, bool);
2018-12-01 15:48:55 -06:00
key!(relro_level, RelroLevel)?;
key!(archive_format);
key!(allow_asm, bool);
key!(main_needs_argc_argv, bool);
key!(has_thread_local, bool);
key!(obj_is_bitcode, bool);
key!(forces_embed_bitcode, bool);
key!(bitcode_llvm_cmdline);
key!(max_atomic_width, Option<u64>);
key!(min_atomic_width, Option<u64>);
key!(atomic_cas, bool);
2018-12-01 15:48:55 -06:00
key!(panic_strategy, PanicStrategy)?;
key!(crt_static_allows_dylibs, bool);
rustc: Implement #[link(cfg(..))] and crt-static This commit is an implementation of [RFC 1721] which adds a new target feature to the compiler, `crt-static`, which can be used to select how the C runtime for a target is linked. Most targets dynamically linke the C runtime by default with the notable exception of some of the musl targets. [RFC 1721]: https://github.com/rust-lang/rfcs/blob/master/text/1721-crt-static.md This commit first adds the new target-feature, `crt-static`. If enabled, then the `cfg(target_feature = "crt-static")` will be available. Targets like musl will have this enabled by default. This feature can be controlled through the standard target-feature interface, `-C target-feature=+crt-static` or `-C target-feature=-crt-static`. Next this adds an gated and unstable `#[link(cfg(..))]` feature to enable the `crt-static` semantics we want with libc. The exact behavior of this attribute is a little squishy, but it's intended to be a forever-unstable implementation detail of the liblibc crate. Specifically the `#[link(cfg(..))]` annotation means that the `#[link]` directive is only active in a compilation unit if that `cfg` value is satisfied. For example when compiling an rlib, these directives are just encoded and ignored for dylibs, and all staticlibs are continued to be put into the rlib as usual. When placing that rlib into a staticlib, executable, or dylib, however, the `cfg` is evaluated *as if it were defined in the final artifact* and the library is decided to be linked or not. Essentially, what'll happen is: * On MSVC with `-C target-feature=-crt-static`, the `msvcrt.lib` library will be linked to. * On MSVC with `-C target-feature=+crt-static`, the `libcmt.lib` library will be linked to. * On musl with `-C target-feature=-crt-static`, the object files in liblibc.rlib are removed and `-lc` is passed instead. * On musl with `-C target-feature=+crt-static`, the object files in liblibc.rlib are used and `-lc` is not passed. This commit does **not** include an update to the liblibc module to implement these changes. I plan to do that just after the 1.14.0 beta release is cut to ensure we get ample time to test this feature. cc #37406
2016-10-31 16:40:13 -07:00
key!(crt_static_default, bool);
key!(crt_static_respected, bool);
key!(stack_probes, StackProbeType)?;
key!(min_global_align, Option<u64>);
key!(default_codegen_units, Option<u64>);
key!(trap_unreachable, bool);
std: Add a new wasm32-unknown-unknown target This commit adds a new target to the compiler: wasm32-unknown-unknown. This target is a reimagining of what it looks like to generate WebAssembly code from Rust. Instead of using Emscripten which can bring with it a weighty runtime this instead is a target which uses only the LLVM backend for WebAssembly and a "custom linker" for now which will hopefully one day be direct calls to lld. Notable features of this target include: * There is zero runtime footprint. The target assumes nothing exists other than the wasm32 instruction set. * There is zero toolchain footprint beyond adding the target. No custom linker is needed, rustc contains everything. * Very small wasm modules can be generated directly from Rust code using this target. * Most of the standard library is stubbed out to return an error, but anything related to allocation works (aka `HashMap`, `Vec`, etc). * Naturally, any `#[no_std]` crate should be 100% compatible with this new target. This target is currently somewhat janky due to how linking works. The "linking" is currently unconditional whole program LTO (aka LLVM is being used as a linker). Naturally that means compiling programs is pretty slow! Eventually though this target should have a linker. This target is also intended to be quite experimental. I'm hoping that this can act as a catalyst for further experimentation in Rust with WebAssembly. Breaking changes are very likely to land to this target, so it's not recommended to rely on it in any critical capacity yet. We'll let you know when it's "production ready". --- Currently testing-wise this target is looking pretty good but isn't complete. I've got almost the entire `run-pass` test suite working with this target (lots of tests ignored, but many passing as well). The `core` test suite is still getting LLVM bugs fixed to get that working and will take some time. Relatively simple programs all seem to work though! --- It's worth nothing that you may not immediately see the "smallest possible wasm module" for the input you feed to rustc. For various reasons it's very difficult to get rid of the final "bloat" in vanilla rustc (again, a real linker should fix all this). For now what you'll have to do is: cargo install --git https://github.com/alexcrichton/wasm-gc wasm-gc foo.wasm bar.wasm And then `bar.wasm` should be the smallest we can get it! --- In any case for now I'd love feedback on this, particularly on the various integration points if you've got better ideas of how to approach them!
2017-10-22 20:01:00 -07:00
key!(requires_lto, bool);
key!(singlethread, bool);
key!(no_builtins, bool);
key!(default_hidden_visibility, bool);
key!(emit_debug_gdb_scripts, bool);
key!(requires_uwtable, bool);
key!(default_uwtable, bool);
key!(simd_types_indirect, bool);
key!(limit_rdylib_exports, bool);
key!(override_export_symbols, opt_list);
key!(merge_functions, MergeFunctions)?;
key!(mcount = "target-mcount");
key!(llvm_mcount_intrinsic, optional);
key!(llvm_abiname);
key!(relax_elf_relocations, bool);
key!(llvm_args, list);
key!(use_ctors_section, bool);
key!(eh_frame_header, bool);
key!(has_thumb_interworking, bool);
key!(debuginfo_kind, DebuginfoKind)?;
rustc: Stabilize `-Zrun-dsymutil` as `-Csplit-debuginfo` This commit adds a new stable codegen option to rustc, `-Csplit-debuginfo`. The old `-Zrun-dsymutil` flag is deleted and now subsumed by this stable flag. Additionally `-Zsplit-dwarf` is also subsumed by this flag but still requires `-Zunstable-options` to actually activate. The `-Csplit-debuginfo` flag takes one of three values: * `off` - This indicates that split-debuginfo from the final artifact is not desired. This is not supported on Windows and is the default on Unix platforms except macOS. On macOS this means that `dsymutil` is not executed. * `packed` - This means that debuginfo is desired in one location separate from the main executable. This is the default on Windows (`*.pdb`) and macOS (`*.dSYM`). On other Unix platforms this subsumes `-Zsplit-dwarf=single` and produces a `*.dwp` file. * `unpacked` - This means that debuginfo will be roughly equivalent to object files, meaning that it's throughout the build directory rather than in one location (often the fastest for local development). This is not the default on any platform and is not supported on Windows. Each target can indicate its own default preference for how debuginfo is handled. Almost all platforms default to `off` except for Windows and macOS which default to `packed` for historical reasons. Some equivalencies for previous unstable flags with the new flags are: * `-Zrun-dsymutil=yes` -> `-Csplit-debuginfo=packed` * `-Zrun-dsymutil=no` -> `-Csplit-debuginfo=unpacked` * `-Zsplit-dwarf=single` -> `-Csplit-debuginfo=packed` * `-Zsplit-dwarf=split` -> `-Csplit-debuginfo=unpacked` Note that `-Csplit-debuginfo` still requires `-Zunstable-options` for non-macOS platforms since split-dwarf support was *just* implemented in rustc. There's some more rationale listed on #79361, but the main gist of the motivation for this commit is that `dsymutil` can take quite a long time to execute in debug builds and provides little benefit. This means that incremental compile times appear that much worse on macOS because the compiler is constantly running `dsymutil` over every single binary it produces during `cargo build` (even build scripts!). Ideally rustc would switch to not running `dsymutil` by default, but that's a problem left to get tackled another day. Closes #79361
2020-11-30 08:39:08 -08:00
key!(split_debuginfo, SplitDebuginfo)?;
key!(supported_split_debuginfo, fallible_list)?;
key!(supported_sanitizers, SanitizerSet)?;
rustc: Add a new `wasm` ABI This commit implements the idea of a new ABI for the WebAssembly target, one called `"wasm"`. This ABI is entirely of my own invention and has no current precedent, but I think that the addition of this ABI might help solve a number of issues with the WebAssembly targets. When `wasm32-unknown-unknown` was first added to Rust I naively "implemented an abi" for the target. I then went to write `wasm-bindgen` which accidentally relied on details of this ABI. Turns out the ABI definition didn't match C, which is causing issues for C/Rust interop. Currently the compiler has a "wasm32 bindgen compat" ABI which is the original implementation I added, and it's purely there for, well, `wasm-bindgen`. Another issue with the WebAssembly target is that it's not clear to me when and if the default C ABI will change to account for WebAssembly's multi-value feature (a feature that allows functions to return multiple values). Even if this does happen, though, it seems like the C ABI will be guided based on the performance of WebAssembly code and will likely not match even what the current wasm-bindgen-compat ABI is today. This leaves a hole in Rust's expressivity in binding WebAssembly where given a particular import type, Rust may not be able to import that signature with an updated C ABI for multi-value. To fix these issues I had the idea of a new ABI for WebAssembly, one called `wasm`. The definition of this ABI is "what you write maps straight to wasm". The goal here is that whatever you write down in the parameter list or in the return values goes straight into the function's signature in the WebAssembly file. This special ABI is for intentionally matching the ABI of an imported function from the environment or exporting a function with the right signature. With the addition of a new ABI, this enables rustc to: * Eventually remove the "wasm-bindgen compat hack". Once this ABI is stable wasm-bindgen can switch to using it everywhere. Afterwards the wasm32-unknown-unknown target can have its default ABI updated to match C. * Expose the ability to precisely match an ABI signature for a WebAssembly function, regardless of what the C ABI that clang chooses turns out to be. * Continue to evolve the definition of the default C ABI to match what clang does on all targets, since the purpose of that ABI will be explicitly matching C rather than generating particular function imports/exports. Naturally this is implemented as an unstable feature initially, but it would be nice for this to get stabilized (if it works) in the near-ish future to remove the wasm32-unknown-unknown incompatibility with the C ABI. Doing this, however, requires the feature to be on stable because wasm-bindgen works with stable Rust.
2021-04-01 16:08:29 -07:00
key!(default_adjusted_cabi, Option<Abi>)?;
key!(generate_arange_section, bool);
add rustc option for using LLVM stack smash protection LLVM has built-in heuristics for adding stack canaries to functions. These heuristics can be selected with LLVM function attributes. This patch adds a rustc option `-Z stack-protector={none,basic,strong,all}` which controls the use of these attributes. This gives rustc the same stack smash protection support as clang offers through options `-fno-stack-protector`, `-fstack-protector`, `-fstack-protector-strong`, and `-fstack-protector-all`. The protection this can offer is demonstrated in test/ui/abi/stack-protector.rs. This fills a gap in the current list of rustc exploit mitigations (https://doc.rust-lang.org/rustc/exploit-mitigations.html), originally discussed in #15179. Stack smash protection adds runtime overhead and is therefore still off by default, but now users have the option to trade performance for security as they see fit. An example use case is adding Rust code in an existing C/C++ code base compiled with stack smash protection. Without the ability to add stack smash protection to the Rust code, the code base artifacts could be exploitable in ways not possible if the code base remained pure C/C++. Stack smash protection support is present in LLVM for almost all the current tier 1/tier 2 targets: see test/assembly/stack-protector/stack-protector-target-support.rs. The one exception is nvptx64-nvidia-cuda. This patch follows clang's example, and adds a warning message printed if stack smash protection is used with this target (see test/ui/stack-protector/warn-stack-protector-unsupported.rs). Support for tier 3 targets has not been checked. Since the heuristics are applied at the LLVM level, the heuristics are expected to add stack smash protection to a fraction of functions comparable to C/C++. Some experiments demonstrating how Rust code is affected by the different heuristics can be found in test/assembly/stack-protector/stack-protector-heuristics-effect.rs. There is potential for better heuristics using Rust-specific safety information. For example it might be reasonable to skip stack smash protection in functions which transitively only use safe Rust code, or which uses only a subset of functions the user declares safe (such as anything under `std.*`). Such alternative heuristics could be added at a later point. LLVM also offers a "safestack" sanitizer as an alternative way to guard against stack smashing (see #26612). This could possibly also be included as a stack-protection heuristic. An alternative is to add it as a sanitizer (#39699). This is what clang does: safestack is exposed with option `-fsanitize=safe-stack`. The options are only supported by the LLVM backend, but as with other codegen options it is visible in the main codegen option help menu. The heuristic names "basic", "strong", and "all" are hopefully sufficiently generic to be usable in other backends as well. Reviewed-by: Nikita Popov <nikic@php.net> Extra commits during review: - [address-review] make the stack-protector option unstable - [address-review] reduce detail level of stack-protector option help text - [address-review] correct grammar in comment - [address-review] use compiler flag to avoid merging functions in test - [address-review] specify min LLVM version in fortanix stack-protector test Only for Fortanix test, since this target specifically requests the `--x86-experimental-lvi-inline-asm-hardening` flag. - [address-review] specify required LLVM components in stack-protector tests - move stack protector option enum closer to other similar option enums - rustc_interface/tests: sort debug option list in tracking hash test - add an explicit `none` stack-protector option Revert "set LLVM requirements for all stack protector support test revisions" This reverts commit a49b74f92a4e7d701d6f6cf63d207a8aff2e0f68.
2021-04-06 21:37:49 +02:00
key!(supports_stack_protector, bool);
key!(entry_name);
key!(entry_abi, Conv)?;
key!(supports_xray, bool);
if base.is_builtin {
// This can cause unfortunate ICEs later down the line.
return Err("may not set is_builtin for targets not built-in".into());
}
base.update_from_cli();
2021-06-03 17:45:09 +02:00
// Each field should have been read using `Json::remove` so any keys remaining are unused.
let remaining_keys = obj.keys();
Ok((
base,
TargetWarnings { unused_fields: remaining_keys.cloned().collect(), incorrect_type },
))
}
/// Load a built-in target
pub fn expect_builtin(target_triple: &TargetTriple) -> Target {
match *target_triple {
TargetTriple::TargetTriple(ref target_triple) => {
load_builtin(target_triple).expect("built-in target")
}
TargetTriple::TargetJson { .. } => {
panic!("built-in targets doesn't support target-paths")
}
}
}
/// Search for a JSON file specifying the given target triple.
///
/// If none is found in `$RUST_TARGET_PATH`, look for a file called `target.json` inside the
/// sysroot under the target-triple's `rustlib` directory. Note that it could also just be a
/// bare filename already, so also check for that. If one of the hardcoded targets we know
/// about, just return it directly.
///
/// The error string could come from any of the APIs called, including filesystem access and
/// JSON decoding.
pub fn search(
target_triple: &TargetTriple,
2021-11-07 10:33:27 +01:00
sysroot: &Path,
) -> Result<(Target, TargetWarnings), String> {
std: Add a new `env` module This is an implementation of [RFC 578][rfc] which adds a new `std::env` module to replace most of the functionality in the current `std::os` module. More details can be found in the RFC itself, but as a summary the following methods have all been deprecated: [rfc]: https://github.com/rust-lang/rfcs/pull/578 * `os::args_as_bytes` => `env::args` * `os::args` => `env::args` * `os::consts` => `env::consts` * `os::dll_filename` => no replacement, use `env::consts` directly * `os::page_size` => `env::page_size` * `os::make_absolute` => use `env::current_dir` + `join` instead * `os::getcwd` => `env::current_dir` * `os::change_dir` => `env::set_current_dir` * `os::homedir` => `env::home_dir` * `os::tmpdir` => `env::temp_dir` * `os::join_paths` => `env::join_paths` * `os::split_paths` => `env::split_paths` * `os::self_exe_name` => `env::current_exe` * `os::self_exe_path` => use `env::current_exe` + `pop` * `os::set_exit_status` => `env::set_exit_status` * `os::get_exit_status` => `env::get_exit_status` * `os::env` => `env::vars` * `os::env_as_bytes` => `env::vars` * `os::getenv` => `env::var` or `env::var_string` * `os::getenv_as_bytes` => `env::var` * `os::setenv` => `env::set_var` * `os::unsetenv` => `env::remove_var` Many function signatures have also been tweaked for various purposes, but the main changes were: * `Vec`-returning APIs now all return iterators instead * All APIs are now centered around `OsString` instead of `Vec<u8>` or `String`. There is currently on convenience API, `env::var_string`, which can be used to get the value of an environment variable as a unicode `String`. All old APIs are `#[deprecated]` in-place and will remain for some time to allow for migrations. The semantics of the APIs have been tweaked slightly with regard to dealing with invalid unicode (panic instead of replacement). The new `std::env` module is all contained within the `env` feature, so crates must add the following to access the new APIs: #![feature(env)] [breaking-change]
2015-01-27 12:20:58 -08:00
use std::env;
use std::fs;
fn load_file(path: &Path) -> Result<(Target, TargetWarnings), String> {
let contents = fs::read_to_string(path).map_err(|e| e.to_string())?;
2021-06-03 17:45:09 +02:00
let obj = serde_json::from_str(&contents).map_err(|e| e.to_string())?;
Target::from_json(obj)
}
2018-08-09 15:42:43 +02:00
match *target_triple {
TargetTriple::TargetTriple(ref target_triple) => {
// check if triple is in list of built-in targets
if let Some(t) = load_builtin(target_triple) {
return Ok((t, TargetWarnings::empty()));
}
// search for a file named `target_triple`.json in RUST_TARGET_PATH
let path = {
let mut target = target_triple.to_string();
target.push_str(".json");
PathBuf::from(target)
};
2018-08-09 15:42:43 +02:00
let target_path = env::var_os("RUST_TARGET_PATH").unwrap_or_default();
for dir in env::split_paths(&target_path) {
let p = dir.join(&path);
if p.is_file() {
return load_file(&p);
}
}
// Additionally look in the sysroot under `lib/rustlib/<triple>/target.json`
// as a fallback.
2022-11-29 11:01:17 +00:00
let rustlib_path = crate::target_rustlib_path(sysroot, target_triple);
let p = PathBuf::from_iter([
Path::new(sysroot),
Path::new(&rustlib_path),
Path::new("target.json"),
]);
if p.is_file() {
return load_file(&p);
}
Err(format!("Could not find specification for target {target_triple:?}"))
}
TargetTriple::TargetJson { ref contents, .. } => {
let obj = serde_json::from_str(contents).map_err(|e| e.to_string())?;
Target::from_json(obj)
}
}
}
}
impl ToJson for Target {
fn to_json(&self) -> Json {
2021-06-03 17:45:09 +02:00
let mut d = serde_json::Map::new();
let default: TargetOptions = Default::default();
let mut target = self.clone();
target.update_to_cli();
macro_rules! target_val {
($attr:ident) => {{
let name = (stringify!($attr)).replace("_", "-");
d.insert(name, target.$attr.to_json());
}};
}
macro_rules! target_option_val {
($attr:ident) => {{
let name = (stringify!($attr)).replace("_", "-");
if default.$attr != target.$attr {
d.insert(name, target.$attr.to_json());
}
}};
($attr:ident, $json_name:expr) => {{
let name = $json_name;
if default.$attr != target.$attr {
d.insert(name.into(), target.$attr.to_json());
}
}};
(link_args - $attr:ident, $json_name:expr) => {{
let name = $json_name;
if default.$attr != target.$attr {
let obj = target
-Z linker-flavor This patch adds a `-Z linker-flavor` flag to rustc which can be used to invoke the linker using a different interface. For example, by default rustc assumes that all the Linux targets will be linked using GCC. This makes it impossible to use LLD as a linker using just `-C linker=ld.lld` because that will invoke LLD with invalid command line arguments. (e.g. rustc will pass -Wl,--gc-sections to LLD but LLD doesn't understand that; --gc-sections would be the right argument) With this patch one can pass `-Z linker-flavor=ld` to rustc to invoke the linker using a LD-like interface. This way, `rustc -C linker=ld.lld -Z linker-flavor=ld` will invoke LLD with the right arguments. `-Z linker-flavor` accepts 4 different arguments: `em` (emcc), `ld`, `gcc`, `msvc` (link.exe). `em`, `gnu` and `msvc` cover all the existing linker interfaces. `ld` is a new flavor for interfacing GNU's ld and LLD. This patch also changes target specifications. `linker-flavor` is now a mandatory field that specifies the *default* linker flavor that the target will use. This change also makes the linker interface *explicit*; before, it used to be derived from other fields like linker-is-gnu, is-like-msvc, is-like-emscripten, etc. Another change to target specifications is that the fields `pre-link-args`, `post-link-args` and `late-link-args` now expect a map from flavor to linker arguments. ``` diff - "pre-link-args": ["-Wl,--as-needed", "-Wl,-z,-noexecstack"], + "pre-link-args": { + "gcc": ["-Wl,--as-needed", "-Wl,-z,-noexecstack"], + "ld": ["--as-needed", "-z,-noexecstack"], + }, ``` [breaking-change] for users of custom targets specifications
2017-02-21 14:47:15 -05:00
.$attr
.iter()
.map(|(k, v)| (k.desc().to_string(), v.clone()))
-Z linker-flavor This patch adds a `-Z linker-flavor` flag to rustc which can be used to invoke the linker using a different interface. For example, by default rustc assumes that all the Linux targets will be linked using GCC. This makes it impossible to use LLD as a linker using just `-C linker=ld.lld` because that will invoke LLD with invalid command line arguments. (e.g. rustc will pass -Wl,--gc-sections to LLD but LLD doesn't understand that; --gc-sections would be the right argument) With this patch one can pass `-Z linker-flavor=ld` to rustc to invoke the linker using a LD-like interface. This way, `rustc -C linker=ld.lld -Z linker-flavor=ld` will invoke LLD with the right arguments. `-Z linker-flavor` accepts 4 different arguments: `em` (emcc), `ld`, `gcc`, `msvc` (link.exe). `em`, `gnu` and `msvc` cover all the existing linker interfaces. `ld` is a new flavor for interfacing GNU's ld and LLD. This patch also changes target specifications. `linker-flavor` is now a mandatory field that specifies the *default* linker flavor that the target will use. This change also makes the linker interface *explicit*; before, it used to be derived from other fields like linker-is-gnu, is-like-msvc, is-like-emscripten, etc. Another change to target specifications is that the fields `pre-link-args`, `post-link-args` and `late-link-args` now expect a map from flavor to linker arguments. ``` diff - "pre-link-args": ["-Wl,--as-needed", "-Wl,-z,-noexecstack"], + "pre-link-args": { + "gcc": ["-Wl,--as-needed", "-Wl,-z,-noexecstack"], + "ld": ["--as-needed", "-z,-noexecstack"], + }, ``` [breaking-change] for users of custom targets specifications
2017-02-21 14:47:15 -05:00
.collect::<BTreeMap<_, _>>();
d.insert(name.to_string(), obj.to_json());
-Z linker-flavor This patch adds a `-Z linker-flavor` flag to rustc which can be used to invoke the linker using a different interface. For example, by default rustc assumes that all the Linux targets will be linked using GCC. This makes it impossible to use LLD as a linker using just `-C linker=ld.lld` because that will invoke LLD with invalid command line arguments. (e.g. rustc will pass -Wl,--gc-sections to LLD but LLD doesn't understand that; --gc-sections would be the right argument) With this patch one can pass `-Z linker-flavor=ld` to rustc to invoke the linker using a LD-like interface. This way, `rustc -C linker=ld.lld -Z linker-flavor=ld` will invoke LLD with the right arguments. `-Z linker-flavor` accepts 4 different arguments: `em` (emcc), `ld`, `gcc`, `msvc` (link.exe). `em`, `gnu` and `msvc` cover all the existing linker interfaces. `ld` is a new flavor for interfacing GNU's ld and LLD. This patch also changes target specifications. `linker-flavor` is now a mandatory field that specifies the *default* linker flavor that the target will use. This change also makes the linker interface *explicit*; before, it used to be derived from other fields like linker-is-gnu, is-like-msvc, is-like-emscripten, etc. Another change to target specifications is that the fields `pre-link-args`, `post-link-args` and `late-link-args` now expect a map from flavor to linker arguments. ``` diff - "pre-link-args": ["-Wl,--as-needed", "-Wl,-z,-noexecstack"], + "pre-link-args": { + "gcc": ["-Wl,--as-needed", "-Wl,-z,-noexecstack"], + "ld": ["--as-needed", "-z,-noexecstack"], + }, ``` [breaking-change] for users of custom targets specifications
2017-02-21 14:47:15 -05:00
}
}};
(env - $attr:ident) => {{
let name = (stringify!($attr)).replace("_", "-");
if default.$attr != target.$attr {
let obj = target
.$attr
.iter()
.map(|&(ref k, ref v)| format!("{k}={v}"))
.collect::<Vec<_>>();
2018-10-26 03:11:11 +09:00
d.insert(name, obj.to_json());
}
}};
}
target_val!(llvm_target);
target_val!(description);
d.insert("target-pointer-width".to_string(), self.pointer_width.to_string().to_json());
target_val!(arch);
target_val!(data_layout);
target_option_val!(is_builtin);
target_option_val!(endian, "target-endian");
target_option_val!(c_int_width, "target-c-int-width");
target_option_val!(os);
target_option_val!(env);
target_option_val!(abi);
target_option_val!(vendor);
target_option_val!(linker);
target_option_val!(linker_flavor_json, "linker-flavor");
target_option_val!(lld_flavor_json, "lld-flavor");
target_option_val!(linker_is_gnu_json, "linker-is-gnu");
target_option_val!(pre_link_objects);
target_option_val!(post_link_objects);
target_option_val!(pre_link_objects_self_contained, "pre-link-objects-fallback");
target_option_val!(post_link_objects_self_contained, "post-link-objects-fallback");
target_option_val!(link_args - pre_link_args_json, "pre-link-args");
target_option_val!(link_args - late_link_args_json, "late-link-args");
target_option_val!(link_args - late_link_args_dynamic_json, "late-link-args-dynamic");
target_option_val!(link_args - late_link_args_static_json, "late-link-args-static");
target_option_val!(link_args - post_link_args_json, "post-link-args");
target_option_val!(link_script);
target_option_val!(env - link_env);
target_option_val!(link_env_remove);
target_option_val!(asm_args);
target_option_val!(cpu);
target_option_val!(features);
target_option_val!(dynamic_linking);
target_option_val!(direct_access_external_data);
target_option_val!(dll_tls_export);
std: Add a new wasm32-unknown-unknown target This commit adds a new target to the compiler: wasm32-unknown-unknown. This target is a reimagining of what it looks like to generate WebAssembly code from Rust. Instead of using Emscripten which can bring with it a weighty runtime this instead is a target which uses only the LLVM backend for WebAssembly and a "custom linker" for now which will hopefully one day be direct calls to lld. Notable features of this target include: * There is zero runtime footprint. The target assumes nothing exists other than the wasm32 instruction set. * There is zero toolchain footprint beyond adding the target. No custom linker is needed, rustc contains everything. * Very small wasm modules can be generated directly from Rust code using this target. * Most of the standard library is stubbed out to return an error, but anything related to allocation works (aka `HashMap`, `Vec`, etc). * Naturally, any `#[no_std]` crate should be 100% compatible with this new target. This target is currently somewhat janky due to how linking works. The "linking" is currently unconditional whole program LTO (aka LLVM is being used as a linker). Naturally that means compiling programs is pretty slow! Eventually though this target should have a linker. This target is also intended to be quite experimental. I'm hoping that this can act as a catalyst for further experimentation in Rust with WebAssembly. Breaking changes are very likely to land to this target, so it's not recommended to rely on it in any critical capacity yet. We'll let you know when it's "production ready". --- Currently testing-wise this target is looking pretty good but isn't complete. I've got almost the entire `run-pass` test suite working with this target (lots of tests ignored, but many passing as well). The `core` test suite is still getting LLVM bugs fixed to get that working and will take some time. Relatively simple programs all seem to work though! --- It's worth nothing that you may not immediately see the "smallest possible wasm module" for the input you feed to rustc. For various reasons it's very difficult to get rid of the final "bloat" in vanilla rustc (again, a real linker should fix all this). For now what you'll have to do is: cargo install --git https://github.com/alexcrichton/wasm-gc wasm-gc foo.wasm bar.wasm And then `bar.wasm` should be the smallest we can get it! --- In any case for now I'd love feedback on this, particularly on the various integration points if you've got better ideas of how to approach them!
2017-10-22 20:01:00 -07:00
target_option_val!(only_cdylib);
target_option_val!(executables);
target_option_val!(relocation_model);
target_option_val!(code_model);
target_option_val!(tls_model);
target_option_val!(disable_redzone);
target_option_val!(frame_pointer);
target_option_val!(function_sections);
target_option_val!(dll_prefix);
target_option_val!(dll_suffix);
target_option_val!(exe_suffix);
target_option_val!(staticlib_prefix);
target_option_val!(staticlib_suffix);
target_option_val!(families, "target-family");
target_option_val!(abi_return_struct_as_int);
2022-08-25 14:37:29 +08:00
target_option_val!(is_like_aix);
target_option_val!(is_like_osx);
target_option_val!(is_like_solaris);
target_option_val!(is_like_windows);
target_option_val!(is_like_msvc);
2020-12-30 12:52:21 -06:00
target_option_val!(is_like_wasm);
target_option_val!(is_like_android);
target_option_val!(default_dwarf_version);
target_option_val!(allows_weak_linkage);
target_option_val!(has_rpath);
target_option_val!(no_default_libraries);
target_option_val!(position_independent_executables);
target_option_val!(static_position_independent_executables);
target_option_val!(plt_by_default);
target_option_val!(relro_level);
target_option_val!(archive_format);
target_option_val!(allow_asm);
target_option_val!(main_needs_argc_argv);
target_option_val!(has_thread_local);
target_option_val!(obj_is_bitcode);
target_option_val!(forces_embed_bitcode);
target_option_val!(bitcode_llvm_cmdline);
target_option_val!(min_atomic_width);
target_option_val!(max_atomic_width);
target_option_val!(atomic_cas);
target_option_val!(panic_strategy);
target_option_val!(crt_static_allows_dylibs);
rustc: Implement #[link(cfg(..))] and crt-static This commit is an implementation of [RFC 1721] which adds a new target feature to the compiler, `crt-static`, which can be used to select how the C runtime for a target is linked. Most targets dynamically linke the C runtime by default with the notable exception of some of the musl targets. [RFC 1721]: https://github.com/rust-lang/rfcs/blob/master/text/1721-crt-static.md This commit first adds the new target-feature, `crt-static`. If enabled, then the `cfg(target_feature = "crt-static")` will be available. Targets like musl will have this enabled by default. This feature can be controlled through the standard target-feature interface, `-C target-feature=+crt-static` or `-C target-feature=-crt-static`. Next this adds an gated and unstable `#[link(cfg(..))]` feature to enable the `crt-static` semantics we want with libc. The exact behavior of this attribute is a little squishy, but it's intended to be a forever-unstable implementation detail of the liblibc crate. Specifically the `#[link(cfg(..))]` annotation means that the `#[link]` directive is only active in a compilation unit if that `cfg` value is satisfied. For example when compiling an rlib, these directives are just encoded and ignored for dylibs, and all staticlibs are continued to be put into the rlib as usual. When placing that rlib into a staticlib, executable, or dylib, however, the `cfg` is evaluated *as if it were defined in the final artifact* and the library is decided to be linked or not. Essentially, what'll happen is: * On MSVC with `-C target-feature=-crt-static`, the `msvcrt.lib` library will be linked to. * On MSVC with `-C target-feature=+crt-static`, the `libcmt.lib` library will be linked to. * On musl with `-C target-feature=-crt-static`, the object files in liblibc.rlib are removed and `-lc` is passed instead. * On musl with `-C target-feature=+crt-static`, the object files in liblibc.rlib are used and `-lc` is not passed. This commit does **not** include an update to the liblibc module to implement these changes. I plan to do that just after the 1.14.0 beta release is cut to ensure we get ample time to test this feature. cc #37406
2016-10-31 16:40:13 -07:00
target_option_val!(crt_static_default);
target_option_val!(crt_static_respected);
target_option_val!(stack_probes);
target_option_val!(min_global_align);
target_option_val!(default_codegen_units);
target_option_val!(trap_unreachable);
std: Add a new wasm32-unknown-unknown target This commit adds a new target to the compiler: wasm32-unknown-unknown. This target is a reimagining of what it looks like to generate WebAssembly code from Rust. Instead of using Emscripten which can bring with it a weighty runtime this instead is a target which uses only the LLVM backend for WebAssembly and a "custom linker" for now which will hopefully one day be direct calls to lld. Notable features of this target include: * There is zero runtime footprint. The target assumes nothing exists other than the wasm32 instruction set. * There is zero toolchain footprint beyond adding the target. No custom linker is needed, rustc contains everything. * Very small wasm modules can be generated directly from Rust code using this target. * Most of the standard library is stubbed out to return an error, but anything related to allocation works (aka `HashMap`, `Vec`, etc). * Naturally, any `#[no_std]` crate should be 100% compatible with this new target. This target is currently somewhat janky due to how linking works. The "linking" is currently unconditional whole program LTO (aka LLVM is being used as a linker). Naturally that means compiling programs is pretty slow! Eventually though this target should have a linker. This target is also intended to be quite experimental. I'm hoping that this can act as a catalyst for further experimentation in Rust with WebAssembly. Breaking changes are very likely to land to this target, so it's not recommended to rely on it in any critical capacity yet. We'll let you know when it's "production ready". --- Currently testing-wise this target is looking pretty good but isn't complete. I've got almost the entire `run-pass` test suite working with this target (lots of tests ignored, but many passing as well). The `core` test suite is still getting LLVM bugs fixed to get that working and will take some time. Relatively simple programs all seem to work though! --- It's worth nothing that you may not immediately see the "smallest possible wasm module" for the input you feed to rustc. For various reasons it's very difficult to get rid of the final "bloat" in vanilla rustc (again, a real linker should fix all this). For now what you'll have to do is: cargo install --git https://github.com/alexcrichton/wasm-gc wasm-gc foo.wasm bar.wasm And then `bar.wasm` should be the smallest we can get it! --- In any case for now I'd love feedback on this, particularly on the various integration points if you've got better ideas of how to approach them!
2017-10-22 20:01:00 -07:00
target_option_val!(requires_lto);
target_option_val!(singlethread);
target_option_val!(no_builtins);
target_option_val!(default_hidden_visibility);
target_option_val!(emit_debug_gdb_scripts);
target_option_val!(requires_uwtable);
target_option_val!(default_uwtable);
target_option_val!(simd_types_indirect);
target_option_val!(limit_rdylib_exports);
target_option_val!(override_export_symbols);
target_option_val!(merge_functions);
target_option_val!(mcount, "target-mcount");
target_option_val!(llvm_mcount_intrinsic);
target_option_val!(llvm_abiname);
target_option_val!(relax_elf_relocations);
target_option_val!(llvm_args);
target_option_val!(use_ctors_section);
target_option_val!(eh_frame_header);
target_option_val!(has_thumb_interworking);
target_option_val!(debuginfo_kind);
rustc: Stabilize `-Zrun-dsymutil` as `-Csplit-debuginfo` This commit adds a new stable codegen option to rustc, `-Csplit-debuginfo`. The old `-Zrun-dsymutil` flag is deleted and now subsumed by this stable flag. Additionally `-Zsplit-dwarf` is also subsumed by this flag but still requires `-Zunstable-options` to actually activate. The `-Csplit-debuginfo` flag takes one of three values: * `off` - This indicates that split-debuginfo from the final artifact is not desired. This is not supported on Windows and is the default on Unix platforms except macOS. On macOS this means that `dsymutil` is not executed. * `packed` - This means that debuginfo is desired in one location separate from the main executable. This is the default on Windows (`*.pdb`) and macOS (`*.dSYM`). On other Unix platforms this subsumes `-Zsplit-dwarf=single` and produces a `*.dwp` file. * `unpacked` - This means that debuginfo will be roughly equivalent to object files, meaning that it's throughout the build directory rather than in one location (often the fastest for local development). This is not the default on any platform and is not supported on Windows. Each target can indicate its own default preference for how debuginfo is handled. Almost all platforms default to `off` except for Windows and macOS which default to `packed` for historical reasons. Some equivalencies for previous unstable flags with the new flags are: * `-Zrun-dsymutil=yes` -> `-Csplit-debuginfo=packed` * `-Zrun-dsymutil=no` -> `-Csplit-debuginfo=unpacked` * `-Zsplit-dwarf=single` -> `-Csplit-debuginfo=packed` * `-Zsplit-dwarf=split` -> `-Csplit-debuginfo=unpacked` Note that `-Csplit-debuginfo` still requires `-Zunstable-options` for non-macOS platforms since split-dwarf support was *just* implemented in rustc. There's some more rationale listed on #79361, but the main gist of the motivation for this commit is that `dsymutil` can take quite a long time to execute in debug builds and provides little benefit. This means that incremental compile times appear that much worse on macOS because the compiler is constantly running `dsymutil` over every single binary it produces during `cargo build` (even build scripts!). Ideally rustc would switch to not running `dsymutil` by default, but that's a problem left to get tackled another day. Closes #79361
2020-11-30 08:39:08 -08:00
target_option_val!(split_debuginfo);
target_option_val!(supported_split_debuginfo);
target_option_val!(supported_sanitizers);
2021-08-10 18:34:13 +00:00
target_option_val!(c_enum_min_bits);
target_option_val!(generate_arange_section);
add rustc option for using LLVM stack smash protection LLVM has built-in heuristics for adding stack canaries to functions. These heuristics can be selected with LLVM function attributes. This patch adds a rustc option `-Z stack-protector={none,basic,strong,all}` which controls the use of these attributes. This gives rustc the same stack smash protection support as clang offers through options `-fno-stack-protector`, `-fstack-protector`, `-fstack-protector-strong`, and `-fstack-protector-all`. The protection this can offer is demonstrated in test/ui/abi/stack-protector.rs. This fills a gap in the current list of rustc exploit mitigations (https://doc.rust-lang.org/rustc/exploit-mitigations.html), originally discussed in #15179. Stack smash protection adds runtime overhead and is therefore still off by default, but now users have the option to trade performance for security as they see fit. An example use case is adding Rust code in an existing C/C++ code base compiled with stack smash protection. Without the ability to add stack smash protection to the Rust code, the code base artifacts could be exploitable in ways not possible if the code base remained pure C/C++. Stack smash protection support is present in LLVM for almost all the current tier 1/tier 2 targets: see test/assembly/stack-protector/stack-protector-target-support.rs. The one exception is nvptx64-nvidia-cuda. This patch follows clang's example, and adds a warning message printed if stack smash protection is used with this target (see test/ui/stack-protector/warn-stack-protector-unsupported.rs). Support for tier 3 targets has not been checked. Since the heuristics are applied at the LLVM level, the heuristics are expected to add stack smash protection to a fraction of functions comparable to C/C++. Some experiments demonstrating how Rust code is affected by the different heuristics can be found in test/assembly/stack-protector/stack-protector-heuristics-effect.rs. There is potential for better heuristics using Rust-specific safety information. For example it might be reasonable to skip stack smash protection in functions which transitively only use safe Rust code, or which uses only a subset of functions the user declares safe (such as anything under `std.*`). Such alternative heuristics could be added at a later point. LLVM also offers a "safestack" sanitizer as an alternative way to guard against stack smashing (see #26612). This could possibly also be included as a stack-protection heuristic. An alternative is to add it as a sanitizer (#39699). This is what clang does: safestack is exposed with option `-fsanitize=safe-stack`. The options are only supported by the LLVM backend, but as with other codegen options it is visible in the main codegen option help menu. The heuristic names "basic", "strong", and "all" are hopefully sufficiently generic to be usable in other backends as well. Reviewed-by: Nikita Popov <nikic@php.net> Extra commits during review: - [address-review] make the stack-protector option unstable - [address-review] reduce detail level of stack-protector option help text - [address-review] correct grammar in comment - [address-review] use compiler flag to avoid merging functions in test - [address-review] specify min LLVM version in fortanix stack-protector test Only for Fortanix test, since this target specifically requests the `--x86-experimental-lvi-inline-asm-hardening` flag. - [address-review] specify required LLVM components in stack-protector tests - move stack protector option enum closer to other similar option enums - rustc_interface/tests: sort debug option list in tracking hash test - add an explicit `none` stack-protector option Revert "set LLVM requirements for all stack protector support test revisions" This reverts commit a49b74f92a4e7d701d6f6cf63d207a8aff2e0f68.
2021-04-06 21:37:49 +02:00
target_option_val!(supports_stack_protector);
target_option_val!(entry_name);
target_option_val!(entry_abi);
target_option_val!(supports_xray);
rustc: Add a new `wasm` ABI This commit implements the idea of a new ABI for the WebAssembly target, one called `"wasm"`. This ABI is entirely of my own invention and has no current precedent, but I think that the addition of this ABI might help solve a number of issues with the WebAssembly targets. When `wasm32-unknown-unknown` was first added to Rust I naively "implemented an abi" for the target. I then went to write `wasm-bindgen` which accidentally relied on details of this ABI. Turns out the ABI definition didn't match C, which is causing issues for C/Rust interop. Currently the compiler has a "wasm32 bindgen compat" ABI which is the original implementation I added, and it's purely there for, well, `wasm-bindgen`. Another issue with the WebAssembly target is that it's not clear to me when and if the default C ABI will change to account for WebAssembly's multi-value feature (a feature that allows functions to return multiple values). Even if this does happen, though, it seems like the C ABI will be guided based on the performance of WebAssembly code and will likely not match even what the current wasm-bindgen-compat ABI is today. This leaves a hole in Rust's expressivity in binding WebAssembly where given a particular import type, Rust may not be able to import that signature with an updated C ABI for multi-value. To fix these issues I had the idea of a new ABI for WebAssembly, one called `wasm`. The definition of this ABI is "what you write maps straight to wasm". The goal here is that whatever you write down in the parameter list or in the return values goes straight into the function's signature in the WebAssembly file. This special ABI is for intentionally matching the ABI of an imported function from the environment or exporting a function with the right signature. With the addition of a new ABI, this enables rustc to: * Eventually remove the "wasm-bindgen compat hack". Once this ABI is stable wasm-bindgen can switch to using it everywhere. Afterwards the wasm32-unknown-unknown target can have its default ABI updated to match C. * Expose the ability to precisely match an ABI signature for a WebAssembly function, regardless of what the C ABI that clang chooses turns out to be. * Continue to evolve the definition of the default C ABI to match what clang does on all targets, since the purpose of that ABI will be explicitly matching C rather than generating particular function imports/exports. Naturally this is implemented as an unstable feature initially, but it would be nice for this to get stabilized (if it works) in the near-ish future to remove the wasm32-unknown-unknown incompatibility with the C ABI. Doing this, however, requires the feature to be on stable because wasm-bindgen works with stable Rust.
2021-04-01 16:08:29 -07:00
if let Some(abi) = self.default_adjusted_cabi {
d.insert("default-adjusted-cabi".into(), Abi::name(abi).to_json());
rustc: Add a new `wasm` ABI This commit implements the idea of a new ABI for the WebAssembly target, one called `"wasm"`. This ABI is entirely of my own invention and has no current precedent, but I think that the addition of this ABI might help solve a number of issues with the WebAssembly targets. When `wasm32-unknown-unknown` was first added to Rust I naively "implemented an abi" for the target. I then went to write `wasm-bindgen` which accidentally relied on details of this ABI. Turns out the ABI definition didn't match C, which is causing issues for C/Rust interop. Currently the compiler has a "wasm32 bindgen compat" ABI which is the original implementation I added, and it's purely there for, well, `wasm-bindgen`. Another issue with the WebAssembly target is that it's not clear to me when and if the default C ABI will change to account for WebAssembly's multi-value feature (a feature that allows functions to return multiple values). Even if this does happen, though, it seems like the C ABI will be guided based on the performance of WebAssembly code and will likely not match even what the current wasm-bindgen-compat ABI is today. This leaves a hole in Rust's expressivity in binding WebAssembly where given a particular import type, Rust may not be able to import that signature with an updated C ABI for multi-value. To fix these issues I had the idea of a new ABI for WebAssembly, one called `wasm`. The definition of this ABI is "what you write maps straight to wasm". The goal here is that whatever you write down in the parameter list or in the return values goes straight into the function's signature in the WebAssembly file. This special ABI is for intentionally matching the ABI of an imported function from the environment or exporting a function with the right signature. With the addition of a new ABI, this enables rustc to: * Eventually remove the "wasm-bindgen compat hack". Once this ABI is stable wasm-bindgen can switch to using it everywhere. Afterwards the wasm32-unknown-unknown target can have its default ABI updated to match C. * Expose the ability to precisely match an ABI signature for a WebAssembly function, regardless of what the C ABI that clang chooses turns out to be. * Continue to evolve the definition of the default C ABI to match what clang does on all targets, since the purpose of that ABI will be explicitly matching C rather than generating particular function imports/exports. Naturally this is implemented as an unstable feature initially, but it would be nice for this to get stabilized (if it works) in the near-ish future to remove the wasm32-unknown-unknown incompatibility with the C ABI. Doing this, however, requires the feature to be on stable because wasm-bindgen works with stable Rust.
2021-04-01 16:08:29 -07:00
}
// Serializing `-Clink-self-contained` needs a dynamic key to support the
// backwards-compatible variants.
d.insert(self.link_self_contained.json_key().into(), self.link_self_contained.to_json());
Json::Object(d)
}
}
/// Either a target triple string or a path to a JSON file.
#[derive(Clone, Debug)]
pub enum TargetTriple {
TargetTriple(String),
TargetJson {
/// Warning: This field may only be used by rustdoc. Using it anywhere else will lead to
/// inconsistencies as it is discarded during serialization.
path_for_rustdoc: PathBuf,
triple: String,
contents: String,
},
}
// Use a manual implementation to ignore the path field
impl PartialEq for TargetTriple {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::TargetTriple(l0), Self::TargetTriple(r0)) => l0 == r0,
(
Self::TargetJson { path_for_rustdoc: _, triple: l_triple, contents: l_contents },
Self::TargetJson { path_for_rustdoc: _, triple: r_triple, contents: r_contents },
) => l_triple == r_triple && l_contents == r_contents,
_ => false,
}
}
}
// Use a manual implementation to ignore the path field
impl Hash for TargetTriple {
fn hash<H: Hasher>(&self, state: &mut H) -> () {
match self {
TargetTriple::TargetTriple(triple) => {
0u8.hash(state);
triple.hash(state)
}
TargetTriple::TargetJson { path_for_rustdoc: _, triple, contents } => {
1u8.hash(state);
triple.hash(state);
contents.hash(state)
}
}
}
}
// Use a manual implementation to prevent encoding the target json file path in the crate metadata
impl<S: Encoder> Encodable<S> for TargetTriple {
fn encode(&self, s: &mut S) {
match self {
TargetTriple::TargetTriple(triple) => {
s.emit_u8(0);
s.emit_str(triple);
}
TargetTriple::TargetJson { path_for_rustdoc: _, triple, contents } => {
s.emit_u8(1);
s.emit_str(triple);
s.emit_str(contents);
}
}
}
}
impl<D: Decoder> Decodable<D> for TargetTriple {
fn decode(d: &mut D) -> Self {
match d.read_u8() {
0 => TargetTriple::TargetTriple(d.read_str().to_owned()),
1 => TargetTriple::TargetJson {
path_for_rustdoc: PathBuf::new(),
triple: d.read_str().to_owned(),
contents: d.read_str().to_owned(),
},
_ => {
panic!("invalid enum variant tag while decoding `TargetTriple`, expected 0..2");
}
}
}
}
impl TargetTriple {
2018-03-24 20:14:59 +01:00
/// Creates a target triple from the passed target triple string.
pub fn from_triple(triple: &str) -> Self {
TargetTriple::TargetTriple(triple.into())
}
2018-03-24 20:14:59 +01:00
/// Creates a target triple from the passed target path.
pub fn from_path(path: &Path) -> Result<Self, io::Error> {
let canonicalized_path = try_canonicalize(path)?;
let contents = std::fs::read_to_string(&canonicalized_path).map_err(|err| {
io::Error::new(
io::ErrorKind::InvalidInput,
format!("target path {canonicalized_path:?} is not a valid file: {err}"),
)
})?;
let triple = canonicalized_path
.file_stem()
.expect("target path must not be empty")
.to_str()
.expect("target path must be valid unicode")
.to_owned();
Ok(TargetTriple::TargetJson { path_for_rustdoc: canonicalized_path, triple, contents })
2018-03-24 20:14:59 +01:00
}
/// Returns a string triple for this target.
///
/// If this target is a path, the file name (without extension) is returned.
pub fn triple(&self) -> &str {
2018-08-09 15:42:43 +02:00
match *self {
TargetTriple::TargetTriple(ref triple)
| TargetTriple::TargetJson { ref triple, .. } => triple,
}
}
/// Returns an extended string triple for this target.
///
/// If this target is a path, a hash of the path is appended to the triple returned
/// by `triple()`.
pub fn debug_triple(&self) -> String {
use std::hash::DefaultHasher;
match self {
TargetTriple::TargetTriple(triple) => triple.to_owned(),
TargetTriple::TargetJson { path_for_rustdoc: _, triple, contents: content } => {
let mut hasher = DefaultHasher::new();
content.hash(&mut hasher);
let hash = hasher.finish();
format!("{triple}-{hash}")
}
}
}
}
impl fmt::Display for TargetTriple {
2019-02-08 21:00:07 +09:00
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.debug_triple())
}
}