mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 13:29:12 +00:00
Merge pull request #4542 from roc-lang/precompiled-legacy
Precompiled legacy linking
This commit is contained in:
commit
ac2d50aea9
8 changed files with 235 additions and 123 deletions
|
@ -1,6 +1,9 @@
|
|||
use bumpalo::Bump;
|
||||
use roc_build::{
|
||||
link::{link, preprocess_host_wasm32, rebuild_host, LinkType, LinkingStrategy},
|
||||
link::{
|
||||
legacy_host_filename, link, preprocess_host_wasm32, preprocessed_host_filename,
|
||||
rebuild_host, LinkType, LinkingStrategy,
|
||||
},
|
||||
program::{self, CodeGenOptions},
|
||||
};
|
||||
use roc_builtins::bitcode;
|
||||
|
@ -106,28 +109,27 @@ pub fn build_file<'a>(
|
|||
}
|
||||
};
|
||||
|
||||
use target_lexicon::Architecture;
|
||||
let emit_wasm = matches!(target.architecture, Architecture::Wasm32);
|
||||
|
||||
// TODO wasm host extension should be something else ideally
|
||||
// .bc does not seem to work because
|
||||
//
|
||||
// > Non-Emscripten WebAssembly hasn't implemented __builtin_return_address
|
||||
//
|
||||
// and zig does not currently emit `.a` webassembly static libraries
|
||||
let (host_extension, app_extension, extension) = {
|
||||
let (app_extension, extension, host_filename) = {
|
||||
use roc_target::OperatingSystem::*;
|
||||
|
||||
match roc_target::OperatingSystem::from(target.operating_system) {
|
||||
Wasi => {
|
||||
if matches!(code_gen_options.opt_level, OptLevel::Development) {
|
||||
("wasm", "wasm", Some("wasm"))
|
||||
("wasm", Some("wasm"), "host.zig".to_string())
|
||||
} else {
|
||||
("zig", "bc", Some("wasm"))
|
||||
("bc", Some("wasm"), "host.zig".to_string())
|
||||
}
|
||||
}
|
||||
Unix => ("o", "o", None),
|
||||
Windows => ("obj", "obj", Some("exe")),
|
||||
Unix => (
|
||||
"o",
|
||||
None,
|
||||
legacy_host_filename(target, code_gen_options.opt_level).unwrap(),
|
||||
),
|
||||
Windows => (
|
||||
"obj",
|
||||
Some("exe"),
|
||||
legacy_host_filename(target, code_gen_options.opt_level).unwrap(),
|
||||
),
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -140,9 +142,7 @@ pub fn build_file<'a>(
|
|||
|
||||
let host_input_path = if let EntryPoint::Executable { platform_path, .. } = &loaded.entry_point
|
||||
{
|
||||
cwd.join(platform_path)
|
||||
.with_file_name("host")
|
||||
.with_extension(host_extension)
|
||||
cwd.join(platform_path).with_file_name(host_filename)
|
||||
} else {
|
||||
unreachable!();
|
||||
};
|
||||
|
@ -172,23 +172,43 @@ pub fn build_file<'a>(
|
|||
})
|
||||
.collect();
|
||||
|
||||
let preprocessed_host_path = if emit_wasm {
|
||||
host_input_path.with_file_name("preprocessedhost.o")
|
||||
let preprocessed_host_path = if linking_strategy == LinkingStrategy::Legacy {
|
||||
host_input_path
|
||||
.with_file_name(legacy_host_filename(target, code_gen_options.opt_level).unwrap())
|
||||
} else {
|
||||
host_input_path.with_file_name("preprocessedhost")
|
||||
host_input_path.with_file_name(preprocessed_host_filename(target).unwrap())
|
||||
};
|
||||
|
||||
let rebuild_thread = spawn_rebuild_thread(
|
||||
code_gen_options.opt_level,
|
||||
linking_strategy,
|
||||
prebuilt,
|
||||
host_input_path.clone(),
|
||||
preprocessed_host_path.clone(),
|
||||
binary_path.clone(),
|
||||
target,
|
||||
exposed_values,
|
||||
exposed_closure_types,
|
||||
);
|
||||
// We don't need to spawn a rebuild thread when using a prebuilt host.
|
||||
let rebuild_thread = if prebuilt {
|
||||
if !preprocessed_host_path.exists() {
|
||||
eprintln!(
|
||||
"\nBecause I was run with --prebuilt-platform=true, I was expecting this file to exist:\n\n {}\n\nHowever, it was not there!\n\nIf you have the platform's source code locally, you may be able to regenerate it by re-running this command with --prebuilt-platform=false\n",
|
||||
preprocessed_host_path.to_string_lossy()
|
||||
);
|
||||
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
if linking_strategy == LinkingStrategy::Surgical {
|
||||
// Copy preprocessed host to executable location.
|
||||
// The surgical linker will modify that copy in-place.
|
||||
std::fs::copy(&preprocessed_host_path, binary_path.as_path()).unwrap();
|
||||
}
|
||||
|
||||
None
|
||||
} else {
|
||||
Some(spawn_rebuild_thread(
|
||||
code_gen_options.opt_level,
|
||||
linking_strategy,
|
||||
host_input_path.clone(),
|
||||
preprocessed_host_path.clone(),
|
||||
binary_path.clone(),
|
||||
target,
|
||||
exposed_values,
|
||||
exposed_closure_types,
|
||||
))
|
||||
};
|
||||
|
||||
let buf = &mut String::with_capacity(1024);
|
||||
|
||||
|
@ -247,19 +267,24 @@ pub fn build_file<'a>(
|
|||
ConcurrentWithApp(JoinHandle<u128>),
|
||||
}
|
||||
|
||||
let rebuild_timing = if linking_strategy == LinkingStrategy::Additive {
|
||||
let rebuild_duration = rebuild_thread
|
||||
.join()
|
||||
.expect("Failed to (re)build platform.");
|
||||
if emit_timings && !prebuilt {
|
||||
println!(
|
||||
"Finished rebuilding the platform in {} ms\n",
|
||||
rebuild_duration
|
||||
);
|
||||
let opt_rebuild_timing = if let Some(rebuild_thread) = rebuild_thread {
|
||||
if linking_strategy == LinkingStrategy::Additive {
|
||||
let rebuild_duration = rebuild_thread
|
||||
.join()
|
||||
.expect("Failed to (re)build platform.");
|
||||
if emit_timings && !prebuilt {
|
||||
println!(
|
||||
"Finished rebuilding the platform in {} ms\n",
|
||||
rebuild_duration
|
||||
);
|
||||
}
|
||||
|
||||
Some(HostRebuildTiming::BeforeApp(rebuild_duration))
|
||||
} else {
|
||||
Some(HostRebuildTiming::ConcurrentWithApp(rebuild_thread))
|
||||
}
|
||||
HostRebuildTiming::BeforeApp(rebuild_duration)
|
||||
} else {
|
||||
HostRebuildTiming::ConcurrentWithApp(rebuild_thread)
|
||||
None
|
||||
};
|
||||
|
||||
let (roc_app_bytes, code_gen_timing, expect_metadata) = program::gen_from_mono_module(
|
||||
|
@ -300,7 +325,7 @@ pub fn build_file<'a>(
|
|||
);
|
||||
}
|
||||
|
||||
if let HostRebuildTiming::ConcurrentWithApp(thread) = rebuild_timing {
|
||||
if let Some(HostRebuildTiming::ConcurrentWithApp(thread)) = opt_rebuild_timing {
|
||||
let rebuild_duration = thread.join().expect("Failed to (re)build platform.");
|
||||
if emit_timings && !prebuilt {
|
||||
println!(
|
||||
|
@ -361,9 +386,8 @@ pub fn build_file<'a>(
|
|||
inputs.push(builtins_host_tempfile.path().to_str().unwrap());
|
||||
}
|
||||
|
||||
let (mut child, _) = // TODO use lld
|
||||
link(target, binary_path.clone(), &inputs, link_type)
|
||||
.map_err(|_| todo!("gracefully handle `ld` failing to spawn."))?;
|
||||
let (mut child, _) = link(target, binary_path.clone(), &inputs, link_type)
|
||||
.map_err(|_| todo!("gracefully handle `ld` failing to spawn."))?;
|
||||
|
||||
let exit_status = child
|
||||
.wait()
|
||||
|
@ -376,12 +400,10 @@ pub fn build_file<'a>(
|
|||
if exit_status.success() {
|
||||
problems
|
||||
} else {
|
||||
let mut problems = problems;
|
||||
|
||||
// Add an error for `ld` failing
|
||||
problems.errors += 1;
|
||||
|
||||
problems
|
||||
todo!(
|
||||
"gracefully handle `ld` (or `zig` in the case of wasm with --optimize) returning exit code {:?}",
|
||||
exit_status.code()
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -406,7 +428,6 @@ pub fn build_file<'a>(
|
|||
fn spawn_rebuild_thread(
|
||||
opt_level: OptLevel,
|
||||
linking_strategy: LinkingStrategy,
|
||||
prebuilt: bool,
|
||||
host_input_path: PathBuf,
|
||||
preprocessed_host_path: PathBuf,
|
||||
binary_path: PathBuf,
|
||||
|
@ -416,54 +437,49 @@ fn spawn_rebuild_thread(
|
|||
) -> std::thread::JoinHandle<u128> {
|
||||
let thread_local_target = target.clone();
|
||||
std::thread::spawn(move || {
|
||||
if !prebuilt {
|
||||
// Printing to stderr because we want stdout to contain only the output of the roc program.
|
||||
// We are aware of the trade-offs.
|
||||
// `cargo run` follows the same approach
|
||||
eprintln!("🔨 Rebuilding platform...");
|
||||
}
|
||||
// Printing to stderr because we want stdout to contain only the output of the roc program.
|
||||
// We are aware of the trade-offs.
|
||||
// `cargo run` follows the same approach
|
||||
eprintln!("🔨 Rebuilding platform...");
|
||||
|
||||
let rebuild_host_start = Instant::now();
|
||||
|
||||
if !prebuilt {
|
||||
match linking_strategy {
|
||||
LinkingStrategy::Additive => {
|
||||
let host_dest = rebuild_host(
|
||||
opt_level,
|
||||
&thread_local_target,
|
||||
host_input_path.as_path(),
|
||||
None,
|
||||
);
|
||||
match linking_strategy {
|
||||
LinkingStrategy::Additive => {
|
||||
let host_dest = rebuild_host(
|
||||
opt_level,
|
||||
&thread_local_target,
|
||||
host_input_path.as_path(),
|
||||
None,
|
||||
);
|
||||
|
||||
preprocess_host_wasm32(host_dest.as_path(), &preprocessed_host_path);
|
||||
}
|
||||
LinkingStrategy::Surgical => {
|
||||
roc_linker::build_and_preprocess_host(
|
||||
opt_level,
|
||||
&thread_local_target,
|
||||
host_input_path.as_path(),
|
||||
preprocessed_host_path.as_path(),
|
||||
exported_symbols,
|
||||
exported_closure_types,
|
||||
);
|
||||
}
|
||||
LinkingStrategy::Legacy => {
|
||||
rebuild_host(
|
||||
opt_level,
|
||||
&thread_local_target,
|
||||
host_input_path.as_path(),
|
||||
None,
|
||||
);
|
||||
}
|
||||
preprocess_host_wasm32(host_dest.as_path(), &preprocessed_host_path);
|
||||
}
|
||||
LinkingStrategy::Surgical => {
|
||||
roc_linker::build_and_preprocess_host(
|
||||
opt_level,
|
||||
&thread_local_target,
|
||||
host_input_path.as_path(),
|
||||
preprocessed_host_path.as_path(),
|
||||
exported_symbols,
|
||||
exported_closure_types,
|
||||
);
|
||||
|
||||
// Copy preprocessed host to executable location.
|
||||
// The surgical linker will modify that copy in-place.
|
||||
std::fs::copy(&preprocessed_host_path, binary_path.as_path()).unwrap();
|
||||
}
|
||||
LinkingStrategy::Legacy => {
|
||||
rebuild_host(
|
||||
opt_level,
|
||||
&thread_local_target,
|
||||
host_input_path.as_path(),
|
||||
None,
|
||||
);
|
||||
}
|
||||
}
|
||||
if linking_strategy == LinkingStrategy::Surgical {
|
||||
// Copy preprocessed host to executable location.
|
||||
std::fs::copy(preprocessed_host_path, binary_path.as_path()).unwrap();
|
||||
}
|
||||
let rebuild_host_end = rebuild_host_start.elapsed();
|
||||
|
||||
rebuild_host_end.as_millis()
|
||||
rebuild_host_start.elapsed().as_millis()
|
||||
})
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue