diff --git a/Cargo.toml b/Cargo.toml index ba661a077..99ab958ab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,12 +23,13 @@ atty = "0.2" bytesize = "1.0" cargo-platform = { path = "crates/cargo-platform", version = "0.1.1" } crates-io = { path = "crates/crates-io", version = "0.31" } +crossbeam-channel = "0.4" crossbeam-utils = "0.7" crypto-hash = "0.3.1" curl = { version = "0.4.23", features = ["http2"] } curl-sys = "0.4.22" env_logger = "0.7.0" -pretty_env_logger = { version = "0.3", optional = true } +pretty_env_logger = { version = "0.4", optional = true } anyhow = "1.0" filetime = "0.2" flate2 = { version = "1.0.3", features = ["zlib"] } diff --git a/src/bin/cargo/commands/build.rs b/src/bin/cargo/commands/build.rs index df3a69c18..1ab83848b 100644 --- a/src/bin/cargo/commands/build.rs +++ b/src/bin/cargo/commands/build.rs @@ -63,7 +63,12 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { ProfileChecking::Checked, )?; - compile_opts.export_dir = args.value_of_path("out-dir", config); + if let Some(out_dir) = args.value_of_path("out-dir", config) { + compile_opts.export_dir = Some(out_dir); + } else if let Some(out_dir) = config.build_config()?.out_dir.as_ref() { + let out_dir = out_dir.resolve_path(config); + compile_opts.export_dir = Some(out_dir); + } if compile_opts.export_dir.is_some() { config .cli_unstable() diff --git a/src/cargo/core/compiler/job_queue.rs b/src/cargo/core/compiler/job_queue.rs index 55832cb90..559549117 100644 --- a/src/cargo/core/compiler/job_queue.rs +++ b/src/cargo/core/compiler/job_queue.rs @@ -54,11 +54,11 @@ use std::collections::{BTreeMap, HashMap, HashSet}; use std::io; use std::marker; use std::mem; -use std::sync::mpsc::{channel, Receiver, Sender}; use std::sync::Arc; use std::time::Duration; use anyhow::format_err; +use crossbeam_channel::{unbounded, Receiver, Sender}; use crossbeam_utils::thread::Scope; use jobserver::{Acquired, Client, HelperThread}; use log::{debug, info, trace}; @@ -341,7 +341,7 @@ impl<'a, 'cfg> JobQueue<'a, 'cfg> { let _p = profile::start("executing the job graph"); self.queue.queue_finished(); - let (tx, rx) = channel(); + let (tx, rx) = unbounded(); let progress = Progress::with_style("Building", ProgressStyle::Ratio, cx.bcx.config); let state = DrainState { total_units: self.queue.len(), diff --git a/src/cargo/core/workspace.rs b/src/cargo/core/workspace.rs index b34ea9aca..c2cb23a8f 100644 --- a/src/cargo/core/workspace.rs +++ b/src/cargo/core/workspace.rs @@ -829,6 +829,10 @@ impl<'cfg> Workspace<'cfg> { } Ok(()) } + + pub fn set_target_dir(&mut self, target_dir: Filesystem) { + self.target_dir = Some(target_dir); + } } impl<'cfg> Packages<'cfg> { diff --git a/src/cargo/ops/cargo_install.rs b/src/cargo/ops/cargo_install.rs index a2c5565e7..505b940e8 100644 --- a/src/cargo/ops/cargo_install.rs +++ b/src/cargo/ops/cargo_install.rs @@ -200,31 +200,35 @@ fn install_one( )? }; - let mut td_opt = None; - let mut needs_cleanup = false; - let overidden_target_dir = if source_id.is_path() { - None - } else if let Some(dir) = config.target_dir()? { - Some(dir) - } else if let Ok(td) = TempFileBuilder::new().prefix("cargo-install").tempdir() { - let p = td.path().to_owned(); - td_opt = Some(td); - Some(Filesystem::new(p)) + let (mut ws, git_package) = if source_id.is_git() { + // Don't use ws.current() in order to keep the package source as a git source so that + // install tracking uses the correct source. + (Workspace::new(pkg.manifest_path(), config)?, Some(&pkg)) + } else if source_id.is_path() { + (Workspace::new(pkg.manifest_path(), config)?, None) } else { - needs_cleanup = true; - Some(Filesystem::new(config.cwd().join("target-install"))) - }; - - let mut ws = match overidden_target_dir { - Some(dir) => Workspace::ephemeral(pkg, config, Some(dir), false)?, - None => { - let mut ws = Workspace::new(pkg.manifest_path(), config)?; - ws.set_require_optional_deps(false); - ws - } + (Workspace::ephemeral(pkg, config, None, false)?, None) }; ws.set_ignore_lock(config.lock_update_allowed()); - let pkg = ws.current()?; + ws.set_require_optional_deps(false); + + let mut td_opt = None; + let mut needs_cleanup = false; + if !source_id.is_path() { + let target_dir = if let Some(dir) = config.target_dir()? { + dir + } else if let Ok(td) = TempFileBuilder::new().prefix("cargo-install").tempdir() { + let p = td.path().to_owned(); + td_opt = Some(td); + Filesystem::new(p) + } else { + needs_cleanup = true; + Filesystem::new(config.cwd().join("target-install")) + }; + ws.set_target_dir(target_dir); + } + + let pkg = git_package.map_or_else(|| ws.current(), |pkg| Ok(pkg))?; if from_cwd { if pkg.manifest().edition() == Edition::Edition2015 { diff --git a/src/cargo/util/config/mod.rs b/src/cargo/util/config/mod.rs index 105aea2a2..39bf92b0a 100644 --- a/src/cargo/util/config/mod.rs +++ b/src/cargo/util/config/mod.rs @@ -1643,6 +1643,7 @@ pub struct CargoBuildConfig { pub rustc_wrapper: Option, pub rustc: Option, pub rustdoc: Option, + pub out_dir: Option, } /// A type to deserialize a list of strings from a toml file. diff --git a/src/doc/src/reference/unstable.md b/src/doc/src/reference/unstable.md index efe8ac545..cace3c973 100644 --- a/src/doc/src/reference/unstable.md +++ b/src/doc/src/reference/unstable.md @@ -76,6 +76,13 @@ directory. Example: cargo +nightly build --out-dir=out -Z unstable-options ``` +This can also be specified in `.cargo/config` files. + +```toml +[build] +out-dir = "out" +``` + ### doctest-xcompile * Tracking Issue: [#7040](https://github.com/rust-lang/cargo/issues/7040) * Tracking Rustc Issue: [#64245](https://github.com/rust-lang/rust/issues/64245) diff --git a/tests/testsuite/install.rs b/tests/testsuite/install.rs index 98dd12fe2..c2777f85a 100644 --- a/tests/testsuite/install.rs +++ b/tests/testsuite/install.rs @@ -316,10 +316,10 @@ fn multiple_crates_git_all() { let p = git::repo(&paths::root().join("foo")) .file( "Cargo.toml", - r#"\ -[workspace] -members = ["bin1", "bin2"] -"#, + r#" + [workspace] + members = ["bin1", "bin2"] + "#, ) .file("bin1/Cargo.toml", &basic_manifest("bin1", "0.1.0")) .file("bin2/Cargo.toml", &basic_manifest("bin2", "0.1.0")) @@ -1422,3 +1422,29 @@ fn install_version_req() { .with_stderr_contains("[INSTALLING] foo v0.0.3") .run(); } + +#[cargo_test] +fn git_install_reads_workspace_manifest() { + let p = git::repo(&paths::root().join("foo")) + .file( + "Cargo.toml", + r#" + [workspace] + members = ["bin1"] + + [profile.release] + incremental = 3 + "#, + ) + .file("bin1/Cargo.toml", &basic_manifest("bin1", "0.1.0")) + .file( + "bin1/src/main.rs", + r#"fn main() { println!("Hello, world!"); }"#, + ) + .build(); + + cargo_process(&format!("install --git {}", p.url().to_string())) + .with_status(101) + .with_stderr_contains(" invalid type: integer `3`[..]") + .run(); +} diff --git a/tests/testsuite/out_dir.rs b/tests/testsuite/out_dir.rs index 9c2f774fa..77079cb41 100644 --- a/tests/testsuite/out_dir.rs +++ b/tests/testsuite/out_dir.rs @@ -246,6 +246,30 @@ fn avoid_build_scripts() { ); } +#[cargo_test] +fn cargo_build_out_dir() { + let p = project() + .file("src/main.rs", r#"fn main() { println!("Hello, World!") }"#) + .file( + ".cargo/config", + r#" + [build] + out-dir = "out" + "#, + ) + .build(); + + p.cargo("build -Z unstable-options") + .masquerade_as_nightly_cargo() + .run(); + check_dir_contents( + &p.root().join("out"), + &["foo"], + &["foo", "foo.dSYM"], + &["foo.exe", "foo.pdb"], + ); +} + fn check_dir_contents( out_dir: &Path, expected_linux: &[&str],