From 0c5f348bc2b62a058fa7c7176b80ea3367ef50b4 Mon Sep 17 00:00:00 2001 From: hi-rustin Date: Wed, 17 Nov 2021 20:34:44 +0800 Subject: [PATCH 1/3] Add crate type flag to rustc command Signed-off-by: hi-rustin --- src/bin/cargo/commands/rustc.rs | 20 +++++++++++++-- src/cargo/core/compiler/build_context/mod.rs | 9 +++++++ src/cargo/core/compiler/mod.rs | 10 ++++++-- src/cargo/ops/cargo_compile.rs | 26 ++++++++++++++++++++ src/cargo/ops/cargo_package.rs | 1 + src/cargo/util/command_prelude.rs | 1 + 6 files changed, 63 insertions(+), 4 deletions(-) diff --git a/src/bin/cargo/commands/rustc.rs b/src/bin/cargo/commands/rustc.rs index d5c6945b6f7..b79bdb9ddf3 100644 --- a/src/bin/cargo/commands/rustc.rs +++ b/src/bin/cargo/commands/rustc.rs @@ -3,6 +3,7 @@ use cargo::ops; use cargo::util::interning::InternedString; const PRINT_ARG_NAME: &str = "print"; +const CRATE_TYPE_ARG_NAME: &str = "crate-type"; pub fn cli() -> App { subcommand("rustc") @@ -35,6 +36,11 @@ pub fn cli() -> App { ) .value_name("INFO"), ) + .arg(multi_opt( + CRATE_TYPE_ARG_NAME, + "CRATE-TYPE", + "Rustc crate-types", + )) .arg_target_dir() .arg_manifest_path() .arg_message_format() @@ -75,8 +81,18 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { .cli_unstable() .fail_if_stable_opt(PRINT_ARG_NAME, 9357)?; ops::print(&ws, &compile_opts, opt_value)?; - } else { - ops::compile(&ws, &compile_opts)?; + return Ok(()); } + let crate_types = values(args, CRATE_TYPE_ARG_NAME); + compile_opts.target_rustc_crate_types = if crate_types.is_empty() { + None + } else { + config + .cli_unstable() + .fail_if_stable_opt(CRATE_TYPE_ARG_NAME, 10083)?; + Some(crate_types) + }; + ops::compile(&ws, &compile_opts)?; + Ok(()) } diff --git a/src/cargo/core/compiler/build_context/mod.rs b/src/cargo/core/compiler/build_context/mod.rs index 624a6e88ae6..9141314a9c7 100644 --- a/src/cargo/core/compiler/build_context/mod.rs +++ b/src/cargo/core/compiler/build_context/mod.rs @@ -33,6 +33,9 @@ pub struct BuildContext<'a, 'cfg> { /// Extra compiler args for either `rustc` or `rustdoc`. pub extra_compiler_args: HashMap>, + // Crate types for `rustc`. + pub target_rustc_crate_types: HashMap>, + /// Package downloader. /// /// This holds ownership of the `Package` objects. @@ -61,6 +64,7 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> { build_config: &'a BuildConfig, profiles: Profiles, extra_compiler_args: HashMap>, + target_rustc_crate_types: HashMap>, target_data: RustcTargetData<'cfg>, roots: Vec, unit_graph: UnitGraph, @@ -80,6 +84,7 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> { build_config, profiles, extra_compiler_args, + target_rustc_crate_types, target_data, roots, unit_graph, @@ -127,4 +132,8 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> { pub fn extra_args_for(&self, unit: &Unit) -> Option<&Vec> { self.extra_compiler_args.get(unit) } + + pub fn rustc_crate_types_args_for(&self, unit: &Unit) -> Option<&Vec> { + self.target_rustc_crate_types.get(unit) + } } diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index 884f1efc367..08a3261b860 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -862,8 +862,14 @@ fn build_base_args( add_allow_features(cx, cmd); if !test { - for crate_type in crate_types.iter() { - cmd.arg("--crate-type").arg(crate_type.as_str()); + if let Some(crate_types) = cx.bcx.rustc_crate_types_args_for(unit) { + for crate_type in crate_types.iter() { + cmd.arg("--crate-type").arg(crate_type); + } + } else { + for crate_type in crate_types.iter() { + cmd.arg("--crate-type").arg(crate_type.as_str()); + } } } diff --git a/src/cargo/ops/cargo_compile.rs b/src/cargo/ops/cargo_compile.rs index 392cef74085..56c21d30d70 100644 --- a/src/cargo/ops/cargo_compile.rs +++ b/src/cargo/ops/cargo_compile.rs @@ -71,6 +71,7 @@ pub struct CompileOptions { /// The specified target will be compiled with all the available arguments, /// note that this only accounts for the *final* invocation of rustc pub target_rustc_args: Option>, + pub target_rustc_crate_types: Option>, /// Extra arguments passed to all selected targets for rustdoc. pub local_rustdoc_args: Option>, /// Whether the `--document-private-items` flags was specified and should @@ -92,6 +93,7 @@ impl<'a> CompileOptions { }, target_rustdoc_args: None, target_rustc_args: None, + target_rustc_crate_types: None, local_rustdoc_args: None, rustdoc_document_private_items: false, honor_rust_version: true, @@ -332,6 +334,7 @@ pub fn create_bcx<'a, 'cfg>( ref filter, ref target_rustdoc_args, ref target_rustc_args, + ref target_rustc_crate_types, ref local_rustdoc_args, rustdoc_document_private_items, honor_rust_version, @@ -644,6 +647,28 @@ pub fn create_bcx<'a, 'cfg>( } } + let mut crate_types = HashMap::new(); + if let Some(args) = target_rustc_crate_types { + if units.len() != 1 { + anyhow::bail!( + "crate types to rustc can only be passed to one \ + target, consider filtering\nthe package by passing, \ + e.g., `--lib` to specify a single target" + ); + } + match units[0].target.kind() { + TargetKind::Lib(_) | TargetKind::ExampleLib(_) => { + crate_types.insert(units[0].clone(), args.clone()); + } + _ => { + anyhow::bail!( + "crate types can only be specified for libraries and examples. \ + Binaries, tests, and benchmarks are always the `bin` crate type" + ); + } + } + } + if honor_rust_version { // Remove any pre-release identifiers for easier comparison let current_version = &target_data.rustc.version; @@ -680,6 +705,7 @@ pub fn create_bcx<'a, 'cfg>( build_config, profiles, extra_compiler_args, + crate_types, target_data, units, unit_graph, diff --git a/src/cargo/ops/cargo_package.rs b/src/cargo/ops/cargo_package.rs index 48477ea25e0..ed264079bec 100644 --- a/src/cargo/ops/cargo_package.rs +++ b/src/cargo/ops/cargo_package.rs @@ -763,6 +763,7 @@ fn run_verify( }, target_rustdoc_args: None, target_rustc_args: rustc_args, + target_rustc_crate_types: None, local_rustdoc_args: None, rustdoc_document_private_items: false, honor_rust_version: true, diff --git a/src/cargo/util/command_prelude.rs b/src/cargo/util/command_prelude.rs index 7389ec56e39..066e900ad46 100644 --- a/src/cargo/util/command_prelude.rs +++ b/src/cargo/util/command_prelude.rs @@ -542,6 +542,7 @@ pub trait ArgMatchesExt { ), target_rustdoc_args: None, target_rustc_args: None, + target_rustc_crate_types: None, local_rustdoc_args: None, rustdoc_document_private_items: false, honor_rust_version: !self._is_present("ignore-rust-version"), From 660ce6bba45b8b9b495fd22e4dedcdb637a86d34 Mon Sep 17 00:00:00 2001 From: hi-rustin Date: Thu, 18 Nov 2021 23:57:42 +0800 Subject: [PATCH 2/3] Add tests Signed-off-by: hi-rustin --- src/bin/cargo/commands/rustc.rs | 2 +- src/cargo/core/compiler/mod.rs | 21 +-- src/cargo/ops/cargo_compile.rs | 5 +- tests/testsuite/rustc.rs | 222 ++++++++++++++++++++++++++++++++ 4 files changed, 239 insertions(+), 11 deletions(-) diff --git a/src/bin/cargo/commands/rustc.rs b/src/bin/cargo/commands/rustc.rs index b79bdb9ddf3..54b4e205ab5 100644 --- a/src/bin/cargo/commands/rustc.rs +++ b/src/bin/cargo/commands/rustc.rs @@ -39,7 +39,7 @@ pub fn cli() -> App { .arg(multi_opt( CRATE_TYPE_ARG_NAME, "CRATE-TYPE", - "Rustc crate-types", + "Comma separated list of types of crates for the compiler to emit (unstable)", )) .arg_target_dir() .arg_manifest_path() diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index 08a3261b860..cb9b3c681ab 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -861,14 +861,19 @@ fn build_base_args( add_error_format_and_color(cx, cmd, cx.rmeta_required(unit)); add_allow_features(cx, cmd); + let mut contains_dy_lib = false; if !test { - if let Some(crate_types) = cx.bcx.rustc_crate_types_args_for(unit) { - for crate_type in crate_types.iter() { - cmd.arg("--crate-type").arg(crate_type); - } - } else { - for crate_type in crate_types.iter() { - cmd.arg("--crate-type").arg(crate_type.as_str()); + let mut crate_types = &crate_types + .iter() + .map(|t| t.as_str().to_string()) + .collect::>(); + if let Some(types) = cx.bcx.rustc_crate_types_args_for(unit) { + crate_types = types; + } + for crate_type in crate_types.iter() { + cmd.arg("--crate-type").arg(crate_type); + if crate_type == CrateType::Dylib.as_str() { + contains_dy_lib = true; } } } @@ -885,7 +890,7 @@ fn build_base_args( } let prefer_dynamic = (unit.target.for_host() && !unit.target.is_custom_build()) - || (crate_types.contains(&CrateType::Dylib) && !cx.is_primary_package(unit)); + || (contains_dy_lib && !cx.is_primary_package(unit)); if prefer_dynamic { cmd.arg("-C").arg("prefer-dynamic"); } diff --git a/src/cargo/ops/cargo_compile.rs b/src/cargo/ops/cargo_compile.rs index 56c21d30d70..81b43124a18 100644 --- a/src/cargo/ops/cargo_compile.rs +++ b/src/cargo/ops/cargo_compile.rs @@ -71,6 +71,7 @@ pub struct CompileOptions { /// The specified target will be compiled with all the available arguments, /// note that this only accounts for the *final* invocation of rustc pub target_rustc_args: Option>, + /// Crate types to be passed to rustc (single target only) pub target_rustc_crate_types: Option>, /// Extra arguments passed to all selected targets for rustdoc. pub local_rustdoc_args: Option>, @@ -653,7 +654,7 @@ pub fn create_bcx<'a, 'cfg>( anyhow::bail!( "crate types to rustc can only be passed to one \ target, consider filtering\nthe package by passing, \ - e.g., `--lib` to specify a single target" + e.g., `--lib` or `--example` to specify a single target" ); } match units[0].target.kind() { @@ -662,7 +663,7 @@ pub fn create_bcx<'a, 'cfg>( } _ => { anyhow::bail!( - "crate types can only be specified for libraries and examples. \ + "crate types can only be specified for libraries and example libraries.\n\ Binaries, tests, and benchmarks are always the `bin` crate type" ); } diff --git a/tests/testsuite/rustc.rs b/tests/testsuite/rustc.rs index 53b5c6fb19a..571e5392783 100644 --- a/tests/testsuite/rustc.rs +++ b/tests/testsuite/rustc.rs @@ -134,6 +134,228 @@ fn fails_with_args_to_all_binaries() { .run(); } +#[cargo_test] +fn fails_with_crate_type_and_without_unstable_options() { + let p = project().file("src/lib.rs", r#" "#).build(); + + p.cargo("rustc --crate-type lib") + .masquerade_as_nightly_cargo() + .with_status(101) + .with_stderr( + "[ERROR] the `crate-type` flag is unstable, pass `-Z unstable-options` to enable it +See https://github.com/rust-lang/cargo/issues/10083 for more information about the `crate-type` flag.", + ) + .run(); +} + +#[cargo_test] +fn fails_with_crate_type_to_multi_binaries() { + let p = project() + .file("src/bin/foo.rs", "fn main() {}") + .file("src/bin/bar.rs", "fn main() {}") + .file("src/bin/baz.rs", "fn main() {}") + .file("src/lib.rs", r#" "#) + .build(); + + p.cargo("rustc --crate-type lib -Zunstable-options") + .masquerade_as_nightly_cargo() + .with_status(101) + .with_stderr( + "[ERROR] crate types to rustc can only be passed to one target, consider filtering +the package by passing, e.g., `--lib` or `--example` to specify a single target", + ) + .run(); +} + +#[cargo_test] +fn fails_with_crate_type_to_multi_examples() { + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [[example]] + name = "ex1" + crate-type = ["rlib"] + [[example]] + name = "ex2" + crate-type = ["rlib"] + "#, + ) + .file("src/lib.rs", "") + .file("examples/ex1.rs", "") + .file("examples/ex2.rs", "") + .build(); + + p.cargo("rustc -v --example ex1 --example ex2 --crate-type lib,cdylib -Zunstable-options") + .masquerade_as_nightly_cargo() + .with_status(101) + .with_stderr( + "[ERROR] crate types to rustc can only be passed to one target, consider filtering +the package by passing, e.g., `--lib` or `--example` to specify a single target", + ) + .run(); +} + +#[cargo_test] +fn fails_with_crate_type_to_binary() { + let p = project().file("src/bin/foo.rs", "fn main() {}").build(); + + p.cargo("rustc --crate-type lib -Zunstable-options") + .masquerade_as_nightly_cargo() + .with_status(101) + .with_stderr( + "[ERROR] crate types can only be specified for libraries and example libraries. +Binaries, tests, and benchmarks are always the `bin` crate type", + ) + .run(); +} + +#[cargo_test] +fn build_with_crate_type_for_foo() { + let p = project() + .file("src/main.rs", "fn main() {}") + .file("src/lib.rs", r#" "#) + .build(); + + p.cargo("rustc -v --lib --crate-type lib -Zunstable-options") + .masquerade_as_nightly_cargo() + .with_stderr( + "\ +[COMPILING] foo v0.0.1 ([CWD]) +[RUNNING] `rustc --crate-name foo src/lib.rs [..]--crate-type lib [..] +[FINISHED] dev [unoptimized + debuginfo] target(s) in [..] +", + ) + .run(); +} + +#[cargo_test] +fn build_with_crate_types_for_foo() { + let p = project() + .file("src/main.rs", "fn main() {}") + .file("src/lib.rs", r#" "#) + .build(); + + p.cargo("rustc -v --lib --crate-type lib,cdylib -Zunstable-options") + .masquerade_as_nightly_cargo() + .with_stderr( + "\ +[COMPILING] foo v0.0.1 ([CWD]) +[RUNNING] `rustc --crate-name foo src/lib.rs [..]--crate-type lib,cdylib [..] +[FINISHED] dev [unoptimized + debuginfo] target(s) in [..] +", + ) + .run(); +} + +#[cargo_test] +fn build_with_crate_type_to_example() { + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [[example]] + name = "ex" + crate-type = ["rlib"] + "#, + ) + .file("src/lib.rs", "") + .file("examples/ex.rs", "") + .build(); + + p.cargo("rustc -v --example ex --crate-type cdylib -Zunstable-options") + .masquerade_as_nightly_cargo() + .with_stderr( + "\ +[COMPILING] foo v0.0.1 ([CWD]) +[RUNNING] `rustc --crate-name foo src/lib.rs [..]--crate-type lib [..] +[RUNNING] `rustc --crate-name ex examples/ex.rs [..]--crate-type cdylib [..] +[FINISHED] dev [unoptimized + debuginfo] target(s) in [..] +", + ) + .run(); +} + +#[cargo_test] +fn build_with_crate_types_to_example() { + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [[example]] + name = "ex" + crate-type = ["rlib"] + "#, + ) + .file("src/lib.rs", "") + .file("examples/ex.rs", "") + .build(); + + p.cargo("rustc -v --example ex --crate-type lib,cdylib -Zunstable-options") + .masquerade_as_nightly_cargo() + .with_stderr( + "\ +[COMPILING] foo v0.0.1 ([CWD]) +[RUNNING] `rustc --crate-name foo src/lib.rs [..]--crate-type lib [..] +[RUNNING] `rustc --crate-name ex examples/ex.rs [..]--crate-type lib,cdylib [..] +[FINISHED] dev [unoptimized + debuginfo] target(s) in [..] +", + ) + .run(); +} + +#[cargo_test] +fn build_with_crate_types_to_one_of_multi_examples() { + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [[example]] + name = "ex1" + crate-type = ["rlib"] + [[example]] + name = "ex2" + crate-type = ["rlib"] + "#, + ) + .file("src/lib.rs", "") + .file("examples/ex1.rs", "") + .file("examples/ex2.rs", "") + .build(); + + p.cargo("rustc -v --example ex1 --crate-type lib,cdylib -Zunstable-options") + .masquerade_as_nightly_cargo() + .with_stderr( + "\ +[COMPILING] foo v0.0.1 ([CWD]) +[RUNNING] `rustc --crate-name foo src/lib.rs [..]--crate-type lib [..] +[RUNNING] `rustc --crate-name ex1 examples/ex1.rs [..]--crate-type lib,cdylib [..] +[FINISHED] dev [unoptimized + debuginfo] target(s) in [..] +", + ) + .run(); +} + #[cargo_test] fn build_with_args_to_one_of_multiple_tests() { let p = project() From 137f9bc3d1fc2fb10bcd207cd4938ede4d45d50c Mon Sep 17 00:00:00 2001 From: hi-rustin Date: Tue, 23 Nov 2021 23:21:39 +0800 Subject: [PATCH 3/3] Add crate-type unstable doc Signed-off-by: hi-rustin --- src/doc/src/reference/unstable.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/doc/src/reference/unstable.md b/src/doc/src/reference/unstable.md index a5b2077b6b6..6b254fd3297 100644 --- a/src/doc/src/reference/unstable.md +++ b/src/doc/src/reference/unstable.md @@ -83,6 +83,7 @@ Each new feature described below should explain how to use it. * [build-std-features](#build-std-features) — Sets features to use with the standard library. * [binary-dep-depinfo](#binary-dep-depinfo) — Causes the dep-info file to track binary dependencies. * [panic-abort-tests](#panic-abort-tests) — Allows running tests with the "abort" panic strategy. + * [crate-type](#crate-type) - Supports passing crate types to the compiler. * rustdoc * [`doctest-in-workspace`](#doctest-in-workspace) — Fixes workspace-relative paths when running doctests. * [rustdoc-map](#rustdoc-map) — Provides mappings for documentation to link to external sites like [docs.rs](https://docs.rs/). @@ -555,6 +556,23 @@ like to stabilize it somehow! [rust-lang/rust#64158]: https://github.com/rust-lang/rust/pull/64158 +### crate-type +* Tracking Issue: [#10083](https://github.com/rust-lang/cargo/issues/10083) +* RFC: [#3180](https://github.com/rust-lang/rfcs/pull/3180) +* Original Pull Request: [#10093](https://github.com/rust-lang/cargo/pull/10093) + +`cargo rustc --crate-type=lib,cdylib` forwards the `--crate-type` flag to `rustc`. +This runs `rustc` with the corresponding +[`--crate-type`](https://doc.rust-lang.org/rustc/command-line-arguments.html#--crate-type-a-list-of-types-of-crates-for-the-compiler-to-emit) +flag, and compiling. + +When using it, it requires the `-Z unstable-options` +command-line option: + +```console +cargo rustc --crate-type lib,cdylib -Z unstable-options +``` + ### config-cli * Tracking Issue: [#7722](https://github.com/rust-lang/cargo/issues/7722)