mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 13:29:12 +00:00
add macho dummy lib generation with ld
This commit is contained in:
parent
d6bdd2aec7
commit
dead264798
3 changed files with 101 additions and 1 deletions
94
crates/linker/src/generate_dylib/macho.rs
Normal file
94
crates/linker/src/generate_dylib/macho.rs
Normal file
|
@ -0,0 +1,94 @@
|
|||
use object::write;
|
||||
use object::{Architecture, BinaryFormat, Endianness, SymbolFlags, SymbolKind, SymbolScope};
|
||||
use roc_error_macros::internal_error;
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
use target_lexicon::Triple;
|
||||
use tempfile::Builder;
|
||||
|
||||
// TODO: Eventually do this from scratch and in memory instead of with ld.
|
||||
pub fn create_dylib_macho(
|
||||
custom_names: &[String],
|
||||
triple: &Triple,
|
||||
) -> object::read::Result<Vec<u8>> {
|
||||
let dummy_obj_file = Builder::new()
|
||||
.prefix("roc_lib")
|
||||
.suffix(".o")
|
||||
.tempfile()
|
||||
.unwrap_or_else(|e| internal_error!("{}", e));
|
||||
let dummy_obj_file = dummy_obj_file.path();
|
||||
let tmp = tempfile::tempdir().unwrap_or_else(|e| internal_error!("{}", e));
|
||||
let dummy_lib_file = tmp.path().to_path_buf().with_file_name("libapp.so");
|
||||
|
||||
let obj_target = BinaryFormat::MachO;
|
||||
let obj_arch = match triple.architecture {
|
||||
target_lexicon::Architecture::X86_64 => Architecture::X86_64,
|
||||
target_lexicon::Architecture::Aarch64(_) => Architecture::Aarch64,
|
||||
_ => {
|
||||
// We should have verified this via supported() before calling this function
|
||||
unreachable!()
|
||||
}
|
||||
};
|
||||
let mut out_object = write::Object::new(obj_target, obj_arch, Endianness::Little);
|
||||
|
||||
let text_section = out_object.section_id(write::StandardSection::Text);
|
||||
|
||||
for name in custom_names {
|
||||
out_object.add_symbol(write::Symbol {
|
||||
name: name.as_bytes().to_vec(),
|
||||
value: 0,
|
||||
size: 0,
|
||||
kind: SymbolKind::Text,
|
||||
scope: SymbolScope::Dynamic,
|
||||
weak: false,
|
||||
section: write::SymbolSection::Section(text_section),
|
||||
flags: SymbolFlags::None,
|
||||
});
|
||||
}
|
||||
|
||||
std::fs::write(
|
||||
&dummy_obj_file,
|
||||
out_object.write().expect("failed to build output object"),
|
||||
)
|
||||
.expect("failed to write object to file");
|
||||
|
||||
// This path only exists on macOS Big Sur, and it causes ld errors
|
||||
// on Catalina if it's specified with -L, so we replace it with a
|
||||
// redundant -lSystem if the directory isn't there.
|
||||
let big_sur_path = "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib";
|
||||
let big_sur_fix = if Path::new(big_sur_path).exists() {
|
||||
"-L/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib"
|
||||
} else {
|
||||
"-lSystem" // We say -lSystem twice in the case of non-Big-Sur OSes, but it's fine.
|
||||
};
|
||||
|
||||
let ld_flag_soname = "-install_name";
|
||||
let ld_prefix_args = [big_sur_fix, "-lSystem", "-dylib"];
|
||||
|
||||
let output = Command::new("ld")
|
||||
.args(ld_prefix_args)
|
||||
.args(&[
|
||||
ld_flag_soname,
|
||||
dummy_lib_file.file_name().unwrap().to_str().unwrap(),
|
||||
dummy_obj_file.to_str().unwrap(),
|
||||
"-o",
|
||||
dummy_lib_file.to_str().unwrap(),
|
||||
])
|
||||
.output()
|
||||
.unwrap();
|
||||
|
||||
if !output.status.success() {
|
||||
match std::str::from_utf8(&output.stderr) {
|
||||
Ok(stderr) => panic!(
|
||||
"Failed to link dummy shared library - stderr of the `ld` command was:\n{}",
|
||||
stderr
|
||||
),
|
||||
Err(utf8_err) => panic!(
|
||||
"Failed to link dummy shared library - stderr of the `ld` command was invalid utf8 ({:?})",
|
||||
utf8_err
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(std::fs::read(dummy_lib_file).expect("Failed to load dummy library"))
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
use target_lexicon::Triple;
|
||||
|
||||
mod elf64;
|
||||
mod macho;
|
||||
mod pe;
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -14,7 +15,7 @@ pub(crate) use pe::APP_DLL;
|
|||
pub fn generate(target: &Triple, custom_names: &[String]) -> object::read::Result<Vec<u8>> {
|
||||
match target.binary_format {
|
||||
target_lexicon::BinaryFormat::Elf => elf64::create_dylib_elf64(custom_names),
|
||||
target_lexicon::BinaryFormat::Macho => todo!("macho dylib creation"),
|
||||
target_lexicon::BinaryFormat::Macho => macho::create_dylib_macho(custom_names, target),
|
||||
target_lexicon::BinaryFormat::Coff => Ok(pe::synthetic_dll(custom_names)),
|
||||
other => unimplemented!("dylib creation for {:?}", other),
|
||||
}
|
||||
|
|
|
@ -139,6 +139,11 @@ pub fn generate_dummy_lib(input_path: &Path, triple: &Triple) -> std::io::Result
|
|||
.collect();
|
||||
|
||||
if let EntryPoint::Executable { platform_path, .. } = &loaded.entry_point {
|
||||
let platform_path = input_path
|
||||
.to_path_buf()
|
||||
.parent()
|
||||
.unwrap()
|
||||
.join(platform_path);
|
||||
let dummy_lib = if let target_lexicon::OperatingSystem::Windows = triple.operating_system {
|
||||
platform_path.with_file_name("libapp.obj")
|
||||
} else {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue