Skip to content

Commit 72ffc4e

Browse files
wngravkviring
authored andcommitted
feat: Parse Cargo's --manifest-path option to determine mounted docker
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 <[email protected]>
1 parent 7b81334 commit 72ffc4e

File tree

6 files changed

+61
-25
lines changed

6 files changed

+61
-25
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
55

66
## [Unreleased]
77

8+
- #494 - Parse Cargo's --manifest-path option to determine mounted docker root
89
- #718 - remove deb subcommand.
910
- #714 - use host target directory when falling back to host cargo.
1011
- #713 - convert relative target directories to absolute paths.

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,9 @@ $ QEMU_STRACE=1 cross run --target aarch64-unknown-linux-gnu
356356
- path dependencies (in Cargo.toml) that point outside the Cargo project won't
357357
work because `cross` use docker containers only mounts the Cargo project so
358358
the container doesn't have access to the rest of the filesystem.
359+
However, you may use Cargo's `--manifest-path` option to reference your
360+
target crate, executed from a common root directory from which all your
361+
dependencies are available.
359362

360363
## Minimum Supported Rust Version (MSRV)
361364

src/cargo.rs

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -62,28 +62,40 @@ impl Root {
6262
}
6363

6464
/// Cargo project root
65-
pub fn root(cd: Option<&Path>) -> Result<Option<Root>> {
66-
#[derive(Deserialize)]
67-
struct Manifest {
68-
workspace_root: PathBuf,
69-
}
70-
let mut command = std::process::Command::new(
71-
std::env::var("CARGO")
72-
.ok()
73-
.unwrap_or_else(|| "cargo".to_string()),
74-
);
75-
command
76-
.arg("metadata")
77-
.arg("--format-version=1")
78-
.arg("--no-deps");
79-
if let Some(cd) = cd {
80-
command.current_dir(cd);
65+
pub fn root(cd: Option<&Path>, manifest_path: Option<PathBuf>) -> Result<Option<Root>> {
66+
if let Some(manifest_path) = manifest_path {
67+
if !manifest_path.is_file() {
68+
eyre::bail!("No manifest found at \"{}\"", manifest_path.display());
69+
}
70+
return Ok(Some(Root {
71+
path: manifest_path
72+
.parent()
73+
.expect("File must have a parent")
74+
.to_owned(),
75+
}));
76+
} else {
77+
#[derive(Deserialize)]
78+
struct Manifest {
79+
workspace_root: PathBuf,
80+
}
81+
let mut command = std::process::Command::new(
82+
std::env::var("CARGO")
83+
.ok()
84+
.unwrap_or_else(|| "cargo".to_string()),
85+
);
86+
command
87+
.arg("metadata")
88+
.arg("--format-version=1")
89+
.arg("--no-deps");
90+
if let Some(cd) = cd {
91+
command.current_dir(cd);
92+
}
93+
let output = command.output()?;
94+
let manifest: Option<Manifest> = serde_json::from_slice(&output.stdout)?;
95+
Ok(manifest.map(|m| Root {
96+
path: m.workspace_root,
97+
}))
8198
}
82-
let output = command.output()?;
83-
let manifest: Option<Manifest> = serde_json::from_slice(&output.stdout)?;
84-
Ok(manifest.map(|m| Root {
85-
path: m.workspace_root,
86-
}))
8799
}
88100

89101
/// Pass-through mode

src/cli.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ pub struct Args {
1414
pub target: Option<Target>,
1515
pub target_dir: Option<PathBuf>,
1616
pub docker_in_docker: bool,
17+
pub manifest_path: Option<PathBuf>,
1718
}
1819

1920
// Fix for issue #581. target_dir must be absolute.
@@ -28,6 +29,7 @@ fn absolute_path(path: PathBuf) -> Result<PathBuf> {
2829
pub fn parse(target_list: &TargetList) -> Result<Args> {
2930
let mut channel = None;
3031
let mut target = None;
32+
let mut manifest_path: Option<PathBuf> = None;
3133
let mut target_dir = None;
3234
let mut sc = None;
3335
let mut all: Vec<String> = Vec::new();
@@ -38,7 +40,21 @@ pub fn parse(target_list: &TargetList) -> Result<Args> {
3840
if arg.is_empty() {
3941
continue;
4042
}
41-
if let ("+", ch) = arg.split_at(1) {
43+
if arg == "--manifest-path" {
44+
all.push(arg);
45+
if let Some(m) = args.next() {
46+
let p = PathBuf::from(&m);
47+
all.push(m);
48+
manifest_path = env::current_dir().ok().map(|cwd| cwd.join(p));
49+
}
50+
} else if arg.starts_with("--manifest-path=") {
51+
manifest_path = arg
52+
.split_once('=')
53+
.map(|x| x.1)
54+
.map(PathBuf::from)
55+
.and_then(|p| env::current_dir().ok().map(|cwd| cwd.join(p)));
56+
all.push(arg);
57+
} else if let ("+", ch) = arg.split_at(1) {
4258
channel = Some(ch.to_string());
4359
} else if arg == "--target" {
4460
all.push(arg);
@@ -83,5 +99,6 @@ pub fn parse(target_list: &TargetList) -> Result<Args> {
8399
target,
84100
target_dir,
85101
docker_in_docker,
102+
manifest_path,
86103
})
87104
}

src/docker.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ pub fn run(
5858
args: &[String],
5959
target_dir: &Option<PathBuf>,
6060
root: &Root,
61+
docker_root: &Path,
6162
config: &Config,
6263
uses_xargo: bool,
6364
sysroot: &Path,
@@ -89,7 +90,7 @@ pub fn run(
8990
let cargo_dir = mount_finder.find_mount_path(cargo_dir);
9091
let xargo_dir = mount_finder.find_mount_path(xargo_dir);
9192
let target_dir = mount_finder.find_mount_path(target_dir);
92-
let host_root = mount_finder.find_mount_path(root);
93+
let host_root = mount_finder.find_mount_path(docker_root);
9394
let mount_root: PathBuf;
9495
#[cfg(target_os = "windows")]
9596
{
@@ -247,7 +248,7 @@ pub fn run(
247248
} else {
248249
// We do this to avoid clashes with path separators. Windows uses `\` as a path separator on Path::join
249250
let cwd = &std::env::current_dir()?;
250-
let working_dir = Path::new("project").join(cwd.strip_prefix(root)?);
251+
let working_dir = Path::new("project").join(cwd.strip_prefix(docker_root)?);
251252
// No [T].join for OsStr
252253
let mut mount_wd = std::ffi::OsString::new();
253254
for part in working_dir.iter() {

src/main.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ fn run() -> Result<ExitStatus> {
279279

280280
let host_version_meta =
281281
rustc_version::version_meta().wrap_err("couldn't fetch the `rustc` version")?;
282-
if let Some(root) = cargo::root(None)? {
282+
if let Some(root) = cargo::root(None, args.manifest_path)? {
283283
let host = host_version_meta.host();
284284
let toml = toml(&root)?;
285285
let config = Config::new(toml);
@@ -394,11 +394,13 @@ fn run() -> Result<ExitStatus> {
394394
docker::register(&target, verbose)?
395395
}
396396

397+
let docker_root = env::current_dir()?;
397398
return docker::run(
398399
&target,
399400
&filtered_args,
400401
&args.target_dir,
401402
&root,
403+
&docker_root,
402404
&config,
403405
uses_xargo,
404406
&sysroot,

0 commit comments

Comments
 (0)