mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-01 07:41:12 +00:00
Enable rebuilding hosts into a dynamic executable
This commit is contained in:
parent
7297e969bd
commit
e96291e9a7
5 changed files with 260 additions and 112 deletions
|
@ -84,30 +84,35 @@ pub fn build_zig_host_native(
|
|||
zig_str_path: &str,
|
||||
target: &str,
|
||||
opt_level: OptLevel,
|
||||
shared_lib_path: Option<&Path>,
|
||||
) -> Output {
|
||||
let mut command = Command::new("zig");
|
||||
command
|
||||
.env_clear()
|
||||
.env("PATH", env_path)
|
||||
.env("HOME", env_home)
|
||||
.args(&[
|
||||
"build-obj",
|
||||
zig_host_src,
|
||||
emit_bin,
|
||||
"--pkg-begin",
|
||||
"str",
|
||||
zig_str_path,
|
||||
"--pkg-end",
|
||||
// include the zig runtime
|
||||
"-fcompiler-rt",
|
||||
// include libc
|
||||
"--library",
|
||||
"c",
|
||||
"-fPIC",
|
||||
// cross-compile?
|
||||
"-target",
|
||||
target,
|
||||
]);
|
||||
.env("HOME", env_home);
|
||||
if let Some(shared_lib_path) = shared_lib_path {
|
||||
command.args(&["build-exe", shared_lib_path.to_str().unwrap()]);
|
||||
} else {
|
||||
command.arg("build-obj");
|
||||
}
|
||||
command.args(&[
|
||||
zig_host_src,
|
||||
emit_bin,
|
||||
"--pkg-begin",
|
||||
"str",
|
||||
zig_str_path,
|
||||
"--pkg-end",
|
||||
// include the zig runtime
|
||||
"-fcompiler-rt",
|
||||
// include libc
|
||||
"--library",
|
||||
"c",
|
||||
"-fPIC",
|
||||
// cross-compile?
|
||||
"-target",
|
||||
target,
|
||||
]);
|
||||
if matches!(opt_level, OptLevel::Optimize) {
|
||||
command.args(&["-O", "ReleaseSafe"]);
|
||||
}
|
||||
|
@ -123,6 +128,7 @@ pub fn build_zig_host_native(
|
|||
zig_str_path: &str,
|
||||
_target: &str,
|
||||
opt_level: OptLevel,
|
||||
shared_lib_path: Option<&Path>,
|
||||
) -> Output {
|
||||
use serde_json::Value;
|
||||
|
||||
|
@ -168,25 +174,29 @@ pub fn build_zig_host_native(
|
|||
command
|
||||
.env_clear()
|
||||
.env("PATH", &env_path)
|
||||
.env("HOME", &env_home)
|
||||
.args(&[
|
||||
"build-obj",
|
||||
zig_host_src,
|
||||
emit_bin,
|
||||
"--pkg-begin",
|
||||
"str",
|
||||
zig_str_path,
|
||||
"--pkg-end",
|
||||
// include the zig runtime
|
||||
"--pkg-begin",
|
||||
"compiler_rt",
|
||||
zig_compiler_rt_path.to_str().unwrap(),
|
||||
"--pkg-end",
|
||||
// include libc
|
||||
"--library",
|
||||
"c",
|
||||
"-fPIC",
|
||||
]);
|
||||
.env("HOME", &env_home);
|
||||
if let Some(shared_lib_path) = shared_lib_path {
|
||||
command.args(&["build-exe", shared_lib_path.to_str().unwrap()]);
|
||||
} else {
|
||||
command.arg("build-obj");
|
||||
}
|
||||
command.args(&[
|
||||
zig_host_src,
|
||||
emit_bin,
|
||||
"--pkg-begin",
|
||||
"str",
|
||||
zig_str_path,
|
||||
"--pkg-end",
|
||||
// include the zig runtime
|
||||
"--pkg-begin",
|
||||
"compiler_rt",
|
||||
zig_compiler_rt_path.to_str().unwrap(),
|
||||
"--pkg-end",
|
||||
// include libc
|
||||
"--library",
|
||||
"c",
|
||||
"-fPIC",
|
||||
]);
|
||||
if matches!(opt_level, OptLevel::Optimize) {
|
||||
command.args(&["-O", "ReleaseSafe"]);
|
||||
}
|
||||
|
@ -200,7 +210,11 @@ pub fn build_zig_host_wasm32(
|
|||
zig_host_src: &str,
|
||||
zig_str_path: &str,
|
||||
opt_level: OptLevel,
|
||||
shared_lib_path: Option<&Path>,
|
||||
) -> Output {
|
||||
if shared_lib_path.is_some() {
|
||||
unimplemented!("Linking a shared library to wasm not yet implemented");
|
||||
}
|
||||
// NOTE currently just to get compiler warnings if the host code is invalid.
|
||||
// the produced artifact is not used
|
||||
//
|
||||
|
@ -239,14 +253,56 @@ pub fn build_zig_host_wasm32(
|
|||
command.output().unwrap()
|
||||
}
|
||||
|
||||
pub fn rebuild_host(opt_level: OptLevel, target: &Triple, host_input_path: &Path) {
|
||||
pub fn build_c_host_native(
|
||||
env_path: &str,
|
||||
env_home: &str,
|
||||
dest: &str,
|
||||
sources: &[&str],
|
||||
opt_level: OptLevel,
|
||||
shared_lib_path: Option<&Path>,
|
||||
) -> Output {
|
||||
let mut command = Command::new("clang");
|
||||
command
|
||||
.env_clear()
|
||||
.env("PATH", &env_path)
|
||||
.env("HOME", &env_home)
|
||||
.args(sources)
|
||||
.args(&["-fPIC", "-o", dest]);
|
||||
if let Some(shared_lib_path) = shared_lib_path {
|
||||
command.args(&[
|
||||
shared_lib_path.to_str().unwrap(),
|
||||
"-lm",
|
||||
"-lpthread",
|
||||
"-ldl",
|
||||
"-lrt",
|
||||
"-lutil",
|
||||
]);
|
||||
} else {
|
||||
command.arg("-c");
|
||||
}
|
||||
if matches!(opt_level, OptLevel::Optimize) {
|
||||
command.arg("-O2");
|
||||
}
|
||||
command.output().unwrap()
|
||||
}
|
||||
|
||||
pub fn rebuild_host(
|
||||
opt_level: OptLevel,
|
||||
target: &Triple,
|
||||
host_input_path: &Path,
|
||||
shared_lib_path: Option<&Path>,
|
||||
) {
|
||||
let c_host_src = host_input_path.with_file_name("host.c");
|
||||
let c_host_dest = host_input_path.with_file_name("c_host.o");
|
||||
let zig_host_src = host_input_path.with_file_name("host.zig");
|
||||
let rust_host_src = host_input_path.with_file_name("host.rs");
|
||||
let rust_host_dest = host_input_path.with_file_name("rust_host.o");
|
||||
let cargo_host_src = host_input_path.with_file_name("Cargo.toml");
|
||||
let host_dest_native = host_input_path.with_file_name("host.o");
|
||||
let host_dest_native = host_input_path.with_file_name(if shared_lib_path.is_some() {
|
||||
"dynhost"
|
||||
} else {
|
||||
"host.o"
|
||||
});
|
||||
let host_dest_wasm = host_input_path.with_file_name("host.bc");
|
||||
|
||||
let env_path = env::var("PATH").unwrap_or_else(|_| "".to_string());
|
||||
|
@ -273,6 +329,7 @@ pub fn rebuild_host(opt_level: OptLevel, target: &Triple, host_input_path: &Path
|
|||
zig_host_src.to_str().unwrap(),
|
||||
zig_str_path.to_str().unwrap(),
|
||||
opt_level,
|
||||
shared_lib_path,
|
||||
)
|
||||
}
|
||||
Architecture::X86_64 => {
|
||||
|
@ -285,6 +342,7 @@ pub fn rebuild_host(opt_level: OptLevel, target: &Triple, host_input_path: &Path
|
|||
zig_str_path.to_str().unwrap(),
|
||||
"native",
|
||||
opt_level,
|
||||
shared_lib_path,
|
||||
)
|
||||
}
|
||||
Architecture::X86_32(_) => {
|
||||
|
@ -297,31 +355,14 @@ pub fn rebuild_host(opt_level: OptLevel, target: &Triple, host_input_path: &Path
|
|||
zig_str_path.to_str().unwrap(),
|
||||
"i386-linux-musl",
|
||||
opt_level,
|
||||
shared_lib_path,
|
||||
)
|
||||
}
|
||||
_ => panic!("Unsupported architecture {:?}", target.architecture),
|
||||
};
|
||||
|
||||
validate_output("host.zig", "zig", output)
|
||||
} else {
|
||||
// Compile host.c
|
||||
let mut command = Command::new("clang");
|
||||
command.env_clear().env("PATH", &env_path).args(&[
|
||||
"-fPIC",
|
||||
"-c",
|
||||
c_host_src.to_str().unwrap(),
|
||||
"-o",
|
||||
c_host_dest.to_str().unwrap(),
|
||||
]);
|
||||
if matches!(opt_level, OptLevel::Optimize) {
|
||||
command.arg("-O2");
|
||||
}
|
||||
let output = command.output().unwrap();
|
||||
|
||||
validate_output("host.c", "clang", output);
|
||||
}
|
||||
|
||||
if cargo_host_src.exists() {
|
||||
} else if cargo_host_src.exists() {
|
||||
// Compile and link Cargo.toml, if it exists
|
||||
let cargo_dir = host_input_path.parent().unwrap();
|
||||
let libhost_dir =
|
||||
|
@ -332,6 +373,7 @@ pub fn rebuild_host(opt_level: OptLevel, target: &Triple, host_input_path: &Path
|
|||
} else {
|
||||
"debug"
|
||||
});
|
||||
let libhost = libhost_dir.join("libhost.a");
|
||||
|
||||
let mut command = Command::new("cargo");
|
||||
command.arg("build").current_dir(cargo_dir);
|
||||
|
@ -342,22 +384,54 @@ pub fn rebuild_host(opt_level: OptLevel, target: &Triple, host_input_path: &Path
|
|||
|
||||
validate_output("src/lib.rs", "cargo build", output);
|
||||
|
||||
let output = Command::new("ld")
|
||||
.env_clear()
|
||||
.env("PATH", &env_path)
|
||||
.args(&[
|
||||
"-r",
|
||||
"-L",
|
||||
libhost_dir.to_str().unwrap(),
|
||||
c_host_dest.to_str().unwrap(),
|
||||
"-lhost",
|
||||
"-o",
|
||||
// Cargo hosts depend on a c wrapper for the api. Compile host.c as well.
|
||||
if shared_lib_path.is_some() {
|
||||
// If compiling to executable, let c deal with linking as well.
|
||||
let output = build_c_host_native(
|
||||
&env_path,
|
||||
&env_home,
|
||||
host_dest_native.to_str().unwrap(),
|
||||
])
|
||||
.output()
|
||||
.unwrap();
|
||||
&[c_host_src.to_str().unwrap(), libhost.to_str().unwrap()],
|
||||
opt_level,
|
||||
shared_lib_path,
|
||||
);
|
||||
validate_output("host.c", "clang", output);
|
||||
} else {
|
||||
let output = build_c_host_native(
|
||||
&env_path,
|
||||
&env_home,
|
||||
c_host_dest.to_str().unwrap(),
|
||||
&[c_host_src.to_str().unwrap()],
|
||||
opt_level,
|
||||
shared_lib_path,
|
||||
);
|
||||
validate_output("host.c", "clang", output);
|
||||
|
||||
validate_output("c_host.o", "ld", output);
|
||||
let output = Command::new("ld")
|
||||
.env_clear()
|
||||
.env("PATH", &env_path)
|
||||
.args(&[
|
||||
"-r",
|
||||
"-L",
|
||||
libhost_dir.to_str().unwrap(),
|
||||
c_host_dest.to_str().unwrap(),
|
||||
"-lhost",
|
||||
"-o",
|
||||
host_dest_native.to_str().unwrap(),
|
||||
])
|
||||
.output()
|
||||
.unwrap();
|
||||
validate_output("c_host.o", "ld", output);
|
||||
|
||||
// Clean up c_host.o
|
||||
let output = Command::new("rm")
|
||||
.env_clear()
|
||||
.args(&["-f", c_host_dest.to_str().unwrap()])
|
||||
.output()
|
||||
.unwrap();
|
||||
|
||||
validate_output("rust_host.o", "rm", output);
|
||||
}
|
||||
} else if rust_host_src.exists() {
|
||||
// Compile and link host.rs, if it exists
|
||||
let mut command = Command::new("rustc");
|
||||
|
@ -373,22 +447,49 @@ pub fn rebuild_host(opt_level: OptLevel, target: &Triple, host_input_path: &Path
|
|||
|
||||
validate_output("host.rs", "rustc", output);
|
||||
|
||||
let output = Command::new("ld")
|
||||
.env_clear()
|
||||
.env("PATH", &env_path)
|
||||
.args(&[
|
||||
"-r",
|
||||
c_host_dest.to_str().unwrap(),
|
||||
rust_host_dest.to_str().unwrap(),
|
||||
"-o",
|
||||
// Rust hosts depend on a c wrapper for the api. Compile host.c as well.
|
||||
if shared_lib_path.is_some() {
|
||||
// If compiling to executable, let c deal with linking as well.
|
||||
let output = build_c_host_native(
|
||||
&env_path,
|
||||
&env_home,
|
||||
host_dest_native.to_str().unwrap(),
|
||||
])
|
||||
.output()
|
||||
.unwrap();
|
||||
&[
|
||||
c_host_src.to_str().unwrap(),
|
||||
rust_host_dest.to_str().unwrap(),
|
||||
],
|
||||
opt_level,
|
||||
shared_lib_path,
|
||||
);
|
||||
validate_output("host.c", "clang", output);
|
||||
} else {
|
||||
let output = build_c_host_native(
|
||||
&env_path,
|
||||
&env_home,
|
||||
c_host_dest.to_str().unwrap(),
|
||||
&[c_host_src.to_str().unwrap()],
|
||||
opt_level,
|
||||
shared_lib_path,
|
||||
);
|
||||
|
||||
validate_output("rust_host.o", "ld", output);
|
||||
validate_output("host.c", "clang", output);
|
||||
let output = Command::new("ld")
|
||||
.env_clear()
|
||||
.env("PATH", &env_path)
|
||||
.args(&[
|
||||
"-r",
|
||||
c_host_dest.to_str().unwrap(),
|
||||
rust_host_dest.to_str().unwrap(),
|
||||
"-o",
|
||||
host_dest_native.to_str().unwrap(),
|
||||
])
|
||||
.output()
|
||||
.unwrap();
|
||||
|
||||
// Clean up rust_host.o
|
||||
validate_output("rust_host.o", "ld", output);
|
||||
}
|
||||
|
||||
// Clean up rust_host.o and c_host.o
|
||||
let output = Command::new("rm")
|
||||
.env_clear()
|
||||
.args(&[
|
||||
|
@ -400,15 +501,17 @@ pub fn rebuild_host(opt_level: OptLevel, target: &Triple, host_input_path: &Path
|
|||
.unwrap();
|
||||
|
||||
validate_output("rust_host.o", "rm", output);
|
||||
} else if c_host_dest.exists() {
|
||||
// Clean up c_host.o
|
||||
let output = Command::new("mv")
|
||||
.env_clear()
|
||||
.args(&[c_host_dest, host_dest_native])
|
||||
.output()
|
||||
.unwrap();
|
||||
|
||||
validate_output("c_host.o", "mv", output);
|
||||
} else if c_host_src.exists() {
|
||||
// Compile host.c, if it exists
|
||||
let output = build_c_host_native(
|
||||
&env_path,
|
||||
&env_home,
|
||||
host_dest_native.to_str().unwrap(),
|
||||
&[c_host_src.to_str().unwrap()],
|
||||
opt_level,
|
||||
shared_lib_path,
|
||||
);
|
||||
validate_output("host.c", "clang", output);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue