move target JSON (de)serialization to separate file
This commit is contained in:
parent
562a85579e
commit
77080d8eb3
2 changed files with 800 additions and 789 deletions
798
compiler/rustc_target/src/spec/json.rs
Normal file
798
compiler/rustc_target/src/spec/json.rs
Normal file
|
@ -0,0 +1,798 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use serde_json::Value;
|
||||||
|
|
||||||
|
use super::{Target, TargetKind, TargetOptions, TargetWarnings};
|
||||||
|
use crate::json::{Json, ToJson};
|
||||||
|
|
||||||
|
impl Target {
|
||||||
|
/// Loads a target descriptor from a JSON object.
|
||||||
|
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.
|
||||||
|
|
||||||
|
let mut obj = match obj {
|
||||||
|
Value::Object(obj) => obj,
|
||||||
|
_ => return Err("Expected JSON object for target")?,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut get_req_field = |name: &str| {
|
||||||
|
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(),
|
||||||
|
metadata: Default::default(),
|
||||||
|
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(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// FIXME: This doesn't properly validate anything and just ignores the data if it's invalid.
|
||||||
|
// That's okay for now, the only use of this is when generating docs, which we don't do for
|
||||||
|
// custom targets.
|
||||||
|
if let Some(Json::Object(mut metadata)) = obj.remove("metadata") {
|
||||||
|
base.metadata.description = metadata
|
||||||
|
.remove("description")
|
||||||
|
.and_then(|desc| desc.as_str().map(|desc| desc.to_owned().into()));
|
||||||
|
base.metadata.tier = metadata
|
||||||
|
.remove("tier")
|
||||||
|
.and_then(|tier| tier.as_u64())
|
||||||
|
.filter(|tier| (1..=3).contains(tier));
|
||||||
|
base.metadata.host_tools =
|
||||||
|
metadata.remove("host_tools").and_then(|host| host.as_bool());
|
||||||
|
base.metadata.std = metadata.remove("std").and_then(|host| host.as_bool());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut incorrect_type = vec![];
|
||||||
|
|
||||||
|
macro_rules! key {
|
||||||
|
($key_name:ident) => ( {
|
||||||
|
let name = (stringify!($key_name)).replace("_", "-");
|
||||||
|
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;
|
||||||
|
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("_", "-");
|
||||||
|
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("_", "-");
|
||||||
|
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("_", "-");
|
||||||
|
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("_", "-");
|
||||||
|
obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
|
||||||
|
match s.parse::<super::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("_", "-");
|
||||||
|
obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
|
||||||
|
match s.parse::<super::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("_", "-");
|
||||||
|
obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
|
||||||
|
match s.parse::<super::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("_", "-");
|
||||||
|
obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
|
||||||
|
match s.parse::<super::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, SmallDataThresholdSupport) => ( {
|
||||||
|
obj.remove("small-data-threshold-support").and_then(|o| o.as_str().and_then(|s| {
|
||||||
|
match s.parse::<super::SmallDataThresholdSupport>() {
|
||||||
|
Ok(support) => base.small_data_threshold_support = support,
|
||||||
|
_ => return Some(Err(format!("'{s}' is not a valid value for small-data-threshold-support."))),
|
||||||
|
}
|
||||||
|
Some(Ok(()))
|
||||||
|
})).unwrap_or(Ok(()))
|
||||||
|
} );
|
||||||
|
($key_name:ident, PanicStrategy) => ( {
|
||||||
|
let name = (stringify!($key_name)).replace("_", "-");
|
||||||
|
obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
|
||||||
|
match s {
|
||||||
|
"unwind" => base.$key_name = super::PanicStrategy::Unwind,
|
||||||
|
"abort" => base.$key_name = super::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("_", "-");
|
||||||
|
obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
|
||||||
|
match s.parse::<super::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, Option<SymbolVisibility>) => ( {
|
||||||
|
let name = (stringify!($key_name)).replace("_", "-");
|
||||||
|
obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
|
||||||
|
match s.parse::<super::SymbolVisibility>() {
|
||||||
|
Ok(level) => base.$key_name = Some(level),
|
||||||
|
_ => return Some(Err(format!("'{}' is not a valid value for \
|
||||||
|
symbol-visibility. Use 'hidden', 'protected, or 'interposable'.",
|
||||||
|
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::<super::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(()))
|
||||||
|
} );
|
||||||
|
($key_name:ident, SplitDebuginfo) => ( {
|
||||||
|
let name = (stringify!($key_name)).replace("_", "-");
|
||||||
|
obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
|
||||||
|
match s.parse::<super::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("_", "-");
|
||||||
|
if let Some(j) = obj.remove(&name) {
|
||||||
|
if let Some(v) = j.as_array() {
|
||||||
|
base.$key_name = v.iter()
|
||||||
|
.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("_", "-");
|
||||||
|
if let Some(j) = obj.remove(&name) {
|
||||||
|
if let Some(v) = j.as_array() {
|
||||||
|
base.$key_name = Some(v.iter()
|
||||||
|
.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("_", "-");
|
||||||
|
if let Some(o) = obj.remove(&name) {
|
||||||
|
base.$key_name = o
|
||||||
|
.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| {
|
||||||
|
if let Some(flavor) = super::LldFlavor::from_str(&s) {
|
||||||
|
base.$key_name = flavor;
|
||||||
|
} else {
|
||||||
|
return Some(Err(format!(
|
||||||
|
"'{}' is not a valid value for lld-flavor. \
|
||||||
|
Use 'darwin', 'gnu', 'link' or 'wasm'.",
|
||||||
|
s)))
|
||||||
|
}
|
||||||
|
Some(Ok(()))
|
||||||
|
})).unwrap_or(Ok(()))
|
||||||
|
} );
|
||||||
|
($key_name:ident = $json_name:expr, LinkerFlavorCli) => ( {
|
||||||
|
let name = $json_name;
|
||||||
|
obj.remove(name).and_then(|o| o.as_str().and_then(|s| {
|
||||||
|
match super::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, super::LinkerFlavorCli::one_of()))),
|
||||||
|
}
|
||||||
|
Some(Ok(()))
|
||||||
|
})).unwrap_or(Ok(()))
|
||||||
|
} );
|
||||||
|
($key_name:ident, StackProbeType) => ( {
|
||||||
|
let name = (stringify!($key_name)).replace("_", "-");
|
||||||
|
obj.remove(&name).and_then(|o| match super::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("_", "-");
|
||||||
|
if let Some(o) = obj.remove(&name) {
|
||||||
|
if let Some(a) = o.as_array() {
|
||||||
|
for s in a {
|
||||||
|
use super::SanitizerSet;
|
||||||
|
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 = super::LinkSelfContainedComponents::empty();
|
||||||
|
for s in component_array {
|
||||||
|
components |= match s.as_str() {
|
||||||
|
Some(s) => {
|
||||||
|
super::LinkSelfContainedComponents::from_str(s)
|
||||||
|
.ok_or_else(|| format!("unknown \
|
||||||
|
`-Clink-self-contained` component: {s}"))?
|
||||||
|
},
|
||||||
|
_ => return Err(format!("not a string: {:?}", s)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
base.$key_name = super::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::<super::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 = super::CrtObjects::new();
|
||||||
|
for (k, v) in obj {
|
||||||
|
let kind = super::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)| {
|
||||||
|
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 = super::LinkArgsCli::new();
|
||||||
|
for (k, v) in obj {
|
||||||
|
let flavor = super::LinkerFlavorCli::from_str(&k).ok_or_else(|| {
|
||||||
|
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)| {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
base.$key_name = args;
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
($key_name:ident, env) => ( {
|
||||||
|
let name = (stringify!($key_name)).replace("_", "-");
|
||||||
|
if let Some(o) = obj.remove(&name) {
|
||||||
|
if let Some(a) = o.as_array() {
|
||||||
|
for o in a {
|
||||||
|
if let Some(s) = o.as_str() {
|
||||||
|
if let [k, v] = *s.split('=').collect::<Vec<_>>() {
|
||||||
|
base.$key_name
|
||||||
|
.to_mut()
|
||||||
|
.push((k.to_string().into(), v.to_string().into()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
incorrect_type.push(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
($key_name:ident, target_families) => ( {
|
||||||
|
if let Some(value) = obj.remove("target-family") {
|
||||||
|
if let Some(v) = value.as_array() {
|
||||||
|
base.$key_name = v.iter()
|
||||||
|
.map(|a| a.as_str().unwrap().to_string().into())
|
||||||
|
.collect();
|
||||||
|
} 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 super::Conv::from_str(s) {
|
||||||
|
Ok(c) => {
|
||||||
|
base.$key_name = c;
|
||||||
|
Some(Ok(()))
|
||||||
|
}
|
||||||
|
Err(e) => Some(Err(e))
|
||||||
|
}
|
||||||
|
})).unwrap_or(Ok(()))
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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!(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", LinkerFlavorCli)?;
|
||||||
|
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);
|
||||||
|
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, target_families);
|
||||||
|
key!(abi_return_struct_as_int, bool);
|
||||||
|
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);
|
||||||
|
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);
|
||||||
|
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!(bitcode_llvm_cmdline);
|
||||||
|
key!(max_atomic_width, Option<u64>);
|
||||||
|
key!(min_atomic_width, Option<u64>);
|
||||||
|
key!(atomic_cas, bool);
|
||||||
|
key!(panic_strategy, PanicStrategy)?;
|
||||||
|
key!(crt_static_allows_dylibs, bool);
|
||||||
|
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);
|
||||||
|
key!(requires_lto, bool);
|
||||||
|
key!(singlethread, bool);
|
||||||
|
key!(no_builtins, bool);
|
||||||
|
key!(default_visibility, Option<SymbolVisibility>)?;
|
||||||
|
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)?;
|
||||||
|
key!(split_debuginfo, SplitDebuginfo)?;
|
||||||
|
key!(supported_split_debuginfo, fallible_list)?;
|
||||||
|
key!(supported_sanitizers, SanitizerSet)?;
|
||||||
|
key!(generate_arange_section, bool);
|
||||||
|
key!(supports_stack_protector, bool);
|
||||||
|
key!(small_data_threshold_support, SmallDataThresholdSupport)?;
|
||||||
|
key!(entry_name);
|
||||||
|
key!(entry_abi, Conv)?;
|
||||||
|
key!(supports_xray, bool);
|
||||||
|
|
||||||
|
base.update_from_cli();
|
||||||
|
base.check_consistency(TargetKind::Json)?;
|
||||||
|
|
||||||
|
// 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,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToJson for Target {
|
||||||
|
fn to_json(&self) -> Json {
|
||||||
|
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
|
||||||
|
.$attr
|
||||||
|
.iter()
|
||||||
|
.map(|(k, v)| (k.desc().to_string(), v.clone()))
|
||||||
|
.collect::<BTreeMap<_, _>>();
|
||||||
|
d.insert(name.to_string(), obj.to_json());
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
(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<_>>();
|
||||||
|
d.insert(name, obj.to_json());
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
target_val!(llvm_target);
|
||||||
|
target_val!(metadata);
|
||||||
|
d.insert("target-pointer-width".to_string(), self.pointer_width.to_string().to_json());
|
||||||
|
target_val!(arch);
|
||||||
|
target_val!(data_layout);
|
||||||
|
|
||||||
|
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);
|
||||||
|
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);
|
||||||
|
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);
|
||||||
|
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!(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);
|
||||||
|
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);
|
||||||
|
target_option_val!(requires_lto);
|
||||||
|
target_option_val!(singlethread);
|
||||||
|
target_option_val!(no_builtins);
|
||||||
|
target_option_val!(default_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);
|
||||||
|
target_option_val!(split_debuginfo);
|
||||||
|
target_option_val!(supported_split_debuginfo);
|
||||||
|
target_option_val!(supported_sanitizers);
|
||||||
|
target_option_val!(c_enum_min_bits);
|
||||||
|
target_option_val!(generate_arange_section);
|
||||||
|
target_option_val!(supports_stack_protector);
|
||||||
|
target_option_val!(small_data_threshold_support);
|
||||||
|
target_option_val!(entry_name);
|
||||||
|
target_option_val!(entry_abi);
|
||||||
|
target_option_val!(supports_xray);
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -34,8 +34,6 @@
|
||||||
//! the target's settings, though `target-feature` and `link-args` will *add*
|
//! the target's settings, though `target-feature` and `link-args` will *add*
|
||||||
//! to the list specified by the target, rather than replace.
|
//! to the list specified by the target, rather than replace.
|
||||||
|
|
||||||
// ignore-tidy-filelength
|
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
|
@ -68,6 +66,8 @@ pub mod abi {
|
||||||
}
|
}
|
||||||
|
|
||||||
mod base;
|
mod base;
|
||||||
|
mod json;
|
||||||
|
|
||||||
pub use base::avr_gnu::ef_avr_arch;
|
pub use base::avr_gnu::ef_avr_arch;
|
||||||
|
|
||||||
/// Linker is called through a C/C++ compiler.
|
/// Linker is called through a C/C++ compiler.
|
||||||
|
@ -3206,622 +3206,6 @@ impl Target {
|
||||||
|| (self.env == "sgx" && self.vendor == "fortanix")
|
|| (self.env == "sgx" && self.vendor == "fortanix")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loads a target descriptor from a JSON object.
|
|
||||||
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.
|
|
||||||
|
|
||||||
let mut obj = match obj {
|
|
||||||
Value::Object(obj) => obj,
|
|
||||||
_ => return Err("Expected JSON object for target")?,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut get_req_field = |name: &str| {
|
|
||||||
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(),
|
|
||||||
metadata: Default::default(),
|
|
||||||
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(),
|
|
||||||
};
|
|
||||||
|
|
||||||
// FIXME: This doesn't properly validate anything and just ignores the data if it's invalid.
|
|
||||||
// That's okay for now, the only use of this is when generating docs, which we don't do for
|
|
||||||
// custom targets.
|
|
||||||
if let Some(Json::Object(mut metadata)) = obj.remove("metadata") {
|
|
||||||
base.metadata.description = metadata
|
|
||||||
.remove("description")
|
|
||||||
.and_then(|desc| desc.as_str().map(|desc| desc.to_owned().into()));
|
|
||||||
base.metadata.tier = metadata
|
|
||||||
.remove("tier")
|
|
||||||
.and_then(|tier| tier.as_u64())
|
|
||||||
.filter(|tier| (1..=3).contains(tier));
|
|
||||||
base.metadata.host_tools =
|
|
||||||
metadata.remove("host_tools").and_then(|host| host.as_bool());
|
|
||||||
base.metadata.std = metadata.remove("std").and_then(|host| host.as_bool());
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut incorrect_type = vec![];
|
|
||||||
|
|
||||||
macro_rules! key {
|
|
||||||
($key_name:ident) => ( {
|
|
||||||
let name = (stringify!($key_name)).replace("_", "-");
|
|
||||||
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;
|
|
||||||
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("_", "-");
|
|
||||||
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("_", "-");
|
|
||||||
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("_", "-");
|
|
||||||
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("_", "-");
|
|
||||||
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("_", "-");
|
|
||||||
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("_", "-");
|
|
||||||
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("_", "-");
|
|
||||||
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, SmallDataThresholdSupport) => ( {
|
|
||||||
obj.remove("small-data-threshold-support").and_then(|o| o.as_str().and_then(|s| {
|
|
||||||
match s.parse::<SmallDataThresholdSupport>() {
|
|
||||||
Ok(support) => base.small_data_threshold_support = support,
|
|
||||||
_ => return Some(Err(format!("'{s}' is not a valid value for small-data-threshold-support."))),
|
|
||||||
}
|
|
||||||
Some(Ok(()))
|
|
||||||
})).unwrap_or(Ok(()))
|
|
||||||
} );
|
|
||||||
($key_name:ident, PanicStrategy) => ( {
|
|
||||||
let name = (stringify!($key_name)).replace("_", "-");
|
|
||||||
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("_", "-");
|
|
||||||
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, Option<SymbolVisibility>) => ( {
|
|
||||||
let name = (stringify!($key_name)).replace("_", "-");
|
|
||||||
obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
|
|
||||||
match s.parse::<SymbolVisibility>() {
|
|
||||||
Ok(level) => base.$key_name = Some(level),
|
|
||||||
_ => return Some(Err(format!("'{}' is not a valid value for \
|
|
||||||
symbol-visibility. Use 'hidden', 'protected, or 'interposable'.",
|
|
||||||
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(()))
|
|
||||||
} );
|
|
||||||
($key_name:ident, SplitDebuginfo) => ( {
|
|
||||||
let name = (stringify!($key_name)).replace("_", "-");
|
|
||||||
obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
|
|
||||||
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("_", "-");
|
|
||||||
if let Some(j) = obj.remove(&name) {
|
|
||||||
if let Some(v) = j.as_array() {
|
|
||||||
base.$key_name = v.iter()
|
|
||||||
.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("_", "-");
|
|
||||||
if let Some(j) = obj.remove(&name) {
|
|
||||||
if let Some(v) = j.as_array() {
|
|
||||||
base.$key_name = Some(v.iter()
|
|
||||||
.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("_", "-");
|
|
||||||
if let Some(o) = obj.remove(&name) {
|
|
||||||
base.$key_name = o
|
|
||||||
.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| {
|
|
||||||
if let Some(flavor) = LldFlavor::from_str(&s) {
|
|
||||||
base.$key_name = flavor;
|
|
||||||
} else {
|
|
||||||
return Some(Err(format!(
|
|
||||||
"'{}' is not a valid value for lld-flavor. \
|
|
||||||
Use 'darwin', 'gnu', 'link' or 'wasm'.",
|
|
||||||
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(()))
|
|
||||||
})).unwrap_or(Ok(()))
|
|
||||||
} );
|
|
||||||
($key_name:ident, StackProbeType) => ( {
|
|
||||||
let name = (stringify!($key_name)).replace("_", "-");
|
|
||||||
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("_", "-");
|
|
||||||
if let Some(o) = obj.remove(&name) {
|
|
||||||
if let Some(a) = o.as_array() {
|
|
||||||
for s in a {
|
|
||||||
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)| {
|
|
||||||
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();
|
|
||||||
for (k, v) in obj {
|
|
||||||
let flavor = LinkerFlavorCli::from_str(&k).ok_or_else(|| {
|
|
||||||
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)| {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
base.$key_name = args;
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
($key_name:ident, env) => ( {
|
|
||||||
let name = (stringify!($key_name)).replace("_", "-");
|
|
||||||
if let Some(o) = obj.remove(&name) {
|
|
||||||
if let Some(a) = o.as_array() {
|
|
||||||
for o in a {
|
|
||||||
if let Some(s) = o.as_str() {
|
|
||||||
if let [k, v] = *s.split('=').collect::<Vec<_>>() {
|
|
||||||
base.$key_name
|
|
||||||
.to_mut()
|
|
||||||
.push((k.to_string().into(), v.to_string().into()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
incorrect_type.push(name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
($key_name:ident, TargetFamilies) => ( {
|
|
||||||
if let Some(value) = obj.remove("target-family") {
|
|
||||||
if let Some(v) = value.as_array() {
|
|
||||||
base.$key_name = v.iter()
|
|
||||||
.map(|a| a.as_str().unwrap().to_string().into())
|
|
||||||
.collect();
|
|
||||||
} 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(()))
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
|
|
||||||
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())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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!(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);
|
|
||||||
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);
|
|
||||||
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);
|
|
||||||
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);
|
|
||||||
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!(bitcode_llvm_cmdline);
|
|
||||||
key!(max_atomic_width, Option<u64>);
|
|
||||||
key!(min_atomic_width, Option<u64>);
|
|
||||||
key!(atomic_cas, bool);
|
|
||||||
key!(panic_strategy, PanicStrategy)?;
|
|
||||||
key!(crt_static_allows_dylibs, bool);
|
|
||||||
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);
|
|
||||||
key!(requires_lto, bool);
|
|
||||||
key!(singlethread, bool);
|
|
||||||
key!(no_builtins, bool);
|
|
||||||
key!(default_visibility, Option<SymbolVisibility>)?;
|
|
||||||
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)?;
|
|
||||||
key!(split_debuginfo, SplitDebuginfo)?;
|
|
||||||
key!(supported_split_debuginfo, fallible_list)?;
|
|
||||||
key!(supported_sanitizers, SanitizerSet)?;
|
|
||||||
key!(generate_arange_section, bool);
|
|
||||||
key!(supports_stack_protector, bool);
|
|
||||||
key!(small_data_threshold_support, SmallDataThresholdSupport)?;
|
|
||||||
key!(entry_name);
|
|
||||||
key!(entry_abi, Conv)?;
|
|
||||||
key!(supports_xray, bool);
|
|
||||||
|
|
||||||
base.update_from_cli();
|
|
||||||
base.check_consistency(TargetKind::Json)?;
|
|
||||||
|
|
||||||
// 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
|
/// Load a built-in target
|
||||||
pub fn expect_builtin(target_tuple: &TargetTuple) -> Target {
|
pub fn expect_builtin(target_tuple: &TargetTuple) -> Target {
|
||||||
match *target_tuple {
|
match *target_tuple {
|
||||||
|
@ -3924,177 +3308,6 @@ impl Target {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToJson for Target {
|
|
||||||
fn to_json(&self) -> Json {
|
|
||||||
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
|
|
||||||
.$attr
|
|
||||||
.iter()
|
|
||||||
.map(|(k, v)| (k.desc().to_string(), v.clone()))
|
|
||||||
.collect::<BTreeMap<_, _>>();
|
|
||||||
d.insert(name.to_string(), obj.to_json());
|
|
||||||
}
|
|
||||||
}};
|
|
||||||
(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<_>>();
|
|
||||||
d.insert(name, obj.to_json());
|
|
||||||
}
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
target_val!(llvm_target);
|
|
||||||
target_val!(metadata);
|
|
||||||
d.insert("target-pointer-width".to_string(), self.pointer_width.to_string().to_json());
|
|
||||||
target_val!(arch);
|
|
||||||
target_val!(data_layout);
|
|
||||||
|
|
||||||
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);
|
|
||||||
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);
|
|
||||||
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);
|
|
||||||
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!(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);
|
|
||||||
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);
|
|
||||||
target_option_val!(requires_lto);
|
|
||||||
target_option_val!(singlethread);
|
|
||||||
target_option_val!(no_builtins);
|
|
||||||
target_option_val!(default_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);
|
|
||||||
target_option_val!(split_debuginfo);
|
|
||||||
target_option_val!(supported_split_debuginfo);
|
|
||||||
target_option_val!(supported_sanitizers);
|
|
||||||
target_option_val!(c_enum_min_bits);
|
|
||||||
target_option_val!(generate_arange_section);
|
|
||||||
target_option_val!(supports_stack_protector);
|
|
||||||
target_option_val!(small_data_threshold_support);
|
|
||||||
target_option_val!(entry_name);
|
|
||||||
target_option_val!(entry_abi);
|
|
||||||
target_option_val!(supports_xray);
|
|
||||||
|
|
||||||
// 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 tuple string or a path to a JSON file.
|
/// Either a target tuple string or a path to a JSON file.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum TargetTuple {
|
pub enum TargetTuple {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue