Skip to content

Commit 0ef25c4

Browse files
committed
Do a better job of cleaning up copied sysroot directories (e.g. includes)
Previously, the sysroot build copied include files from several different directories into the final sysroot include dir, but did not do anything to reset the state of the include directory. If the same sysroot dir was used to build sysroots from multiple different versions of hyperlight-libc, since the headers provided are different, downstream code would get a confusing (and likely to fail to compile) mix of the include files from the two libcs. This changes the way that the include directory (and other copied sysroot directories) are constructed, to ensure that stale files are removed as well as new files being copied. In a somewhat-related issue, when building a C sysroot, cargo-hyperlight needs to build hyperlight-libc (as part of hyperlight-guest-capi), and it turns out that that build was itself getting the output include directory, which meant that rebuidls could also result in stale include files being added. This commit changes the logic involved in building hyperlight-guest-capi to ensure that the output sysroot include directory (which is not yet populated) isn't on the include path. Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com>
1 parent 8d68abc commit 0ef25c4

7 files changed

Lines changed: 88 additions & 45 deletions

File tree

src/command.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ impl Debug for Command {
6464
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
6565
let args = self.build_args_infallible();
6666
let mut cmd = self.command();
67-
cmd.populate_from_args(&args);
67+
cmd.populate_from_args(&args, false);
6868

6969
write!(f, "env ")?;
7070
if let Some(current_dir) = &self.current_dir {
@@ -659,7 +659,7 @@ impl Command {
659659
.context("Failed to prepare sysroot")?;
660660

661661
self.command()
662-
.populate_from_args(&args)
662+
.populate_from_args(&args, false)
663663
.checked_status()
664664
.context("Failed to execute cargo")?;
665665
Ok(())

src/lib.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,11 @@ impl Args {
8686
}
8787

8888
trait CargoCommandExt {
89-
fn populate_from_args(&mut self, args: &Args) -> &mut Self;
89+
fn populate_from_args(&mut self, args: &Args, bootstrap: bool) -> &mut Self;
9090
}
9191

9292
impl CargoCommandExt for std::process::Command {
93-
fn populate_from_args(&mut self, args: &Args) -> &mut Self {
93+
fn populate_from_args(&mut self, args: &Args, bootstrap: bool) -> &mut Self {
9494
self.target(&args.target);
9595
self.sysroot(args.sysroot_dir());
9696
self.append_rustflags("--cfg=hyperlight");
@@ -109,7 +109,7 @@ impl CargoCommandExt for std::process::Command {
109109
} else {
110110
// do nothing, let cc-rs find ar itself
111111
}
112-
self.append_cflags(&args.target, toolchain::cflags(args).joined());
112+
self.append_cflags(&args.target, toolchain::cflags(args, bootstrap).joined());
113113

114114
self
115115
}

src/main.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
use std::env;
21
use std::ffi::{OsStr, OsString};
2+
use std::{env, iter};
33

44
use anyhow::{Result, anyhow};
55
use cargo_hyperlight::{Args, cargo, toolchain, toolchain_flags};
@@ -30,7 +30,7 @@ impl FlagKind {
3030
fn get_flags(&self, args: &Args) -> toolchain_flags::Flags {
3131
use FlagKind::*;
3232
match self {
33-
C => toolchain::cflags(args),
33+
C => toolchain::cflags(args, false),
3434
Ld => toolchain::ldflags(args),
3535
Libs => toolchain::libs(args),
3636
}
@@ -73,14 +73,18 @@ impl SpecialCommand {
7373
.as_ref()
7474
.ok_or(anyhow!("Usage: cargo-hyperlight build-c-sysroot [opts] --c-sysroot-dir </path/to/sysroot>"))?;
7575
built_args.prepare_sysroot()?;
76-
util::copy_glob(&built_args.wrapper_dir(), &sysroot_dir.join("bin"), "**/*")?;
77-
util::copy_glob(
78-
&built_args.includes_dir(),
76+
util::union_glob(
77+
iter::once(&built_args.wrapper_dir()),
78+
&sysroot_dir.join("bin"),
79+
"**/*",
80+
)?;
81+
util::union_glob(
82+
iter::once(&built_args.includes_dir()),
7983
&sysroot_dir.join("include"),
8084
"**/*.h",
8185
)?;
82-
util::copy_glob_with_predicate(
83-
&built_args.c_libs_dir(),
86+
util::union_glob_with_predicate(
87+
iter::once(&built_args.c_libs_dir()),
8488
&sysroot_dir.join("lib"),
8589
"**/*",
8690
|x| !x.starts_with("rustlib"),

src/toolchain.rs

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ fn find_package_dirs(args: &Args) -> Result<PackageDirectories> {
8787
})
8888
}
8989

90-
fn copy_includes(src_dir: &Path, dst_dir: &Path) -> Result<()> {
91-
util::copy_glob(src_dir, dst_dir, "**/*.h")
90+
fn copy_includes(src_dirs: impl Iterator<Item: AsRef<Path>>, dst_dir: &Path) -> Result<()> {
91+
util::union_glob(src_dirs, dst_dir, "**/*.h")
9292
}
9393

9494
fn build_guest_capi(args: &Args, capi_dir: &Path) -> Result<()> {
@@ -101,7 +101,7 @@ fn build_guest_capi(args: &Args, capi_dir: &Path) -> Result<()> {
101101
.target_dir(args.build_dir())
102102
.arg("--message-format=json")
103103
.env_remove("RUSTC_WORKSPACE_WRAPPER")
104-
.populate_from_args(args)
104+
.populate_from_args(args, true)
105105
.output()
106106
.context("Failed to build capi cargo project")?;
107107
ensure!(
@@ -265,14 +265,20 @@ pub fn prepare(args: &Args) -> Result<()> {
265265
include_dirs.push("third_party/musl/arch/x86_64");
266266
}
267267

268-
for dir in include_dirs {
269-
copy_includes(&libc_dir.join(dir), &include_dst_dir)?;
270-
}
271-
if args.with_guest_capi {
272-
let capi_dir = package_dirs.guest_capi()?;
273-
build_guest_capi(args, &capi_dir)?;
274-
copy_includes(&capi_dir.join("include"), &include_dst_dir)?;
275-
}
268+
let capi_dir = args
269+
.with_guest_capi
270+
.then(|| {
271+
let d = package_dirs.guest_capi()?;
272+
build_guest_capi(args, &d)?;
273+
Ok::<_, anyhow::Error>(d)
274+
})
275+
.transpose()?;
276+
277+
let include_dirs = include_dirs
278+
.into_iter()
279+
.map(|dir| libc_dir.join(dir))
280+
.chain(capi_dir.map(|x| x.join("include")).into_iter());
281+
copy_includes(include_dirs, &include_dst_dir)?;
276282

277283
build_wrappers(args)?;
278284

@@ -291,8 +297,8 @@ impl From<&Args> for toolchain_flags::Args {
291297
}
292298
}
293299

294-
pub fn cflags(args: &Args) -> toolchain_flags::Flags {
295-
toolchain_flags::cflags(&args.into())
300+
pub fn cflags(args: &Args, bootstrap: bool) -> toolchain_flags::Flags {
301+
toolchain_flags::cflags(&args.into(), bootstrap)
296302
}
297303
pub fn ldflags(args: &Args) -> toolchain_flags::Flags {
298304
toolchain_flags::ldflags(&args.into())

src/toolchain_flags.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ impl Flags {
4545
}
4646
}
4747

48-
pub(crate) fn cflags(args: &Args) -> Flags {
48+
pub(crate) fn cflags(args: &Args, bootstrap: bool) -> Flags {
4949
let common_flags: &[&str] = &[
5050
"-U__linux__",
5151
"-fPIC",
@@ -74,8 +74,10 @@ pub(crate) fn cflags(args: &Args) -> Flags {
7474
flags.push(os("-march=armv8.1-a+fp+simd"));
7575
}
7676

77-
flags.push(os("-isystem"));
78-
flags.push(Cow::Owned(args.includes_dir.clone().into()));
77+
if !bootstrap {
78+
flags.push(os("-isystem"));
79+
flags.push(Cow::Owned(args.includes_dir.clone().into()));
80+
}
7981
Flags(flags)
8082
}
8183

src/util.rs

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,62 @@
1+
use std::collections::HashSet;
12
use std::fs;
23
use std::path::Path;
34

45
use anyhow::{Context, Result};
56

6-
pub(crate) fn copy_glob_with_predicate(
7-
src_dir: &Path,
7+
pub(crate) fn union_glob_with_predicate(
8+
src_dirs: impl Iterator<Item: AsRef<Path>>,
89
dst_dir: &Path,
910
glob: &str,
1011
predicate: impl Fn(&Path) -> bool,
1112
) -> Result<()> {
12-
let files = glob::glob(&format!("{}/{}", src_dir.display(), glob))
13-
.context("Failed to read include source directory")?;
14-
for file in files {
15-
let src = file.context("Failed to read include source file")?;
16-
let dst = src.strip_prefix(src_dir).unwrap();
17-
if !predicate(dst) {
18-
continue;
13+
let mut copied = HashSet::new();
14+
15+
for src_dir in src_dirs {
16+
let src_dir = src_dir.as_ref();
17+
let files = glob::glob(&format!("{}/{}", src_dir.display(), glob))
18+
.context("Failed to read source directory")?;
19+
for file in files {
20+
let src = file.context("Failed to read source file")?;
21+
if !src.is_file() {
22+
// contents will also show up
23+
continue;
24+
}
25+
let suffix = src.strip_prefix(src_dir)?;
26+
if !predicate(suffix) {
27+
continue;
28+
}
29+
let dst = dst_dir.join(suffix);
30+
31+
let parent_dir = dst.parent().ok_or(anyhow::anyhow!(
32+
"Could not get parent directory of destination file"
33+
))?;
34+
fs::create_dir_all(parent_dir).context("Failed to create subdirectory")?;
35+
fs::copy(&src, &dst).context("Failed to copy file")?;
36+
copied.insert(dst);
1937
}
20-
let dst = dst_dir.join(dst);
38+
}
2139

22-
fs::create_dir_all(dst.parent().unwrap())
23-
.context("Failed to create include subdirectory")?;
24-
fs::copy(&src, &dst).context("Failed to copy include file")?;
40+
// This doesn't do a good job of cleaning up empty directories,
41+
// but that shouldn't cause any problems right now, since this is
42+
// only used for header files/libraries/binaries.
43+
let dst_files = glob::glob(&format!("{}/**/*", dst_dir.display()))
44+
.context("Failed to read destination directory")?;
45+
for dst_file in dst_files {
46+
let dst = dst_file.context("Failed to read destination file")?;
47+
if !copied.contains(&dst) {
48+
if dst.is_file() {
49+
fs::remove_file(dst).context("Failed to remove stale destination file")?;
50+
}
51+
}
2552
}
2653
Ok(())
2754
}
2855

29-
pub(crate) fn copy_glob(src_dir: &Path, dst_dir: &Path, glob: &str) -> Result<()> {
30-
copy_glob_with_predicate(src_dir, dst_dir, glob, |_| true)
56+
pub(crate) fn union_glob(
57+
src_dir: impl Iterator<Item: AsRef<Path>>,
58+
dst_dir: &Path,
59+
glob: &str,
60+
) -> Result<()> {
61+
union_glob_with_predicate(src_dir, dst_dir, glob, |_| true)
3162
}

src/wrapper/_main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ fn usage() -> ! {
2121
fn hyperlight_config(args: &Args, mut cmd: env::ArgsOs) {
2222
while let Some(flag) = cmd.next() {
2323
if flag == "--cflags" {
24-
println!("{}", toolchain_flags::cflags(&args).joined().to_str().unwrap());
24+
println!("{}", toolchain_flags::cflags(&args, false).joined().to_str().unwrap());
2525
} else if flag == "--ldflags" {
2626
println!("{}", toolchain_flags::ldflags(&args).joined().to_str().unwrap());
2727
} else if flag == "--libs" {
@@ -93,7 +93,7 @@ fn clang(args: &Args, tool_name: &str, cmd: env::ArgsOs) {
9393
}
9494
}
9595
let mut proc = std::process::Command::new(find_next(args, tool_name));
96-
proc.args(toolchain_flags::cflags(&args).0);
96+
proc.args(toolchain_flags::cflags(&args, false).0);
9797
if !found_non_link_flag && found_non_flag {
9898
proc.args(toolchain_flags::ldflags(&args).0);
9999
}

0 commit comments

Comments
 (0)