From 2f686cfc6ebd4f8fc4096061e81af139d49b11c7 Mon Sep 17 00:00:00 2001 From: ridwanabdillahi <91507758+ridwanabdillahi@users.noreply.github.com> Date: Thu, 18 Nov 2021 13:31:06 -0800 Subject: [PATCH 01/13] Add support for specifying Natvis files in Cargo.toml and passing them through to rustc. --- src/cargo/core/compiler/mod.rs | 19 ++ src/cargo/core/features.rs | 3 + src/cargo/core/manifest.rs | 7 + src/cargo/util/toml/mod.rs | 18 ++ src/doc/src/reference/unstable.md | 27 ++ tests/testsuite/main.rs | 1 + tests/testsuite/natvis.rs | 453 ++++++++++++++++++++++++++++++ 7 files changed, 528 insertions(+) create mode 100644 tests/testsuite/natvis.rs diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index 884f1efc367..5f1794aa580 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -611,6 +611,7 @@ fn prepare_rustc( base.inherit_jobserver(&cx.jobserver); } build_base_args(cx, &mut base, unit, crate_types)?; + build_natvis(&mut base, unit)?; build_deps_args(&mut base, cx, unit)?; Ok(base) } @@ -1057,6 +1058,24 @@ fn lto_args(cx: &Context<'_, '_>, unit: &Unit) -> Vec { result } +fn build_natvis( + cmd: &mut ProcessBuilder, + unit: &Unit, +) -> CargoResult<()> { + if let Some(natvis) = &unit.pkg.manifest().natvis() { + unit.pkg.manifest().unstable_features().require(Feature::natvis())?; + cmd.arg("-Z").arg(&{ + let mut arg = OsString::from("natvis="); + arg.push(OsString::from(natvis.iter().map(|file| { + unit.pkg.root().join(file).display().to_string() + }).collect::>().join(","))); + arg + }); + } + + Ok(()) +} + fn build_deps_args( cmd: &mut ProcessBuilder, cx: &mut Context<'_, '_>, diff --git a/src/cargo/core/features.rs b/src/cargo/core/features.rs index a84ff390223..57ab28b6887 100644 --- a/src/cargo/core/features.rs +++ b/src/cargo/core/features.rs @@ -409,6 +409,9 @@ features! { // Allow specifying different binary name apart from the crate name (unstable, different_binary_name, "", "reference/unstable.html#different-binary-name"), + + // Allow specifying natvis files to embed in the PDB when using the MSVC Linker. + (unstable, natvis, "", "reference/unstable.html#natvis"), } pub struct Feature { diff --git a/src/cargo/core/manifest.rs b/src/cargo/core/manifest.rs index b0bc0576a7a..572bdd31447 100644 --- a/src/cargo/core/manifest.rs +++ b/src/cargo/core/manifest.rs @@ -32,6 +32,7 @@ pub enum EitherManifest { pub struct Manifest { summary: Summary, targets: Vec, + natvis: Option>, default_kind: Option, forced_kind: Option, links: Option, @@ -392,6 +393,7 @@ impl Manifest { original: Rc, metabuild: Option>, resolve_behavior: Option, + natvis: Option>, ) -> Manifest { Manifest { summary, @@ -417,6 +419,7 @@ impl Manifest { default_run, metabuild, resolve_behavior, + natvis } } @@ -485,6 +488,10 @@ impl Manifest { self.links.as_deref() } + pub fn natvis(&self) -> &Option> { + &self.natvis + } + pub fn workspace_config(&self) -> &WorkspaceConfig { &self.workspace } diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index e34b0809330..69cf21762ad 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -302,6 +302,7 @@ pub struct TomlManifest { replace: Option>, patch: Option>>, workspace: Option, + debug_visualizations: Option, badges: Option>>, } @@ -904,6 +905,16 @@ pub struct TomlWorkspace { metadata: Option, } +/// Represents the `debug-visualizations` section of a `Cargo.toml`. +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct TomlDebugVisualizations { + natvis: Option>, + + // Note that this field must come last due to the way toml serialization + // works which requires tables to be emitted after all values. + metadata: Option, +} + impl TomlProject { pub fn to_package_id(&self, source_id: SourceId) -> CargoResult { PackageId::new(self.name, self.version.clone(), source_id) @@ -1019,6 +1030,7 @@ impl TomlManifest { replace: None, patch: None, workspace: None, + debug_visualizations: self.debug_visualizations.clone(), badges: self.badges.clone(), cargo_features: self.cargo_features.clone(), }); @@ -1372,6 +1384,11 @@ impl TomlManifest { .transpose()? .map(CompileKind::Target); + let natvis = if let Some(debug_visualizations) = me.debug_visualizations.clone() { + debug_visualizations.natvis.clone() + } else { + None + }; let custom_metadata = project.metadata.clone(); let mut manifest = Manifest::new( summary, @@ -1396,6 +1413,7 @@ impl TomlManifest { Rc::clone(me), project.metabuild.clone().map(|sov| sov.0), resolve_behavior, + natvis, ); if project.license_file.is_some() && project.license.is_some() { manifest.warnings_mut().add_warning( diff --git a/src/doc/src/reference/unstable.md b/src/doc/src/reference/unstable.md index a5b2077b6b6..d48b2a483dd 100644 --- a/src/doc/src/reference/unstable.md +++ b/src/doc/src/reference/unstable.md @@ -89,6 +89,7 @@ Each new feature described below should explain how to use it. * `Cargo.toml` extensions * [Profile `strip` option](#profile-strip-option) — Forces the removal of debug information and symbols from executables. * [per-package-target](#per-package-target) — Sets the `--target` to use for each individual package. + * [natvis](#natvis) — Allows the specification of Natvis`(.natvis)` files to be embedded in a PDB when linking via the MSVC Linker. * Information and metadata * [Build-plan](#build-plan) — Emits JSON information on which commands will be run. * [timings](#timings) — Generates a report on how long individual dependencies took to run. @@ -949,6 +950,32 @@ In this example, the crate is always built for as a plugin for a main program that runs on the host (or provided on the command line) target. +### natvis +* Tracking Issue: [#0000](https://github.com/rust-lang/cargo/pull/0000) +* Original Pull Request: [#0000](https://github.com/rust-lang/cargo/pull/0000) +* Original Issue: [#0000](https://github.com/rust-lang/cargo/pull/0000) + +The `natvis` feature adds a new section and key to the manifest: +`[debug-visualizations]` and `debug-visualizations.natvis`. The `natvis` +key takes a list of `.natvis` files which will be linked into the PDB +generated if using the MSVC Linker. + +Example: + +```toml +cargo-features = ["natvis"] + +[package] +name = "foo" +version = "0.0.1" + +[debug-visualizations] +natvis = ["foo.natvis", "bar.natvis"] +``` + +In this example, the crate `foo` will embed `foo.natvis` and `bar.natvis` +into the PDB being generated when using the MSVC Linker. + ### credential-process * Tracking Issue: [#8933](https://github.com/rust-lang/cargo/issues/8933) * RFC: [#2730](https://github.com/rust-lang/rfcs/pull/2730) diff --git a/tests/testsuite/main.rs b/tests/testsuite/main.rs index 8c30bf929a8..ddd3ecf02fe 100644 --- a/tests/testsuite/main.rs +++ b/tests/testsuite/main.rs @@ -77,6 +77,7 @@ mod metabuild; mod metadata; mod minimal_versions; mod multitarget; +mod natvis; mod net_config; mod new; mod offline; diff --git a/tests/testsuite/natvis.rs b/tests/testsuite/natvis.rs new file mode 100644 index 00000000000..418e392a946 --- /dev/null +++ b/tests/testsuite/natvis.rs @@ -0,0 +1,453 @@ +//! Tests for natvis Cargo.toml syntax + +use cargo_test_support::project; +use cargo_test_support::registry::Package; + +#[cargo_test] +fn gated() { + let p = project() + .file( + "Cargo.toml", + r#" + [project] + name = "foo" + version = "0.0.1" + + [debug-visualizations] + natvis = ["foo.natvis"] + "#, + ) + .file("src/main.rs", "fn main() { assert!(true) }") + .build(); + + // Run cargo build. + p.cargo("build") + .masquerade_as_nightly_cargo() + .with_status(101) + .with_stderr_contains("[..]feature `natvis` is required") + .run(); +} + +#[cargo_test] +fn natvis_file_does_not_exist() { + let p = project() + .file( + "Cargo.toml", + r#" + cargo-features = ["natvis"] + + [project] + name = "foo" + version = "0.0.1" + + [debug-visualizations] + natvis = ["foo.natvis"] + "#, + ) + .file("src/main.rs", "fn main() { assert!(true) }") + .build(); + + let natvis_path = p.root().join("foo.natvis").display().to_string(); + let expected_msg = format!("[..]incorrect value `{}` for debugging option `natvis`[..]", natvis_path); + + // Run cargo build. + p.cargo("build") + .masquerade_as_nightly_cargo() + .with_status(101) + .with_stderr_contains(expected_msg) + .run(); +} + +#[cargo_test] +fn invalid_natvis_extension() { + let p = project() + .file( + "Cargo.toml", + r#" + cargo-features = ["natvis"] + + [project] + name = "foo" + version = "0.0.1" + + [debug-visualizations] + natvis = ["foo.rs"] + "#, + ) + .file("src/main.rs", "fn main() { assert!(true) }") + .build(); + + let natvis_path = p.root().join("foo.rs").display().to_string(); + let expected_msg = format!("[..]incorrect value `{}` for debugging option `natvis`[..]", natvis_path); + + // Run cargo build. + p.cargo("build") + .masquerade_as_nightly_cargo() + .with_status(101) + .with_stderr_contains(expected_msg) + .run(); +} + +#[cargo_test] +fn simple_test() { + let p = project() + .file( + "Cargo.toml", + r#" + cargo-features = ["natvis"] + + [project] + name = "foo" + version = "0.0.1" + + [debug-visualizations] + natvis = ["foo.natvis"] + "#, + ) + .file( + "src/main.rs", + r#" + fn main() { assert!(true) } + + pub struct Foo { + pub x: i32, + pub y: i32, + pub z: i32 + } + "#, + ).file( + "foo.natvis", + r#" + + + + x:{x}, y:{y}, z:{z} + + x + y + z + + + + "#, + ).build(); + + // Run cargo build. + p.cargo("build") + .masquerade_as_nightly_cargo() + .run(); +} + +#[cargo_test] +fn direct_dependency_with_natvis() { + let p = project() + .file( + "Cargo.toml", + r#" + [project] + name = "foo" + version = "0.0.1" + + [dependencies] + test_dependency = { path = "src/test_dependency" } + "#, + ) + .file( + "src/main.rs", + r#" + fn main() { assert!(true) } + "#, + ) + .file( + "src/test_dependency/src/lib.rs", + r#" + pub struct Foo { + pub x: i32, + pub y: i32, + pub z: i32 + } + "#) + .file( + "src/test_dependency/Cargo.toml", + r#" + cargo-features = ["natvis"] + + [project] + name = "test_dependency" + version = "0.0.1" + + [debug-visualizations] + natvis = ["test_dependency.natvis"] + "#, + ) + .file( + "src/test_dependency/test_dependency.natvis", + r#" + + + + x:{x}, y:{y}, z:{z} + + x + y + z + + + + "#, + ).build(); + + let natvis_path = p.root().join("src/test_dependency/test_dependency.natvis").display().to_string(); + + // Run cargo build. + p.cargo("build -v") + .masquerade_as_nightly_cargo() + .with_status(0) + .with_stderr_contains(format!("[..]-Z natvis={}[..]", natvis_path)) + .run(); +} + +#[cargo_test] +fn multiple_natvis_files() { + let p = project() + .file( + "Cargo.toml", + r#" + cargo-features = ["natvis"] + + [project] + name = "foo" + version = "0.0.1" + + [debug-visualizations] + natvis = ["foo.natvis", "bar.natvis"] + "#, + ) + .file( + "src/main.rs", + r#" + fn main() { assert!(true) } + + pub struct Foo { + pub x: i32, + pub y: i32, + pub z: i32 + } + + pub struct Bar { + pub x: i32, + pub y: i32, + pub z: i32 + } + "#, + ) + .file( + "foo.natvis", + r#" + + + + x:{x}, y:{y}, z:{z} + + x + y + z + + + + "#, + ) + .file( + "bar.natvis", + r#" + + + + x:{x}, y:{y}, z:{z} + + x + y + z + + + + "#, + ).build(); + + let foo_natvis_path = p.root().join("foo.natvis").display().to_string(); + let bar_natvis_path = p.root().join("bar.natvis").display().to_string(); + + // Run cargo build. + p.cargo("build -v") + .masquerade_as_nightly_cargo() + .with_status(0) + .with_stderr_contains(format!("[..]-Z natvis={},{}[..]", foo_natvis_path, bar_natvis_path)) + .run(); +} + +#[cargo_test] +fn indirect_dependency_with_natvis() { + let p = project() + .file( + "Cargo.toml", + r#" + cargo-features = ["natvis"] + + [project] + name = "foo" + version = "0.0.1" + + [debug-visualizations] + natvis = ["foo.natvis"] + + [dependencies] + test_dependency = { path = "src/test_dependency" } + "#, + ) + .file( + "src/main.rs", + r#" + fn main() { assert!(true) } + + pub struct Foo { + pub x: i32, + pub y: i32, + pub z: i32 + } + "#, + ) + .file( + "foo.natvis", + r#" + + + + x:{x}, y:{y}, z:{z} + + x + y + z + + + + "#, + ) + .file( + "src/test_dependency/Cargo.toml", + r#" + [project] + name = "test_dependency" + version = "0.0.1" + + [dependencies] + nested_dependency = { path = "src/nested_dependency" } + "#, + ) + .file("src/test_dependency/src/lib.rs",r#""#,) + .file( + "src/test_dependency/src/nested_dependency/Cargo.toml", + r#" + cargo-features = ["natvis"] + + [project] + name = "nested_dependency" + version = "0.0.1" + + [debug-visualizations] + natvis = ["nested_dependency.natvis"] + "#, + ) + .file( + "src/test_dependency/src/nested_dependency/src/lib.rs", + r#" + pub struct Bar { + pub x: i32, + pub y: i32, + pub z: i32 + } + "#, + ) + .file( + "src/test_dependency/src/nested_dependency/nested_dependency.natvis", + r#" + + + + x:{x}, y:{y}, z:{z} + + x + y + z + + + + "#, + ).build(); + + let foo_natvis_path = p.root().join("foo.natvis").display().to_string(); + let nested_dependency_natvis_path = p.root().join("src/test_dependency/src/nested_dependency/nested_dependency.natvis").display().to_string(); + + // Run cargo build. + p.cargo("build -v") + .masquerade_as_nightly_cargo() + .with_status(0) + .with_stderr_contains(format!("[..]-Z natvis={}[..]", foo_natvis_path)) + .with_stderr_contains(format!("[..]-Z natvis={}[..]", nested_dependency_natvis_path)) + .run(); +} + +#[cargo_test] +fn testing() { + Package::new("bar", "0.0.1") + .file( + "Cargo.toml", + r#" + cargo-features = ["natvis"] + + [project] + name = "bar" + version = "0.0.1" + + [debug-visualizations] + natvis = ["bar.natvis"] + "#, + ) + .file( + "bar.natvis", + r#" + + + + x:{x}, y:{y}, z:{z} + + x + y + z + + + + "#, + ) + .file("src/lib.rs","") + .publish(); + + let p = project() + .file( + "Cargo.toml", + r#" + [project] + name = "foo" + version = "0.0.1" + + [dependencies] + bar = "0.0.1" + "#, + ) + .file("src/main.rs", "fn main() {}") + .build(); + + p.cargo("build -v") + .masquerade_as_nightly_cargo() + .with_stderr_contains(format!("[..]-Z natvis=[..]/bar.natvis[..]")) + .run(); +} \ No newline at end of file From e672a956a14ddbb515f2643addf247ac7d4305d2 Mon Sep 17 00:00:00 2001 From: ridwanabdillahi <91507758+ridwanabdillahi@users.noreply.github.com> Date: Wed, 1 Dec 2021 13:04:13 -0800 Subject: [PATCH 02/13] Add fingerprinting support to ensure any changes to the set of Natvis files to be embedded causes a rebuild. --- src/cargo/core/compiler/fingerprint.rs | 3 ++ src/cargo/core/compiler/mod.rs | 43 ++++++++++++++++---------- src/cargo/util/toml/mod.rs | 36 +++++++++++++++++++-- 3 files changed, 62 insertions(+), 20 deletions(-) diff --git a/src/cargo/core/compiler/fingerprint.rs b/src/cargo/core/compiler/fingerprint.rs index 90e99da5c9f..b47fcd1a799 100644 --- a/src/cargo/core/compiler/fingerprint.rs +++ b/src/cargo/core/compiler/fingerprint.rs @@ -1330,6 +1330,9 @@ fn calculate_normal(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult, unit: &Unit) -> CargoResult { } } - build_deps_args(&mut rustdoc, cx, unit)?; + let mut unstable_opts = false; + build_deps_args(&mut rustdoc, cx, unit, &mut unstable_opts)?; + + // This will only be set if we're already using a feature + // requiring nightly rust + if unstable_opts { + rustdoc.arg("-Z").arg("unstable-options"); + } + rustdoc::add_root_urls(cx, unit, &mut rustdoc)?; rustdoc.args(bcx.rustdocflags_args(unit)); @@ -1061,14 +1078,13 @@ fn lto_args(cx: &Context<'_, '_>, unit: &Unit) -> Vec { fn build_natvis( cmd: &mut ProcessBuilder, unit: &Unit, + unstable_opts: &mut bool ) -> CargoResult<()> { if let Some(natvis) = &unit.pkg.manifest().natvis() { - unit.pkg.manifest().unstable_features().require(Feature::natvis())?; - cmd.arg("-Z").arg(&{ + *unstable_opts = true; + cmd.arg("-C").arg(&{ let mut arg = OsString::from("natvis="); - arg.push(OsString::from(natvis.iter().map(|file| { - unit.pkg.root().join(file).display().to_string() - }).collect::>().join(","))); + arg.push(OsString::from(natvis.iter().join(","))); arg }); } @@ -1080,6 +1096,7 @@ fn build_deps_args( cmd: &mut ProcessBuilder, cx: &mut Context<'_, '_>, unit: &Unit, + unstable_opts: &mut bool ) -> CargoResult<()> { let bcx = cx.bcx; cmd.arg("-L").arg(&{ @@ -1123,24 +1140,16 @@ fn build_deps_args( } } - let mut unstable_opts = false; - for dep in deps { if dep.unit.mode.is_run_custom_build() { cmd.env("OUT_DIR", &cx.files().build_script_out_dir(&dep.unit)); } } - for arg in extern_args(cx, unit, &mut unstable_opts)? { + for arg in extern_args(cx, unit, unstable_opts)? { cmd.arg(arg); } - // This will only be set if we're already using a feature - // requiring nightly rust - if unstable_opts { - cmd.arg("-Z").arg("unstable-options"); - } - Ok(()) } diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index 69cf21762ad..97305c1f531 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -1,5 +1,6 @@ use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::fmt; +use std::fs; use std::marker::PhantomData; use std::path::{Path, PathBuf}; use std::rc::Rc; @@ -1384,11 +1385,40 @@ impl TomlManifest { .transpose()? .map(CompileKind::Target); - let natvis = if let Some(debug_visualizations) = me.debug_visualizations.clone() { - debug_visualizations.natvis.clone() - } else { + let mut natvis = HashSet::new(); + if let Some(debug_visualizations) = me.debug_visualizations.clone() { + features.require(Feature::natvis())?; + if let Some(natvis_files) = debug_visualizations.natvis { + natvis_files.iter().for_each(|file| { + let path = paths::normalize_path(&package_root.join(file)); + natvis.insert(path.display().to_string()); + }); + } + } + + if features.require(Feature::natvis()).is_ok() { + let natvis_dir_path = package_root.join("dbgvis").join("natvis"); + if let Ok(natvis_dir) = fs::read_dir(&natvis_dir_path) { + for entry in natvis_dir { + match entry { + Ok(entry) => { + let path = entry.path(); + if path.extension() == Some("natvis".as_ref()) { + natvis.insert(path.display().to_string()); + } + } + Err(_) => {} + } + } + } + } + + let natvis = if natvis.is_empty() { None + } else { + Some(natvis.iter().map(|file| { file.clone() }).collect::>()) }; + let custom_metadata = project.metadata.clone(); let mut manifest = Manifest::new( summary, From 9099f1c551eae62e2a4bc8d8b2df7b603ed60003 Mon Sep 17 00:00:00 2001 From: ridwanabdillahi <91507758+ridwanabdillahi@users.noreply.github.com> Date: Wed, 1 Dec 2021 15:50:45 -0800 Subject: [PATCH 03/13] Fix broken unit tests. --- src/cargo/util/toml/mod.rs | 11 ++++------- tests/testsuite/natvis.rs | 20 ++++++++++---------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index 97305c1f531..3db35e74221 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -1400,14 +1400,11 @@ impl TomlManifest { let natvis_dir_path = package_root.join("dbgvis").join("natvis"); if let Ok(natvis_dir) = fs::read_dir(&natvis_dir_path) { for entry in natvis_dir { - match entry { - Ok(entry) => { - let path = entry.path(); - if path.extension() == Some("natvis".as_ref()) { - natvis.insert(path.display().to_string()); - } + if let Ok(entry) = entry { + let path = entry.path(); + if path.extension() == Some("natvis".as_ref()) { + natvis.insert(path.display().to_string()); } - Err(_) => {} } } } diff --git a/tests/testsuite/natvis.rs b/tests/testsuite/natvis.rs index 418e392a946..98d8115cf23 100644 --- a/tests/testsuite/natvis.rs +++ b/tests/testsuite/natvis.rs @@ -48,7 +48,7 @@ fn natvis_file_does_not_exist() { .build(); let natvis_path = p.root().join("foo.natvis").display().to_string(); - let expected_msg = format!("[..]incorrect value `{}` for debugging option `natvis`[..]", natvis_path); + let expected_msg = format!("[..]incorrect value `{}` for codegen option `natvis`[..]", natvis_path); // Run cargo build. p.cargo("build") @@ -78,7 +78,7 @@ fn invalid_natvis_extension() { .build(); let natvis_path = p.root().join("foo.rs").display().to_string(); - let expected_msg = format!("[..]incorrect value `{}` for debugging option `natvis`[..]", natvis_path); + let expected_msg = format!("[..]incorrect value `{}` for codegen option `natvis`[..]", natvis_path); // Run cargo build. p.cargo("build") @@ -203,7 +203,7 @@ fn direct_dependency_with_natvis() { p.cargo("build -v") .masquerade_as_nightly_cargo() .with_status(0) - .with_stderr_contains(format!("[..]-Z natvis={}[..]", natvis_path)) + .with_stderr_contains(format!("[..]-C natvis={}[..]", natvis_path)) .run(); } @@ -220,7 +220,7 @@ fn multiple_natvis_files() { version = "0.0.1" [debug-visualizations] - natvis = ["foo.natvis", "bar.natvis"] + natvis = ["bar.natvis", "foo.natvis"] "#, ) .file( @@ -274,14 +274,14 @@ fn multiple_natvis_files() { "#, ).build(); - let foo_natvis_path = p.root().join("foo.natvis").display().to_string(); let bar_natvis_path = p.root().join("bar.natvis").display().to_string(); + let foo_natvis_path = p.root().join("foo.natvis").display().to_string(); // Run cargo build. p.cargo("build -v") .masquerade_as_nightly_cargo() .with_status(0) - .with_stderr_contains(format!("[..]-Z natvis={},{}[..]", foo_natvis_path, bar_natvis_path)) + .with_stderr_contains(format!("[..]-C natvis={},{}[..]", bar_natvis_path, foo_natvis_path)) .run(); } @@ -391,13 +391,13 @@ fn indirect_dependency_with_natvis() { p.cargo("build -v") .masquerade_as_nightly_cargo() .with_status(0) - .with_stderr_contains(format!("[..]-Z natvis={}[..]", foo_natvis_path)) - .with_stderr_contains(format!("[..]-Z natvis={}[..]", nested_dependency_natvis_path)) + .with_stderr_contains(format!("[..]-C natvis={}[..]", foo_natvis_path)) + .with_stderr_contains(format!("[..]-C natvis={}[..]", nested_dependency_natvis_path)) .run(); } #[cargo_test] -fn testing() { +fn registry_dependency_natvis() { Package::new("bar", "0.0.1") .file( "Cargo.toml", @@ -448,6 +448,6 @@ fn testing() { p.cargo("build -v") .masquerade_as_nightly_cargo() - .with_stderr_contains(format!("[..]-Z natvis=[..]/bar.natvis[..]")) + .with_stderr_contains(format!("[..]-C natvis=[..]/bar.natvis[..]")) .run(); } \ No newline at end of file From 8a59eac5345ac788e6027a4a4542a618cdc4fa82 Mon Sep 17 00:00:00 2001 From: ridwanabdillahi <91507758+ridwanabdillahi@users.noreply.github.com> Date: Thu, 2 Dec 2021 12:26:07 -0800 Subject: [PATCH 04/13] Fix fingerprinting failures by using a BTreeSet instead of a Vector. --- src/cargo/core/manifest.rs | 8 ++++---- src/cargo/util/toml/mod.rs | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/cargo/core/manifest.rs b/src/cargo/core/manifest.rs index 572bdd31447..e879c42e4bf 100644 --- a/src/cargo/core/manifest.rs +++ b/src/cargo/core/manifest.rs @@ -1,4 +1,4 @@ -use std::collections::{BTreeMap, HashMap}; +use std::collections::{BTreeMap, HashMap, BTreeSet}; use std::fmt; use std::hash::{Hash, Hasher}; use std::path::{Path, PathBuf}; @@ -32,7 +32,7 @@ pub enum EitherManifest { pub struct Manifest { summary: Summary, targets: Vec, - natvis: Option>, + natvis: Option>, default_kind: Option, forced_kind: Option, links: Option, @@ -393,7 +393,7 @@ impl Manifest { original: Rc, metabuild: Option>, resolve_behavior: Option, - natvis: Option>, + natvis: Option>, ) -> Manifest { Manifest { summary, @@ -488,7 +488,7 @@ impl Manifest { self.links.as_deref() } - pub fn natvis(&self) -> &Option> { + pub fn natvis(&self) -> &Option> { &self.natvis } diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index 3db35e74221..0ac4d00bb90 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -1385,7 +1385,7 @@ impl TomlManifest { .transpose()? .map(CompileKind::Target); - let mut natvis = HashSet::new(); + let mut natvis = BTreeSet::new(); if let Some(debug_visualizations) = me.debug_visualizations.clone() { features.require(Feature::natvis())?; if let Some(natvis_files) = debug_visualizations.natvis { @@ -1397,12 +1397,13 @@ impl TomlManifest { } if features.require(Feature::natvis()).is_ok() { - let natvis_dir_path = package_root.join("dbgvis").join("natvis"); + let natvis_ext = "natvis"; + let natvis_dir_path = package_root.join("dbgvis").join(natvis_ext); if let Ok(natvis_dir) = fs::read_dir(&natvis_dir_path) { for entry in natvis_dir { if let Ok(entry) = entry { let path = entry.path(); - if path.extension() == Some("natvis".as_ref()) { + if path.extension() == Some(natvis_ext.as_ref()) { natvis.insert(path.display().to_string()); } } @@ -1413,9 +1414,8 @@ impl TomlManifest { let natvis = if natvis.is_empty() { None } else { - Some(natvis.iter().map(|file| { file.clone() }).collect::>()) + Some(natvis) }; - let custom_metadata = project.metadata.clone(); let mut manifest = Manifest::new( summary, From 92995380a5705d6e497d65836bb43381879fb696 Mon Sep 17 00:00:00 2001 From: ridwanabdillahi <91507758+ridwanabdillahi@users.noreply.github.com> Date: Thu, 2 Dec 2021 12:27:28 -0800 Subject: [PATCH 05/13] Update test name. --- tests/testsuite/natvis.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/testsuite/natvis.rs b/tests/testsuite/natvis.rs index 98d8115cf23..34dc71974ba 100644 --- a/tests/testsuite/natvis.rs +++ b/tests/testsuite/natvis.rs @@ -397,7 +397,7 @@ fn indirect_dependency_with_natvis() { } #[cargo_test] -fn registry_dependency_natvis() { +fn registry_dependency_with_natvis() { Package::new("bar", "0.0.1") .file( "Cargo.toml", From 65f81887bf44c408cdf85b537410d6cbdf52689b Mon Sep 17 00:00:00 2001 From: ridwanabdillahi <91507758+ridwanabdillahi@users.noreply.github.com> Date: Fri, 3 Dec 2021 13:50:25 -0800 Subject: [PATCH 06/13] Minor cleanups. --- src/cargo/core/compiler/mod.rs | 6 +++--- src/cargo/core/manifest.rs | 2 +- src/cargo/util/toml/mod.rs | 2 ++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index 18f7b5d0d3d..eb111212996 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -666,10 +666,11 @@ fn rustdoc(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult { Ok(output_dir.join(format!("{}.examples", unit.buildkey()))) }; + let mut unstable_opts = false; if unit.mode.is_doc_scrape() { debug_assert!(cx.bcx.scrape_units.contains(unit)); - rustdoc.arg("-Zunstable-options"); + *unstable_opts = true; rustdoc .arg("--scrape-examples-output-path") @@ -690,7 +691,7 @@ fn rustdoc(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult { // We only pass scraped examples to packages in the workspace // since examples are only coming from reverse-dependencies of workspace packages - rustdoc.arg("-Zunstable-options"); + *unstable_opts = true; for scrape_unit in &cx.bcx.scrape_units { rustdoc @@ -699,7 +700,6 @@ fn rustdoc(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult { } } - let mut unstable_opts = false; build_deps_args(&mut rustdoc, cx, unit, &mut unstable_opts)?; // This will only be set if we're already using a feature diff --git a/src/cargo/core/manifest.rs b/src/cargo/core/manifest.rs index e879c42e4bf..bd2c68dd2b7 100644 --- a/src/cargo/core/manifest.rs +++ b/src/cargo/core/manifest.rs @@ -32,7 +32,6 @@ pub enum EitherManifest { pub struct Manifest { summary: Summary, targets: Vec, - natvis: Option>, default_kind: Option, forced_kind: Option, links: Option, @@ -54,6 +53,7 @@ pub struct Manifest { default_run: Option, metabuild: Option>, resolve_behavior: Option, + natvis: Option>, } /// When parsing `Cargo.toml`, some warnings should silenced diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index 0ac4d00bb90..39d6e343eb0 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -1386,6 +1386,7 @@ impl TomlManifest { .map(CompileKind::Target); let mut natvis = BTreeSet::new(); + // Collect the Natvis files specified via the toml file and normalize the absolute paths. if let Some(debug_visualizations) = me.debug_visualizations.clone() { features.require(Feature::natvis())?; if let Some(natvis_files) = debug_visualizations.natvis { @@ -1396,6 +1397,7 @@ impl TomlManifest { } } + // Append all of the Natvis files in the pre-determined directory under the package root, `dbgvis/natvis`. if features.require(Feature::natvis()).is_ok() { let natvis_ext = "natvis"; let natvis_dir_path = package_root.join("dbgvis").join(natvis_ext); From 43bda3d5ffc51b231d772ff23d68f635be5443db Mon Sep 17 00:00:00 2001 From: ridwanabdillahi <91507758+ridwanabdillahi@users.noreply.github.com> Date: Wed, 8 Dec 2021 13:08:14 -0800 Subject: [PATCH 07/13] Minor refactors and formatting cleanups. --- src/cargo/core/compiler/mod.rs | 10 +- src/cargo/core/manifest.rs | 10 +- src/cargo/util/toml/mod.rs | 8 +- tests/testsuite/natvis.rs | 930 +++++++++++++++++---------------- 4 files changed, 491 insertions(+), 467 deletions(-) diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index eb111212996..c4183d5c429 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -670,7 +670,7 @@ fn rustdoc(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult { if unit.mode.is_doc_scrape() { debug_assert!(cx.bcx.scrape_units.contains(unit)); - *unstable_opts = true; + unstable_opts = true; rustdoc .arg("--scrape-examples-output-path") @@ -691,7 +691,7 @@ fn rustdoc(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult { // We only pass scraped examples to packages in the workspace // since examples are only coming from reverse-dependencies of workspace packages - *unstable_opts = true; + unstable_opts = true; for scrape_unit in &cx.bcx.scrape_units { rustdoc @@ -1089,13 +1089,13 @@ fn lto_args(cx: &Context<'_, '_>, unit: &Unit) -> Vec { fn build_natvis( cmd: &mut ProcessBuilder, unit: &Unit, - unstable_opts: &mut bool + unstable_opts: &mut bool, ) -> CargoResult<()> { if let Some(natvis) = &unit.pkg.manifest().natvis() { *unstable_opts = true; cmd.arg("-C").arg(&{ let mut arg = OsString::from("natvis="); - arg.push(OsString::from(natvis.iter().join(","))); + arg.push(OsString::from(natvis.iter().map(|f| f.display()).join(","))); arg }); } @@ -1107,7 +1107,7 @@ fn build_deps_args( cmd: &mut ProcessBuilder, cx: &mut Context<'_, '_>, unit: &Unit, - unstable_opts: &mut bool + unstable_opts: &mut bool, ) -> CargoResult<()> { let bcx = cx.bcx; cmd.arg("-L").arg(&{ diff --git a/src/cargo/core/manifest.rs b/src/cargo/core/manifest.rs index bd2c68dd2b7..508c3f1a84f 100644 --- a/src/cargo/core/manifest.rs +++ b/src/cargo/core/manifest.rs @@ -1,4 +1,4 @@ -use std::collections::{BTreeMap, HashMap, BTreeSet}; +use std::collections::{BTreeMap, BTreeSet, HashMap}; use std::fmt; use std::hash::{Hash, Hasher}; use std::path::{Path, PathBuf}; @@ -53,7 +53,7 @@ pub struct Manifest { default_run: Option, metabuild: Option>, resolve_behavior: Option, - natvis: Option>, + natvis: Option>, } /// When parsing `Cargo.toml`, some warnings should silenced @@ -393,7 +393,7 @@ impl Manifest { original: Rc, metabuild: Option>, resolve_behavior: Option, - natvis: Option>, + natvis: Option>, ) -> Manifest { Manifest { summary, @@ -419,7 +419,7 @@ impl Manifest { default_run, metabuild, resolve_behavior, - natvis + natvis, } } @@ -488,7 +488,7 @@ impl Manifest { self.links.as_deref() } - pub fn natvis(&self) -> &Option> { + pub fn natvis(&self) -> &Option> { &self.natvis } diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index 39d6e343eb0..1c5cba0f1e0 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -1390,10 +1390,10 @@ impl TomlManifest { if let Some(debug_visualizations) = me.debug_visualizations.clone() { features.require(Feature::natvis())?; if let Some(natvis_files) = debug_visualizations.natvis { - natvis_files.iter().for_each(|file| { + for file in &natvis_files { let path = paths::normalize_path(&package_root.join(file)); - natvis.insert(path.display().to_string()); - }); + natvis.insert(path); + } } } @@ -1406,7 +1406,7 @@ impl TomlManifest { if let Ok(entry) = entry { let path = entry.path(); if path.extension() == Some(natvis_ext.as_ref()) { - natvis.insert(path.display().to_string()); + natvis.insert(path); } } } diff --git a/tests/testsuite/natvis.rs b/tests/testsuite/natvis.rs index 34dc71974ba..164ac18475e 100644 --- a/tests/testsuite/natvis.rs +++ b/tests/testsuite/natvis.rs @@ -1,453 +1,477 @@ -//! Tests for natvis Cargo.toml syntax - -use cargo_test_support::project; -use cargo_test_support::registry::Package; - -#[cargo_test] -fn gated() { - let p = project() - .file( - "Cargo.toml", - r#" - [project] - name = "foo" - version = "0.0.1" - - [debug-visualizations] - natvis = ["foo.natvis"] - "#, - ) - .file("src/main.rs", "fn main() { assert!(true) }") - .build(); - - // Run cargo build. - p.cargo("build") - .masquerade_as_nightly_cargo() - .with_status(101) - .with_stderr_contains("[..]feature `natvis` is required") - .run(); -} - -#[cargo_test] -fn natvis_file_does_not_exist() { - let p = project() - .file( - "Cargo.toml", - r#" - cargo-features = ["natvis"] - - [project] - name = "foo" - version = "0.0.1" - - [debug-visualizations] - natvis = ["foo.natvis"] - "#, - ) - .file("src/main.rs", "fn main() { assert!(true) }") - .build(); - - let natvis_path = p.root().join("foo.natvis").display().to_string(); - let expected_msg = format!("[..]incorrect value `{}` for codegen option `natvis`[..]", natvis_path); - - // Run cargo build. - p.cargo("build") - .masquerade_as_nightly_cargo() - .with_status(101) - .with_stderr_contains(expected_msg) - .run(); -} - -#[cargo_test] -fn invalid_natvis_extension() { - let p = project() - .file( - "Cargo.toml", - r#" - cargo-features = ["natvis"] - - [project] - name = "foo" - version = "0.0.1" - - [debug-visualizations] - natvis = ["foo.rs"] - "#, - ) - .file("src/main.rs", "fn main() { assert!(true) }") - .build(); - - let natvis_path = p.root().join("foo.rs").display().to_string(); - let expected_msg = format!("[..]incorrect value `{}` for codegen option `natvis`[..]", natvis_path); - - // Run cargo build. - p.cargo("build") - .masquerade_as_nightly_cargo() - .with_status(101) - .with_stderr_contains(expected_msg) - .run(); -} - -#[cargo_test] -fn simple_test() { - let p = project() - .file( - "Cargo.toml", - r#" - cargo-features = ["natvis"] - - [project] - name = "foo" - version = "0.0.1" - - [debug-visualizations] - natvis = ["foo.natvis"] - "#, - ) - .file( - "src/main.rs", - r#" - fn main() { assert!(true) } - - pub struct Foo { - pub x: i32, - pub y: i32, - pub z: i32 - } - "#, - ).file( - "foo.natvis", - r#" - - - - x:{x}, y:{y}, z:{z} - - x - y - z - - - - "#, - ).build(); - - // Run cargo build. - p.cargo("build") - .masquerade_as_nightly_cargo() - .run(); -} - -#[cargo_test] -fn direct_dependency_with_natvis() { - let p = project() - .file( - "Cargo.toml", - r#" - [project] - name = "foo" - version = "0.0.1" - - [dependencies] - test_dependency = { path = "src/test_dependency" } - "#, - ) - .file( - "src/main.rs", - r#" - fn main() { assert!(true) } - "#, - ) - .file( - "src/test_dependency/src/lib.rs", - r#" - pub struct Foo { - pub x: i32, - pub y: i32, - pub z: i32 - } - "#) - .file( - "src/test_dependency/Cargo.toml", - r#" - cargo-features = ["natvis"] - - [project] - name = "test_dependency" - version = "0.0.1" - - [debug-visualizations] - natvis = ["test_dependency.natvis"] - "#, - ) - .file( - "src/test_dependency/test_dependency.natvis", - r#" - - - - x:{x}, y:{y}, z:{z} - - x - y - z - - - - "#, - ).build(); - - let natvis_path = p.root().join("src/test_dependency/test_dependency.natvis").display().to_string(); - - // Run cargo build. - p.cargo("build -v") - .masquerade_as_nightly_cargo() - .with_status(0) - .with_stderr_contains(format!("[..]-C natvis={}[..]", natvis_path)) - .run(); -} - -#[cargo_test] -fn multiple_natvis_files() { - let p = project() - .file( - "Cargo.toml", - r#" - cargo-features = ["natvis"] - - [project] - name = "foo" - version = "0.0.1" - - [debug-visualizations] - natvis = ["bar.natvis", "foo.natvis"] - "#, - ) - .file( - "src/main.rs", - r#" - fn main() { assert!(true) } - - pub struct Foo { - pub x: i32, - pub y: i32, - pub z: i32 - } - - pub struct Bar { - pub x: i32, - pub y: i32, - pub z: i32 - } - "#, - ) - .file( - "foo.natvis", - r#" - - - - x:{x}, y:{y}, z:{z} - - x - y - z - - - - "#, - ) - .file( - "bar.natvis", - r#" - - - - x:{x}, y:{y}, z:{z} - - x - y - z - - - - "#, - ).build(); - - let bar_natvis_path = p.root().join("bar.natvis").display().to_string(); - let foo_natvis_path = p.root().join("foo.natvis").display().to_string(); - - // Run cargo build. - p.cargo("build -v") - .masquerade_as_nightly_cargo() - .with_status(0) - .with_stderr_contains(format!("[..]-C natvis={},{}[..]", bar_natvis_path, foo_natvis_path)) - .run(); -} - -#[cargo_test] -fn indirect_dependency_with_natvis() { - let p = project() - .file( - "Cargo.toml", - r#" - cargo-features = ["natvis"] - - [project] - name = "foo" - version = "0.0.1" - - [debug-visualizations] - natvis = ["foo.natvis"] - - [dependencies] - test_dependency = { path = "src/test_dependency" } - "#, - ) - .file( - "src/main.rs", - r#" - fn main() { assert!(true) } - - pub struct Foo { - pub x: i32, - pub y: i32, - pub z: i32 - } - "#, - ) - .file( - "foo.natvis", - r#" - - - - x:{x}, y:{y}, z:{z} - - x - y - z - - - - "#, - ) - .file( - "src/test_dependency/Cargo.toml", - r#" - [project] - name = "test_dependency" - version = "0.0.1" - - [dependencies] - nested_dependency = { path = "src/nested_dependency" } - "#, - ) - .file("src/test_dependency/src/lib.rs",r#""#,) - .file( - "src/test_dependency/src/nested_dependency/Cargo.toml", - r#" - cargo-features = ["natvis"] - - [project] - name = "nested_dependency" - version = "0.0.1" - - [debug-visualizations] - natvis = ["nested_dependency.natvis"] - "#, - ) - .file( - "src/test_dependency/src/nested_dependency/src/lib.rs", - r#" - pub struct Bar { - pub x: i32, - pub y: i32, - pub z: i32 - } - "#, - ) - .file( - "src/test_dependency/src/nested_dependency/nested_dependency.natvis", - r#" - - - - x:{x}, y:{y}, z:{z} - - x - y - z - - - - "#, - ).build(); - - let foo_natvis_path = p.root().join("foo.natvis").display().to_string(); - let nested_dependency_natvis_path = p.root().join("src/test_dependency/src/nested_dependency/nested_dependency.natvis").display().to_string(); - - // Run cargo build. - p.cargo("build -v") - .masquerade_as_nightly_cargo() - .with_status(0) - .with_stderr_contains(format!("[..]-C natvis={}[..]", foo_natvis_path)) - .with_stderr_contains(format!("[..]-C natvis={}[..]", nested_dependency_natvis_path)) - .run(); -} - -#[cargo_test] -fn registry_dependency_with_natvis() { - Package::new("bar", "0.0.1") - .file( - "Cargo.toml", - r#" - cargo-features = ["natvis"] - - [project] - name = "bar" - version = "0.0.1" - - [debug-visualizations] - natvis = ["bar.natvis"] - "#, - ) - .file( - "bar.natvis", - r#" - - - - x:{x}, y:{y}, z:{z} - - x - y - z - - - - "#, - ) - .file("src/lib.rs","") - .publish(); - - let p = project() - .file( - "Cargo.toml", - r#" - [project] - name = "foo" - version = "0.0.1" - - [dependencies] - bar = "0.0.1" - "#, - ) - .file("src/main.rs", "fn main() {}") - .build(); - - p.cargo("build -v") - .masquerade_as_nightly_cargo() - .with_stderr_contains(format!("[..]-C natvis=[..]/bar.natvis[..]")) - .run(); -} \ No newline at end of file +//! Tests for natvis Cargo.toml syntax + +use cargo_test_support::project; +use cargo_test_support::registry::Package; + +#[cargo_test] +fn gated() { + let p = project() + .file( + "Cargo.toml", + r#" + [project] + name = "foo" + version = "0.0.1" + + [debug-visualizations] + natvis = ["foo.natvis"] + "#, + ) + .file("src/main.rs", "fn main() { assert!(true) }") + .build(); + + // Run cargo build. + p.cargo("build") + .masquerade_as_nightly_cargo() + .with_status(101) + .with_stderr_contains("[..]feature `natvis` is required") + .run(); +} + +#[cargo_test] +fn natvis_file_does_not_exist() { + let p = project() + .file( + "Cargo.toml", + r#" + cargo-features = ["natvis"] + + [project] + name = "foo" + version = "0.0.1" + + [debug-visualizations] + natvis = ["foo.natvis"] + "#, + ) + .file("src/main.rs", "fn main() { assert!(true) }") + .build(); + + let natvis_path = p.root().join("foo.natvis").display().to_string(); + let expected_msg = format!( + "[..]incorrect value `{}` for codegen option `natvis`[..]", + natvis_path + ); + + // Run cargo build. + p.cargo("build") + .masquerade_as_nightly_cargo() + .with_status(101) + .with_stderr_contains(expected_msg) + .run(); +} + +#[cargo_test] +fn invalid_natvis_extension() { + let p = project() + .file( + "Cargo.toml", + r#" + cargo-features = ["natvis"] + + [project] + name = "foo" + version = "0.0.1" + + [debug-visualizations] + natvis = ["foo.rs"] + "#, + ) + .file("src/main.rs", "fn main() { assert!(true) }") + .build(); + + let natvis_path = p.root().join("foo.rs").display().to_string(); + let expected_msg = format!( + "[..]incorrect value `{}` for codegen option `natvis`[..]", + natvis_path + ); + + // Run cargo build. + p.cargo("build") + .masquerade_as_nightly_cargo() + .with_status(101) + .with_stderr_contains(expected_msg) + .run(); +} + +#[cargo_test] +fn simple_test() { + let p = project() + .file( + "Cargo.toml", + r#" + cargo-features = ["natvis"] + + [project] + name = "foo" + version = "0.0.1" + + [debug-visualizations] + natvis = ["foo.natvis"] + "#, + ) + .file( + "src/main.rs", + r#" + fn main() { assert!(true) } + + pub struct Foo { + pub x: i32, + pub y: i32, + pub z: i32 + } + "#, + ) + .file( + "foo.natvis", + r#" + + + + x:{x}, y:{y}, z:{z} + + x + y + z + + + + "#, + ) + .build(); + + // Run cargo build. + p.cargo("build").masquerade_as_nightly_cargo().run(); +} + +#[cargo_test] +fn direct_dependency_with_natvis() { + let p = project() + .file( + "Cargo.toml", + r#" + [project] + name = "foo" + version = "0.0.1" + + [dependencies] + test_dependency = { path = "src/test_dependency" } + "#, + ) + .file( + "src/main.rs", + r#" + fn main() { assert!(true) } + "#, + ) + .file( + "src/test_dependency/src/lib.rs", + r#" + pub struct Foo { + pub x: i32, + pub y: i32, + pub z: i32 + } + "#, + ) + .file( + "src/test_dependency/Cargo.toml", + r#" + cargo-features = ["natvis"] + + [project] + name = "test_dependency" + version = "0.0.1" + + [debug-visualizations] + natvis = ["test_dependency.natvis"] + "#, + ) + .file( + "src/test_dependency/test_dependency.natvis", + r#" + + + + x:{x}, y:{y}, z:{z} + + x + y + z + + + + "#, + ) + .build(); + + let natvis_path = p + .root() + .join("src/test_dependency/test_dependency.natvis") + .display() + .to_string(); + + // Run cargo build. + p.cargo("build -v") + .masquerade_as_nightly_cargo() + .with_status(0) + .with_stderr_contains(format!("[..]-C natvis={}[..]", natvis_path)) + .run(); +} + +#[cargo_test] +fn multiple_natvis_files() { + let p = project() + .file( + "Cargo.toml", + r#" + cargo-features = ["natvis"] + + [project] + name = "foo" + version = "0.0.1" + + [debug-visualizations] + natvis = ["bar.natvis", "foo.natvis"] + "#, + ) + .file( + "src/main.rs", + r#" + fn main() { assert!(true) } + + pub struct Foo { + pub x: i32, + pub y: i32, + pub z: i32 + } + + pub struct Bar { + pub x: i32, + pub y: i32, + pub z: i32 + } + "#, + ) + .file( + "foo.natvis", + r#" + + + + x:{x}, y:{y}, z:{z} + + x + y + z + + + + "#, + ) + .file( + "bar.natvis", + r#" + + + + x:{x}, y:{y}, z:{z} + + x + y + z + + + + "#, + ) + .build(); + + let bar_natvis_path = p.root().join("bar.natvis").display().to_string(); + let foo_natvis_path = p.root().join("foo.natvis").display().to_string(); + + // Run cargo build. + p.cargo("build -v") + .masquerade_as_nightly_cargo() + .with_status(0) + .with_stderr_contains(format!( + "[..]-C natvis={},{}[..]", + bar_natvis_path, foo_natvis_path + )) + .run(); +} + +#[cargo_test] +fn indirect_dependency_with_natvis() { + let p = project() + .file( + "Cargo.toml", + r#" + cargo-features = ["natvis"] + + [project] + name = "foo" + version = "0.0.1" + + [debug-visualizations] + natvis = ["foo.natvis"] + + [dependencies] + test_dependency = { path = "src/test_dependency" } + "#, + ) + .file( + "src/main.rs", + r#" + fn main() { assert!(true) } + + pub struct Foo { + pub x: i32, + pub y: i32, + pub z: i32 + } + "#, + ) + .file( + "foo.natvis", + r#" + + + + x:{x}, y:{y}, z:{z} + + x + y + z + + + + "#, + ) + .file( + "src/test_dependency/Cargo.toml", + r#" + [project] + name = "test_dependency" + version = "0.0.1" + + [dependencies] + nested_dependency = { path = "src/nested_dependency" } + "#, + ) + .file("src/test_dependency/src/lib.rs", r#""#) + .file( + "src/test_dependency/src/nested_dependency/Cargo.toml", + r#" + cargo-features = ["natvis"] + + [project] + name = "nested_dependency" + version = "0.0.1" + + [debug-visualizations] + natvis = ["nested_dependency.natvis"] + "#, + ) + .file( + "src/test_dependency/src/nested_dependency/src/lib.rs", + r#" + pub struct Bar { + pub x: i32, + pub y: i32, + pub z: i32 + } + "#, + ) + .file( + "src/test_dependency/src/nested_dependency/nested_dependency.natvis", + r#" + + + + x:{x}, y:{y}, z:{z} + + x + y + z + + + + "#, + ) + .build(); + + let foo_natvis_path = p.root().join("foo.natvis").display().to_string(); + let nested_dependency_natvis_path = p + .root() + .join("src/test_dependency/src/nested_dependency/nested_dependency.natvis") + .display() + .to_string(); + + // Run cargo build. + p.cargo("build -v") + .masquerade_as_nightly_cargo() + .with_status(0) + .with_stderr_contains(format!("[..]-C natvis={}[..]", foo_natvis_path)) + .with_stderr_contains(format!( + "[..]-C natvis={}[..]", + nested_dependency_natvis_path + )) + .run(); +} + +#[cargo_test] +fn registry_dependency_with_natvis() { + Package::new("bar", "0.0.1") + .file( + "Cargo.toml", + r#" + cargo-features = ["natvis"] + + [project] + name = "bar" + version = "0.0.1" + + [debug-visualizations] + natvis = ["bar.natvis"] + "#, + ) + .file( + "bar.natvis", + r#" + + + + x:{x}, y:{y}, z:{z} + + x + y + z + + + + "#, + ) + .file("src/lib.rs", "") + .publish(); + + let p = project() + .file( + "Cargo.toml", + r#" + [project] + name = "foo" + version = "0.0.1" + + [dependencies] + bar = "0.0.1" + "#, + ) + .file("src/main.rs", "fn main() {}") + .build(); + + p.cargo("build -v") + .masquerade_as_nightly_cargo() + .with_stderr_contains(format!("[..]-C natvis=[..]/bar.natvis[..]")) + .run(); +} From 9b76e5e8138cfa2fda406083598fc1d2b03efad2 Mon Sep 17 00:00:00 2001 From: ridwanabdillahi <91507758+ridwanabdillahi@users.noreply.github.com> Date: Thu, 9 Dec 2021 17:31:51 -0800 Subject: [PATCH 08/13] Update new toml section name. --- src/cargo/util/toml/mod.rs | 34 ++++++++++++++++++++----------- src/doc/src/reference/unstable.md | 4 ++-- tests/testsuite/natvis.rs | 30 +++++++++++++-------------- 3 files changed, 39 insertions(+), 29 deletions(-) diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index 1c5cba0f1e0..b8b0715e7f9 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -303,7 +303,7 @@ pub struct TomlManifest { replace: Option>, patch: Option>>, workspace: Option, - debug_visualizations: Option, + debugger_visualizations: Option, badges: Option>>, } @@ -906,10 +906,10 @@ pub struct TomlWorkspace { metadata: Option, } -/// Represents the `debug-visualizations` section of a `Cargo.toml`. +/// Represents the `debugger-visualizations` section of a `Cargo.toml`. #[derive(Clone, Debug, Deserialize, Serialize)] -pub struct TomlDebugVisualizations { - natvis: Option>, +pub struct TomlDebuggerVisualizations { + natvis: Option>, // Note that this field must come last due to the way toml serialization // works which requires tables to be emitted after all values. @@ -1031,7 +1031,7 @@ impl TomlManifest { replace: None, patch: None, workspace: None, - debug_visualizations: self.debug_visualizations.clone(), + debugger_visualizations: self.debugger_visualizations.clone(), badges: self.badges.clone(), cargo_features: self.cargo_features.clone(), }); @@ -1386,20 +1386,30 @@ impl TomlManifest { .map(CompileKind::Target); let mut natvis = BTreeSet::new(); - // Collect the Natvis files specified via the toml file and normalize the absolute paths. - if let Some(debug_visualizations) = me.debug_visualizations.clone() { + let mut natvis_manifest_override = false; + let natvis_ext = "natvis"; + + // Collect the Natvis files specified via the toml file, if any exist, and normalize the absolute paths. + if let Some(debugger_visualizations) = me.debugger_visualizations.clone() { features.require(Feature::natvis())?; - if let Some(natvis_files) = debug_visualizations.natvis { + if let Some(natvis_files) = debugger_visualizations.natvis { + natvis_manifest_override = true; for file in &natvis_files { - let path = paths::normalize_path(&package_root.join(file)); + let path = paths::normalize_path(&package_root.join(file.clone().0)); + if path.extension() != Some(natvis_ext.as_ref()) { + warnings.push(format!( + "Natvis file `{}` does not have the expected `.natvis` extension.", + path.display().to_string() + )); + } natvis.insert(path); } } } - // Append all of the Natvis files in the pre-determined directory under the package root, `dbgvis/natvis`. - if features.require(Feature::natvis()).is_ok() { - let natvis_ext = "natvis"; + // If the `natvis` manifest key was not specified, append all of the Natvis files in the pre-determined + // directory under the package root, `dbgvis/natvis`. + if !natvis_manifest_override && features.require(Feature::natvis()).is_ok() { let natvis_dir_path = package_root.join("dbgvis").join(natvis_ext); if let Ok(natvis_dir) = fs::read_dir(&natvis_dir_path) { for entry in natvis_dir { diff --git a/src/doc/src/reference/unstable.md b/src/doc/src/reference/unstable.md index 821ca511b0a..8fd41f8ccc3 100644 --- a/src/doc/src/reference/unstable.md +++ b/src/doc/src/reference/unstable.md @@ -974,7 +974,7 @@ the command line) target. * Original Issue: [#0000](https://github.com/rust-lang/cargo/pull/0000) The `natvis` feature adds a new section and key to the manifest: -`[debug-visualizations]` and `debug-visualizations.natvis`. The `natvis` +`[debugger-visualizations]` and `debugger-visualizations.natvis`. The `natvis` key takes a list of `.natvis` files which will be linked into the PDB generated if using the MSVC Linker. @@ -987,7 +987,7 @@ cargo-features = ["natvis"] name = "foo" version = "0.0.1" -[debug-visualizations] +[debugger-visualizations] natvis = ["foo.natvis", "bar.natvis"] ``` diff --git a/tests/testsuite/natvis.rs b/tests/testsuite/natvis.rs index 164ac18475e..2d581015bc2 100644 --- a/tests/testsuite/natvis.rs +++ b/tests/testsuite/natvis.rs @@ -13,7 +13,7 @@ fn gated() { name = "foo" version = "0.0.1" - [debug-visualizations] + [debugger-visualizations] natvis = ["foo.natvis"] "#, ) @@ -29,7 +29,8 @@ fn gated() { } #[cargo_test] -fn natvis_file_does_not_exist() { +#[cfg(target_env = "msvc")] +fn file_does_not_exist() { let p = project() .file( "Cargo.toml", @@ -40,7 +41,7 @@ fn natvis_file_does_not_exist() { name = "foo" version = "0.0.1" - [debug-visualizations] + [debugger-visualizations] natvis = ["foo.natvis"] "#, ) @@ -49,7 +50,7 @@ fn natvis_file_does_not_exist() { let natvis_path = p.root().join("foo.natvis").display().to_string(); let expected_msg = format!( - "[..]incorrect value `{}` for codegen option `natvis`[..]", + "[..]fatal error LNK1181: cannot open input file '{}'[..]", natvis_path ); @@ -73,23 +74,22 @@ fn invalid_natvis_extension() { name = "foo" version = "0.0.1" - [debug-visualizations] - natvis = ["foo.rs"] + [debugger-visualizations] + natvis = ["src/main.rs"] "#, ) .file("src/main.rs", "fn main() { assert!(true) }") .build(); - let natvis_path = p.root().join("foo.rs").display().to_string(); + let natvis_path = p.root().join("src").join("main.rs").display().to_string(); let expected_msg = format!( - "[..]incorrect value `{}` for codegen option `natvis`[..]", + "warning: Natvis file `{}` does not have the expected `.natvis` extension.", natvis_path ); // Run cargo build. p.cargo("build") .masquerade_as_nightly_cargo() - .with_status(101) .with_stderr_contains(expected_msg) .run(); } @@ -106,7 +106,7 @@ fn simple_test() { name = "foo" version = "0.0.1" - [debug-visualizations] + [debugger-visualizations] natvis = ["foo.natvis"] "#, ) @@ -183,7 +183,7 @@ fn direct_dependency_with_natvis() { name = "test_dependency" version = "0.0.1" - [debug-visualizations] + [debugger-visualizations] natvis = ["test_dependency.natvis"] "#, ) @@ -231,7 +231,7 @@ fn multiple_natvis_files() { name = "foo" version = "0.0.1" - [debug-visualizations] + [debugger-visualizations] natvis = ["bar.natvis", "foo.natvis"] "#, ) @@ -313,7 +313,7 @@ fn indirect_dependency_with_natvis() { name = "foo" version = "0.0.1" - [debug-visualizations] + [debugger-visualizations] natvis = ["foo.natvis"] [dependencies] @@ -369,7 +369,7 @@ fn indirect_dependency_with_natvis() { name = "nested_dependency" version = "0.0.1" - [debug-visualizations] + [debugger-visualizations] natvis = ["nested_dependency.natvis"] "#, ) @@ -432,7 +432,7 @@ fn registry_dependency_with_natvis() { name = "bar" version = "0.0.1" - [debug-visualizations] + [debugger-visualizations] natvis = ["bar.natvis"] "#, ) From e160ff2fdd7cae60fe2a62a3c46d1b2e0281e805 Mon Sep 17 00:00:00 2001 From: ridwanabdillahi <91507758+ridwanabdillahi@users.noreply.github.com> Date: Fri, 7 Jan 2022 12:51:02 -0800 Subject: [PATCH 09/13] Only add natvis for the primary unit of each package. --- src/cargo/core/compiler/mod.rs | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index 2874ef75b77..49e4e65a49e 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -613,7 +613,7 @@ fn prepare_rustc( base.inherit_jobserver(&cx.jobserver); } build_base_args(cx, &mut base, unit, crate_types)?; - build_natvis(&mut base, unit, &mut unstable_opts)?; + build_natvis(&mut base, cx, unit, &mut unstable_opts)?; build_deps_args(&mut base, cx, unit, &mut unstable_opts)?; // This will only be set if we're already using a feature @@ -1089,16 +1089,32 @@ fn lto_args(cx: &Context<'_, '_>, unit: &Unit) -> Vec { fn build_natvis( cmd: &mut ProcessBuilder, + cx: &mut Context<'_, '_>, unit: &Unit, unstable_opts: &mut bool, ) -> CargoResult<()> { if let Some(natvis) = &unit.pkg.manifest().natvis() { - *unstable_opts = true; - cmd.arg("-C").arg(&{ - let mut arg = OsString::from("natvis="); - arg.push(OsString::from(natvis.iter().map(|f| f.display()).join(","))); - arg - }); + // Only add natvis for the primary unit of each package. + // This will ensure units that depend on the primary + // unit, i.e. bins, integration tests or examples, will not + // have a duplicate set of natvis files. + let mut add_natvis = true; + let deps = cx.unit_deps(unit); + for dep in deps { + if cx.is_primary_package(&dep.unit) { + add_natvis = false; + break; + } + } + + if add_natvis { + *unstable_opts = true; + cmd.arg("-C").arg(&{ + let mut arg = OsString::from("natvis="); + arg.push(OsString::from(natvis.iter().map(|f| f.display()).join(","))); + arg + }); + } } Ok(()) From 4693d67a6a687f9e72274efb491a8a04e389e53b Mon Sep 17 00:00:00 2001 From: ridwanabdillahi <91507758+ridwanabdillahi@users.noreply.github.com> Date: Thu, 20 Jan 2022 00:59:08 -0800 Subject: [PATCH 10/13] Update the natvis flag specified to the rustc command when multiple natvis files are passed. --- src/cargo/core/compiler/mod.rs | 13 +-- tests/testsuite/natvis.rs | 144 ++++++++++++++++++++++++++++++++- 2 files changed, 147 insertions(+), 10 deletions(-) diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index 49e4e65a49e..d15b3121082 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -30,7 +30,6 @@ use std::path::{Path, PathBuf}; use std::sync::Arc; use anyhow::{Context as _, Error}; -use itertools::Itertools; use lazycell::LazyCell; use log::debug; @@ -1109,11 +1108,13 @@ fn build_natvis( if add_natvis { *unstable_opts = true; - cmd.arg("-C").arg(&{ - let mut arg = OsString::from("natvis="); - arg.push(OsString::from(natvis.iter().map(|f| f.display()).join(","))); - arg - }); + for file in natvis { + cmd.arg("-C").arg(&{ + let mut arg = OsString::from("natvis="); + arg.push(file); + arg + }); + } } } diff --git a/tests/testsuite/natvis.rs b/tests/testsuite/natvis.rs index 2d581015bc2..27315ab7593 100644 --- a/tests/testsuite/natvis.rs +++ b/tests/testsuite/natvis.rs @@ -294,10 +294,146 @@ fn multiple_natvis_files() { p.cargo("build -v") .masquerade_as_nightly_cargo() .with_status(0) - .with_stderr_contains(format!( - "[..]-C natvis={},{}[..]", - bar_natvis_path, foo_natvis_path - )) + .with_stderr_contains(format!("[..]-C natvis={}[..]", bar_natvis_path)) + .with_stderr_contains(format!("[..]-C natvis={}[..]", foo_natvis_path)) + .run(); +} + +#[cargo_test] +fn natvis_from_dbgvis_directory() { + let p = project() + .file( + "Cargo.toml", + r#" + cargo-features = ["natvis"] + + [project] + name = "foo" + version = "0.0.1" + "#, + ) + .file( + "src/main.rs", + r#" + fn main() { assert!(true) } + + pub struct Foo { + pub x: i32, + pub y: i32, + pub z: i32 + } + "#, + ) + .file( + "dbgvis/natvis/foo.natvis", + r#" + + + + x:{x}, y:{y}, z:{z} + + x + y + z + + + + "#, + ) + .build(); + + let foo_natvis_path = p + .root() + .join("dbgvis/natvis/foo.natvis") + .display() + .to_string(); + + // Run cargo build. + p.cargo("build -v") + .masquerade_as_nightly_cargo() + .with_stderr_contains(format!("[..]-C natvis={}[..]", foo_natvis_path)) + .run(); +} + +#[cargo_test] +fn natvis_toml_and_dbgvis_directory() { + let p = project() + .file( + "Cargo.toml", + r#" + cargo-features = ["natvis"] + + [project] + name = "foo" + version = "0.0.1" + + [debugger-visualizations] + natvis = ["src/bar.natvis"] + "#, + ) + .file( + "src/main.rs", + r#" + fn main() { assert!(true) } + + pub struct Foo { + pub x: i32, + pub y: i32, + pub z: i32 + } + "#, + ) + .file( + "src/bar.natvis", + r#" + + + + x:{x}, y:{y}, z:{z} + + x + y + z + + + + "#, + ) + .file( + "dbgvis/natvis/foo.natvis", + r#" + + + + x:{x}, y:{y}, z:{z} + + x + y + z + + + + "#, + ) + .build(); + + let foo_natvis_path = p + .root() + .join("dbgvis/natvis/foo.natvis") + .display() + .to_string(); + + let bar_natvis_path = p + .root() + .join("src/bar.natvis") + .display() + .to_string(); + + // Run cargo build. + p.cargo("build -v") + .masquerade_as_nightly_cargo() + .with_stderr_contains(format!("[..]-C natvis={}[..]", bar_natvis_path)) + .with_stderr_does_not_contain(format!("[..]-C natvis={}[..]", foo_natvis_path)) .run(); } From efb14ace69e568a77bfb123048b356ba7d5d0156 Mon Sep 17 00:00:00 2001 From: ridwanabdillahi <91507758+ridwanabdillahi@users.noreply.github.com> Date: Thu, 27 Jan 2022 16:45:15 -0800 Subject: [PATCH 11/13] Add support for Cargo to automatically finding `.natvis` in subdirectories under the `dbgvis/natvis/` directory. --- src/cargo/util/toml/mod.rs | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index b9018e4b1f4..e3ef1414f1e 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -1436,21 +1436,30 @@ impl TomlManifest { } // If the `natvis` manifest key was not specified, append all of the Natvis files in the pre-determined - // directory under the package root, `dbgvis/natvis`. - if !natvis_manifest_override && features.require(Feature::natvis()).is_ok() { - let natvis_dir_path = package_root.join("dbgvis").join(natvis_ext); - if let Ok(natvis_dir) = fs::read_dir(&natvis_dir_path) { - for entry in natvis_dir { - if let Ok(entry) = entry { - let path = entry.path(); - if path.extension() == Some(natvis_ext.as_ref()) { - natvis.insert(path); + // directory under the package root, `dbgvis/natvis/**/`. + fn find_natvis_files(path: &PathBuf, natvis: &mut BTreeSet) { + if let Ok(path) = fs::read_dir(&path) { + for entry in path { + match entry { + Ok(entry) => { + let path = entry.path(); + if path.is_dir() { + find_natvis_files(&path, natvis); + } else if path.is_file() && path.extension() == Some("natvis".as_ref()) { + natvis.insert(path); + } } + Err(_) => { } } } } } + if !natvis_manifest_override && features.require(Feature::natvis()).is_ok() { + let natvis_dir_path = package_root.join("dbgvis").join(natvis_ext); + find_natvis_files(&natvis_dir_path, &mut natvis); + } + let natvis = if natvis.is_empty() { None } else { From 2b5cd4a1cacac49279799b2e596d10ba6d44c9d2 Mon Sep 17 00:00:00 2001 From: ridwanabdillahi <91507758+ridwanabdillahi@users.noreply.github.com> Date: Fri, 28 Jan 2022 12:22:05 -0800 Subject: [PATCH 12/13] Fix broken tests after latest changes to the compiler. --- src/cargo/util/toml/mod.rs | 13 ++++++++++--- tests/testsuite/natvis.rs | 11 ++--------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index e3ef1414f1e..dff4ae4f7b8 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -1424,13 +1424,20 @@ impl TomlManifest { natvis_manifest_override = true; for file in &natvis_files { let path = paths::normalize_path(&package_root.join(file.clone().0)); - if path.extension() != Some(natvis_ext.as_ref()) { + if !path.exists() { warnings.push(format!( - "Natvis file `{}` does not have the expected `.natvis` extension.", + "Natvis file `{}` does not exist. Skipping file.", path.display().to_string() )); + } else { + if path.extension() != Some(natvis_ext.as_ref()) { + warnings.push(format!( + "Natvis file `{}` does not have the expected `.natvis` extension.", + path.display().to_string() + )); + } + natvis.insert(path); } - natvis.insert(path); } } } diff --git a/tests/testsuite/natvis.rs b/tests/testsuite/natvis.rs index 27315ab7593..26ae06e1227 100644 --- a/tests/testsuite/natvis.rs +++ b/tests/testsuite/natvis.rs @@ -29,7 +29,6 @@ fn gated() { } #[cargo_test] -#[cfg(target_env = "msvc")] fn file_does_not_exist() { let p = project() .file( @@ -48,17 +47,11 @@ fn file_does_not_exist() { .file("src/main.rs", "fn main() { assert!(true) }") .build(); - let natvis_path = p.root().join("foo.natvis").display().to_string(); - let expected_msg = format!( - "[..]fatal error LNK1181: cannot open input file '{}'[..]", - natvis_path - ); - + let foo = p.root().join("foo.natvis"); // Run cargo build. p.cargo("build") .masquerade_as_nightly_cargo() - .with_status(101) - .with_stderr_contains(expected_msg) + .with_stderr_contains(format!("[..]Natvis file `{}` does not exist. Skipping file.[..]", foo.display().to_string())) .run(); } From 24d07bc2274ed1c38699811063f2d83490ce205a Mon Sep 17 00:00:00 2001 From: ridwanabdillahi <91507758+ridwanabdillahi@users.noreply.github.com> Date: Mon, 31 Jan 2022 10:45:34 -0800 Subject: [PATCH 13/13] Update documentation regarding finding Natvis files in Cargo automatically. --- src/doc/src/reference/unstable.md | 10 +++++++--- tests/testsuite/natvis.rs | 23 +++++++++++++++++++++++ 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/doc/src/reference/unstable.md b/src/doc/src/reference/unstable.md index 3e48192556f..d1c9dd57d4f 100644 --- a/src/doc/src/reference/unstable.md +++ b/src/doc/src/reference/unstable.md @@ -883,9 +883,13 @@ the command line) target. * Original Issue: [#0000](https://github.com/rust-lang/cargo/pull/0000) The `natvis` feature adds a new section and key to the manifest: -`[debugger-visualizations]` and `debugger-visualizations.natvis`. The `natvis` -key takes a list of `.natvis` files which will be linked into the PDB -generated if using the MSVC Linker. +`[debugger-visualizations]` and `debugger-visualizations.natvis` which +takes a list of `.natvis` files. The `natvis` feature also allows Cargo +to automatically find Natvis files that live in a predetermined +directory relative to the root of the package, `dbgvis/natvis`, including +its subdirectories. This will be the default for including Natvis files in +a package and will be overridden if the manifest key is specified. The Natvis +files will then be linked into the PDB generated if using the MSVC Linker. Example: diff --git a/tests/testsuite/natvis.rs b/tests/testsuite/natvis.rs index 26ae06e1227..e543a842ab8 100644 --- a/tests/testsuite/natvis.rs +++ b/tests/testsuite/natvis.rs @@ -333,6 +333,22 @@ fn natvis_from_dbgvis_directory() { "#, ) + .file( + "dbgvis/natvis/foo/bar.natvis", + r#" + + + + x:{x}, y:{y}, z:{z} + + x + y + z + + + + "#, + ) .build(); let foo_natvis_path = p @@ -341,10 +357,17 @@ fn natvis_from_dbgvis_directory() { .display() .to_string(); + let bar_natvis_path = p + .root() + .join("dbgvis/natvis/natvis/bar.natvis") + .display() + .to_string(); + // Run cargo build. p.cargo("build -v") .masquerade_as_nightly_cargo() .with_stderr_contains(format!("[..]-C natvis={}[..]", foo_natvis_path)) + .with_stderr_contains(format!("[..]-C natvis={}[..]", bar_natvis_path)) .run(); }