use std::path::{Path, PathBuf};
use std::{env, fs};
fn copy_includes<P: AsRef<Path>, Q: AsRef<Path> + std::fmt::Debug>(include_dir: P, base: Q) {
let entries = fs::read_dir(&base)
.unwrap_or_else(|e| panic!("could not open include dir {:?}: {}", base, e));
for entry in entries {
let entry =
entry.unwrap_or_else(|e| panic!("could not read include dir {:?}: {}", base, e));
let src = entry.path();
let dst = include_dir.as_ref().join(entry.file_name());
let kind = entry
.file_type()
.unwrap_or_else(|e| panic!("could not find type of {:?}: {}", src, e));
if kind.is_dir() {
fs::create_dir_all(&dst)
.unwrap_or_else(|e| panic!("could not create include dir {:?}, {}", &dst, e));
copy_includes(&dst, src);
} else if Some(std::ffi::OsStr::new("h")) == src.extension() {
fs::copy(&src, &dst)
.unwrap_or_else(|e| panic!("could not copy header {:?}, {}", &src, e));
}
}
}
fn cargo_main() {
println!("cargo:rerun-if-changed=third_party");
println!("cargo:rerun-if-changed=src/alloca");
println!("cargo:rerun-if-changed=include");
let mut cfg = cc::Build::new();
if cfg!(feature = "printf") {
cfg.include("third_party/printf")
.file("third_party/printf/printf.c");
}
if cfg!(feature = "libc") {
cfg.file("third_party/libc/musl/src/ctype/isalpha.c")
.file("third_party/libc/musl/src/ctype/isalnum.c")
.file("third_party/libc/musl/src/ctype/isdigit.c")
.file("third_party/libc/musl/src/ctype/isgraph.c")
.file("third_party/libc/musl/src/ctype/islower.c")
.file("third_party/libc/musl/src/ctype/isprint.c")
.file("third_party/libc/musl/src/ctype/isspace.c")
.file("third_party/libc/musl/src/ctype/isupper.c")
.file("third_party/libc/musl/src/ctype/isxdigit.c")
.file("third_party/libc/musl/src/ctype/tolower.c")
.file("third_party/libc/musl/src/ctype/toupper.c")
.file("third_party/libc/musl/src/errno/__errno_location.c")
.file("third_party/libc/musl/src/internal/floatscan.c")
.file("third_party/libc/musl/src/internal/intscan.c")
.file("third_party/libc/musl/src/internal/shgetc.c")
.file("third_party/libc/musl/src/math/copysign.c")
.file("third_party/libc/musl/src/math/copysignl.c")
.file("third_party/libc/musl/src/math/fabs.c")
.file("third_party/libc/musl/src/math/fabsl.c")
.file("third_party/libc/musl/src/math/fmod.c")
.file("third_party/libc/musl/src/math/fmodl.c")
.file("third_party/libc/musl/src/math/scalbnl.c")
.file("third_party/libc/musl/src/math/__signbit.c")
.file("third_party/libc/musl/src/math/__signbitl.c")
.file("third_party/libc/musl/src/math/__fpclassify.c")
.file("third_party/libc/musl/src/math/__fpclassifyl.c")
.file("third_party/libc/musl/src/stdio/__toread.c")
.file("third_party/libc/musl/src/stdio/__uflow.c")
.file("third_party/libc/musl/src/stdlib/atoi.c")
.file("third_party/libc/musl/src/stdlib/strtod.c")
.file("third_party/libc/musl/src/stdlib/strtol.c")
.file("third_party/libc/musl/src/stdlib/qsort.c")
.file("third_party/libc/musl/src/stdlib/qsort_nr.c")
.file("third_party/libc/musl/src/stdlib/bsearch.c")
.file("third_party/libc/musl/src/string/memchr.c")
.file("third_party/libc/musl/src/string/memcmp.c")
.file("third_party/libc/musl/src/string/memcpy.c")
.file("third_party/libc/musl/src/string/memmove.c")
.file("third_party/libc/musl/src/string/memset.c")
.file("third_party/libc/musl/src/string/stpncpy.c")
.file("third_party/libc/musl/src/string/strchr.c")
.file("third_party/libc/musl/src/string/strchrnul.c")
.file("third_party/libc/musl/src/string/strcmp.c")
.file("third_party/libc/musl/src/string/strcspn.c")
.file("third_party/libc/musl/src/string/strlen.c")
.file("third_party/libc/musl/src/string/strncasecmp.c")
.file("third_party/libc/musl/src/string/strncat.c")
.file("third_party/libc/musl/src/string/strncmp.c")
.file("third_party/libc/musl/src/string/strncpy.c")
.file("third_party/libc/musl/src/string/strspn.c")
.file("third_party/libc/musl/src/string/strstr.c")
.file("third_party/libc/musl/src/prng/rand.c")
.include("third_party/libc/musl/src/include")
.include("third_party/libc/musl/include")
.include("third_party/libc/musl/src/internal")
.include("third_party/libc/musl/arch/generic")
.include("third_party/libc/musl/arch/x86_64");
}
if cfg!(feature = "alloca") {
cfg.file("src/alloca/alloca.c")
.define("_alloca", "_alloca_wrapper")
.flag("-Wno-return-stack-address");
}
let is_pe = env::var("CARGO_CFG_WINDOWS").is_ok();
if cfg!(any(
feature = "printf",
feature = "libc",
feature = "alloca"
)) {
if is_pe {
cfg.define("hidden", "");
cfg.define("weak_alias(old, new) ", " ");
cfg.define("__DEFINED_va_list", None);
cfg.define("__DEFINED___isoc_va_list", None);
}
cfg.define("__x86_64__", None);
cfg.define("__LITTLE_ENDIAN__", None);
cfg.define("malloc", "hlmalloc");
cfg.define("calloc", "hlcalloc");
cfg.define("free", "hlfree");
cfg.define("realloc", "hlrealloc");
cfg.flag("-Wno-sign-compare");
cfg.flag("-Wno-bitwise-op-parentheses");
cfg.flag("-Wno-unknown-pragmas");
cfg.flag("-Wno-shift-op-parentheses");
cfg.flag("-Wno-logical-op-parentheses");
cfg.flag("-Wno-unused-but-set-variable");
if is_pe {
cfg.compiler("clang-cl");
} else {
cfg.flag("-fPIC");
cfg.flag("--target=x86_64-unknown-linux-none");
cfg.flag("-fno-stack-protector");
cfg.flag("-fstack-clash-protection");
cfg.flag("-mstack-probe-size=4096");
cfg.compiler("clang");
}
if cfg!(windows) {
env::set_var("AR_x86_64_unknown_none", "llvm-ar");
} else {
env::set_var("AR_x86_64_pc_windows_msvc", "llvm-lib");
}
cfg.compile("hyperlight_guest");
}
let out_dir = env::var("OUT_DIR").expect("cargo OUT_DIR not set");
let include_dir = PathBuf::from(&out_dir).join("include");
fs::create_dir_all(&include_dir)
.unwrap_or_else(|e| panic!("Could not create include dir {:?}: {}", &include_dir, e));
if cfg!(feature = "printf") {
copy_includes(&include_dir, "third_party/printf/");
}
if cfg!(feature = "libc") {
copy_includes(&include_dir, "include");
copy_includes(&include_dir, "third_party/libc/musl/include");
copy_includes(&include_dir, "third_party/libc/musl/arch/generic");
copy_includes(&include_dir, "third_party/libc/musl/arch/x86_64");
copy_includes(&include_dir, "third_party/libc/musl/src/internal");
}
let include_str = include_dir
.to_str()
.expect("out dir include dir was not valid utf-8");
println!("cargo::metadata=include={}", include_str);
if let Ok(binroot) = env::var("HYPERLIGHT_GUEST_TOOLCHAIN_ROOT") {
let binroot = PathBuf::from(binroot);
let binpath = env::current_exe().expect("couldn't get build script path");
fs::create_dir_all(&binroot)
.unwrap_or_else(|e| panic!("Could not create binary root {:?}: {}", &binroot, e));
fs::write(binroot.join(".out_dir"), out_dir).expect("Could not write out_dir");
fs::copy(&binpath, binroot.join("ml64.exe")).expect("Could not copy to ml64.exe");
fs::copy(&binpath, binroot.join("clang")).expect("Could not copy to clang");
fs::copy(&binpath, binroot.join("clang.exe")).expect("Could not copy to clang.exe");
fs::copy(&binpath, binroot.join("clang-cl")).expect("Could not copy to clang-cl");
fs::copy(&binpath, binroot.join("clang-cl.exe")).expect("Could not copy to clang-cl.exe");
}
}
#[derive(PartialEq)]
enum Tool {
CargoBuildScript,
Ml64,
Clang,
ClangCl,
}
impl From<&std::ffi::OsStr> for Tool {
fn from(x: &std::ffi::OsStr) -> Tool {
if x == "ml64.exe" {
Tool::Ml64
} else if x == "clang" || x == "clang.exe" {
Tool::Clang
} else if x == "clang-cl" || x == "clang-cl.exe" {
Tool::ClangCl
} else {
Tool::CargoBuildScript
}
}
}
fn find_next(root_dir: &Path, tool_name: &str) -> PathBuf {
let path = env::var_os("PATH").expect("$PATH should exist");
let paths: Vec<_> = env::split_paths(&path).collect();
for path in &paths {
let abs_path = fs::canonicalize(path);
let abs_path = abs_path.as_ref().unwrap_or(path);
if abs_path == root_dir {
continue;
}
let base_path = path.join(tool_name);
if base_path.exists() {
return base_path;
}
let exe_path = base_path.with_extension("exe");
if exe_path.exists() {
return exe_path;
}
}
panic!("Could not find another implementation of {}", tool_name);
}
fn main() -> std::process::ExitCode {
let exe = env::current_exe().expect("expected program name");
let name = Path::file_name(exe.as_ref()).expect("program name should not be directory");
let tool: Tool = name.into();
if tool == Tool::CargoBuildScript {
cargo_main();
return std::process::ExitCode::SUCCESS;
}
let exe_abs = fs::canonicalize(&exe).expect("program name should be possible to canonicalize");
let root_dir = exe_abs
.parent()
.expect("program name should be in a directory");
let out_dir = std::fs::read_to_string(root_dir.join(".out_dir"))
.expect(".out_dir should have a valid path in it");
let mut args = env::args();
args.next(); let include_dir = <String as AsRef<Path>>::as_ref(&out_dir).join("include");
match tool {
Tool::Ml64 => std::process::Command::new("llvm-ml")
.arg("-m64")
.args(args)
.status()
.ok()
.and_then(|x| (x.code()))
.map(|x| (x as u8).into())
.unwrap_or(std::process::ExitCode::FAILURE),
Tool::Clang => std::process::Command::new(find_next(root_dir, "clang"))
.arg("--target=x86_64-unknown-linux-none")
.args([
"-fno-stack-protector",
"-fstack-clash-protection",
"-mstack-probe-size=4096",
])
.arg("-nostdinc")
.arg("-isystem")
.arg(include_dir)
.args(args)
.status()
.ok()
.and_then(|x| (x.code()))
.map(|x| (x as u8).into())
.unwrap_or(std::process::ExitCode::FAILURE),
Tool::ClangCl => std::process::Command::new(find_next(root_dir, "clang-cl"))
.arg("-nostdinc")
.arg("/external:I")
.arg(include_dir)
.args(args)
.status()
.ok()
.and_then(|x| (x.code()))
.map(|x| (x as u8).into())
.unwrap_or(std::process::ExitCode::FAILURE),
_ => std::process::ExitCode::FAILURE,
}
}