diff --git a/CHANGELOG.md b/CHANGELOG.md index 4569e18f0..c9d0d2fd9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +- #494 - Parse Cargo's --manifest-path option to determine mounted docker root - #696 - bump freebsd to 12.3 - #629 - Update Android NDK version and API version - #681 - Warn on unknown fields and confusable targets diff --git a/README.md b/README.md index a9ecfd16b..1ecf7c313 100644 --- a/README.md +++ b/README.md @@ -355,6 +355,9 @@ $ QEMU_STRACE=1 cross run --target aarch64-unknown-linux-gnu - path dependencies (in Cargo.toml) that point outside the Cargo project won't work because `cross` use docker containers only mounts the Cargo project so the container doesn't have access to the rest of the filesystem. + However, you may use Cargo's `--manifest-path` option to reference your + target crate, executed from a common root directory from which all your + dependencies are available. ## Minimum Supported Rust Version (MSRV) diff --git a/src/cargo.rs b/src/cargo.rs index 947fee36f..d32c08c1a 100644 --- a/src/cargo.rs +++ b/src/cargo.rs @@ -64,28 +64,40 @@ impl Root { } /// Cargo project root -pub fn root(cd: Option<&Path>) -> Result> { - #[derive(Deserialize)] - struct Manifest { - workspace_root: PathBuf, - } - let mut command = std::process::Command::new( - std::env::var("CARGO") - .ok() - .unwrap_or_else(|| "cargo".to_string()), - ); - command - .arg("metadata") - .arg("--format-version=1") - .arg("--no-deps"); - if let Some(cd) = cd { - command.current_dir(cd); +pub fn root(cd: Option<&Path>, manifest_path: Option) -> Result> { + if let Some(manifest_path) = manifest_path { + if !manifest_path.is_file() { + eyre::bail!("No manifest found at \"{}\"", manifest_path.display()); + } + return Ok(Some(Root { + path: manifest_path + .parent() + .expect("File must have a parent") + .to_owned(), + })); + } else { + #[derive(Deserialize)] + struct Manifest { + workspace_root: PathBuf, + } + let mut command = std::process::Command::new( + std::env::var("CARGO") + .ok() + .unwrap_or_else(|| "cargo".to_string()), + ); + command + .arg("metadata") + .arg("--format-version=1") + .arg("--no-deps"); + if let Some(cd) = cd { + command.current_dir(cd); + } + let output = command.output()?; + let manifest: Option = serde_json::from_slice(&output.stdout)?; + Ok(manifest.map(|m| Root { + path: m.workspace_root, + })) } - let output = command.output()?; - let manifest: Option = serde_json::from_slice(&output.stdout)?; - Ok(manifest.map(|m| Root { - path: m.workspace_root, - })) } /// Pass-through mode diff --git a/src/cli.rs b/src/cli.rs index f62ee82de..91c0c83f0 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -13,11 +13,13 @@ pub struct Args { pub target: Option, pub target_dir: Option, pub docker_in_docker: bool, + pub manifest_path: Option, } pub fn parse(target_list: &TargetList) -> Args { let mut channel = None; let mut target = None; + let mut manifest_path: Option = None; let mut target_dir = None; let mut sc = None; let mut all: Vec = Vec::new(); @@ -28,7 +30,21 @@ pub fn parse(target_list: &TargetList) -> Args { if arg.is_empty() { continue; } - if let ("+", ch) = arg.split_at(1) { + if arg == "--manifest-path" { + all.push(arg); + if let Some(m) = args.next() { + let p = PathBuf::from(&m); + all.push(m); + manifest_path = env::current_dir().ok().map(|cwd| cwd.join(p)); + } + } else if arg.starts_with("--manifest-path=") { + manifest_path = arg + .split_once('=') + .map(|x| x.1) + .map(PathBuf::from) + .and_then(|p| env::current_dir().ok().map(|cwd| cwd.join(p))); + all.push(arg); + } else if let ("+", ch) = arg.split_at(1) { channel = Some(ch.to_string()); } else if arg == "--target" { all.push(arg); @@ -73,5 +89,6 @@ pub fn parse(target_list: &TargetList) -> Args { target, target_dir, docker_in_docker, + manifest_path, } } diff --git a/src/docker.rs b/src/docker.rs index aa2da7348..cac40162b 100644 --- a/src/docker.rs +++ b/src/docker.rs @@ -58,6 +58,7 @@ pub fn run( args: &[String], target_dir: &Option, root: &Root, + docker_root: &Path, config: &Config, uses_xargo: bool, sysroot: &Path, @@ -89,7 +90,7 @@ pub fn run( let cargo_dir = mount_finder.find_mount_path(cargo_dir); let xargo_dir = mount_finder.find_mount_path(xargo_dir); let target_dir = mount_finder.find_mount_path(target_dir); - let host_root = mount_finder.find_mount_path(root); + let host_root = mount_finder.find_mount_path(docker_root); let mount_root: PathBuf; #[cfg(target_os = "windows")] { @@ -247,7 +248,7 @@ pub fn run( } else { // We do this to avoid clashes with path separators. Windows uses `\` as a path separator on Path::join let cwd = &std::env::current_dir()?; - let working_dir = Path::new("project").join(cwd.strip_prefix(root)?); + let working_dir = Path::new("project").join(cwd.strip_prefix(docker_root)?); // No [T].join for OsStr let mut mount_wd = std::ffi::OsString::new(); for part in working_dir.iter() { diff --git a/src/main.rs b/src/main.rs index 1d019d037..5e8e3377f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -279,7 +279,7 @@ fn run() -> Result { let host_version_meta = rustc_version::version_meta().wrap_err("couldn't fetch the `rustc` version")?; - if let Some(root) = cargo::root(None)? { + if let Some(root) = cargo::root(None, args.manifest_path)? { let host = host_version_meta.host(); let toml = toml(&root)?; let config = Config::new(toml); @@ -394,11 +394,13 @@ fn run() -> Result { docker::register(&target, verbose)? } + let docker_root = env::current_dir()?; return docker::run( &target, &filtered_args, &args.target_dir, &root, + &docker_root, &config, uses_xargo, &sysroot,