diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..7447b09c3 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +# smoelius: Force `LF` line endings in `.stderr` files. +# See https://github.com/Manishearth/compiletest-rs/issues/154 +*.stderr eol=lf diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ee568030b..f5d5d4b8a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,7 +39,7 @@ jobs: test: strategy: matrix: - environment: [ubuntu-latest, macos-latest] + environment: [ubuntu-latest, macos-latest, windows-latest] runs-on: ${{ matrix.environment }} diff --git a/Cargo.lock b/Cargo.lock index 22caf9717..da2ddbf9f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -516,6 +516,7 @@ name = "dylint-link" version = "1.0.1" dependencies = [ "anyhow", + "cc", "dylint_internal", "env_logger 0.9.0", "if_chain", diff --git a/cargo-dylint/tests/custom_toolchain.rs b/cargo-dylint/tests/custom_toolchain.rs index 393933c60..6080b8f0f 100644 --- a/cargo-dylint/tests/custom_toolchain.rs +++ b/cargo-dylint/tests/custom_toolchain.rs @@ -1,63 +1,69 @@ -use anyhow::{anyhow, Result}; -use dylint_internal::{ - find_and_replace, - rustup::{toolchain_path, SanitizeEnvironment}, - Command, -}; -use std::path::Path; -use tempfile::{tempdir, NamedTempFile}; -use test_env_log::test; +// smoelius: As per `dylint-link/src/main.rs`: +// "Only the MSVC toolchain is supported on Windows" +#[cfg(not(target_os = "windows"))] +mod custom_toolchain { + use anyhow::{anyhow, Result}; + use dylint_internal::{ + find_and_replace, + rustup::{toolchain_path, SanitizeEnvironment}, + Command, + }; + use std::path::Path; + use tempfile::{tempdir, NamedTempFile}; + use test_env_log::test; -#[test] -fn custom_toolchain() { - let tempdir = tempdir().unwrap(); + #[test] + fn custom_toolchain() { + let tempdir = tempdir().unwrap(); - dylint_internal::checkout_dylint_template(tempdir.path()).unwrap(); + dylint_internal::checkout_dylint_template(tempdir.path()).unwrap(); - let toolchain_path = toolchain_path(tempdir.path()).unwrap(); + let toolchain_path = toolchain_path(tempdir.path()).unwrap(); - let custom_toolchain = random_string().unwrap(); + let custom_toolchain = random_string().unwrap(); - link_toolchain(&custom_toolchain, &toolchain_path).unwrap(); + link_toolchain(&custom_toolchain, &toolchain_path).unwrap(); - patch_dylint_template(tempdir.path(), &custom_toolchain).unwrap(); + patch_dylint_template(tempdir.path(), &custom_toolchain).unwrap(); - dylint_internal::test() - .sanitize_environment() - .current_dir(tempdir.path()) - .success() - .unwrap(); + dylint_internal::test() + .sanitize_environment() + .current_dir(tempdir.path()) + .success() + .unwrap(); - uninstall_toolchain(&custom_toolchain).unwrap(); -} + uninstall_toolchain(&custom_toolchain).unwrap(); + } -fn random_string() -> Result { - let tempfile = NamedTempFile::new()?; - tempfile - .path() - .file_name() - .map(|s| s.to_string_lossy().trim_start_matches('.').to_string()) - .ok_or_else(|| anyhow!("Could not get file name")) -} + fn random_string() -> Result { + let tempfile = NamedTempFile::new()?; + tempfile + .path() + .file_name() + .map(|s| s.to_string_lossy().trim_start_matches('.').to_string()) + .ok_or_else(|| anyhow!("Could not get file name")) + } -fn link_toolchain(toolchain: &str, path: &Path) -> Result<()> { - Command::new("rustup") - .args(&["toolchain", "link", toolchain, &path.to_string_lossy()]) - .success() -} + fn link_toolchain(toolchain: &str, path: &Path) -> Result<()> { + Command::new("rustup") + .args(&["toolchain", "link", toolchain, &path.to_string_lossy()]) + .success() + } -fn patch_dylint_template(path: &Path, channel: &str) -> Result<()> { - find_and_replace( - &path.join("rust-toolchain"), - &[&format!( - r#"s/(?m)^channel = "[^"]*"$/channel = "{}"/"#, - channel, - )], - ) -} + fn patch_dylint_template(path: &Path, channel: &str) -> Result<()> { + // smoelius: See https://github.com/rust-lang/regex/issues/244 + find_and_replace( + &path.join("rust-toolchain"), + &[&format!( + r#"s/(?m)^channel = "[^"]*"/channel = "{}"/"#, + channel, + )], + ) + } -fn uninstall_toolchain(toolchain: &str) -> Result<()> { - Command::new("rustup") - .args(&["toolchain", "uninstall", toolchain]) - .success() + fn uninstall_toolchain(toolchain: &str) -> Result<()> { + Command::new("rustup") + .args(&["toolchain", "uninstall", toolchain]) + .success() + } } diff --git a/cargo-dylint/tests/dylint_driver_path.rs b/cargo-dylint/tests/dylint_driver_path.rs index 5440bdcd6..dde9ca536 100644 --- a/cargo-dylint/tests/dylint_driver_path.rs +++ b/cargo-dylint/tests/dylint_driver_path.rs @@ -1,7 +1,6 @@ use dylint_internal::{ env, rustup::{toolchain_path, SanitizeEnvironment}, - Command, }; use std::fs::create_dir_all; use tempfile::tempdir_in; @@ -31,7 +30,10 @@ fn dylint_driver_path() { // https://github.com/trailofbits/dylint/issues/54 let toolchain_path = toolchain_path(tempdir.path()).unwrap(); let toolchain = toolchain_path.iter().last().unwrap(); - Command::new(dylint_driver_path.join(toolchain).join("dylint-driver")) - .success() - .unwrap(); + let mut command = dylint_internal::driver( + &toolchain.to_string_lossy().to_string(), + &dylint_driver_path.join(toolchain).join("dylint-driver"), + ) + .unwrap(); + command.success().unwrap(); } diff --git a/cargo-dylint/tests/list.rs b/cargo-dylint/tests/list.rs index d328248c1..aaf276253 100644 --- a/cargo-dylint/tests/list.rs +++ b/cargo-dylint/tests/list.rs @@ -52,10 +52,11 @@ fn one_name_multiple_toolchains() { } fn patch_dylint_template(path: &Path, channel: &str, clippy_utils_tag: &str) -> Result<()> { + // smoelius: See https://github.com/rust-lang/regex/issues/244 find_and_replace( &path.join("rust-toolchain"), &[&format!( - r#"s/(?m)^channel = "[^"]*"$/channel = "{}"/"#, + r#"s/(?m)^channel = "[^"]*"/channel = "{}"/"#, channel, )], )?; diff --git a/dylint-link/Cargo.toml b/dylint-link/Cargo.toml index 3eca020df..673f0e4e0 100644 --- a/dylint-link/Cargo.toml +++ b/dylint-link/Cargo.toml @@ -13,3 +13,6 @@ env_logger = "0.9.0" if_chain = "1.0.1" dylint_internal = { version = "=1.0.1", path = "../internal" } + +[target.'cfg(target_os = "windows")'.dependencies] +cc = "1.0.69" diff --git a/dylint-link/src/main.rs b/dylint-link/src/main.rs index a2ed18f34..a416961cc 100644 --- a/dylint-link/src/main.rs +++ b/dylint-link/src/main.rs @@ -2,6 +2,8 @@ #![deny(clippy::unwrap_used)] #![deny(clippy::panic)] +#[cfg(target_os = "windows")] +use anyhow::ensure; use anyhow::{anyhow, Result}; use dylint_internal::{ env::{self, var}, @@ -14,41 +16,134 @@ use std::{ fs::copy, path::{Path, PathBuf}, }; +#[cfg(target_os = "windows")] +use std::{fs::File, io::Read}; fn main() -> Result<()> { env_logger::init(); + let linker = linker()?; let args: Vec = std::env::args().collect(); + Command::new(linker).args(&args[1..]).success()?; - Command::new("cc").args(&args[1..]).success()?; + if let Some(path) = output_path(args.iter())? { + copy_library(&path)?; + } + + Ok(()) +} - let cargo_pkg_name = var(env::CARGO_PKG_NAME)?; +#[cfg(target_os = "windows")] +fn linker() -> Result { let rustup_toolchain = var(env::RUSTUP_TOOLCHAIN)?; + let split_toolchain: Vec<_> = rustup_toolchain.split('-').collect(); + if_chain! { + if split_toolchain.last() == Some(&"msvc"); + let len = split_toolchain.len(); + if len >= 4; + then { + // MinerSebas: Removes the Release Information: "nightly-2021-04-08-x86_64-pc-windows-msvc" -> "x86_64-pc-windows-msvc" + let trimmed_toolchain: String = split_toolchain[len - 4..].join("-"); + if let Some(tool) = cc::windows_registry::find_tool(&trimmed_toolchain, "link.exe") { + Ok(tool.path().into()) + } else { + Err(anyhow!("Could not find the MSVC Linker")) + } + } else { + Err(anyhow!("Only the MSVC toolchain is supported on Windows")) + } + } +} + +#[cfg(not(target_os = "windows"))] +#[allow(clippy::unnecessary_wraps)] +fn linker() -> Result { + Ok(PathBuf::from("cc")) +} + +#[cfg(target_os = "windows")] +fn output_path<'a, I>(iter: I) -> Result> +where + I: Iterator, +{ + for arg in iter { + if let Some(path) = arg.strip_prefix("/OUT:") { + return Ok(Some(path.into())); + } + if let Some(path) = arg.strip_prefix('@') { + return extract_out_path_from_linker_response_file(path); + } + } - let mut args = std::env::args(); - while let Some(arg) = args.next() { + Ok(None) +} + +#[cfg(not(target_os = "windows"))] +fn output_path<'a, I>(mut iter: I) -> Result> +where + I: Iterator, +{ + while let Some(arg) = iter.next() { if arg == "-o" { - if_chain! { - if let Some(path) = args.next(); - let path = Path::new(&path); - if let Some(lib_name) = parse_path(path); - if lib_name == cargo_pkg_name.replace("-", "_"); - then { - let filename_with_toolchain = format!( - "{}{}@{}{}", - consts::DLL_PREFIX, - lib_name, - rustup_toolchain, - consts::DLL_SUFFIX - ); - let parent = path - .parent() - .ok_or_else(|| anyhow!("Could not get parent directory"))?; - let path_with_toolchain = strip_deps(parent).join(filename_with_toolchain); - copy(path, path_with_toolchain)?; - } + if let Some(path) = iter.next() { + return Ok(Some(path.into())); } - break; + } + } + + Ok(None) +} + +#[cfg(target_os = "windows")] +fn extract_out_path_from_linker_response_file(path: impl AsRef) -> Result> { + // MinerSebas: On Windows the cmd line has a Limit of 8191 Characters. + // If your command would exceed this you can instead use a Linker Response File to set arguments. + // (https://docs.microsoft.com/en-us/cpp/build/reference/at-specify-a-linker-response-file?view=msvc-160) + + // MinerSebas: Read the Linker Response File + let mut buf: Vec = Vec::new(); + File::open(path)?.read_to_end(&mut buf)?; + + // MinerSebas: Convert the File from UTF-16 to a Rust UTF-8 String + // (Only necessary for MSVC, the GNU Linker uses UTF-8 isntead.) + // Based on: https://stackoverflow.com/a/57172592 + let file: Vec = buf + .chunks_exact(2) + .into_iter() + .map(|a| u16::from_ne_bytes([a[0], a[1]])) + .collect(); + let file = String::from_utf16_lossy(file.as_slice()); + + let paths: Vec<_> = file + .lines() + .flat_map(|line| line.trim().trim_matches('"').strip_prefix("/OUT:")) + .collect(); + + ensure!(paths.len() <= 1, "Found multiple output paths"); + + // smoelius: Do not raise an error if no output path is found. + Ok(paths.last().map(Into::into)) +} + +fn copy_library(path: &Path) -> Result<()> { + if_chain! { + if let Some(lib_name) = parse_path(path); + let cargo_pkg_name = var(env::CARGO_PKG_NAME)?; + if lib_name == cargo_pkg_name.replace("-", "_"); + then { + let rustup_toolchain = var(env::RUSTUP_TOOLCHAIN)?; + let filename_with_toolchain = format!( + "{}{}@{}{}", + consts::DLL_PREFIX, + lib_name, + rustup_toolchain, + consts::DLL_SUFFIX + ); + let parent = path + .parent() + .ok_or_else(|| anyhow!("Could not get parent directory"))?; + let path_with_toolchain = strip_deps(parent).join(filename_with_toolchain); + copy(path, path_with_toolchain)?; } } diff --git a/dylint/src/driver_builder.rs b/dylint/src/driver_builder.rs index c48e91f84..0bf4b4c67 100644 --- a/dylint/src/driver_builder.rs +++ b/dylint/src/driver_builder.rs @@ -3,12 +3,10 @@ use anyhow::{anyhow, ensure, Result}; use dylint_internal::{ env::{self, var}, rustup::{toolchain_path, SanitizeEnvironment}, - Command, }; use semver::Version; use std::{ - env::{consts, join_paths, split_paths}, - ffi::OsString, + env::consts, fs::{copy, create_dir_all, write}, path::{Path, PathBuf}, process::Stdio, @@ -76,7 +74,7 @@ pub fn get(opts: &crate::Dylint, toolchain: &str) -> Result { } let driver = driver_dir.join("dylint-driver"); - if !driver.exists() || is_outdated(opts, &driver, toolchain)? { + if !driver.exists() || is_outdated(opts, toolchain, &driver)? { build(opts, toolchain, &driver)?; } @@ -99,33 +97,9 @@ fn dylint_drivers() -> Result { } } -fn is_outdated(opts: &crate::Dylint, driver: &Path, toolchain: &str) -> Result { - let path = var(env::PATH)?; - - let path = { - if cfg!(target_os = "windows") { - // MinerSebas: To succesfully determine the dylint driver Version on Windows, - // it is neccesary to add some Libraries to the Path. - let rustup_home = var(env::RUSTUP_HOME)?; - - join_paths( - std::iter::once( - Path::new(&rustup_home) - .join("toolchains") - .join(toolchain) - .join("bin"), - ) - .chain(split_paths(&path)), - )? - } else { - OsString::from(path) - } - }; - - let output = Command::new(driver) - .envs(vec![(env::PATH, path)]) - .args(&["-V"]) - .output()?; +fn is_outdated(opts: &crate::Dylint, toolchain: &str, driver: &Path) -> Result { + let mut command = dylint_internal::driver(toolchain, driver)?; + let output = command.args(&["-V"]).output()?; let stdout = std::str::from_utf8(&output.stdout)?; let theirs = stdout .trim_end() @@ -171,6 +145,7 @@ fn build(opts: &crate::Dylint, toolchain: &str, driver: &Path) -> Result<()> { .expect("Could not get parent directory") .join("driver") .to_string_lossy() + .replace('\\', "\\\\") ); let dylint_driver_spec = format!("{}{}", version_spec, path_spec); diff --git a/dylint/src/lib.rs b/dylint/src/lib.rs index 17580c9e5..e59c31c67 100644 --- a/dylint/src/lib.rs +++ b/dylint/src/lib.rs @@ -3,10 +3,7 @@ #![deny(clippy::panic)] use anyhow::{anyhow, bail, ensure, Context, Result}; -use dylint_internal::{ - env::{self, var}, - Command, -}; +use dylint_internal::env::{self, var}; use lazy_static::lazy_static; use std::{ collections::{BTreeMap, BTreeSet}, @@ -378,7 +375,8 @@ fn list_lints( // smoelius: `-W help` is the normal way to list lints, so we can be sure it // gets the lints loaded. However, we don't actually use it to list the lints. - Command::new(driver) + let mut command = dylint_internal::driver(toolchain, &driver)?; + command .envs(vec![ (env::DYLINT_LIBS.to_owned(), dylint_libs), (env::DYLINT_LIST.to_owned(), "1".to_owned()), diff --git a/dylint/src/metadata.rs b/dylint/src/metadata.rs index 91d714d62..5b0538cad 100644 --- a/dylint/src/metadata.rs +++ b/dylint/src/metadata.rs @@ -317,7 +317,7 @@ fn target_dir(metadata: &Metadata, package_root: &Path, package_id: PackageId) - } // smoelius: `pkg_dir` and `target_short_hash` are based on functions with the same names in -// https://github.com/rust-lang/cargo/blob/master/src/cargo/core/compiler/context/compilation_files.rs. +// https://github.com/rust-lang/cargo/blob/master/src/cargo/core/compiler/context/compilation_files.rs fn pkg_dir(package_root: &Path, pkg_id: PackageId) -> String { let name = pkg_id.name(); diff --git a/examples/allow_clippy/.cargo/config.toml b/examples/allow_clippy/.cargo/config.toml index a49056359..46e6d7d4b 100644 --- a/examples/allow_clippy/.cargo/config.toml +++ b/examples/allow_clippy/.cargo/config.toml @@ -6,3 +6,6 @@ linker = "dylint-link" [target.x86_64-unknown-linux-gnu] linker = "dylint-link" + +[target.x86_64-pc-windows-msvc] +linker = "dylint-link" diff --git a/examples/clippy/.cargo/config.toml b/examples/clippy/.cargo/config.toml index a49056359..46e6d7d4b 100644 --- a/examples/clippy/.cargo/config.toml +++ b/examples/clippy/.cargo/config.toml @@ -6,3 +6,6 @@ linker = "dylint-link" [target.x86_64-unknown-linux-gnu] linker = "dylint-link" + +[target.x86_64-pc-windows-msvc] +linker = "dylint-link" diff --git a/examples/env_literal/.cargo/config.toml b/examples/env_literal/.cargo/config.toml index a49056359..46e6d7d4b 100644 --- a/examples/env_literal/.cargo/config.toml +++ b/examples/env_literal/.cargo/config.toml @@ -6,3 +6,6 @@ linker = "dylint-link" [target.x86_64-unknown-linux-gnu] linker = "dylint-link" + +[target.x86_64-pc-windows-msvc] +linker = "dylint-link" diff --git a/examples/path_separator_in_string_literal/.cargo/config.toml b/examples/path_separator_in_string_literal/.cargo/config.toml index a49056359..46e6d7d4b 100644 --- a/examples/path_separator_in_string_literal/.cargo/config.toml +++ b/examples/path_separator_in_string_literal/.cargo/config.toml @@ -6,3 +6,6 @@ linker = "dylint-link" [target.x86_64-unknown-linux-gnu] linker = "dylint-link" + +[target.x86_64-pc-windows-msvc] +linker = "dylint-link" diff --git a/examples/path_separator_in_string_literal/src/lib.rs b/examples/path_separator_in_string_literal/src/lib.rs index 8f45d08b9..bee11e5f5 100644 --- a/examples/path_separator_in_string_literal/src/lib.rs +++ b/examples/path_separator_in_string_literal/src/lib.rs @@ -25,6 +25,13 @@ pub fn register_lints(_sess: &rustc_session::Session, lint_store: &mut rustc_lin fn ui() { dylint_testing::ui_test( env!("CARGO_PKG_NAME"), - &std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("ui"), + &std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join(&format!( + "ui_{}", + if cfg!(target_os = "windows") { + "windows" + } else { + "non_windows" + } + )), ); } diff --git a/examples/path_separator_in_string_literal/ui/main.rs b/examples/path_separator_in_string_literal/ui_non_windows/main.rs similarity index 100% rename from examples/path_separator_in_string_literal/ui/main.rs rename to examples/path_separator_in_string_literal/ui_non_windows/main.rs diff --git a/examples/path_separator_in_string_literal/ui/main.stderr b/examples/path_separator_in_string_literal/ui_non_windows/main.stderr similarity index 100% rename from examples/path_separator_in_string_literal/ui/main.stderr rename to examples/path_separator_in_string_literal/ui_non_windows/main.stderr diff --git a/examples/path_separator_in_string_literal/ui_windows/main.rs b/examples/path_separator_in_string_literal/ui_windows/main.rs new file mode 100644 index 000000000..0d6f78127 --- /dev/null +++ b/examples/path_separator_in_string_literal/ui_windows/main.rs @@ -0,0 +1,4 @@ +fn main() { + let _ = std::path::Path::new("..\\target"); + let _ = std::path::PathBuf::from("..\\target"); +} diff --git a/examples/path_separator_in_string_literal/ui_windows/main.stderr b/examples/path_separator_in_string_literal/ui_windows/main.stderr new file mode 100644 index 000000000..960b0724b --- /dev/null +++ b/examples/path_separator_in_string_literal/ui_windows/main.stderr @@ -0,0 +1,16 @@ +error: path separators in string literals is not portable + --> $DIR/main.rs:2:13 + | +LL | let _ = std::path::Path::new("../target"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `&std::path::Path::new("..").join("target")` + | + = note: `-D path-separator-in-string-literal` implied by `-D warnings` + +error: path separators in string literals is not portable + --> $DIR/main.rs:3:13 + | +LL | let _ = std::path::PathBuf::from("../target"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `std::path::PathBuf::from("..").join("target")` + +error: aborting due to 2 previous errors + diff --git a/examples/question_mark_in_expression/.cargo/config.toml b/examples/question_mark_in_expression/.cargo/config.toml index a49056359..46e6d7d4b 100644 --- a/examples/question_mark_in_expression/.cargo/config.toml +++ b/examples/question_mark_in_expression/.cargo/config.toml @@ -6,3 +6,6 @@ linker = "dylint-link" [target.x86_64-unknown-linux-gnu] linker = "dylint-link" + +[target.x86_64-pc-windows-msvc] +linker = "dylint-link" diff --git a/examples/try_io_result/.cargo/config.toml b/examples/try_io_result/.cargo/config.toml index a49056359..46e6d7d4b 100644 --- a/examples/try_io_result/.cargo/config.toml +++ b/examples/try_io_result/.cargo/config.toml @@ -6,3 +6,6 @@ linker = "dylint-link" [target.x86_64-unknown-linux-gnu] linker = "dylint-link" + +[target.x86_64-pc-windows-msvc] +linker = "dylint-link" diff --git a/internal/src/command.rs b/internal/src/command.rs index 53586068a..665d6af50 100644 --- a/internal/src/command.rs +++ b/internal/src/command.rs @@ -1,5 +1,7 @@ +use crate::env::{self, var}; use anyhow::{ensure, Result}; use std::{ + env::{join_paths, split_paths}, ffi::{OsStr, OsString}, path::Path, process::{Output, Stdio}, @@ -84,3 +86,31 @@ impl Command { Ok(()) } } + +pub fn driver(toolchain: &str, driver: &Path) -> Result { + let path = var(env::PATH)?; + + let path = { + if cfg!(target_os = "windows") { + // MinerSebas: To succesfully determine the dylint driver Version on Windows, + // it is neccesary to add some Libraries to the Path. + let rustup_home = var(env::RUSTUP_HOME)?; + + join_paths( + std::iter::once( + Path::new(&rustup_home) + .join("toolchains") + .join(toolchain) + .join("bin"), + ) + .chain(split_paths(&path)), + )? + } else { + OsString::from(path) + } + }; + + let mut command = Command::new(driver); + command.envs(vec![(env::PATH, path)]); + Ok(command) +} diff --git a/internal/src/testing.rs b/internal/src/testing.rs index 7ab90e668..a6db13de5 100644 --- a/internal/src/testing.rs +++ b/internal/src/testing.rs @@ -7,7 +7,7 @@ use std::{fs::OpenOptions, io::Write, path::Path}; const DYLINT_TEMPLATE_URL: &str = "https://github.com/trailofbits/dylint-template"; -const DYLINT_TEMPLATE_REV: &str = "6d6f2858874b254e41a26bab388eab0406a7e5e7"; +const DYLINT_TEMPLATE_REV: &str = "b4955a9ccb5193050e604e7a1670321a4dc0e26e"; pub fn checkout_dylint_template(path: &Path) -> Result<()> { crate::checkout(DYLINT_TEMPLATE_URL, DYLINT_TEMPLATE_REV, path)?; @@ -50,7 +50,12 @@ fn use_local_packages(path: &Path) -> Result<()> { .manifest_path .parent() .ok_or_else(|| anyhow!("Could not get parent"))?; - writeln!(file, r#"{} = {{ path = "{}" }}"#, package.name, path)?; + writeln!( + file, + r#"{} = {{ path = "{}" }}"#, + package.name, + path.to_string().replace('\\', "\\\\") + )?; } Ok(()) @@ -59,6 +64,6 @@ fn use_local_packages(path: &Path) -> Result<()> { fn allow_unused_extern_crates(path: &Path) -> Result<()> { find_and_replace( &path.join("src").join("lib.rs"), - &[r#"s/(?m)^#!\[warn\(unused_extern_crates\)\]\n//"#], + &[r#"s/(?m)^#!\[warn\(unused_extern_crates\)\]\r?\n//"#], ) } diff --git a/utils/testing/src/lib.rs b/utils/testing/src/lib.rs index 5db0f0017..1095728ce 100644 --- a/utils/testing/src/lib.rs +++ b/utils/testing/src/lib.rs @@ -123,17 +123,17 @@ fn linking_flags(metadata: &Metadata, package: &Package, target: &Target) -> Res let mut linking_flags = Vec::new(); - let mut iter = rustc_flags.iter(); + let mut iter = rustc_flags.into_iter(); while let Some(flag) = iter.next() { if flag.starts_with("--edition=") { linking_flags.push(flag); } else if flag == "--extern" || flag == "-L" { - let arg = next(flag, &mut iter)?; - linking_flags.extend_from_slice(&[flag, arg]); + let arg = next(&flag, &mut iter)?; + linking_flags.extend(vec![flag, arg.trim_matches('\'').to_owned()]); } } - Ok(linking_flags.into_iter().cloned().collect()) + Ok(linking_flags) } // smoelius: We need to recover the `rustc` flags used to build a target. I can see three options: