Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cargo build --out-dir #5203

Merged
merged 4 commits into from
Apr 3, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/bin/command_prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ pub trait ArgMatchesExt {
message_format,
target_rustdoc_args: None,
target_rustc_args: None,
export_dir: None,
};
Ok(opts)
}
Expand Down
9 changes: 8 additions & 1 deletion src/bin/commands/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ pub fn cli() -> App {
.arg_release("Build artifacts in release mode, with optimizations")
.arg_features()
.arg_target_triple("Build for the target triple")
.arg(opt("out-dir", "Copy final artifacts to this directory").value_name("PATH"))
.arg_manifest_path()
.arg_message_format()
.after_help(
Expand All @@ -49,7 +50,13 @@ the --release flag will use the `release` profile instead.

pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
let ws = args.workspace(config)?;
let compile_opts = args.compile_options(config, CompileMode::Build)?;
let mut compile_opts = args.compile_options(config, CompileMode::Build)?;
compile_opts.export_dir = args.value_of_path("out-dir", config);
if compile_opts.export_dir.is_some() && !config.cli_unstable().out_dir {
Err(format_err!(
"`--out-dir` flag is unstable, pass `-Z out-dir` to enable it"
))?;
};
ops::compile(&ws, &compile_opts)?;
Ok(())
}
2 changes: 2 additions & 0 deletions src/cargo/core/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,7 @@ pub struct CliUnstable {
pub no_index_update: bool,
pub avoid_dev_deps: bool,
pub minimal_versions: bool,
pub out_dir: bool,
}

impl CliUnstable {
Expand Down Expand Up @@ -319,6 +320,7 @@ impl CliUnstable {
"no-index-update" => self.no_index_update = true,
"avoid-dev-deps" => self.avoid_dev_deps = true,
"minimal-versions" => self.minimal_versions = true,
"out-dir" => self.out_dir = true,
_ => bail!("unknown `-Z` flag specified: {}", k),
}

Expand Down
1 change: 1 addition & 0 deletions src/cargo/ops/cargo_clean.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ pub fn clean(ws: &Workspace, opts: &CleanOptions) -> CargoResult<()> {
..BuildConfig::default()
},
profiles,
None,
&units,
)?;

Expand Down
10 changes: 9 additions & 1 deletion src/cargo/ops/cargo_compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ pub struct CompileOptions<'a> {
/// The specified target will be compiled with all the available arguments,
/// note that this only accounts for the *final* invocation of rustc
pub target_rustc_args: Option<Vec<String>>,
/// The directory to copy final artifacts to. Note that even if `out_dir` is
/// set, a copy of artifacts still could be found a `target/(debug\release)`
/// as usual.
// Note that, although the cmd-line flag name is `out-dir`, in code we use
// `export_dir`, to avoid confusion with out dir at `target/debug/deps`.
pub export_dir: Option<PathBuf>,
}

impl<'a> CompileOptions<'a> {
Expand All @@ -84,6 +90,7 @@ impl<'a> CompileOptions<'a> {
message_format: MessageFormat::Human,
target_rustdoc_args: None,
target_rustc_args: None,
export_dir: None,
}
}
}
Expand Down Expand Up @@ -233,6 +240,7 @@ pub fn compile_ws<'a>(
ref filter,
ref target_rustdoc_args,
ref target_rustc_args,
ref export_dir,
} = *options;

let target = match target {
Expand Down Expand Up @@ -330,7 +338,6 @@ pub fn compile_ws<'a>(
package_targets.push((to_build, vec![(target, profile)]));
}
}

let mut ret = {
let _p = profile::start("compiling");
let mut build_config = scrape_build_config(config, jobs, target)?;
Expand All @@ -349,6 +356,7 @@ pub fn compile_ws<'a>(
config,
build_config,
profiles,
export_dir.clone(),
&exec,
)?
};
Expand Down
1 change: 1 addition & 0 deletions src/cargo/ops/cargo_package.rs
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,7 @@ fn run_verify(ws: &Workspace, tar: &FileLock, opts: &PackageOpts) -> CargoResult
mode: ops::CompileMode::Build,
target_rustdoc_args: None,
target_rustc_args: None,
export_dir: None,
},
Arc::new(DefaultExecutor),
)?;
Expand Down
12 changes: 12 additions & 0 deletions src/cargo/ops/cargo_rustc/context/compilation_files.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ pub struct CompilationFiles<'a, 'cfg: 'a> {
pub(super) host: Layout,
/// The target directory layout for the target (if different from then host)
pub(super) target: Option<Layout>,
export_dir: Option<(PathBuf, Vec<Unit<'a>>)>,
ws: &'a Workspace<'cfg>,
metas: HashMap<Unit<'a>, Option<Metadata>>,
/// For each Unit, a list all files produced.
Expand All @@ -49,6 +50,7 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> {
roots: &[Unit<'a>],
host: Layout,
target: Option<Layout>,
export_dir: Option<PathBuf>,
ws: &'a Workspace<'cfg>,
cx: &Context<'a, 'cfg>,
) -> CompilationFiles<'a, 'cfg> {
Expand All @@ -65,6 +67,7 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> {
ws,
host,
target,
export_dir: export_dir.map(|dir| (dir, roots.to_vec())),
metas,
outputs,
}
Expand Down Expand Up @@ -107,6 +110,15 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> {
}
}

pub fn export_dir(&self, unit: &Unit<'a>) -> Option<PathBuf> {
let &(ref dir, ref roots) = self.export_dir.as_ref()?;
if roots.contains(unit) {
Some(dir.clone())
} else {
None
}
}

pub fn pkg_dir(&self, unit: &Unit<'a>) -> String {
let name = unit.pkg.package_id().name();
match self.metas[unit] {
Expand Down
5 changes: 3 additions & 2 deletions src/cargo/ops/cargo_rustc/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use std::collections::{HashMap, HashSet};
use std::env;
use std::path::Path;
use std::path::{Path, PathBuf};
use std::str::{self, FromStr};
use std::sync::Arc;

Expand Down Expand Up @@ -105,6 +105,7 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
config: &'cfg Config,
build_config: BuildConfig,
profiles: &'a Profiles,
export_dir: Option<PathBuf>,
units: &[Unit<'a>],
) -> CargoResult<Context<'a, 'cfg>> {
let dest = if build_config.release {
Expand Down Expand Up @@ -164,7 +165,7 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
cx.probe_target_info()?;
let deps = build_unit_dependencies(units, &cx)?;
cx.unit_dependencies = deps;
let files = CompilationFiles::new(units, host_layout, target_layout, ws, &cx);
let files = CompilationFiles::new(units, host_layout, target_layout, export_dir, ws, &cx);
cx.files = Some(files);
Ok(cx)
}
Expand Down
86 changes: 52 additions & 34 deletions src/cargo/ops/cargo_rustc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::env;
use std::ffi::{OsStr, OsString};
use std::fs;
use std::io::{self, Write};
use std::path::{self, PathBuf};
use std::path::{self, Path, PathBuf};
use std::sync::Arc;

use same_file::is_same_file;
Expand Down Expand Up @@ -141,6 +141,7 @@ pub fn compile_targets<'a, 'cfg: 'a>(
config: &'cfg Config,
build_config: BuildConfig,
profiles: &'a Profiles,
export_dir: Option<PathBuf>,
exec: &Arc<Executor>,
) -> CargoResult<Compilation<'cfg>> {
let units = pkg_targets
Expand Down Expand Up @@ -171,6 +172,7 @@ pub fn compile_targets<'a, 'cfg: 'a>(
config,
build_config,
profiles,
export_dir,
&units,
)?;

Expand Down Expand Up @@ -569,6 +571,7 @@ fn link_targets<'a, 'cfg>(
fresh: bool,
) -> CargoResult<Work> {
let outputs = cx.outputs(unit)?;
let export_dir = cx.files().export_dir(unit);
let package_id = unit.pkg.package_id().clone();
let target = unit.target.clone();
let profile = unit.profile.clone();
Expand Down Expand Up @@ -600,41 +603,14 @@ fn link_targets<'a, 'cfg>(
}
};
destinations.push(dst.display().to_string());
hardlink_or_copy(&src, &dst)?;
if let Some(ref path) = export_dir {
if !path.exists() {
fs::create_dir_all(path)?;
}

debug!("linking {} to {}", src.display(), dst.display());
if is_same_file(src, dst).unwrap_or(false) {
continue;
}
if dst.exists() {
paths::remove_file(&dst)?;
hardlink_or_copy(&src, &path.join(dst.file_name().unwrap()))?;
}

let link_result = if src.is_dir() {
#[cfg(unix)]
use std::os::unix::fs::symlink;
#[cfg(target_os = "redox")]
use std::os::redox::fs::symlink;
#[cfg(windows)]
use std::os::windows::fs::symlink_dir as symlink;

let dst_dir = dst.parent().unwrap();
assert!(src.starts_with(dst_dir));
symlink(src.strip_prefix(dst_dir).unwrap(), dst)
} else {
fs::hard_link(src, dst)
};
link_result
.or_else(|err| {
debug!("link failed {}. falling back to fs::copy", err);
fs::copy(src, dst).map(|_| ())
})
.chain_err(|| {
format!(
"failed to link or copy `{}` to `{}`",
src.display(),
dst.display()
)
})?;
}

if json_messages {
Expand All @@ -651,6 +627,48 @@ fn link_targets<'a, 'cfg>(
}))
}

fn hardlink_or_copy(src: &Path, dst: &Path) -> CargoResult<()> {
debug!("linking {} to {}", src.display(), dst.display());
if is_same_file(src, dst).unwrap_or(false) {
return Ok(());
}
if dst.exists() {
paths::remove_file(&dst)?;
}

let link_result = if src.is_dir() {
#[cfg(unix)]
use std::os::unix::fs::symlink;
#[cfg(target_os = "redox")]
use std::os::redox::fs::symlink;
#[cfg(windows)]
use std::os::windows::fs::symlink_dir as symlink;

let dst_dir = dst.parent().unwrap();
let src = if src.starts_with(dst_dir) {
src.strip_prefix(dst_dir).unwrap()
} else {
src
};
symlink(src, dst)
} else {
fs::hard_link(src, dst)
};
link_result
.or_else(|err| {
debug!("link failed {}. falling back to fs::copy", err);
fs::copy(src, dst).map(|_| ())
})
.chain_err(|| {
format!(
"failed to link or copy `{}` to `{}`",
src.display(),
dst.display()
)
})?;
Ok(())
}

fn load_build_deps(cx: &Context, unit: &Unit) -> Option<Arc<BuildScripts>> {
cx.build_scripts.get(unit).cloned()
}
Expand Down
2 changes: 1 addition & 1 deletion src/cargo/util/toml/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use url::Url;

use core::{GitReference, PackageIdSpec, Profiles, SourceId, WorkspaceConfig, WorkspaceRootConfig};
use core::{Dependency, Manifest, PackageId, Summary, Target};
use core::{EitherManifest, Edition, Feature, Features, VirtualManifest};
use core::{Edition, EitherManifest, Feature, Features, VirtualManifest};
use core::dependency::{Kind, Platform};
use core::manifest::{LibKind, Lto, ManifestMetadata, Profile};
use sources::CRATES_IO;
Expand Down
1 change: 1 addition & 0 deletions tests/testsuite/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ mod login;
mod metadata;
mod net_config;
mod new;
mod out_dir;
mod overrides;
mod package;
mod patch;
Expand Down
Loading