Skip to content

Commit 4ae4aad

Browse files
committed
Auto merge of #9002 - volks73:feature-rustc-cfg-argument, r=alexcrichton
Add --cfg and --rustc-cfg flags to output compiler configuration This PR is my attempt to address #8923. I have added the `--cfg` flag to the `cargo rustc` subcommand and the `--rustc-cfg` flag to the `cargo build`, `cargo check`, `cargo test`, and `cargo bench` subcommands, respectively. Both versions of the flag, `--cfg` and `--rustc-cfg`, do the same thing, but I thought it looked weird for the `cargo rustc` subcommand to be `cargo rustc --rustc-cfg`. The following example invocations are possible, once stabilized: - `cargo rustc --cfg` - `cargo build --rustc-cfg` - `cargo check --rustc-cfg` - `cargo test --rustc-cfg` - `cargo bench --rustc-cfg` In each case, compilation is aborted and only compiler configuration is emitted. All of the context creation and configuration is still executed, but execution of the compilation job is aborted. Similar to the `--unit-graph` implementation, the `--cfg/--rustc-cfg` flag is hidden, marked as a "unstable", and requires the `-Z unstable-options` flag at the moment. A complete example invocation with this PR would be: ```bash $ cargo +nightly rustc -Z unstable-options --cfg ``` I am open to alternatives for the flag name. I have thought of `--compiler-cfg`, `--compile-cfg`, and `--target-cfg`, but I went with `--rustc-cfg` because it is the Rust compiler (rustc) configuration (cfg). The `--target-cfg` could be confusing because there are Cargo targets and Compiler targets. A lone `--cfg` for the build, check, test, and bench subcommands would also be ambiguous and configuration that is being displayed. Originally, I was only going to add the `--cfg` flag to the `cargo rustc` subcommand, but build, check, test, and bench all have the `--unit-graph` flag, and I used that flag's implementation and existence as a template for this implementation. I am not opposed to having just the `--cfg` flag for the `cargo rustc` subcommand as originally proposed in #8923. I discovered during my initial investigation to implement the feature and familiarization with the Cargo codebase, that as part of the build context creation and compilation process, Cargo internally calls the `rustc --print cfg` command for all targets and stores the output in the `RustcTargetData` type. It does this for the host and any explicitly defined targets for cross-compilation. Compilation features, such as `+crt-static`, added to the compilation process through Cargo environment variables or TOML configuration directives are added to the internal `rustc --print cfg` command call. So, the `--cfg/--rustc-cfg` just emits the contents of the `RustcTagetData` type as JSON. There is no need to call the `rustc --print cfg` command again. The implementation then becomes nearly identical to the `--unit-graph` implementation. The output is only in JSON, similar to the `--unit-graph` feature, instead of the key-value and name style of the `rustc --print cfg` output because it easily resolves issues related to multi-targets, explicit target (`--target <TRIPLE>`) versus host configurations, and cross compilation. Subcommands and other projects can parse the JSON to recreate the key-value and name style if desired based on a specific target or the host. Here is an example of the JSON output (formatted for humans, the actual output is condensed), which is also available as a comment in the `cargo::core::compiler::rustc_cfg` module: ```javascript { "version": 1, "host": { "names": ["windows", "debug_assertions"], "arch":"x86_64", "endian":"little", "env":"msvc", "family":"windows", "features":["fxsr","sse","sse2"], "os":"windows", "pointer_width":"64", "vendor":"pc" }, "targets": { "x86_64-unknown-linux-gnu": { "names": ["debug_assertions", "unix"], "arch":"x86_64", "endian":"little", "env":"gnu", "family":"unix", "features": ["fxsr","sse","sse2"], "os":"linux", "pointer_width":"64", "vendor":"unknown" }, "i686-pc-windows-msvc": { "names": ["windows", "debug_assertions"], "arch":"x86", "endian":"little", "env":"msvc", "family":"windows", "features":["fxsr","sse","sse2"], "os":"windows", "pointer_width":"32", "vendor":"pc" } } } ``` I decided to remove the "target_" prefix from the relevant configurations to reduce "noise" in the output. Again, I am open to alternatives or suggestions on the JSON format.
2 parents 6243e8e + 2a5355f commit 4ae4aad

File tree

5 files changed

+152
-5
lines changed

5 files changed

+152
-5
lines changed

src/bin/cargo/commands/rustc.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ use crate::command_prelude::*;
22

33
use cargo::ops;
44

5+
const PRINT_ARG_NAME: &str = "print";
6+
57
pub fn cli() -> App {
68
subcommand("rustc")
79
.setting(AppSettings::TrailingVarArg)
@@ -26,6 +28,13 @@ pub fn cli() -> App {
2628
.arg_profile("Build artifacts with the specified profile")
2729
.arg_features()
2830
.arg_target_triple("Target triple which compiles will be for")
31+
.arg(
32+
opt(
33+
PRINT_ARG_NAME,
34+
"Output compiler information without compiling",
35+
)
36+
.value_name("INFO"),
37+
)
2938
.arg_target_dir()
3039
.arg_manifest_path()
3140
.arg_message_format()
@@ -62,6 +71,13 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
6271
} else {
6372
Some(target_args)
6473
};
65-
ops::compile(&ws, &compile_opts)?;
74+
if let Some(opt_value) = args.value_of(PRINT_ARG_NAME) {
75+
config
76+
.cli_unstable()
77+
.fail_if_stable_opt(PRINT_ARG_NAME, 8923)?;
78+
ops::print(&ws, &compile_opts, opt_value)?;
79+
} else {
80+
ops::compile(&ws, &compile_opts)?;
81+
}
6682
Ok(())
6783
}

src/cargo/ops/cargo_compile.rs

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ use std::collections::{BTreeSet, HashMap, HashSet};
2626
use std::hash::{Hash, Hasher};
2727
use std::sync::Arc;
2828

29-
use crate::core::compiler::standard_lib;
3029
use crate::core::compiler::unit_dependencies::build_unit_dependencies;
3130
use crate::core::compiler::unit_graph::{self, UnitDep, UnitGraph};
31+
use crate::core::compiler::{standard_lib, TargetInfo};
3232
use crate::core::compiler::{BuildConfig, BuildContext, Compilation, Context};
3333
use crate::core::compiler::{CompileKind, CompileMode, CompileTarget, RustcTargetData, Unit};
3434
use crate::core::compiler::{DefaultExecutor, Executor, UnitInterner};
@@ -37,6 +37,7 @@ use crate::core::resolver::features::{self, FeaturesFor, RequestedFeatures};
3737
use crate::core::resolver::{HasDevUnits, Resolve, ResolveOpts};
3838
use crate::core::{FeatureValue, Package, PackageSet, Shell, Summary, Target};
3939
use crate::core::{PackageId, PackageIdSpec, SourceId, TargetKind, Workspace};
40+
use crate::drop_println;
4041
use crate::ops;
4142
use crate::ops::resolve::WorkspaceResolve;
4243
use crate::util::config::Config;
@@ -289,12 +290,42 @@ pub fn compile_ws<'a>(
289290
unit_graph::emit_serialized_unit_graph(&bcx.roots, &bcx.unit_graph)?;
290291
return Compilation::new(&bcx);
291292
}
292-
293293
let _p = profile::start("compiling");
294294
let cx = Context::new(&bcx)?;
295295
cx.compile(exec)
296296
}
297297

298+
pub fn print<'a>(
299+
ws: &Workspace<'a>,
300+
options: &CompileOptions,
301+
print_opt_value: &str,
302+
) -> CargoResult<()> {
303+
let CompileOptions {
304+
ref build_config,
305+
ref target_rustc_args,
306+
..
307+
} = *options;
308+
let config = ws.config();
309+
let rustc = config.load_global_rustc(Some(ws))?;
310+
for (index, kind) in build_config.requested_kinds.iter().enumerate() {
311+
if index != 0 {
312+
drop_println!(config);
313+
}
314+
let target_info = TargetInfo::new(config, &build_config.requested_kinds, &rustc, *kind)?;
315+
let mut process = rustc.process();
316+
process.args(&target_info.rustflags);
317+
if let Some(args) = target_rustc_args {
318+
process.args(args);
319+
}
320+
if let CompileKind::Target(t) = kind {
321+
process.arg("--target").arg(t.short_name());
322+
}
323+
process.arg("--print").arg(print_opt_value);
324+
process.exec()?;
325+
}
326+
Ok(())
327+
}
328+
298329
pub fn create_bcx<'a, 'cfg>(
299330
ws: &'a Workspace<'cfg>,
300331
options: &'a CompileOptions,

src/cargo/ops/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
pub use self::cargo_clean::{clean, CleanOptions};
22
pub use self::cargo_compile::{
3-
compile, compile_with_exec, compile_ws, create_bcx, resolve_all_features, CompileOptions,
3+
compile, compile_with_exec, compile_ws, create_bcx, print, resolve_all_features, CompileOptions,
44
};
55
pub use self::cargo_compile::{CompileFilter, FilterRule, LibRule, Packages};
66
pub use self::cargo_doc::{doc, DocOptions};

src/cargo/util/command_prelude.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,6 @@ pub trait ArgMatchesExt {
472472
.cli_unstable()
473473
.fail_if_stable_opt("--unit-graph", 8002)?;
474474
}
475-
476475
let opts = CompileOptions {
477476
build_config,
478477
features: self._values_of("features"),

tests/testsuite/rustc.rs

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,3 +458,104 @@ fn rustc_test_with_implicit_bin() {
458458
)
459459
.run();
460460
}
461+
462+
#[cargo_test]
463+
fn rustc_with_print_cfg_single_target() {
464+
let p = project()
465+
.file("Cargo.toml", &basic_bin_manifest("foo"))
466+
.file("src/main.rs", r#"fn main() {} "#)
467+
.build();
468+
469+
p.cargo("rustc -Z unstable-options --target x86_64-pc-windows-msvc --print cfg")
470+
.masquerade_as_nightly_cargo()
471+
.with_stdout_contains("debug_assertions")
472+
.with_stdout_contains("target_arch=\"x86_64\"")
473+
.with_stdout_contains("target_endian=\"little\"")
474+
.with_stdout_contains("target_env=\"msvc\"")
475+
.with_stdout_contains("target_family=\"windows\"")
476+
.with_stdout_contains("target_os=\"windows\"")
477+
.with_stdout_contains("target_pointer_width=\"64\"")
478+
.with_stdout_contains("target_vendor=\"pc\"")
479+
.with_stdout_contains("windows")
480+
.run();
481+
}
482+
483+
#[cargo_test]
484+
fn rustc_with_print_cfg_multiple_targets() {
485+
let p = project()
486+
.file("Cargo.toml", &basic_bin_manifest("foo"))
487+
.file("src/main.rs", r#"fn main() {} "#)
488+
.build();
489+
490+
p.cargo("rustc -Z unstable-options -Z multitarget --target x86_64-pc-windows-msvc --target i686-unknown-linux-gnu --print cfg")
491+
.masquerade_as_nightly_cargo()
492+
.with_stdout_contains("debug_assertions")
493+
.with_stdout_contains("target_arch=\"x86_64\"")
494+
.with_stdout_contains("target_endian=\"little\"")
495+
.with_stdout_contains("target_env=\"msvc\"")
496+
.with_stdout_contains("target_family=\"windows\"")
497+
.with_stdout_contains("target_os=\"windows\"")
498+
.with_stdout_contains("target_pointer_width=\"64\"")
499+
.with_stdout_contains("target_vendor=\"pc\"")
500+
.with_stdout_contains("windows")
501+
.with_stdout_contains("target_env=\"gnu\"")
502+
.with_stdout_contains("target_family=\"unix\"")
503+
.with_stdout_contains("target_pointer_width=\"32\"")
504+
.with_stdout_contains("target_vendor=\"unknown\"")
505+
.with_stdout_contains("target_os=\"linux\"")
506+
.with_stdout_contains("unix")
507+
.run();
508+
}
509+
510+
#[cargo_test]
511+
fn rustc_with_print_cfg_rustflags_env_var() {
512+
let p = project()
513+
.file("Cargo.toml", &basic_bin_manifest("foo"))
514+
.file("src/main.rs", r#"fn main() {} "#)
515+
.build();
516+
517+
p.cargo("rustc -Z unstable-options --target x86_64-pc-windows-msvc --print cfg")
518+
.masquerade_as_nightly_cargo()
519+
.env("RUSTFLAGS", "-C target-feature=+crt-static")
520+
.with_stdout_contains("debug_assertions")
521+
.with_stdout_contains("target_arch=\"x86_64\"")
522+
.with_stdout_contains("target_endian=\"little\"")
523+
.with_stdout_contains("target_env=\"msvc\"")
524+
.with_stdout_contains("target_family=\"windows\"")
525+
.with_stdout_contains("target_feature=\"crt-static\"")
526+
.with_stdout_contains("target_os=\"windows\"")
527+
.with_stdout_contains("target_pointer_width=\"64\"")
528+
.with_stdout_contains("target_vendor=\"pc\"")
529+
.with_stdout_contains("windows")
530+
.run();
531+
}
532+
533+
#[cargo_test]
534+
fn rustc_with_print_cfg_config_toml() {
535+
let p = project()
536+
.file("Cargo.toml", &basic_bin_manifest("foo"))
537+
.file(
538+
".cargo/config.toml",
539+
r#"
540+
[target.x86_64-pc-windows-msvc]
541+
rustflags = ["-C", "target-feature=+crt-static"]
542+
"#,
543+
)
544+
.file("src/main.rs", r#"fn main() {} "#)
545+
.build();
546+
547+
p.cargo("rustc -Z unstable-options --target x86_64-pc-windows-msvc --print cfg")
548+
.masquerade_as_nightly_cargo()
549+
.env("RUSTFLAGS", "-C target-feature=+crt-static")
550+
.with_stdout_contains("debug_assertions")
551+
.with_stdout_contains("target_arch=\"x86_64\"")
552+
.with_stdout_contains("target_endian=\"little\"")
553+
.with_stdout_contains("target_env=\"msvc\"")
554+
.with_stdout_contains("target_family=\"windows\"")
555+
.with_stdout_contains("target_feature=\"crt-static\"")
556+
.with_stdout_contains("target_os=\"windows\"")
557+
.with_stdout_contains("target_pointer_width=\"64\"")
558+
.with_stdout_contains("target_vendor=\"pc\"")
559+
.with_stdout_contains("windows")
560+
.run();
561+
}

0 commit comments

Comments
 (0)