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
115
116
117
118
use anyhow::{anyhow, Context, Result};
use fs_extra::dir::{copy, CopyOptions};
use std::{
fs,
path::{Path, PathBuf},
process::Command,
};
fn get_rustc_sysroot() -> Result<PathBuf> {
let rustc = Command::new("rustc")
.arg("--print")
.arg("sysroot")
.output()?;
let sysroot = PathBuf::from(
std::str::from_utf8(&rustc.stdout)
.context("Failed to convert sysroot path to utf-8")?
.trim(),
);
Ok(sysroot)
}
fn get_rustc_target_libdir(target: Option<&Path>) -> Result<PathBuf> {
let mut rustc = Command::new("rustc");
rustc.arg("--print").arg("target-libdir");
if let Some(target) = target {
rustc.arg("--target").arg(target);
}
let rustc = rustc.output()?;
let sysroot = PathBuf::from(
std::str::from_utf8(&rustc.stdout)
.context("Failed to convert sysroot path to utf-8")?
.trim(),
);
Ok(sysroot)
}
pub fn get_rust_src() -> Result<PathBuf> {
let root = get_rustc_sysroot()?;
let sys = root
.join("lib")
.join("rustlib")
.join("src")
.join("rust")
.join("library");
if root
.file_stem()
.and_then(|f| f.to_str())
.and_then(|s| s.split('-').next())
.context("Error parsing rust-src path")?
!= "nightly"
{
return Err(anyhow!(
"A nightly Rust version is required to build the sysroot"
));
}
Ok(sys)
}
#[allow(clippy::blocks_in_if_conditions)]
pub fn copy_host_tools(local_sysroot: &Path) -> Result<()> {
let root = get_rustc_target_libdir(None)?;
let host = root
.parent()
.and_then(|f| f.file_stem())
.and_then(|f| f.to_str())
.context("Error parsing host target triple")?;
let local_sysroot = local_sysroot.join("lib").join("rustlib").join(&host);
let src = root;
let src_meta = fs::metadata(&src)
.with_context(|| format!("Couldn't get metadata for {}", src.display()))?;
let to_meta = fs::metadata(&local_sysroot)
.with_context(|| format!("Couldn't get metadata for {}", local_sysroot.display()));
if let Ok(to_meta) = to_meta {
if to_meta.modified().with_context(|| {
format!(
"Couldn't get modification time for {}",
local_sysroot.display()
)
})? > src_meta.modified().with_context(|| {
format!(
"Couldn't get modification time for {}",
local_sysroot.display()
)
})? {
return Ok(());
}
}
let mut options = CopyOptions::new();
options.overwrite = true;
let local_sysroot = local_sysroot
.parent()
.context("Error getting local sysroot parent directory")?;
copy(&src, &local_sysroot, &options).with_context(|| {
format!(
"Couldn't copy from `{}` to `{}`",
src.display(),
local_sysroot.display()
)
})?;
Ok(())
}