mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 13:29:12 +00:00
Merge pull request #3919 from roc-lang/surgical-no-break-caching
surgical linker: don't generate dynhost if it's unchanged
This commit is contained in:
commit
7e31f67910
1 changed files with 61 additions and 3 deletions
|
@ -136,10 +136,68 @@ fn generate_dynamic_lib(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !dummy_lib_is_up_to_date(target, dummy_lib_path, &custom_names) {
|
||||||
let bytes = crate::generate_dylib::generate(target, &custom_names)
|
let bytes = crate::generate_dylib::generate(target, &custom_names)
|
||||||
.unwrap_or_else(|e| internal_error!("{}", e));
|
.unwrap_or_else(|e| internal_error!("{}", e));
|
||||||
|
|
||||||
std::fs::write(dummy_lib_path, &bytes).unwrap_or_else(|e| internal_error!("{}", e))
|
std::fs::write(dummy_lib_path, &bytes).unwrap_or_else(|e| internal_error!("{}", e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn object_matches_target<'a>(target: &Triple, object: &object::File<'a, &'a [u8]>) -> bool {
|
||||||
|
use target_lexicon::{Architecture as TLA, OperatingSystem as TLO};
|
||||||
|
|
||||||
|
match target.architecture {
|
||||||
|
TLA::X86_64 => {
|
||||||
|
if object.architecture() != object::Architecture::X86_64 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let target_format = match target.operating_system {
|
||||||
|
TLO::Linux => object::BinaryFormat::Elf,
|
||||||
|
TLO::Windows => object::BinaryFormat::Pe,
|
||||||
|
_ => todo!("surgical linker does not support target {:?}", target),
|
||||||
|
};
|
||||||
|
|
||||||
|
object.format() == target_format
|
||||||
|
}
|
||||||
|
TLA::Aarch64(_) => object.architecture() == object::Architecture::Aarch64,
|
||||||
|
_ => todo!("surgical linker does not support target {:?}", target),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks whether the dummy `.dll/.so` is up to date, in other words that it exports exactly the
|
||||||
|
/// symbols that it is supposed to export, and is built for the right target. If this is the case,
|
||||||
|
/// we can skip rebuildingthe dummy lib.
|
||||||
|
fn dummy_lib_is_up_to_date(
|
||||||
|
target: &Triple,
|
||||||
|
dummy_lib_path: &Path,
|
||||||
|
custom_names: &[String],
|
||||||
|
) -> bool {
|
||||||
|
if !std::path::Path::exists(dummy_lib_path) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let exec_file = fs::File::open(dummy_lib_path).unwrap_or_else(|e| internal_error!("{}", e));
|
||||||
|
let exec_mmap = unsafe { Mmap::map(&exec_file).unwrap_or_else(|e| internal_error!("{}", e)) };
|
||||||
|
let exec_data = &*exec_mmap;
|
||||||
|
|
||||||
|
let object = object::File::parse(exec_data).unwrap();
|
||||||
|
|
||||||
|
// the user may have been cross-compiling.
|
||||||
|
// The dynhost on disk must match our current target
|
||||||
|
if !object_matches_target(target, &object) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we made this dynhost file. For the file to be the same as what we'd generate,
|
||||||
|
// we need all symbols to be there and in the correct order
|
||||||
|
let dynamic_symbols: Vec<_> = object.exports().unwrap();
|
||||||
|
|
||||||
|
let it1 = dynamic_symbols.iter().map(|e| e.name());
|
||||||
|
let it2 = custom_names.iter().map(|s| s.as_bytes());
|
||||||
|
|
||||||
|
it1.eq(it2)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_roc_symbol(sym: &object::Symbol) -> bool {
|
fn is_roc_symbol(sym: &object::Symbol) -> bool {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue