1 use super::{Config, ConfigKey, ConfigRelativePath, OptValue, PathAndArgs, StringList, CV}
;
2 use crate::core
::compiler
::{BuildOutput, LinkType}
;
3 use crate::util
::CargoResult
;
4 use serde
::Deserialize
;
5 use std
::collections
::{BTreeMap, HashMap}
;
6 use std
::path
::PathBuf
;
7 use toml_edit
::easy
as toml
;
9 /// Config definition of a `[target.'cfg(…)']` table.
11 /// This is a subset of `TargetConfig`.
12 #[derive(Debug, Deserialize)]
13 pub struct TargetCfgConfig
{
14 pub runner
: OptValue
<PathAndArgs
>,
15 pub rustflags
: OptValue
<StringList
>,
16 // This is here just to ignore fields from normal `TargetConfig` because
17 // all `[target]` tables are getting deserialized, whether they start with
20 pub other
: BTreeMap
<String
, toml
::Value
>,
23 /// Config definition of a `[target]` table or `[host]`.
24 #[derive(Debug, Clone)]
25 pub struct TargetConfig
{
26 /// Process to run as a wrapper for `cargo run`, `test`, and `bench` commands.
27 pub runner
: OptValue
<PathAndArgs
>,
28 /// Additional rustc flags to pass.
29 pub rustflags
: OptValue
<StringList
>,
30 /// The path of the linker for this target.
31 pub linker
: OptValue
<ConfigRelativePath
>,
32 /// Build script override for the given library name.
34 /// Any package with a `links` value for the given library name will skip
35 /// running its build script and instead use the given output from the
37 pub links_overrides
: BTreeMap
<String
, BuildOutput
>,
40 /// Loads all of the `target.'cfg()'` tables.
41 pub(super) fn load_target_cfgs(config
: &Config
) -> CargoResult
<Vec
<(String
, TargetCfgConfig
)>> {
42 // Load all [target] tables, filter out the cfg() entries.
43 let mut result
= Vec
::new();
44 // Use a BTreeMap so the keys are sorted. This is important for
45 // deterministic ordering of rustflags, which affects fingerprinting and
46 // rebuilds. We may perhaps one day wish to ensure a deterministic
47 // ordering via the order keys were defined in files perhaps.
48 let target
: BTreeMap
<String
, TargetCfgConfig
> = config
.get("target")?
;
49 log
::debug
!("Got all targets {:#?}", target
);
50 for (key
, cfg
) in target
{
51 if key
.starts_with("cfg(") {
52 // Unfortunately this is not able to display the location of the
53 // unused key. Using config::Value<toml::Value> doesn't work. One
54 // solution might be to create a special "Any" type, but I think
55 // that will be quite difficult with the current design.
56 for other_key
in cfg
.other
.keys() {
57 config
.shell().warn(format
!(
58 "unused key `{}` in [target] config table `{}`",
62 result
.push((key
, cfg
));
68 /// Returns true if the `[target]` table should be applied to host targets.
69 pub(super) fn get_target_applies_to_host(config
: &Config
) -> CargoResult
<bool
> {
70 if config
.cli_unstable().target_applies_to_host
{
71 if let Ok(target_applies_to_host
) = config
.get
::<bool
>("target-applies-to-host") {
72 Ok(target_applies_to_host
)
74 Ok(!config
.cli_unstable().host_config
)
76 } else if config
.cli_unstable().host_config
{
78 "the -Zhost-config flag requires the -Ztarget-applies-to-host flag to be set"
85 /// Loads a single `[host]` table for the given triple.
86 pub(super) fn load_host_triple(config
: &Config
, triple
: &str) -> CargoResult
<TargetConfig
> {
87 if config
.cli_unstable().host_config
{
88 let host_triple_prefix
= format
!("host.{}", triple
);
89 let host_triple_key
= ConfigKey
::from_str(&host_triple_prefix
);
90 let host_prefix
= match config
.get_cv(&host_triple_key
)?
{
91 Some(_
) => host_triple_prefix
,
92 None
=> "host".to_string(),
94 load_config_table(config
, &host_prefix
)
100 links_overrides
: BTreeMap
::new(),
105 /// Loads a single `[target]` table for the given triple.
106 pub(super) fn load_target_triple(config
: &Config
, triple
: &str) -> CargoResult
<TargetConfig
> {
107 load_config_table(config
, &format
!("target.{}", triple
))
110 /// Loads a single table for the given prefix.
111 fn load_config_table(config
: &Config
, prefix
: &str) -> CargoResult
<TargetConfig
> {
112 // This needs to get each field individually because it cannot fetch the
113 // struct all at once due to `links_overrides`. Can't use `serde(flatten)`
114 // because it causes serde to use `deserialize_map` which means the config
115 // deserializer does not know which keys to deserialize, which means
116 // environment variables would not work.
117 let runner
: OptValue
<PathAndArgs
> = config
.get(&format
!("{}.runner", prefix
))?
;
118 let rustflags
: OptValue
<StringList
> = config
.get(&format
!("{}.rustflags", prefix
))?
;
119 let linker
: OptValue
<ConfigRelativePath
> = config
.get(&format
!("{}.linker", prefix
))?
;
120 // Links do not support environment variables.
121 let target_key
= ConfigKey
::from_str(prefix
);
122 let links_overrides
= match config
.get_table(&target_key
)?
{
123 Some(links
) => parse_links_overrides(&target_key
, links
.val
, config
)?
,
124 None
=> BTreeMap
::new(),
134 fn parse_links_overrides(
135 target_key
: &ConfigKey
,
136 links
: HashMap
<String
, CV
>,
138 ) -> CargoResult
<BTreeMap
<String
, BuildOutput
>> {
139 let mut links_overrides
= BTreeMap
::new();
140 let extra_check_cfg
= match config
.cli_unstable().check_cfg
{
141 Some((_
, _
, _
, output
)) => output
,
145 for (lib_name
, value
) in links
{
146 // Skip these keys, it shares the namespace with `TargetConfig`.
147 match lib_name
.as_str() {
148 // `ar` is a historical thing.
149 "ar" | "linker" | "runner" | "rustflags" => continue,
152 let mut output
= BuildOutput
::default();
153 let table
= value
.table(&format
!("{}.{}", target_key
, lib_name
))?
.0;
154 // We require deterministic order of evaluation, so we must sort the pairs by key first.
155 let mut pairs
= Vec
::new();
156 for (k
, value
) in table
{
157 pairs
.push((k
, value
));
159 pairs
.sort_by_key(|p
| p
.0);
160 for (key
, value
) in pairs
{
163 let flags
= value
.string(key
)?
;
164 let whence
= format
!("target config `{}.{}` (in {})", target_key
, key
, flags
.1);
165 let (paths
, links
) = BuildOutput
::parse_rustc_flags(flags
.0, &whence
)?
;
166 output
.library_paths
.extend(paths
);
167 output
.library_links
.extend(links
);
169 "rustc-link-lib" => {
170 let list
= value
.list(key
)?
;
173 .extend(list
.iter().map(|v
| v
.0.clone()));
175 "rustc-link-search" => {
176 let list
= value
.list(key
)?
;
179 .extend(list
.iter().map(|v
| PathBuf
::from(&v
.0)));
181 "rustc-link-arg-cdylib" | "rustc-cdylib-link-arg" => {
182 let args
= extra_link_args(LinkType
::Cdylib
, key
, value
)?
;
183 output
.linker_args
.extend(args
);
185 "rustc-link-arg-bins" => {
186 let args
= extra_link_args(LinkType
::Bin
, key
, value
)?
;
187 output
.linker_args
.extend(args
);
189 "rustc-link-arg" => {
190 let args
= extra_link_args(LinkType
::All
, key
, value
)?
;
191 output
.linker_args
.extend(args
);
193 "rustc-link-arg-tests" => {
194 let args
= extra_link_args(LinkType
::Test
, key
, value
)?
;
195 output
.linker_args
.extend(args
);
197 "rustc-link-arg-benches" => {
198 let args
= extra_link_args(LinkType
::Bench
, key
, value
)?
;
199 output
.linker_args
.extend(args
);
201 "rustc-link-arg-examples" => {
202 let args
= extra_link_args(LinkType
::Example
, key
, value
)?
;
203 output
.linker_args
.extend(args
);
206 let list
= value
.list(key
)?
;
207 output
.cfgs
.extend(list
.iter().map(|v
| v
.0.clone()));
209 "rustc-check-cfg" => {
211 let list
= value
.list(key
)?
;
212 output
.check_cfgs
.extend(list
.iter().map(|v
| v
.0.clone()));
214 config
.shell().warn(format
!(
215 "target config `{}.{}` requires -Zcheck-cfg=output flag",
221 for (name
, val
) in value
.table(key
)?
.0 {
222 let val
= val
.string(name
)?
.0;
223 output
.env
.push((name
.clone(), val
.to_string()));
226 "warning" | "rerun-if-changed" | "rerun-if-env-changed" => {
227 anyhow
::bail
!("`{}` is not supported in build script overrides", key
);
230 let val
= value
.string(key
)?
.0;
231 output
.metadata
.push((key
.clone(), val
.to_string()));
235 links_overrides
.insert(lib_name
, output
);
240 fn extra_link_args
<'a
>(
244 ) -> CargoResult
<impl Iterator
<Item
= (LinkType
, String
)> + 'a
> {
245 let args
= value
.list(key
)?
;
246 Ok(args
.iter().map(move |v
| (link_type
.clone(), v
.0.clone())))