mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 21:39:07 +00:00
refactor cli/src/build.rs
This commit is contained in:
parent
a2c760aa56
commit
1995d8b3df
5 changed files with 235 additions and 156 deletions
|
@ -69,6 +69,7 @@ roc_wasm_interp = { path = "../wasm_interp", optional = true }
|
||||||
|
|
||||||
ven_pretty = { path = "../vendor/pretty" }
|
ven_pretty = { path = "../vendor/pretty" }
|
||||||
|
|
||||||
|
indoc.workspace = true
|
||||||
clap.workspace = true
|
clap.workspace = true
|
||||||
const_format.workspace = true
|
const_format.workspace = true
|
||||||
mimalloc.workspace = true
|
mimalloc.workspace = true
|
||||||
|
|
|
@ -58,6 +58,41 @@ pub enum BuildFileError<'a> {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> BuildFileError<'a> {
|
||||||
|
fn from_mono_error(error: LoadMonomorphizedError<'a>, compilation_start: Instant) -> Self {
|
||||||
|
match error {
|
||||||
|
LoadMonomorphizedError::LoadingProblem(problem) => {
|
||||||
|
BuildFileError::LoadingProblem(problem)
|
||||||
|
}
|
||||||
|
LoadMonomorphizedError::ErrorModule(module) => BuildFileError::ErrorModule {
|
||||||
|
module,
|
||||||
|
total_time: compilation_start.elapsed(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn standard_load_config(
|
||||||
|
target: &Triple,
|
||||||
|
order: BuildOrdering,
|
||||||
|
threading: Threading,
|
||||||
|
) -> LoadConfig {
|
||||||
|
let target_info = TargetInfo::from(target);
|
||||||
|
|
||||||
|
let exec_mode = match order {
|
||||||
|
BuildOrdering::BuildIfChecks => ExecutionMode::ExecutableIfCheck,
|
||||||
|
BuildOrdering::AlwaysBuild => ExecutionMode::Executable,
|
||||||
|
};
|
||||||
|
|
||||||
|
LoadConfig {
|
||||||
|
target_info,
|
||||||
|
render: RenderTarget::ColorTerminal,
|
||||||
|
palette: DEFAULT_PALETTE,
|
||||||
|
threading,
|
||||||
|
exec_mode,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn build_file<'a>(
|
pub fn build_file<'a>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
|
@ -68,84 +103,100 @@ pub fn build_file<'a>(
|
||||||
link_type: LinkType,
|
link_type: LinkType,
|
||||||
linking_strategy: LinkingStrategy,
|
linking_strategy: LinkingStrategy,
|
||||||
prebuilt_requested: bool,
|
prebuilt_requested: bool,
|
||||||
threading: Threading,
|
|
||||||
wasm_dev_stack_bytes: Option<u32>,
|
wasm_dev_stack_bytes: Option<u32>,
|
||||||
roc_cache_dir: RocCacheDir<'_>,
|
roc_cache_dir: RocCacheDir<'_>,
|
||||||
order: BuildOrdering,
|
load_config: LoadConfig,
|
||||||
) -> Result<BuiltFile<'a>, BuildFileError<'a>> {
|
) -> Result<BuiltFile<'a>, BuildFileError<'a>> {
|
||||||
let compilation_start = Instant::now();
|
let compilation_start = Instant::now();
|
||||||
let target_info = TargetInfo::from(target);
|
|
||||||
|
|
||||||
// Step 1: compile the app and generate the .o file
|
// Step 1: compile the app and generate the .o file
|
||||||
let exec_mode = match order {
|
let loaded =
|
||||||
BuildOrdering::BuildIfChecks => ExecutionMode::ExecutableIfCheck,
|
roc_load::load_and_monomorphize(arena, app_module_path.clone(), roc_cache_dir, load_config)
|
||||||
BuildOrdering::AlwaysBuild => ExecutionMode::Executable,
|
.map_err(|e| BuildFileError::from_mono_error(e, compilation_start))?;
|
||||||
|
|
||||||
|
build_loaded_file(
|
||||||
|
arena,
|
||||||
|
target,
|
||||||
|
app_module_path,
|
||||||
|
code_gen_options,
|
||||||
|
emit_timings,
|
||||||
|
link_type,
|
||||||
|
linking_strategy,
|
||||||
|
prebuilt_requested,
|
||||||
|
wasm_dev_stack_bytes,
|
||||||
|
loaded,
|
||||||
|
compilation_start,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
fn build_loaded_file<'a>(
|
||||||
|
arena: &'a Bump,
|
||||||
|
target: &Triple,
|
||||||
|
app_module_path: PathBuf,
|
||||||
|
code_gen_options: CodeGenOptions,
|
||||||
|
emit_timings: bool,
|
||||||
|
link_type: LinkType,
|
||||||
|
linking_strategy: LinkingStrategy,
|
||||||
|
prebuilt_requested: bool,
|
||||||
|
wasm_dev_stack_bytes: Option<u32>,
|
||||||
|
loaded: roc_load::MonomorphizedModule<'a>,
|
||||||
|
compilation_start: Instant,
|
||||||
|
) -> Result<BuiltFile<'a>, BuildFileError<'a>> {
|
||||||
|
let operating_system = roc_target::OperatingSystem::from(target.operating_system);
|
||||||
|
|
||||||
|
let host_input_path = match &loaded.entry_point {
|
||||||
|
EntryPoint::Executable { platform_path, .. } => {
|
||||||
|
use roc_target::OperatingSystem::*;
|
||||||
|
|
||||||
|
let host_filename = match operating_system {
|
||||||
|
Wasi => "host.zig".to_string(),
|
||||||
|
Unix => legacy_host_filename(target, code_gen_options.opt_level).unwrap(),
|
||||||
|
Windows => legacy_host_filename(target, code_gen_options.opt_level).unwrap(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let load_config = LoadConfig {
|
platform_path.with_file_name(host_filename)
|
||||||
target_info,
|
}
|
||||||
// TODO: expose this from CLI?
|
_ => unreachable!(),
|
||||||
render: RenderTarget::ColorTerminal,
|
|
||||||
palette: DEFAULT_PALETTE,
|
|
||||||
threading,
|
|
||||||
exec_mode,
|
|
||||||
};
|
};
|
||||||
let load_result =
|
|
||||||
roc_load::load_and_monomorphize(arena, app_module_path.clone(), roc_cache_dir, load_config);
|
let preprocessed_host_path = if linking_strategy == LinkingStrategy::Legacy {
|
||||||
let loaded = match load_result {
|
let filename = legacy_host_filename(target, code_gen_options.opt_level).unwrap();
|
||||||
Ok(loaded) => loaded,
|
host_input_path.with_file_name(filename)
|
||||||
Err(LoadMonomorphizedError::LoadingProblem(problem)) => {
|
} else {
|
||||||
return Err(BuildFileError::LoadingProblem(problem))
|
let filename = preprocessed_host_filename(target).unwrap();
|
||||||
}
|
host_input_path.with_file_name(filename)
|
||||||
Err(LoadMonomorphizedError::ErrorModule(module)) => {
|
|
||||||
return Err(BuildFileError::ErrorModule {
|
|
||||||
module,
|
|
||||||
total_time: compilation_start.elapsed(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// For example, if we're loading the platform from a URL, it's automatically prebuilt
|
// For example, if we're loading the platform from a URL, it's automatically prebuilt
|
||||||
// even if the --prebuilt-platform=true CLI flag wasn't set.
|
// even if the --prebuilt-platform=true CLI flag wasn't set.
|
||||||
let is_prebuilt = prebuilt_requested || loaded.uses_prebuilt_platform;
|
let is_platform_prebuilt = prebuilt_requested || loaded.uses_prebuilt_platform;
|
||||||
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", Some("wasm"), "host.zig".to_string())
|
|
||||||
} else {
|
|
||||||
("bc", Some("wasm"), "host.zig".to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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(),
|
|
||||||
),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let cwd = app_module_path.parent().unwrap();
|
let cwd = app_module_path.parent().unwrap();
|
||||||
let mut binary_path = cwd.join(&*loaded.output_path);
|
let mut output_exe_path = cwd.join(&*loaded.output_path);
|
||||||
|
|
||||||
if let Some(extension) = extension {
|
if let Some(extension) = operating_system.executable_file_ext() {
|
||||||
binary_path.set_extension(extension);
|
output_exe_path.set_extension(extension);
|
||||||
}
|
}
|
||||||
|
|
||||||
let host_input_path = if let EntryPoint::Executable { platform_path, .. } = &loaded.entry_point
|
// We don't need to spawn a rebuild thread when using a prebuilt host.
|
||||||
{
|
let rebuild_thread = if matches!(link_type, LinkType::Dylib | LinkType::None) {
|
||||||
platform_path.with_file_name(host_filename)
|
None
|
||||||
} else {
|
} else if is_platform_prebuilt {
|
||||||
unreachable!();
|
if !preprocessed_host_path.exists() {
|
||||||
};
|
invalid_prebuilt_platform(prebuilt_requested, preprocessed_host_path);
|
||||||
|
|
||||||
|
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, output_exe_path.as_path()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
} else {
|
||||||
// TODO this should probably be moved before load_and_monomorphize.
|
// TODO this should probably be moved before load_and_monomorphize.
|
||||||
// To do this we will need to preprocess files just for their exported symbols.
|
// To do this we will need to preprocess files just for their exported symbols.
|
||||||
// Also, we should no longer need to do this once we have platforms on
|
// Also, we should no longer need to do this once we have platforms on
|
||||||
|
@ -171,51 +222,18 @@ pub fn build_file<'a>(
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let preprocessed_host_path = if linking_strategy == LinkingStrategy::Legacy {
|
let join_handle = spawn_rebuild_thread(
|
||||||
host_input_path
|
|
||||||
.with_file_name(legacy_host_filename(target, code_gen_options.opt_level).unwrap())
|
|
||||||
} else {
|
|
||||||
host_input_path.with_file_name(preprocessed_host_filename(target).unwrap())
|
|
||||||
};
|
|
||||||
|
|
||||||
// We don't need to spawn a rebuild thread when using a prebuilt host.
|
|
||||||
let rebuild_thread = if matches!(link_type, LinkType::Dylib | LinkType::None) {
|
|
||||||
None
|
|
||||||
} else if is_prebuilt {
|
|
||||||
if !preprocessed_host_path.exists() {
|
|
||||||
if prebuilt_requested {
|
|
||||||
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 generate it by re-running this command with --prebuilt-platform=false\n",
|
|
||||||
preprocessed_host_path.to_string_lossy()
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
eprintln!(
|
|
||||||
"\nI 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 generate 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,
|
code_gen_options.opt_level,
|
||||||
linking_strategy,
|
linking_strategy,
|
||||||
host_input_path.clone(),
|
host_input_path.clone(),
|
||||||
preprocessed_host_path.clone(),
|
preprocessed_host_path.clone(),
|
||||||
binary_path.clone(),
|
output_exe_path.clone(),
|
||||||
target,
|
target,
|
||||||
exposed_values,
|
exposed_values,
|
||||||
exposed_closure_types,
|
exposed_closure_types,
|
||||||
))
|
);
|
||||||
|
|
||||||
|
Some(join_handle)
|
||||||
};
|
};
|
||||||
|
|
||||||
let buf = &mut String::with_capacity(1024);
|
let buf = &mut String::with_capacity(1024);
|
||||||
|
@ -235,29 +253,8 @@ pub fn build_file<'a>(
|
||||||
|
|
||||||
buf.push('\n');
|
buf.push('\n');
|
||||||
|
|
||||||
report_timing(buf, "Read .roc file from disk", module_timing.read_roc_file);
|
use std::fmt::Write;
|
||||||
report_timing(buf, "Parse header", module_timing.parse_header);
|
write!(buf, "{}", module_timing).unwrap();
|
||||||
report_timing(buf, "Parse body", module_timing.parse_body);
|
|
||||||
report_timing(buf, "Canonicalize", module_timing.canonicalize);
|
|
||||||
report_timing(buf, "Constrain", module_timing.constrain);
|
|
||||||
report_timing(buf, "Solve", module_timing.solve);
|
|
||||||
report_timing(
|
|
||||||
buf,
|
|
||||||
"Find Specializations",
|
|
||||||
module_timing.find_specializations,
|
|
||||||
);
|
|
||||||
let multiple_make_specializations_passes = module_timing.make_specializations.len() > 1;
|
|
||||||
for (i, pass_time) in module_timing.make_specializations.iter().enumerate() {
|
|
||||||
let suffix = if multiple_make_specializations_passes {
|
|
||||||
format!(" (Pass {})", i)
|
|
||||||
} else {
|
|
||||||
String::new()
|
|
||||||
};
|
|
||||||
report_timing(buf, &format!("Make Specializations{}", suffix), *pass_time);
|
|
||||||
}
|
|
||||||
report_timing(buf, "Other", module_timing.other());
|
|
||||||
buf.push('\n');
|
|
||||||
report_timing(buf, "Total", module_timing.total());
|
|
||||||
|
|
||||||
if it.peek().is_some() {
|
if it.peek().is_some() {
|
||||||
buf.push('\n');
|
buf.push('\n');
|
||||||
|
@ -281,7 +278,7 @@ pub fn build_file<'a>(
|
||||||
.join()
|
.join()
|
||||||
.expect("Failed to (re)build platform.");
|
.expect("Failed to (re)build platform.");
|
||||||
|
|
||||||
if emit_timings && !is_prebuilt {
|
if emit_timings && !is_platform_prebuilt {
|
||||||
println!(
|
println!(
|
||||||
"Finished rebuilding the platform in {} ms\n",
|
"Finished rebuilding the platform in {} ms\n",
|
||||||
rebuild_duration
|
rebuild_duration
|
||||||
|
@ -336,7 +333,7 @@ pub fn build_file<'a>(
|
||||||
if let Some(HostRebuildTiming::ConcurrentWithApp(thread)) = opt_rebuild_timing {
|
if let Some(HostRebuildTiming::ConcurrentWithApp(thread)) = opt_rebuild_timing {
|
||||||
let rebuild_duration = thread.join().expect("Failed to (re)build platform.");
|
let rebuild_duration = thread.join().expect("Failed to (re)build platform.");
|
||||||
|
|
||||||
if emit_timings && !is_prebuilt {
|
if emit_timings && !is_platform_prebuilt {
|
||||||
println!(
|
println!(
|
||||||
"Finished rebuilding the platform in {} ms\n",
|
"Finished rebuilding the platform in {} ms\n",
|
||||||
rebuild_duration
|
rebuild_duration
|
||||||
|
@ -346,47 +343,45 @@ pub fn build_file<'a>(
|
||||||
|
|
||||||
// Step 2: link the prebuilt platform and compiled app
|
// Step 2: link the prebuilt platform and compiled app
|
||||||
let link_start = Instant::now();
|
let link_start = Instant::now();
|
||||||
let problems = match (linking_strategy, link_type) {
|
|
||||||
|
match (linking_strategy, link_type) {
|
||||||
(LinkingStrategy::Surgical, _) => {
|
(LinkingStrategy::Surgical, _) => {
|
||||||
roc_linker::link_preprocessed_host(
|
roc_linker::link_preprocessed_host(
|
||||||
target,
|
target,
|
||||||
&host_input_path,
|
&host_input_path,
|
||||||
&roc_app_bytes,
|
&roc_app_bytes,
|
||||||
&binary_path,
|
&output_exe_path,
|
||||||
);
|
);
|
||||||
|
|
||||||
problems
|
|
||||||
}
|
}
|
||||||
(LinkingStrategy::Additive, _) | (LinkingStrategy::Legacy, LinkType::None) => {
|
(LinkingStrategy::Additive, _) | (LinkingStrategy::Legacy, LinkType::None) => {
|
||||||
// Just copy the object file to the output folder.
|
// Just copy the object file to the output folder.
|
||||||
binary_path.set_extension(app_extension);
|
output_exe_path.set_extension(operating_system.object_file_ext());
|
||||||
std::fs::write(&binary_path, &*roc_app_bytes).unwrap();
|
std::fs::write(&output_exe_path, &*roc_app_bytes).unwrap();
|
||||||
problems
|
|
||||||
}
|
}
|
||||||
(LinkingStrategy::Legacy, _) => {
|
(LinkingStrategy::Legacy, _) => {
|
||||||
let app_o_file = tempfile::Builder::new()
|
let app_o_file = tempfile::Builder::new()
|
||||||
.prefix("roc_app")
|
.prefix("roc_app")
|
||||||
.suffix(&format!(".{}", app_extension))
|
.suffix(&format!(".{}", operating_system.object_file_ext()))
|
||||||
.tempfile()
|
.tempfile()
|
||||||
.map_err(|err| todo!("TODO Gracefully handle tempfile creation error {:?}", err))?;
|
.map_err(|err| todo!("TODO Gracefully handle tempfile creation error {:?}", err))?;
|
||||||
let app_o_file = app_o_file.path();
|
let app_o_file = app_o_file.path();
|
||||||
|
|
||||||
std::fs::write(app_o_file, &*roc_app_bytes).unwrap();
|
std::fs::write(app_o_file, &*roc_app_bytes).unwrap();
|
||||||
|
|
||||||
|
let builtins_host_tempfile =
|
||||||
|
bitcode::host_tempfile().expect("failed to write host builtins object to tempfile");
|
||||||
|
|
||||||
let mut inputs = vec![app_o_file.to_str().unwrap()];
|
let mut inputs = vec![app_o_file.to_str().unwrap()];
|
||||||
|
|
||||||
if !matches!(link_type, LinkType::Dylib | LinkType::None) {
|
if !matches!(link_type, LinkType::Dylib | LinkType::None) {
|
||||||
inputs.push(host_input_path.as_path().to_str().unwrap());
|
inputs.push(host_input_path.as_path().to_str().unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
let builtins_host_tempfile =
|
|
||||||
bitcode::host_tempfile().expect("failed to write host builtins object to tempfile");
|
|
||||||
|
|
||||||
if matches!(code_gen_options.backend, program::CodeGenBackend::Assembly) {
|
if matches!(code_gen_options.backend, program::CodeGenBackend::Assembly) {
|
||||||
inputs.push(builtins_host_tempfile.path().to_str().unwrap());
|
inputs.push(builtins_host_tempfile.path().to_str().unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
let (mut child, _) = link(target, binary_path.clone(), &inputs, link_type)
|
let (mut child, _) = link(target, output_exe_path.clone(), &inputs, link_type)
|
||||||
.map_err(|_| todo!("gracefully handle `ld` failing to spawn."))?;
|
.map_err(|_| todo!("gracefully handle `ld` failing to spawn."))?;
|
||||||
|
|
||||||
let exit_status = child
|
let exit_status = child
|
||||||
|
@ -397,16 +392,14 @@ pub fn build_file<'a>(
|
||||||
// (and thus deleted) before the child process is done using it!
|
// (and thus deleted) before the child process is done using it!
|
||||||
let _ = builtins_host_tempfile;
|
let _ = builtins_host_tempfile;
|
||||||
|
|
||||||
if exit_status.success() {
|
if !exit_status.success() {
|
||||||
problems
|
|
||||||
} else {
|
|
||||||
todo!(
|
todo!(
|
||||||
"gracefully handle `ld` (or `zig` in the case of wasm with --optimize) returning exit code {:?}",
|
"gracefully handle `ld` (or `zig` in the case of wasm with --optimize) returning exit code {:?}",
|
||||||
exit_status.code()
|
exit_status.code()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
let linking_time = link_start.elapsed();
|
let linking_time = link_start.elapsed();
|
||||||
|
|
||||||
|
@ -417,20 +410,43 @@ pub fn build_file<'a>(
|
||||||
let total_time = compilation_start.elapsed();
|
let total_time = compilation_start.elapsed();
|
||||||
|
|
||||||
Ok(BuiltFile {
|
Ok(BuiltFile {
|
||||||
binary_path,
|
binary_path: output_exe_path,
|
||||||
problems,
|
problems,
|
||||||
total_time,
|
total_time,
|
||||||
expect_metadata,
|
expect_metadata,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn invalid_prebuilt_platform(prebuilt_requested: bool, preprocessed_host_path: PathBuf) {
|
||||||
|
let prefix = match prebuilt_requested {
|
||||||
|
true => "Because I was run with --prebuilt-platform=true, ",
|
||||||
|
false => "",
|
||||||
|
};
|
||||||
|
|
||||||
|
eprintln!(
|
||||||
|
indoc::indoc!(
|
||||||
|
r#"
|
||||||
|
{}I was expecting this file to exist:
|
||||||
|
|
||||||
|
{}
|
||||||
|
|
||||||
|
However, it was not there!
|
||||||
|
|
||||||
|
If you have the platform's source code locally, you may be able to generate it by re-running this command with --prebuilt-platform=false
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
prefix,
|
||||||
|
preprocessed_host_path.to_string_lossy(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn spawn_rebuild_thread(
|
fn spawn_rebuild_thread(
|
||||||
opt_level: OptLevel,
|
opt_level: OptLevel,
|
||||||
linking_strategy: LinkingStrategy,
|
linking_strategy: LinkingStrategy,
|
||||||
host_input_path: PathBuf,
|
host_input_path: PathBuf,
|
||||||
preprocessed_host_path: PathBuf,
|
preprocessed_host_path: PathBuf,
|
||||||
binary_path: PathBuf,
|
output_exe_path: PathBuf,
|
||||||
target: &Triple,
|
target: &Triple,
|
||||||
exported_symbols: Vec<String>,
|
exported_symbols: Vec<String>,
|
||||||
exported_closure_types: Vec<String>,
|
exported_closure_types: Vec<String>,
|
||||||
|
@ -467,7 +483,7 @@ fn spawn_rebuild_thread(
|
||||||
|
|
||||||
// Copy preprocessed host to executable location.
|
// Copy preprocessed host to executable location.
|
||||||
// The surgical linker will modify that copy in-place.
|
// The surgical linker will modify that copy in-place.
|
||||||
std::fs::copy(&preprocessed_host_path, binary_path.as_path()).unwrap();
|
std::fs::copy(&preprocessed_host_path, output_exe_path.as_path()).unwrap();
|
||||||
}
|
}
|
||||||
LinkingStrategy::Legacy => {
|
LinkingStrategy::Legacy => {
|
||||||
rebuild_host(
|
rebuild_host(
|
||||||
|
|
|
@ -34,7 +34,7 @@ pub mod build;
|
||||||
mod format;
|
mod format;
|
||||||
pub use format::format;
|
pub use format::format;
|
||||||
|
|
||||||
use crate::build::{BuildFileError, BuildOrdering};
|
use crate::build::{standard_load_config, BuildFileError, BuildOrdering};
|
||||||
|
|
||||||
const DEFAULT_ROC_FILENAME: &str = "main.roc";
|
const DEFAULT_ROC_FILENAME: &str = "main.roc";
|
||||||
|
|
||||||
|
@ -672,6 +672,8 @@ pub fn build(
|
||||||
emit_debug_info,
|
emit_debug_info,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let load_config = standard_load_config(&triple, build_ordering, threading);
|
||||||
|
|
||||||
let res_binary_path = build_file(
|
let res_binary_path = build_file(
|
||||||
&arena,
|
&arena,
|
||||||
&triple,
|
&triple,
|
||||||
|
@ -681,10 +683,9 @@ pub fn build(
|
||||||
link_type,
|
link_type,
|
||||||
linking_strategy,
|
linking_strategy,
|
||||||
prebuilt,
|
prebuilt,
|
||||||
threading,
|
|
||||||
wasm_dev_stack_bytes,
|
wasm_dev_stack_bytes,
|
||||||
roc_cache_dir,
|
roc_cache_dir,
|
||||||
build_ordering,
|
load_config,
|
||||||
);
|
);
|
||||||
|
|
||||||
match res_binary_path {
|
match res_binary_path {
|
||||||
|
|
|
@ -1148,6 +1148,51 @@ impl ModuleTiming {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn report_timing(
|
||||||
|
buf: &mut impl std::fmt::Write,
|
||||||
|
label: &str,
|
||||||
|
duration: Duration,
|
||||||
|
) -> std::fmt::Result {
|
||||||
|
writeln!(
|
||||||
|
buf,
|
||||||
|
" {:9.3} ms {}",
|
||||||
|
duration.as_secs_f64() * 1000.0,
|
||||||
|
label,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for ModuleTiming {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let module_timing = self;
|
||||||
|
|
||||||
|
report_timing(f, "Read .roc file from disk", module_timing.read_roc_file)?;
|
||||||
|
report_timing(f, "Parse header", module_timing.parse_header)?;
|
||||||
|
report_timing(f, "Parse body", module_timing.parse_body)?;
|
||||||
|
report_timing(f, "Canonicalize", module_timing.canonicalize)?;
|
||||||
|
report_timing(f, "Constrain", module_timing.constrain)?;
|
||||||
|
report_timing(f, "Solve", module_timing.solve)?;
|
||||||
|
report_timing(
|
||||||
|
f,
|
||||||
|
"Find Specializations",
|
||||||
|
module_timing.find_specializations,
|
||||||
|
)?;
|
||||||
|
let multiple_make_specializations_passes = module_timing.make_specializations.len() > 1;
|
||||||
|
for (i, pass_time) in module_timing.make_specializations.iter().enumerate() {
|
||||||
|
let suffix = if multiple_make_specializations_passes {
|
||||||
|
format!(" (Pass {})", i)
|
||||||
|
} else {
|
||||||
|
String::new()
|
||||||
|
};
|
||||||
|
report_timing(f, &format!("Make Specializations{}", suffix), *pass_time)?;
|
||||||
|
}
|
||||||
|
report_timing(f, "Other", module_timing.other())?;
|
||||||
|
f.write_str("\n")?;
|
||||||
|
report_timing(f, "Total", module_timing.total())?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A message sent _to_ a worker thread, describing the work to be done
|
/// A message sent _to_ a worker thread, describing the work to be done
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
|
|
@ -24,6 +24,22 @@ impl OperatingSystem {
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const fn object_file_ext(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
OperatingSystem::Windows => "obj",
|
||||||
|
OperatingSystem::Unix => "o",
|
||||||
|
OperatingSystem::Wasi => "o",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn executable_file_ext(&self) -> Option<&str> {
|
||||||
|
match self {
|
||||||
|
OperatingSystem::Windows => Some("exe"),
|
||||||
|
OperatingSystem::Unix => None,
|
||||||
|
OperatingSystem::Wasi => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<target_lexicon::OperatingSystem> for OperatingSystem {
|
impl From<target_lexicon::OperatingSystem> for OperatingSystem {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue