cargo/util/config/
target.rs1use super::{Config, ConfigKey, ConfigRelativePath, OptValue, PathAndArgs, StringList, CV};
2use crate::core::compiler::BuildOutput;
3use crate::util::CargoResult;
4use serde::Deserialize;
5use std::collections::{BTreeMap, HashMap};
6use std::path::PathBuf;
7
8#[derive(Debug, Deserialize)]
12pub struct TargetCfgConfig {
13 pub runner: OptValue<PathAndArgs>,
14 pub rustflags: OptValue<StringList>,
15 #[serde(flatten)]
19 pub other: BTreeMap<String, toml::Value>,
20}
21
22#[derive(Debug)]
24pub struct TargetConfig {
25 pub runner: OptValue<PathAndArgs>,
27 pub rustflags: OptValue<StringList>,
29 pub linker: OptValue<ConfigRelativePath>,
31 pub links_overrides: BTreeMap<String, BuildOutput>,
37}
38
39pub(super) fn load_target_cfgs(config: &Config) -> CargoResult<Vec<(String, TargetCfgConfig)>> {
41 let mut result = Vec::new();
43 let target: BTreeMap<String, TargetCfgConfig> = config.get("target")?;
48 log::debug!("Got all targets {:#?}", target);
49 for (key, cfg) in target {
50 if key.starts_with("cfg(") {
51 for other_key in cfg.other.keys() {
56 config.shell().warn(format!(
57 "unused key `{}` in [target] config table `{}`",
58 other_key, key
59 ))?;
60 }
61 result.push((key, cfg));
62 }
63 }
64 Ok(result)
65}
66
67pub(super) fn load_target_triple(config: &Config, triple: &str) -> CargoResult<TargetConfig> {
69 let runner: OptValue<PathAndArgs> = config.get(&format!("target.{}.runner", triple))?;
75 let rustflags: OptValue<StringList> = config.get(&format!("target.{}.rustflags", triple))?;
76 let linker: OptValue<ConfigRelativePath> = config.get(&format!("target.{}.linker", triple))?;
77 let target_key = ConfigKey::from_str(&format!("target.{}", triple));
79 let links_overrides = match config.get_table(&target_key)? {
80 Some(links) => parse_links_overrides(&target_key, links.val)?,
81 None => BTreeMap::new(),
82 };
83 Ok(TargetConfig {
84 runner,
85 rustflags,
86 linker,
87 links_overrides,
88 })
89}
90
91fn parse_links_overrides(
92 target_key: &ConfigKey,
93 links: HashMap<String, CV>,
94) -> CargoResult<BTreeMap<String, BuildOutput>> {
95 let mut links_overrides = BTreeMap::new();
96 for (lib_name, value) in links {
97 match lib_name.as_str() {
99 "ar" | "linker" | "runner" | "rustflags" => continue,
101 _ => {}
102 }
103 let mut output = BuildOutput::default();
104 let table = value.table(&format!("{}.{}", target_key, lib_name))?.0;
105 let mut pairs = Vec::new();
107 for (k, value) in table {
108 pairs.push((k, value));
109 }
110 pairs.sort_by_key(|p| p.0);
111 for (key, value) in pairs {
112 match key.as_str() {
113 "rustc-flags" => {
114 let flags = value.string(key)?;
115 let whence = format!("target config `{}.{}` (in {})", target_key, key, flags.1);
116 let (paths, links) = BuildOutput::parse_rustc_flags(flags.0, &whence)?;
117 output.library_paths.extend(paths);
118 output.library_links.extend(links);
119 }
120 "rustc-link-lib" => {
121 let list = value.list(key)?;
122 output
123 .library_links
124 .extend(list.iter().map(|v| v.0.clone()));
125 }
126 "rustc-link-search" => {
127 let list = value.list(key)?;
128 output
129 .library_paths
130 .extend(list.iter().map(|v| PathBuf::from(&v.0)));
131 }
132 "rustc-cdylib-link-arg" => {
133 let args = value.list(key)?;
134 output.linker_args.extend(args.iter().map(|v| v.0.clone()));
135 }
136 "rustc-cfg" => {
137 let list = value.list(key)?;
138 output.cfgs.extend(list.iter().map(|v| v.0.clone()));
139 }
140 "rustc-env" => {
141 for (name, val) in value.table(key)?.0 {
142 let val = val.string(name)?.0;
143 output.env.push((name.clone(), val.to_string()));
144 }
145 }
146 "warning" | "rerun-if-changed" | "rerun-if-env-changed" => {
147 anyhow::bail!("`{}` is not supported in build script overrides", key);
148 }
149 _ => {
150 let val = value.string(key)?.0;
151 output.metadata.push((key.clone(), val.to_string()));
152 }
153 }
154 }
155 links_overrides.insert(lib_name, output);
156 }
157 Ok(links_overrides)
158}