From 817b6d1cfdf9b532137917fd6e1e74ed53a000dd Mon Sep 17 00:00:00 2001 From: roblabla Date: Sun, 4 Dec 2022 17:38:01 +0100 Subject: [PATCH 1/2] Raw-Dylib: Create stub .lib lazily, don't insert them in rlib --- compiler/rustc_codegen_ssa/src/back/link.rs | 22 ++++----------------- 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 7f6947e3c79d8..05e70eb81e912 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -359,21 +359,6 @@ fn link_rlib<'a>( } } - for (raw_dylib_name, raw_dylib_imports) in - collate_raw_dylibs(sess, &codegen_results.crate_info.used_libraries)? - { - let output_path = archive_builder_builder.create_dll_import_lib( - sess, - &raw_dylib_name, - &raw_dylib_imports, - tmpdir.as_ref(), - ); - - ab.add_archive(&output_path, Box::new(|_| false)).unwrap_or_else(|e| { - sess.fatal(&format!("failed to add native library {}: {}", output_path.display(), e)); - }); - } - if let Some(trailing_metadata) = trailing_metadata { // Note that it is important that we add all of our non-object "magical // files" *after* all of the object files in the archive. The reason for @@ -414,12 +399,13 @@ fn link_rlib<'a>( /// collate the symbols together by library name before generating the import libraries. fn collate_raw_dylibs( sess: &Session, - used_libraries: &[NativeLib], + crate_info: &CrateInfo, ) -> Result)>, ErrorGuaranteed> { // Use index maps to preserve original order of imports and libraries. let mut dylib_table = FxIndexMap::>::default(); - for lib in used_libraries { + let all_libs = crate_info.used_libraries.iter().chain(crate_info.native_libraries.values().flatten()); + for lib in all_libs { if lib.kind == NativeLibKind::RawDylib { let ext = if matches!(lib.verbatim, Some(true)) { "" } else { ".dll" }; let name = format!("{}{}", lib.name.expect("unnamed raw-dylib library"), ext); @@ -2008,7 +1994,7 @@ fn linker_with_args<'a>( // Link with the import library generated for any raw-dylib functions. for (raw_dylib_name, raw_dylib_imports) in - collate_raw_dylibs(sess, &codegen_results.crate_info.used_libraries)? + collate_raw_dylibs(sess, &codegen_results.crate_info)? { cmd.add_object(&archive_builder_builder.create_dll_import_lib( sess, From 9eb2cdf8bd15f6224b28245f4f1d0043561f5c85 Mon Sep 17 00:00:00 2001 From: roblabla Date: Sun, 4 Dec 2022 17:54:12 +0100 Subject: [PATCH 2/2] Implement raw dylib for macos --- .../rustc_codegen_llvm/src/back/archive.rs | 93 ++++++++++++++++--- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 22 +++++ compiler/rustc_codegen_ssa/src/back/link.rs | 8 +- .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 56 +++++++++++ compiler/rustc_metadata/src/native_libs.rs | 4 +- 5 files changed, 168 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index 27039cda25382..ce6280e5514a8 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -9,7 +9,7 @@ use std::ptr; use std::str; use crate::llvm::archive_ro::{ArchiveRO, Child}; -use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport}; +use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport, LLVMRustTbdExport}; use rustc_codegen_ssa::back::archive::{ArchiveBuilder, ArchiveBuilderBuilder}; use rustc_session::cstore::{DllCallingConvention, DllImport}; use rustc_session::Session; @@ -104,33 +104,102 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder { dll_imports: &[DllImport], tmpdir: &Path, ) -> PathBuf { + let target = &sess.target; + let windows_toolchain = target.vendor == "pc" && target.os == "windows"; + let mingw_gnu_toolchain = windows_toolchain && target.env == "gnu" && target.abi.is_empty(); + let apple_toolchain = target.is_like_osx; + let output_path = { - let mut output_path: PathBuf = tmpdir.to_path_buf(); - output_path.push(format!("{}_imports", lib_name)); - output_path.with_extension("lib") + let mut filename = lib_name.replace('/', "_"); + if apple_toolchain { + filename.push_str("tbd"); + } else { + filename.push_str("lib"); + } + tmpdir.join(filename) }; - let target = &sess.target; - let mingw_gnu_toolchain = target.vendor == "pc" - && target.os == "windows" - && target.env == "gnu" - && target.abi.is_empty(); - let import_name_and_ordinal_vector: Vec<(String, Option)> = dll_imports .iter() .map(|import: &DllImport| { - if sess.target.arch == "x86" { + if sess.target.arch == "x86" && windows_toolchain { ( LlvmArchiveBuilder::i686_decorated_name(import, mingw_gnu_toolchain), import.ordinal, ) + } else if apple_toolchain { + (format!("_{}", import.name), import.ordinal) } else { (import.name.to_string(), import.ordinal) } }) .collect(); - if mingw_gnu_toolchain { + if apple_toolchain { + // we've checked for \0 characters in the library name already + let dll_name_z = CString::new(lib_name).unwrap(); + + let output_path_z = rustc_fs_util::path_to_c_string(&output_path); + + tracing::info!("invoking LLVMRustWriteTbdFile"); + tracing::info!(" dll_name {:#?}", dll_name_z); + tracing::info!(" output_path {}", output_path.display()); + tracing::info!( + " import names: {}", + dll_imports + .iter() + .map(|import| import.name.to_string()) + .collect::>() + .join(", "), + ); + + let cstring_import_name_vector: Vec = import_name_and_ordinal_vector + .into_iter() + .map(|(name, _ordinal)| CString::new(name).unwrap()) + .collect(); + + let ffi_exports: Vec = cstring_import_name_vector + .iter() + .map(|name_z| LLVMRustTbdExport::new(name_z.as_ptr(), 0)) + .collect(); + + // Get LLVM architecture from the target triple. + let arch = sess.target.llvm_target.split("-").nth(0).unwrap(); + + let plat = match (&*target.options.os, &*target.options.abi) { + ("macos", "") => "macos", + ("ios", "") => "ios", + ("tvos", "") => "tvos", + ("watchos", "") => "watchos", + ("macos", "macabi") => "maccatalyst", + ("ios", "sim") => "ios-simulator", + ("tvos", "sim") => "tvos-simulator", + ("watchos", "sim") => "watchos-simulator", + _ => "unknown", + }; + + let target = CString::new(format!("{}-{}", arch, plat)).unwrap(); + let ffi_targets = &[target.as_ptr()]; + + let result = unsafe { + crate::llvm::LLVMRustWriteTbdFile( + dll_name_z.as_ptr(), + output_path_z.as_ptr(), + ffi_exports.as_ptr(), + ffi_exports.len(), + ffi_targets.as_ptr(), + ffi_targets.len(), + ) + }; + + if result == crate::llvm::LLVMRustResult::Failure { + sess.fatal(&format!( + "Error creating apple import library for {}: {}", + lib_name, + llvm::last_error().unwrap_or("unknown LLVM error".to_string()) + )); + } + } else if mingw_gnu_toolchain { // The binutils linker used on -windows-gnu targets cannot read the import // libraries generated by LLVM: in our attempts, the linker produced an .EXE // that loaded but crashed with an AV upon calling one of the imported diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 4ca3dd78caede..84a52e80b1e17 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -49,6 +49,19 @@ impl LLVMRustCOFFShortExport { } } +// Rust version of the C struct with the same name in rustc_llvm/llvm-wrapper/RustWrapper.cpp. +#[repr(C)] +pub struct LLVMRustTbdExport { + pub name: *const c_char, + pub symbol_flags: u8, +} + +impl LLVMRustTbdExport { + pub fn new(name: *const c_char, symbol_flags: u8) -> LLVMRustTbdExport { + LLVMRustTbdExport { name, symbol_flags } + } +} + /// Translation of LLVM's MachineTypes enum, defined in llvm\include\llvm\BinaryFormat\COFF.h. /// /// We include only architectures supported on Windows. @@ -2552,4 +2565,13 @@ extern "C" { pub fn LLVMRustGetMangledName(V: &Value, out: &RustString); pub fn LLVMRustGetElementTypeArgIndex(CallSite: &Value) -> i32; + + pub fn LLVMRustWriteTbdFile( + ImportName: *const c_char, + Path: *const c_char, + Exports: *const LLVMRustTbdExport, + NumExports: usize, + LlvmTriples: *const *const c_char, + NumLlvmTriples: usize, + ) -> LLVMRustResult; } diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 05e70eb81e912..b0f111b51fb2c 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -407,7 +407,13 @@ fn collate_raw_dylibs( let all_libs = crate_info.used_libraries.iter().chain(crate_info.native_libraries.values().flatten()); for lib in all_libs { if lib.kind == NativeLibKind::RawDylib { - let ext = if matches!(lib.verbatim, Some(true)) { "" } else { ".dll" }; + let ext = if matches!(lib.verbatim, Some(true)) { + "" + } else if sess.target.is_like_osx { + ".dylib" + } else { + ".dll" + }; let name = format!("{}{}", lib.name.expect("unnamed raw-dylib library"), ext); let imports = dylib_table.entry(name.clone()).or_default(); for import in &lib.dll_imports { diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 931ce78721cb8..56379c420d159 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -15,6 +15,8 @@ #include "llvm/Bitcode/BitcodeWriterPass.h" #include "llvm/Support/Signals.h" #include "llvm/ADT/Optional.h" +#include "llvm/TextAPI/InterfaceFile.h" +#include "llvm/TextAPI/TextAPIWriter.h" #include @@ -1959,3 +1961,57 @@ extern "C" int32_t LLVMRustGetElementTypeArgIndex(LLVMValueRef CallSite) { #endif return -1; } + + +// This struct contains all necessary info about a symbol exported from a tbd. +struct LLVMRustTbdExport { + const char* name; + uint8_t symbol_flags; +}; + +extern "C" LLVMRustResult LLVMRustWriteTbdFile( + const char* ImportName, + const char* Path, + const LLVMRustTbdExport* Exports, + size_t NumExports, + const char** LlvmTriples, + size_t NumLlvmTriples) +{ + llvm::MachO::InterfaceFile tbd; + + tbd.setFileType(llvm::MachO::FileType::TBD_V4); + tbd.setTwoLevelNamespace(); + + llvm::MachO::TargetList targets; + for (size_t i = 0; i < NumLlvmTriples; ++i) { + printf("Target is %s\n", LlvmTriples[i]); + auto target = llvm::MachO::Target::create(LlvmTriples[i]); + if (!target) { + return LLVMRustResult::Failure; + } + targets.emplace_back(target.get()); + } + + for (auto target = targets.begin(); target != targets.end(); ++target) { + tbd.addTarget(*target); + } + + tbd.setInstallName(StringRef(ImportName)); + + for (size_t i = 0; i < NumExports; ++i) { + auto symbol_kind = llvm::MachO::SymbolKind::GlobalSymbol; + auto flags = static_cast(Exports[i].symbol_flags); + tbd.addSymbol(symbol_kind, StringRef(Exports[i].name), targets, flags); + } + + std::error_code ec; + llvm::raw_fd_ostream fd(Path, ec); + if (ec) { + return LLVMRustResult::Failure; + } + llvm::Error err = llvm::MachO::TextAPIWriter::writeToStream(fd, tbd); + if (err) { + return LLVMRustResult::Failure; + } + return LLVMRustResult::Success; +} diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index c5e39507d7e4d..5502de759a1c6 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -111,12 +111,12 @@ impl<'tcx> Collector<'tcx> { NativeLibKind::Framework { as_needed: None } } "raw-dylib" => { - if !sess.target.is_like_windows { + if !sess.target.is_like_windows && !sess.target.is_like_osx { struct_span_err!( sess, span, E0455, - "link kind `raw-dylib` is only supported on Windows targets" + "link kind `raw-dylib` is only supported on Windows and Apple targets" ) .emit(); } else if !features.raw_dylib {