Skip to content

Commit

Permalink
Auto merge of #3854 - tee-too:fix-3499, r=alexcrichton
Browse files Browse the repository at this point in the history
Add `[target.'cfg(...)']` syntax for rustc(doc)flags in .cargo/config

Allow to use the Rust `cfg(...)` syntax to configure rust(doc)flags.
The flags are concatenated when a build matches several `cfg`, or
several `cfg` and a $triple.

Fix #3499.
  • Loading branch information
bors committed Apr 4, 2017
2 parents 305fa68 + e6e6f10 commit f5348cc
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 6 deletions.
40 changes: 35 additions & 5 deletions src/cargo/ops/cargo_rustc/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use std::sync::Arc;
use core::{Package, PackageId, PackageSet, Resolve, Target, Profile};
use core::{TargetKind, Profiles, Dependency, Workspace};
use core::dependency::Kind as DepKind;
use util::{self, CargoResult, ChainError, internal, Config, profile, Cfg, human};
use util::{self, CargoResult, ChainError, internal, Config, profile, Cfg, CfgExpr, human};

use super::TargetConfig;
use super::custom_build::{BuildState, BuildScripts};
Expand Down Expand Up @@ -178,6 +178,7 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
-> CargoResult<()> {
let rustflags = env_args(self.config,
&self.build_config,
&self.info(&kind),
kind,
"RUSTFLAGS")?;
let mut process = self.config.rustc()?.process();
Expand Down Expand Up @@ -872,22 +873,30 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
}

pub fn rustflags_args(&self, unit: &Unit) -> CargoResult<Vec<String>> {
env_args(self.config, &self.build_config, unit.kind, "RUSTFLAGS")
env_args(self.config, &self.build_config, self.info(&unit.kind), unit.kind, "RUSTFLAGS")
}

pub fn rustdocflags_args(&self, unit: &Unit) -> CargoResult<Vec<String>> {
env_args(self.config, &self.build_config, unit.kind, "RUSTDOCFLAGS")
env_args(self.config, &self.build_config, self.info(&unit.kind), unit.kind, "RUSTDOCFLAGS")
}

pub fn show_warnings(&self, pkg: &PackageId) -> bool {
pkg.source_id().is_path() || self.config.extra_verbose()
}

fn info(&self, kind: &Kind) -> &TargetInfo {
match *kind {
Kind::Host => &self.host_info,
Kind::Target => &self.target_info,
}
}
}

// Acquire extra flags to pass to the compiler from the
// RUSTFLAGS environment variable and similar config values
fn env_args(config: &Config,
build_config: &BuildConfig,
target_info: &TargetInfo,
kind: Kind,
name: &str) -> CargoResult<Vec<String>> {
// We *want* to apply RUSTFLAGS only to builds for the
Expand Down Expand Up @@ -928,13 +937,34 @@ fn env_args(config: &Config,
return Ok(args.collect());
}

let mut rustflags = Vec::new();

let name = name.chars().flat_map(|c| c.to_lowercase()).collect::<String>();
// Then the target.*.rustflags value
// Then the target.*.rustflags value...
let target = build_config.requested_target.as_ref().unwrap_or(&build_config.host_triple);
let key = format!("target.{}.{}", target, name);
if let Some(args) = config.get_list_or_split_string(&key)? {
let args = args.val.into_iter();
return Ok(args.collect());
rustflags.extend(args);
}
// ...including target.'cfg(...)'.rustflags
if let Some(ref target_cfg) = target_info.cfg {
if let Some(table) = config.get_table("target")? {
let cfgs = table.val.iter().map(|(t, _)| (CfgExpr::from_str(t), t))
.filter_map(|(c, n)| c.map(|c| (c, n)).ok())
.filter(|&(ref c, _)| c.matches(target_cfg));
for (_, n) in cfgs {
let key = format!("target.'{}'.{}", n, name);
if let Some(args) = config.get_list_or_split_string(&key)? {
let args = args.val.into_iter();
rustflags.extend(args);
}
}
}
}

if !rustflags.is_empty() {
return Ok(rustflags);
}

// Then the build.rustflags value
Expand Down
10 changes: 9 additions & 1 deletion src/doc/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ vcs = "none"

# For the following sections, $triple refers to any valid target triple, not the
# literal string "$triple", and it will apply whenever that target triple is
# being compiled to.
# being compiled to. 'cfg(...)' refers to the Rust-like `#[cfg]` syntax for
# conditional compilation.
[target]
# For Cargo builds which do not mention --target, this is the linker
# which is passed to rustc (via `-C linker=`). By default this flag is not
Expand All @@ -73,6 +74,13 @@ linker = ".."
# this value overrides build.rustflags when both are present
rustflags = ["..", ".."]

[target.'cfg(...)']
# Similar for the $triple configuration, but using the `cfg` syntax.
# If several `cfg` and $triple targets are candidates, then the rustflags
# are concatenated. The `cfg` syntax only applies to rustflags, and not to
# linker.
rustflags = ["..", ".."]

# Configuration keys related to the registry
[registry]
index = "..." # URL of the registry index (defaults to the central repository)
Expand Down
73 changes: 73 additions & 0 deletions tests/rustflags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -950,6 +950,79 @@ fn target_rustflags_precedence() {
execs().with_status(101));
}

#[test]
fn cfg_rustflags_normal_source() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.1"
"#)
.file("src/lib.rs", "")
.file("src/bin/a.rs", "fn main() {}")
.file("examples/b.rs", "fn main() {}")
.file("tests/c.rs", "#[test] fn f() { }")
.file("benches/d.rs", r#"
#![feature(test)]
extern crate test;
#[bench] fn run1(_ben: &mut test::Bencher) { }"#)
.file(".cargo/config", "
[target.'cfg(feature=\"feat\")']
rustflags = [\"-Z\", \"bogus\"]
");
p.build();

assert_that(p.cargo("build").arg("--features").arg("\"feat\"")
.arg("--lib"),
execs().with_status(101));
assert_that(p.cargo("build").arg("--features").arg("\"feat\"")
.arg("--bin=a"),
execs().with_status(101));
assert_that(p.cargo("build").arg("--features").arg("\"feat\"")
.arg("--example=b"),
execs().with_status(101));
assert_that(p.cargo("test").arg("--features").arg("\"feat\""),
execs().with_status(101));
assert_that(p.cargo("bench").arg("--features").arg("\"feat\""),
execs().with_status(101));
}

// target.'cfg(...)'.rustflags takes precedence over build.rustflags
#[test]
fn cfg_rustflags_precedence() {
let p = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.1"
"#)
.file("src/lib.rs", "")
.file(".cargo/config", "
[build]
rustflags = [\"--cfg\", \"foo\"]
[target.'cfg(feature = \"feat\"')]
rustflags = [\"-Z\", \"bogus\"]
");
p.build();

assert_that(p.cargo("build").arg("--features").arg("\"feat\"")
.arg("--lib"),
execs().with_status(101));
assert_that(p.cargo("build").arg("--features").arg("\"feat\"")
.arg("--bin=a"),
execs().with_status(101));
assert_that(p.cargo("build").arg("--features").arg("\"feat\"")
.arg("--example=b"),
execs().with_status(101));
assert_that(p.cargo("test").arg("--features").arg("\"feat\""),
execs().with_status(101));
assert_that(p.cargo("bench").arg("--features").arg("\"feat\""),
execs().with_status(101));
}



#[test]
fn target_rustflags_string_and_array_form1() {
let p1 = project("foo")
Expand Down

0 comments on commit f5348cc

Please sign in to comment.