Skip to content

Commit

Permalink
feat: Parse Cargo's --manifest-path option to determine mounted docker
Browse files Browse the repository at this point in the history
root

This commits adds support for parsing the `--manifest-path` option to cross. So
far, the `Cargo.toml` manifest of the crate (or its Cargo workspace) to compile
has been assumed to be in the current working directory. This means, that
relative crate dependencies were not supported, because those paths were not
mapped into the docker container.

Take the following example structure, where `my-bin` depends on `my-lib`:
.
├── my-bin
│   ├── Cargo.toml
│   └── src
│       └── main.rs
└── my-lib
    ├── Cargo.toml
    └── src
        └── lib.rs

This commits enables such scenarios, by running cross from `.` like so:
`cross build --manifest-path=my-lib/Cargo.toml --target x86_64-pc-windows-gnu`,
as `.` is mapped as the container's root, and the options passed through to
Cargo.

Related cross-rs#388 cross-rs#139 cross-rs#277 cross-rs#78

Co-authored-by: Kviring Alexey <alex@kviring.com>
  • Loading branch information
2 people authored and Emilgardis committed Apr 29, 2022
1 parent 2c90587 commit ba6549b
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 25 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
54 changes: 33 additions & 21 deletions src/cargo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,28 +64,40 @@ impl Root {
}

/// Cargo project root
pub fn root(cd: Option<&Path>) -> Result<Option<Root>> {
#[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<PathBuf>) -> Result<Option<Root>> {
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<Manifest> = serde_json::from_slice(&output.stdout)?;
Ok(manifest.map(|m| Root {
path: m.workspace_root,
}))
}
let output = command.output()?;
let manifest: Option<Manifest> = serde_json::from_slice(&output.stdout)?;
Ok(manifest.map(|m| Root {
path: m.workspace_root,
}))
}

/// Pass-through mode
Expand Down
19 changes: 18 additions & 1 deletion src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@ pub struct Args {
pub target: Option<Target>,
pub target_dir: Option<PathBuf>,
pub docker_in_docker: bool,
pub manifest_path: Option<PathBuf>,
}

pub fn parse(target_list: &TargetList) -> Args {
let mut channel = None;
let mut target = None;
let mut manifest_path: Option<PathBuf> = None;
let mut target_dir = None;
let mut sc = None;
let mut all: Vec<String> = Vec::new();
Expand All @@ -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);
Expand Down Expand Up @@ -73,5 +89,6 @@ pub fn parse(target_list: &TargetList) -> Args {
target,
target_dir,
docker_in_docker,
manifest_path,
}
}
5 changes: 3 additions & 2 deletions src/docker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ pub fn run(
args: &[String],
target_dir: &Option<PathBuf>,
root: &Root,
docker_root: &Path,
config: &Config,
uses_xargo: bool,
sysroot: &Path,
Expand Down Expand Up @@ -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")]
{
Expand Down Expand Up @@ -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() {
Expand Down
4 changes: 3 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ fn run() -> Result<ExitStatus> {

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);
Expand Down Expand Up @@ -394,11 +394,13 @@ fn run() -> Result<ExitStatus> {
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,
Expand Down

0 comments on commit ba6549b

Please sign in to comment.