1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
use anyhow::{anyhow, bail, ensure, Context};
use cargo_metadata::{Metadata, MetadataCommand, Package};
use dlopen::utils::{PLATFORM_FILE_EXTENSION, PLATFORM_FILE_PREFIX};
use std::{
io::{BufRead, BufReader},
path::PathBuf,
process::{Command, Stdio},
};
use crate::args::CargoArguments;
pub fn get_metadata(args: &CargoArguments) -> cargo_metadata::Result<Metadata> {
let mut metadata_command = MetadataCommand::new();
if let Some(manifest_path) = &args.manifest_path {
metadata_command.manifest_path(manifest_path);
}
metadata_command.exec()
}
pub fn get_host_target() -> anyhow::Result<String> {
let output = Command::new("rustc")
.args(&["-Vv"])
.stdout(Stdio::piped())
.output()
.context("failed to spawn `rustc`")?;
ensure!(
output.status.success(),
"`rustc` exited with a failure code [{0}]",
output.status
);
let mut reader = BufReader::new(&output.stdout[..]);
let mut string = String::new();
while reader.read_line(&mut string)? != 0 {
if let Some(triple) = string.strip_prefix("host: ").map(|s| s.trim()) {
return Ok(triple.to_string());
}
string.clear();
}
Err(anyhow!(
"unable to find host target triple in rustc output: \n{}",
textwrap::indent(
&String::from_utf8(output.stdout)
.context("failed to parse in output from `rustc` as UTF-8")?,
" "
)
))
}
pub fn build_artifact<'a>(
cargo_args: &'a CargoArguments,
target_override: &str,
package: &'a Package,
) -> anyhow::Result<Option<PathBuf>> {
let mut build_command = Command::new(&cargo_args.cargo_path)
.args(
[
"rustc",
&format!("--target={}", target_override),
if cargo_args.offline { "--offline" } else { "" },
if cargo_args.release { "--release" } else { "" },
"--",
"--crate-type=dylib",
"--cfg=preflight",
]
.iter()
.filter(|x| !x.is_empty()),
)
.env("__PREFLIGHT", "")
.spawn()
.context("`cargo` failed to run to completion")?;
let status = build_command
.wait()
.context("`cargo` failed to run to completion")?;
let mut artifacts = glob::glob(&format!(
"target/{target}/{profile}/deps/{prefix}{package}*.{ext}",
target = target_override,
profile = if cargo_args.release {
"release"
} else {
"debug"
},
prefix = PLATFORM_FILE_PREFIX,
package = package.name,
ext = PLATFORM_FILE_EXTENSION
))
.context("Failed to read glob pattern")?
.collect::<Result<Vec<_>, _>>()
.context("Failed to get artifact path")?;
let artifact = match artifacts.len() {
0 | 1 => artifacts.pop(),
_ => bail!("found ambiguous dylib artifacts: {:?}", artifacts),
};
ensure!(
status.success(),
"`rustc` exited with a failure code [{0}]",
status
);
Ok(artifact)
}