From be04b0781215a04837f110d8872ffdaba8591e73 Mon Sep 17 00:00:00 2001 From: Noratrieb <48135649+Noratrieb@users.noreply.github.com> Date: Sat, 18 Jan 2025 18:19:42 +0100 Subject: [PATCH] Support raw-dylib link kind on ELF raw-dylib is a link kind that allows rustc to link against a library without having any library files present. This currently only exists on Windows. rustc will take all the symbols from raw-dylib link blocks and put them in an import library, where they can then be resolved by the linker. While import libraries don't exist on ELF, it would still be convenient to have this same functionality. Not having the libraries present at build-time can be convenient for several reasons, especially cross-compilation. With raw-dylib, code linking against a library can be cross-compiled without needing to have these libraries available on the build machine. If the libc crate makes use of this, it would allow cross-compilation without having any libc available on the build machine. This is not yet possible with this implementation, at least against libc's like glibc that use symbol versioning. The raw-dylib kind could be extended with support for symbol versioning in the future. This implementation is very experimental and I have not tested it very well. I have tested it for a toy example and the lz4-sys crate, where it was able to successfully link a binary despite not having a corresponding library at build-time. --- compiler/rustc_codegen_ssa/src/back/link.rs | 311 +++++++++++++++--- .../rustc_codegen_ssa/src/back/metadata.rs | 96 ++---- compiler/rustc_feature/src/unstable.rs | 2 + compiler/rustc_metadata/messages.ftl | 3 + compiler/rustc_metadata/src/native_libs.rs | 21 +- compiler/rustc_session/src/utils.rs | 1 + compiler/rustc_span/src/symbol.rs | 1 + compiler/rustc_target/src/spec/mod.rs | 68 +++- src/tools/compiletest/src/directive-list.rs | 2 + src/tools/compiletest/src/header/cfg.rs | 9 + .../run-make/raw-dylib-elf-verbatim/library.c | 3 + tests/run-make/raw-dylib-elf-verbatim/main.rs | 11 + .../raw-dylib-elf-verbatim/output.txt | 1 + .../run-make/raw-dylib-elf-verbatim/rmake.rs | 26 ++ tests/run-make/raw-dylib-elf/library.c | 3 + tests/run-make/raw-dylib-elf/main.rs | 11 + tests/run-make/raw-dylib-elf/output.txt | 1 + tests/run-make/raw-dylib-elf/rmake.rs | 24 ++ tests/run-make/reproducible-build/linker.rs | 2 + .../feature-gate-raw-dylib-elf.rs | 8 + .../feature-gate-raw-dylib-elf.stderr | 13 + .../raw-dylib/elf/multiple-libraries.rs | 33 ++ .../raw-dylib/elf/single-symbol.rs | 25 ++ .../ui/linkage-attr/raw-dylib/elf/verbatim.rs | 25 ++ .../raw-dylib/windows}/dlltool-failed.rs | 0 .../raw-dylib/windows}/dlltool-failed.stderr | 0 .../import-name-type-invalid-format.rs | 0 .../import-name-type-invalid-format.stderr | 0 .../windows}/import-name-type-multiple.rs | 0 .../windows}/import-name-type-multiple.stderr | 0 .../import-name-type-unknown-value.rs | 0 .../import-name-type-unknown-value.stderr | 0 .../import-name-type-unsupported-link-kind.rs | 0 ...ort-name-type-unsupported-link-kind.stderr | 0 .../windows}/import-name-type-x86-only.rs | 0 .../windows}/import-name-type-x86-only.stderr | 0 .../raw-dylib/windows}/invalid-dlltool.rs | 0 .../raw-dylib/windows}/invalid-dlltool.stderr | 0 .../windows}/link-ordinal-and-name.rs | 0 .../windows}/link-ordinal-and-name.stderr | 0 .../windows}/link-ordinal-invalid-format.rs | 0 .../link-ordinal-invalid-format.stderr | 0 .../windows}/link-ordinal-missing-argument.rs | 0 .../link-ordinal-missing-argument.stderr | 0 .../windows}/link-ordinal-multiple.rs | 0 .../windows}/link-ordinal-multiple.stderr | 0 .../windows}/link-ordinal-not-foreign-fn.rs | 0 .../link-ordinal-not-foreign-fn.stderr | 0 .../windows}/link-ordinal-too-large.rs | 0 .../windows}/link-ordinal-too-large.stderr | 0 .../link-ordinal-too-many-arguments.rs | 0 .../link-ordinal-too-many-arguments.stderr | 0 .../link-ordinal-unsupported-link-kind.rs | 0 .../link-ordinal-unsupported-link-kind.stderr | 0 .../windows}/multiple-declarations.rs | 0 .../windows}/multiple-declarations.stderr | 0 .../windows/raw-dylib-windows-only.elf.stderr | 13 + .../windows/raw-dylib-windows-only.rs | 9 + .../raw-dylib/windows}/unsupported-abi.rs | 0 .../raw-dylib/windows}/unsupported-abi.stderr | 0 .../raw-dylib-windows-only.rs | 5 - .../raw-dylib-windows-only.stderr | 9 - 62 files changed, 609 insertions(+), 127 deletions(-) create mode 100644 tests/run-make/raw-dylib-elf-verbatim/library.c create mode 100644 tests/run-make/raw-dylib-elf-verbatim/main.rs create mode 100644 tests/run-make/raw-dylib-elf-verbatim/output.txt create mode 100644 tests/run-make/raw-dylib-elf-verbatim/rmake.rs create mode 100644 tests/run-make/raw-dylib-elf/library.c create mode 100644 tests/run-make/raw-dylib-elf/main.rs create mode 100644 tests/run-make/raw-dylib-elf/output.txt create mode 100644 tests/run-make/raw-dylib-elf/rmake.rs create mode 100644 tests/ui/feature-gates/feature-gate-raw-dylib-elf.rs create mode 100644 tests/ui/feature-gates/feature-gate-raw-dylib-elf.stderr create mode 100644 tests/ui/linkage-attr/raw-dylib/elf/multiple-libraries.rs create mode 100644 tests/ui/linkage-attr/raw-dylib/elf/single-symbol.rs create mode 100644 tests/ui/linkage-attr/raw-dylib/elf/verbatim.rs rename tests/ui/{rfcs/rfc-2627-raw-dylib => linkage-attr/raw-dylib/windows}/dlltool-failed.rs (100%) rename tests/ui/{rfcs/rfc-2627-raw-dylib => linkage-attr/raw-dylib/windows}/dlltool-failed.stderr (100%) rename tests/ui/{rfcs/rfc-2627-raw-dylib => linkage-attr/raw-dylib/windows}/import-name-type-invalid-format.rs (100%) rename tests/ui/{rfcs/rfc-2627-raw-dylib => linkage-attr/raw-dylib/windows}/import-name-type-invalid-format.stderr (100%) rename tests/ui/{rfcs/rfc-2627-raw-dylib => linkage-attr/raw-dylib/windows}/import-name-type-multiple.rs (100%) rename tests/ui/{rfcs/rfc-2627-raw-dylib => linkage-attr/raw-dylib/windows}/import-name-type-multiple.stderr (100%) rename tests/ui/{rfcs/rfc-2627-raw-dylib => linkage-attr/raw-dylib/windows}/import-name-type-unknown-value.rs (100%) rename tests/ui/{rfcs/rfc-2627-raw-dylib => linkage-attr/raw-dylib/windows}/import-name-type-unknown-value.stderr (100%) rename tests/ui/{rfcs/rfc-2627-raw-dylib => linkage-attr/raw-dylib/windows}/import-name-type-unsupported-link-kind.rs (100%) rename tests/ui/{rfcs/rfc-2627-raw-dylib => linkage-attr/raw-dylib/windows}/import-name-type-unsupported-link-kind.stderr (100%) rename tests/ui/{rfcs/rfc-2627-raw-dylib => linkage-attr/raw-dylib/windows}/import-name-type-x86-only.rs (100%) rename tests/ui/{rfcs/rfc-2627-raw-dylib => linkage-attr/raw-dylib/windows}/import-name-type-x86-only.stderr (100%) rename tests/ui/{rfcs/rfc-2627-raw-dylib => linkage-attr/raw-dylib/windows}/invalid-dlltool.rs (100%) rename tests/ui/{rfcs/rfc-2627-raw-dylib => linkage-attr/raw-dylib/windows}/invalid-dlltool.stderr (100%) rename tests/ui/{rfcs/rfc-2627-raw-dylib => linkage-attr/raw-dylib/windows}/link-ordinal-and-name.rs (100%) rename tests/ui/{rfcs/rfc-2627-raw-dylib => linkage-attr/raw-dylib/windows}/link-ordinal-and-name.stderr (100%) rename tests/ui/{rfcs/rfc-2627-raw-dylib => linkage-attr/raw-dylib/windows}/link-ordinal-invalid-format.rs (100%) rename tests/ui/{rfcs/rfc-2627-raw-dylib => linkage-attr/raw-dylib/windows}/link-ordinal-invalid-format.stderr (100%) rename tests/ui/{rfcs/rfc-2627-raw-dylib => linkage-attr/raw-dylib/windows}/link-ordinal-missing-argument.rs (100%) rename tests/ui/{rfcs/rfc-2627-raw-dylib => linkage-attr/raw-dylib/windows}/link-ordinal-missing-argument.stderr (100%) rename tests/ui/{rfcs/rfc-2627-raw-dylib => linkage-attr/raw-dylib/windows}/link-ordinal-multiple.rs (100%) rename tests/ui/{rfcs/rfc-2627-raw-dylib => linkage-attr/raw-dylib/windows}/link-ordinal-multiple.stderr (100%) rename tests/ui/{rfcs/rfc-2627-raw-dylib => linkage-attr/raw-dylib/windows}/link-ordinal-not-foreign-fn.rs (100%) rename tests/ui/{rfcs/rfc-2627-raw-dylib => linkage-attr/raw-dylib/windows}/link-ordinal-not-foreign-fn.stderr (100%) rename tests/ui/{rfcs/rfc-2627-raw-dylib => linkage-attr/raw-dylib/windows}/link-ordinal-too-large.rs (100%) rename tests/ui/{rfcs/rfc-2627-raw-dylib => linkage-attr/raw-dylib/windows}/link-ordinal-too-large.stderr (100%) rename tests/ui/{rfcs/rfc-2627-raw-dylib => linkage-attr/raw-dylib/windows}/link-ordinal-too-many-arguments.rs (100%) rename tests/ui/{rfcs/rfc-2627-raw-dylib => linkage-attr/raw-dylib/windows}/link-ordinal-too-many-arguments.stderr (100%) rename tests/ui/{rfcs/rfc-2627-raw-dylib => linkage-attr/raw-dylib/windows}/link-ordinal-unsupported-link-kind.rs (100%) rename tests/ui/{rfcs/rfc-2627-raw-dylib => linkage-attr/raw-dylib/windows}/link-ordinal-unsupported-link-kind.stderr (100%) rename tests/ui/{rfcs/rfc-2627-raw-dylib => linkage-attr/raw-dylib/windows}/multiple-declarations.rs (100%) rename tests/ui/{rfcs/rfc-2627-raw-dylib => linkage-attr/raw-dylib/windows}/multiple-declarations.stderr (100%) create mode 100644 tests/ui/linkage-attr/raw-dylib/windows/raw-dylib-windows-only.elf.stderr create mode 100644 tests/ui/linkage-attr/raw-dylib/windows/raw-dylib-windows-only.rs rename tests/ui/{rfcs/rfc-2627-raw-dylib => linkage-attr/raw-dylib/windows}/unsupported-abi.rs (100%) rename tests/ui/{rfcs/rfc-2627-raw-dylib => linkage-attr/raw-dylib/windows}/unsupported-abi.stderr (100%) delete mode 100644 tests/ui/rfcs/rfc-2627-raw-dylib/raw-dylib-windows-only.rs delete mode 100644 tests/ui/rfcs/rfc-2627-raw-dylib/raw-dylib-windows-only.stderr diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index df35b5e8426f1..e22a688c36630 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -51,6 +51,7 @@ use super::linker::{self, Linker}; use super::metadata::{MetadataPosition, create_wrapper_file}; use super::rpath::{self, RPathConfig}; use super::{apple, versioned_llvm_target}; +use crate::errors::ErrorCreatingImportLibrary; use crate::{ CodegenResults, CompiledModule, CrateInfo, NativeLib, common, errors, looks_like_rust_object_file, @@ -378,16 +379,22 @@ fn link_rlib<'a>( } } - for output_path in create_dll_import_libs( - sess, - archive_builder_builder, - codegen_results.crate_info.used_libraries.iter(), - tmpdir.as_ref(), - true, - ) { - ab.add_archive(&output_path, Box::new(|_| false)).unwrap_or_else(|error| { - sess.dcx().emit_fatal(errors::AddNativeLibrary { library_path: output_path, error }); - }); + // On Windows, we add the raw-dylib import libraries to the rlibs already. + // But on ELF, this is not possible, as a shared object cannot be a member of a static library. + // Instead, we add all raw-dylibs to the final link on ELF. + if sess.target.is_like_windows { + for output_path in create_raw_dylib_dll_import_libs( + sess, + archive_builder_builder, + codegen_results.crate_info.used_libraries.iter(), + tmpdir.as_ref(), + true, + ) { + ab.add_archive(&output_path, Box::new(|_| false)).unwrap_or_else(|error| { + sess.dcx() + .emit_fatal(errors::AddNativeLibrary { library_path: output_path, error }); + }); + } } if let Some(trailing_metadata) = trailing_metadata { @@ -428,6 +435,12 @@ fn link_rlib<'a>( ab } +#[derive(Debug, PartialEq, Eq, Hash, Clone)] +struct RawDylibName { + filename: String, + library_name: Symbol, +} + /// Extract all symbols defined in raw-dylib libraries, collated by library name. /// /// If we have multiple extern blocks that specify symbols defined in the same raw-dylib library, @@ -437,15 +450,27 @@ fn link_rlib<'a>( fn collate_raw_dylibs<'a>( sess: &Session, used_libraries: impl IntoIterator, -) -> Vec<(String, Vec)> { + is_direct_dependency: bool, +) -> Vec<(RawDylibName, Vec, bool)> { // Use index maps to preserve original order of imports and libraries. - let mut dylib_table = FxIndexMap::>::default(); + let mut dylib_table = + FxIndexMap::<(RawDylibName, bool), FxIndexMap>::default(); for lib in used_libraries { if lib.kind == NativeLibKind::RawDylib { - let ext = if lib.verbatim { "" } else { ".dll" }; - let name = format!("{}{}", lib.name, ext); - let imports = dylib_table.entry(name.clone()).or_default(); + let ext = if lib.verbatim { "" } else { sess.target.dll_suffix.as_ref() }; + + let filename = if sess.target.is_like_windows { + let name_suffix = + if is_direct_dependency { "_imports" } else { "_imports_indirect" }; + format!("{}{ext}{name_suffix}.lib", lib.name) + } else { + let prefix = if lib.verbatim { "" } else { sess.target.dll_prefix.as_ref() }; + format!("{prefix}{}{ext}", lib.name) + }; + + let name = RawDylibName { filename, library_name: lib.name }; + let imports = dylib_table.entry((name.clone(), lib.verbatim)).or_default(); for import in &lib.dll_imports { if let Some(old_import) = imports.insert(import.name, import) { // FIXME: when we add support for ordinals, figure out if we need to do anything @@ -454,7 +479,7 @@ fn collate_raw_dylibs<'a>( sess.dcx().emit_err(errors::MultipleExternalFuncDecl { span: import.span, function: import.name, - library_name: &name, + library_name: &name.filename, }); } } @@ -464,24 +489,23 @@ fn collate_raw_dylibs<'a>( sess.dcx().abort_if_errors(); dylib_table .into_iter() - .map(|(name, imports)| { - (name, imports.into_iter().map(|(_, import)| import.clone()).collect()) + .map(|((name, verbatim), imports)| { + (name, imports.into_iter().map(|(_, import)| import.clone()).collect(), verbatim) }) .collect() } -fn create_dll_import_libs<'a>( +fn create_raw_dylib_dll_import_libs<'a>( sess: &Session, archive_builder_builder: &dyn ArchiveBuilderBuilder, used_libraries: impl IntoIterator, tmpdir: &Path, is_direct_dependency: bool, ) -> Vec { - collate_raw_dylibs(sess, used_libraries) + collate_raw_dylibs(sess, used_libraries, is_direct_dependency) .into_iter() - .map(|(raw_dylib_name, raw_dylib_imports)| { - let name_suffix = if is_direct_dependency { "_imports" } else { "_imports_indirect" }; - let output_path = tmpdir.join(format!("{raw_dylib_name}{name_suffix}.lib")); + .map(|(raw_dylib_name, raw_dylib_imports, _)| { + let output_path = tmpdir.join(&raw_dylib_name.filename); let mingw_gnu_toolchain = common::is_mingw_gnu_toolchain(&sess.target); @@ -520,7 +544,7 @@ fn create_dll_import_libs<'a>( archive_builder_builder.create_dll_import_lib( sess, - &raw_dylib_name, + &raw_dylib_name.filename, items, &output_path, ); @@ -530,6 +554,38 @@ fn create_dll_import_libs<'a>( .collect() } +fn create_raw_dylib_elf_stub_shared_objects<'a>( + sess: &Session, + used_libraries: impl IntoIterator, + raw_dylib_so_dir: &Path, +) -> Vec<(Symbol, bool)> { + collate_raw_dylibs(sess, used_libraries, false) + .into_iter() + .map(|(raw_dylib_name, raw_dylib_imports, verbatim)| { + let filename = raw_dylib_name.filename; + + let shared_object = create_elf_raw_dylib_stub(&raw_dylib_imports, sess); + + let so_path = raw_dylib_so_dir.join(&filename); + let file = match fs::File::create_new(&so_path) { + Ok(file) => file, + Err(error) => sess.dcx().emit_fatal(ErrorCreatingImportLibrary { + lib_name: &filename, + error: error.to_string(), + }), + }; + if let Err(error) = BufWriter::new(file).write_all(&shared_object) { + sess.dcx().emit_fatal(ErrorCreatingImportLibrary { + lib_name: &filename, + error: error.to_string(), + }); + }; + + (raw_dylib_name.library_name, verbatim) + }) + .collect() +} + /// Create a static archive. /// /// This is essentially the same thing as an rlib, but it also involves adding all of the upstream @@ -2319,15 +2375,38 @@ fn linker_with_args( link_output_kind, ); + // Raw-dylibs from all crates. + let raw_dylib_dir = tmpdir.join("raw-dylibs"); + if sess.target.binary_format() == object::BinaryFormat::Elf { + // On ELF we can't pass the raw-dylibs stubs to the linker as a path, + // instead we need to pass them via -l. To find the stub, we need to add + // the directory of the stub to the linker search path. + // We make an extra directory for this to avoid polluting the search path. + if let Err(error) = fs::create_dir(&raw_dylib_dir) { + sess.dcx().emit_fatal(errors::CreateTempDir { error }) + } + cmd.include_path(&raw_dylib_dir); + } + // Link with the import library generated for any raw-dylib functions. - for output_path in create_dll_import_libs( - sess, - archive_builder_builder, - codegen_results.crate_info.used_libraries.iter(), - tmpdir, - true, - ) { - cmd.add_object(&output_path); + if sess.target.is_like_windows { + for output_path in create_raw_dylib_dll_import_libs( + sess, + archive_builder_builder, + codegen_results.crate_info.used_libraries.iter(), + tmpdir, + true, + ) { + cmd.add_object(&output_path); + } + } else { + for (library_name, verbatim) in create_raw_dylib_elf_stub_shared_objects( + sess, + codegen_results.crate_info.used_libraries.iter(), + &raw_dylib_dir, + ) { + cmd.link_dylib_by_name(library_name.as_str(), verbatim, false); + } } // As with add_upstream_native_libraries, we need to add the upstream raw-dylib symbols in case // they are used within inlined functions or instantiated generic functions. We do this *after* @@ -2346,19 +2425,34 @@ fn linker_with_args( .native_libraries .iter() .filter_map(|(&cnum, libraries)| { - (dependency_linkage[cnum] != Linkage::Static).then_some(libraries) + if sess.target.is_like_windows { + (dependency_linkage[cnum] != Linkage::Static).then_some(libraries) + } else { + Some(libraries) + } }) .flatten() .collect::>(); native_libraries_from_nonstatics.sort_unstable_by(|a, b| a.name.as_str().cmp(b.name.as_str())); - for output_path in create_dll_import_libs( - sess, - archive_builder_builder, - native_libraries_from_nonstatics, - tmpdir, - false, - ) { - cmd.add_object(&output_path); + + if sess.target.is_like_windows { + for output_path in create_raw_dylib_dll_import_libs( + sess, + archive_builder_builder, + native_libraries_from_nonstatics, + tmpdir, + false, + ) { + cmd.add_object(&output_path); + } + } else { + for (library_name, verbatim) in create_raw_dylib_elf_stub_shared_objects( + sess, + native_libraries_from_nonstatics, + &raw_dylib_dir, + ) { + cmd.link_dylib_by_name(library_name.as_str(), verbatim, false); + } } // Library linking above uses some global state for things like `-Bstatic`/`-Bdynamic` to make @@ -3356,3 +3450,138 @@ fn add_lld_args( } } } + +/// Create an ELF .so stub file for raw-dylib. +/// It exports all the provided symbols, but is otherwise empty. +fn create_elf_raw_dylib_stub(symbols: &[DllImport], sess: &Session) -> Vec { + use object::write::elf as write; + use object::{Architecture, elf}; + + let mut stub_buf = Vec::new(); + + // When using the low-level object::write::elf, the order of the reservations + // needs to match the order of the writing. + + let mut stub = write::Writer::new(object::Endianness::Little, true, &mut stub_buf); + + // These initial reservations don't reserve any space yet. + stub.reserve_null_dynamic_symbol_index(); + + let dynstrs = symbols + .iter() + .map(|sym| { + stub.reserve_dynamic_symbol_index(); + (sym, stub.add_dynamic_string(sym.name.as_str().as_bytes())) + }) + .collect::>(); + + stub.reserve_shstrtab_section_index(); + let text_section_name = stub.add_section_name(".text".as_bytes()); + let text_section = stub.reserve_section_index(); + stub.reserve_dynstr_section_index(); + stub.reserve_dynsym_section_index(); + + // These reservations determine the actual layout order of the object file. + stub.reserve_file_header(); + stub.reserve_shstrtab(); + stub.reserve_section_headers(); + stub.reserve_dynstr(); + stub.reserve_dynsym(); + + // File header + let Some((arch, sub_arch)) = sess.target.object_architecture(&sess.unstable_target_features) + else { + sess.dcx().fatal(format!( + "raw-dylib is not supported for the architecture `{}`", + sess.target.arch + )); + }; + let e_machine = match (arch, sub_arch) { + (Architecture::Aarch64, None) => elf::EM_AARCH64, + (Architecture::Aarch64_Ilp32, None) => elf::EM_AARCH64, + (Architecture::Arm, None) => elf::EM_ARM, + (Architecture::Avr, None) => elf::EM_AVR, + (Architecture::Bpf, None) => elf::EM_BPF, + (Architecture::Csky, None) => elf::EM_CSKY, + (Architecture::E2K32, None) => elf::EM_MCST_ELBRUS, + (Architecture::E2K64, None) => elf::EM_MCST_ELBRUS, + (Architecture::I386, None) => elf::EM_386, + (Architecture::X86_64, None) => elf::EM_X86_64, + (Architecture::X86_64_X32, None) => elf::EM_X86_64, + (Architecture::Hexagon, None) => elf::EM_HEXAGON, + (Architecture::LoongArch64, None) => elf::EM_LOONGARCH, + (Architecture::M68k, None) => elf::EM_68K, + (Architecture::Mips, None) => elf::EM_MIPS, + (Architecture::Mips64, None) => elf::EM_MIPS, + (Architecture::Mips64_N32, None) => elf::EM_MIPS, + (Architecture::Msp430, None) => elf::EM_MSP430, + (Architecture::PowerPc, None) => elf::EM_PPC, + (Architecture::PowerPc64, None) => elf::EM_PPC64, + (Architecture::Riscv32, None) => elf::EM_RISCV, + (Architecture::Riscv64, None) => elf::EM_RISCV, + (Architecture::S390x, None) => elf::EM_S390, + (Architecture::Sbf, None) => elf::EM_SBF, + (Architecture::Sharc, None) => elf::EM_SHARC, + (Architecture::Sparc, None) => elf::EM_SPARC, + (Architecture::Sparc32Plus, None) => elf::EM_SPARC32PLUS, + (Architecture::Sparc64, None) => elf::EM_SPARCV9, + (Architecture::Xtensa, None) => elf::EM_XTENSA, + _ => { + sess.dcx().fatal(format!( + "raw-dylib is not supported for the architecture `{}`", + sess.target.arch + )); + } + }; + + stub.write_file_header(&write::FileHeader { + os_abi: super::metadata::elf_os_abi(sess), + abi_version: 0, + e_type: object::elf::ET_DYN, + e_machine, + e_entry: 0, + e_flags: super::metadata::elf_e_flags(arch, sess), + }) + .unwrap(); + + // .shstrtab + stub.write_shstrtab(); + + // Section headers + stub.write_null_section_header(); + stub.write_shstrtab_section_header(); + // Create a dummy .text section for our dummy symbols. + stub.write_section_header(&write::SectionHeader { + name: Some(text_section_name), + sh_type: elf::SHT_PROGBITS, + sh_flags: 0, + sh_addr: 0, + sh_offset: 0, + sh_size: 0, + sh_link: 0, + sh_info: 0, + sh_addralign: 1, + sh_entsize: 0, + }); + stub.write_dynstr_section_header(0); + stub.write_dynsym_section_header(0, 1); + + // .dynstr + stub.write_dynstr(); + + // .dynsym + stub.write_null_dynamic_symbol(); + for (_, name) in dynstrs { + stub.write_dynamic_symbol(&write::Sym { + name: Some(name), + st_info: (elf::STB_GLOBAL << 4) | elf::STT_NOTYPE, + st_other: elf::STV_DEFAULT, + section: Some(text_section), + st_shndx: 0, // ignored by object in favor of the `section` field + st_value: 0, + st_size: 0, + }); + } + + stub_buf +} diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index ba7b53321a83d..40ad70057ee9f 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -9,8 +9,7 @@ use itertools::Itertools; use object::write::{self, StandardSegment, Symbol, SymbolSection}; use object::{ Architecture, BinaryFormat, Endianness, FileFlags, Object, ObjectSection, ObjectSymbol, - SectionFlags, SectionKind, SubArchitecture, SymbolFlags, SymbolKind, SymbolScope, elf, pe, - xcoff, + SectionFlags, SectionKind, SymbolFlags, SymbolKind, SymbolScope, elf, pe, xcoff, }; use rustc_abi::Endian; use rustc_data_structures::memmap::Mmap; @@ -206,61 +205,12 @@ pub(crate) fn create_object_file(sess: &Session) -> Option Endianness::Little, Endian::Big => Endianness::Big, }; - let (architecture, sub_architecture) = match &sess.target.arch[..] { - "arm" => (Architecture::Arm, None), - "aarch64" => ( - if sess.target.pointer_width == 32 { - Architecture::Aarch64_Ilp32 - } else { - Architecture::Aarch64 - }, - None, - ), - "x86" => (Architecture::I386, None), - "s390x" => (Architecture::S390x, None), - "mips" | "mips32r6" => (Architecture::Mips, None), - "mips64" | "mips64r6" => (Architecture::Mips64, None), - "x86_64" => ( - if sess.target.pointer_width == 32 { - Architecture::X86_64_X32 - } else { - Architecture::X86_64 - }, - None, - ), - "powerpc" => (Architecture::PowerPc, None), - "powerpc64" => (Architecture::PowerPc64, None), - "riscv32" => (Architecture::Riscv32, None), - "riscv64" => (Architecture::Riscv64, None), - "sparc" => { - if sess.unstable_target_features.contains(&sym::v8plus) { - // Target uses V8+, aka EM_SPARC32PLUS, aka 64-bit V9 but in 32-bit mode - (Architecture::Sparc32Plus, None) - } else { - // Target uses V7 or V8, aka EM_SPARC - (Architecture::Sparc, None) - } - } - "sparc64" => (Architecture::Sparc64, None), - "avr" => (Architecture::Avr, None), - "msp430" => (Architecture::Msp430, None), - "hexagon" => (Architecture::Hexagon, None), - "bpf" => (Architecture::Bpf, None), - "loongarch64" => (Architecture::LoongArch64, None), - "csky" => (Architecture::Csky, None), - "arm64ec" => (Architecture::Aarch64, Some(SubArchitecture::Arm64EC)), - // Unsupported architecture. - _ => return None, - }; - let binary_format = if sess.target.is_like_osx { - BinaryFormat::MachO - } else if sess.target.is_like_windows { - BinaryFormat::Coff - } else if sess.target.is_like_aix { - BinaryFormat::Xcoff - } else { - BinaryFormat::Elf + let Some((architecture, sub_architecture)) = + sess.target.object_architecture(&sess.unstable_target_features) + else { + return None; }; + let binary_format = sess.target.binary_format(); let mut file = write::Object::new(binary_format, architecture, endianness); file.set_sub_architecture(sub_architecture); @@ -300,7 +250,26 @@ pub(crate) fn create_object_file(sess: &Session) -> Option u8 { + match sess.target.options.os.as_ref() { + "hermit" => elf::ELFOSABI_STANDALONE, + "freebsd" => elf::ELFOSABI_FREEBSD, + "solaris" => elf::ELFOSABI_SOLARIS, + _ => elf::ELFOSABI_NONE, + } +} + +pub(super) fn elf_e_flags(architecture: Architecture, sess: &Session) -> u32 { + match architecture { Architecture::Mips => { let arch = match sess.target.options.cpu.as_ref() { "mips1" => elf::EF_MIPS_ARCH_1, @@ -391,18 +360,7 @@ pub(crate) fn create_object_file(sess: &Session) -> Option 0, - }; - // adapted from LLVM's `MCELFObjectTargetWriter::getOSABI` - let os_abi = match sess.target.options.os.as_ref() { - "hermit" => elf::ELFOSABI_STANDALONE, - "freebsd" => elf::ELFOSABI_FREEBSD, - "solaris" => elf::ELFOSABI_SOLARIS, - _ => elf::ELFOSABI_NONE, - }; - let abi_version = 0; - add_gnu_property_note(&mut file, architecture, binary_format, endianness); - file.flags = FileFlags::Elf { os_abi, abi_version, e_flags }; - Some(file) + } } /// Mach-O files contain information about: diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 1dcde45333102..c690dd8154ad5 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -594,6 +594,8 @@ declare_features! ( (unstable, precise_capturing_in_traits, "1.83.0", Some(130044)), /// Allows macro attributes on expressions, statements and non-inline modules. (unstable, proc_macro_hygiene, "1.30.0", Some(54727)), + /// Allows the use of raw-dylibs on ELF platforms + (incomplete, raw_dylib_elf, "CURRENT_RUSTC_VERSION", Some(135694)), /// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024. (incomplete, ref_pat_eat_one_layer_2024, "1.79.0", Some(123076)), /// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024—structural variant diff --git a/compiler/rustc_metadata/messages.ftl b/compiler/rustc_metadata/messages.ftl index 6d7d88fa8d7af..df1396bd610f1 100644 --- a/compiler/rustc_metadata/messages.ftl +++ b/compiler/rustc_metadata/messages.ftl @@ -233,6 +233,9 @@ metadata_prev_alloc_error_handler = metadata_prev_global_alloc = previous global allocator defined here +metadata_raw_dylib_elf_unstable = + link kind `raw-dylib` is unstable on ELF platforms + metadata_raw_dylib_no_nul = link name must not contain NUL characters if link kind is `raw-dylib` diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index 2a1e4b261e737..4be54a2a3511d 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -17,7 +17,7 @@ use rustc_session::search_paths::PathKind; use rustc_session::utils::NativeLibKind; use rustc_span::def_id::{DefId, LOCAL_CRATE}; use rustc_span::{Symbol, sym}; -use rustc_target::spec::LinkSelfContainedComponents; +use rustc_target::spec::{BinaryFormat, LinkSelfContainedComponents}; use crate::{errors, fluent_generated}; @@ -263,9 +263,26 @@ impl<'tcx> Collector<'tcx> { NativeLibKind::Framework { as_needed: None } } "raw-dylib" => { - if !sess.target.is_like_windows { + if sess.target.is_like_windows { + // raw-dylib is stable and working on Windows + } else if sess.target.binary_format() == BinaryFormat::Elf + && features.raw_dylib_elf() + { + // raw-dylib is unstable on ELF, but the user opted in + } else if sess.target.binary_format() == BinaryFormat::Elf + && sess.is_nightly_build() + { + feature_err( + sess, + sym::raw_dylib_elf, + span, + fluent_generated::metadata_raw_dylib_elf_unstable, + ) + .emit(); + } else { sess.dcx().emit_err(errors::RawDylibOnlyWindows { span }); } + NativeLibKind::RawDylib } "link-arg" => { diff --git a/compiler/rustc_session/src/utils.rs b/compiler/rustc_session/src/utils.rs index 9182789cf0269..fcede379b893a 100644 --- a/compiler/rustc_session/src/utils.rs +++ b/compiler/rustc_session/src/utils.rs @@ -34,6 +34,7 @@ pub enum NativeLibKind { as_needed: Option, }, /// Dynamic library (e.g. `foo.dll` on Windows) without a corresponding import library. + /// On Linux, it refers to a generated shared library stub. RawDylib, /// A macOS-specific kind of dynamic libraries. Framework { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index b57b5df26097a..1f54e5a4aa783 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1597,6 +1597,7 @@ symbols! { quote, range_inclusive_new, raw_dylib, + raw_dylib_elf, raw_eq, raw_identifiers, raw_ref_op, diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 1f2df7f0168cb..7e3a14c2da802 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -42,7 +42,7 @@ use std::path::{Path, PathBuf}; use std::str::FromStr; use std::{fmt, io}; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_fs_util::try_canonicalize; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; @@ -69,6 +69,7 @@ mod base; mod json; pub use base::avr_gnu::ef_avr_arch; +pub use object::BinaryFormat; /// Linker is called through a C/C++ compiler. #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] @@ -3394,6 +3395,71 @@ impl Target { s => s.clone(), } } + + pub fn binary_format(&self) -> object::BinaryFormat { + if self.is_like_osx { + object::BinaryFormat::MachO + } else if self.is_like_windows { + object::BinaryFormat::Coff + } else if self.is_like_aix { + object::BinaryFormat::Xcoff + } else { + object::BinaryFormat::Elf + } + } + + pub fn object_architecture( + &self, + unstable_target_features: &FxIndexSet, + ) -> Option<(object::Architecture, Option)> { + use object::Architecture; + Some(match self.arch.as_ref() { + "arm" => (Architecture::Arm, None), + "aarch64" => ( + if self.pointer_width == 32 { + Architecture::Aarch64_Ilp32 + } else { + Architecture::Aarch64 + }, + None, + ), + "x86" => (Architecture::I386, None), + "s390x" => (Architecture::S390x, None), + "mips" | "mips32r6" => (Architecture::Mips, None), + "mips64" | "mips64r6" => (Architecture::Mips64, None), + "x86_64" => ( + if self.pointer_width == 32 { + Architecture::X86_64_X32 + } else { + Architecture::X86_64 + }, + None, + ), + "powerpc" => (Architecture::PowerPc, None), + "powerpc64" => (Architecture::PowerPc64, None), + "riscv32" => (Architecture::Riscv32, None), + "riscv64" => (Architecture::Riscv64, None), + "sparc" => { + if unstable_target_features.contains(&sym::v8plus) { + // Target uses V8+, aka EM_SPARC32PLUS, aka 64-bit V9 but in 32-bit mode + (Architecture::Sparc32Plus, None) + } else { + // Target uses V7 or V8, aka EM_SPARC + (Architecture::Sparc, None) + } + } + "sparc64" => (Architecture::Sparc64, None), + "avr" => (Architecture::Avr, None), + "msp430" => (Architecture::Msp430, None), + "hexagon" => (Architecture::Hexagon, None), + "bpf" => (Architecture::Bpf, None), + "loongarch64" => (Architecture::LoongArch64, None), + "csky" => (Architecture::Csky, None), + "arm64ec" => (Architecture::Aarch64, Some(object::SubArchitecture::Arm64EC)), + // Unsupported architecture. + _ => return None, + }) + } } /// Either a target tuple string or a path to a JSON file. diff --git a/src/tools/compiletest/src/directive-list.rs b/src/tools/compiletest/src/directive-list.rs index 01068af3e8c24..24a67ed0322e3 100644 --- a/src/tools/compiletest/src/directive-list.rs +++ b/src/tools/compiletest/src/directive-list.rs @@ -48,6 +48,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "ignore-coverage-run", "ignore-cross-compile", "ignore-eabi", + "ignore-elf", "ignore-emscripten", "ignore-endian-big", "ignore-enzyme", @@ -175,6 +176,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "only-beta", "only-bpf", "only-cdb", + "only-elf", "only-gnu", "only-i686-pc-windows-gnu", "only-i686-pc-windows-msvc", diff --git a/src/tools/compiletest/src/header/cfg.rs b/src/tools/compiletest/src/header/cfg.rs index 3f7225195ce0b..cc3081f72d44a 100644 --- a/src/tools/compiletest/src/header/cfg.rs +++ b/src/tools/compiletest/src/header/cfg.rs @@ -166,6 +166,15 @@ fn parse_cfg_name_directive<'a>( message: "when the target vendor is Apple" } + condition! { + name: "elf", + condition: !config.target.contains("windows") + && !config.target.contains("apple") + && !config.target.contains("aix") + && !config.target.contains("uefi"), + message: "when the target binary format is ELF" + } + condition! { name: "enzyme", condition: config.has_enzyme, diff --git a/tests/run-make/raw-dylib-elf-verbatim/library.c b/tests/run-make/raw-dylib-elf-verbatim/library.c new file mode 100644 index 0000000000000..2e3a95b7edeca --- /dev/null +++ b/tests/run-make/raw-dylib-elf-verbatim/library.c @@ -0,0 +1,3 @@ +int this_is_a_library_function() { + return 42; +} diff --git a/tests/run-make/raw-dylib-elf-verbatim/main.rs b/tests/run-make/raw-dylib-elf-verbatim/main.rs new file mode 100644 index 0000000000000..044b7400a8412 --- /dev/null +++ b/tests/run-make/raw-dylib-elf-verbatim/main.rs @@ -0,0 +1,11 @@ +#![feature(raw_dylib_elf)] +#![allow(incomplete_features)] + +#[link(name = "liblibrary.so.1", kind = "raw-dylib", modifiers = "+verbatim")] +unsafe extern "C" { + safe fn this_is_a_library_function() -> core::ffi::c_int; +} + +fn main() { + println!("{}", this_is_a_library_function()) +} diff --git a/tests/run-make/raw-dylib-elf-verbatim/output.txt b/tests/run-make/raw-dylib-elf-verbatim/output.txt new file mode 100644 index 0000000000000..d81cc0710eb6c --- /dev/null +++ b/tests/run-make/raw-dylib-elf-verbatim/output.txt @@ -0,0 +1 @@ +42 diff --git a/tests/run-make/raw-dylib-elf-verbatim/rmake.rs b/tests/run-make/raw-dylib-elf-verbatim/rmake.rs new file mode 100644 index 0000000000000..a6573e28359aa --- /dev/null +++ b/tests/run-make/raw-dylib-elf-verbatim/rmake.rs @@ -0,0 +1,26 @@ +//@ only-elf + +//! Ensure ELF raw-dylib is able to link against the verbatim versioned library +//! without it being present, and then be executed against this library. + +use run_make_support::{build_native_dynamic_lib, cwd, diff, rfs, run, rustc}; + +fn main() { + // We compile the binary without having the library present. + // We also set the rpath to the current directory so we can pick up the library at runtime. + rustc() + .crate_type("bin") + .input("main.rs") + .arg(&format!("-Wl,-rpath={}", cwd().display())) + .run(); + + // Now, *after* building the binary, we build the library... + build_native_dynamic_lib("library"); + // ... rename it to have the versioned library name... + rfs::rename("liblibrary.so", "liblibrary.so.1"); + + // ... and run with this library, ensuring it was linked correctly at runtime. + let output = run("main").stdout_utf8(); + + diff().expected_file("output.txt").actual_text("actual", output).run(); +} diff --git a/tests/run-make/raw-dylib-elf/library.c b/tests/run-make/raw-dylib-elf/library.c new file mode 100644 index 0000000000000..2e3a95b7edeca --- /dev/null +++ b/tests/run-make/raw-dylib-elf/library.c @@ -0,0 +1,3 @@ +int this_is_a_library_function() { + return 42; +} diff --git a/tests/run-make/raw-dylib-elf/main.rs b/tests/run-make/raw-dylib-elf/main.rs new file mode 100644 index 0000000000000..3be944d295148 --- /dev/null +++ b/tests/run-make/raw-dylib-elf/main.rs @@ -0,0 +1,11 @@ +#![feature(raw_dylib_elf)] +#![allow(incomplete_features)] + +#[link(name = "library", kind = "raw-dylib")] +unsafe extern "C" { + safe fn this_is_a_library_function() -> core::ffi::c_int; +} + +fn main() { + println!("{}", this_is_a_library_function()) +} diff --git a/tests/run-make/raw-dylib-elf/output.txt b/tests/run-make/raw-dylib-elf/output.txt new file mode 100644 index 0000000000000..d81cc0710eb6c --- /dev/null +++ b/tests/run-make/raw-dylib-elf/output.txt @@ -0,0 +1 @@ +42 diff --git a/tests/run-make/raw-dylib-elf/rmake.rs b/tests/run-make/raw-dylib-elf/rmake.rs new file mode 100644 index 0000000000000..96ae9f446f3b9 --- /dev/null +++ b/tests/run-make/raw-dylib-elf/rmake.rs @@ -0,0 +1,24 @@ +//@ only-elf + +//! Ensure ELF raw-dylib is able to link the binary without having the library present, +//! and then successfully run against the real library. + +use run_make_support::{build_native_dynamic_lib, cwd, diff, run, rustc}; + +fn main() { + // We compile the binary without having the library present. + // We also set the rpath to the current directory so we can pick up the library at runtime. + rustc() + .crate_type("bin") + .input("main.rs") + .arg(&format!("-Wl,-rpath={}", cwd().display())) + .run(); + + // Now, *after* building the binary, we build the library... + build_native_dynamic_lib("library"); + + // ... and run with this library, ensuring it was linked correctly at runtime. + let output = run("main").stdout_utf8(); + + diff().expected_file("output.txt").actual_text("actual", output).run(); +} diff --git a/tests/run-make/reproducible-build/linker.rs b/tests/run-make/reproducible-build/linker.rs index ab3b4049cc321..2f57d9f9be9a4 100644 --- a/tests/run-make/reproducible-build/linker.rs +++ b/tests/run-make/reproducible-build/linker.rs @@ -17,6 +17,8 @@ fn main() { for arg in env::args().skip(1) { let path = Path::new(&arg); if !path.is_file() { + // This directory is produced during linking in a temporary directory (ELF only). + let arg = if arg.ends_with("/raw-dylibs") { "/raw-dylibs" } else { &*arg }; out.push_str(&arg); out.push_str("\n"); continue; diff --git a/tests/ui/feature-gates/feature-gate-raw-dylib-elf.rs b/tests/ui/feature-gates/feature-gate-raw-dylib-elf.rs new file mode 100644 index 0000000000000..a9ac5ce8b8337 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-raw-dylib-elf.rs @@ -0,0 +1,8 @@ +//@ only-elf + +#[link(name = "meow", kind = "raw-dylib")] //~ ERROR: link kind `raw-dylib` is unstable on ELF platforms +unsafe extern "C" { + safe fn meowmeow(); +} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-raw-dylib-elf.stderr b/tests/ui/feature-gates/feature-gate-raw-dylib-elf.stderr new file mode 100644 index 0000000000000..63d9183511ef1 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-raw-dylib-elf.stderr @@ -0,0 +1,13 @@ +error[E0658]: link kind `raw-dylib` is unstable on ELF platforms + --> $DIR/feature-gate-raw-dylib-elf.rs:3:30 + | +LL | #[link(name = "meow", kind = "raw-dylib")] + | ^^^^^^^^^^^ + | + = note: see issue #135694 for more information + = help: add `#![feature(raw_dylib_elf)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/linkage-attr/raw-dylib/elf/multiple-libraries.rs b/tests/ui/linkage-attr/raw-dylib/elf/multiple-libraries.rs new file mode 100644 index 0000000000000..68cf76695ed85 --- /dev/null +++ b/tests/ui/linkage-attr/raw-dylib/elf/multiple-libraries.rs @@ -0,0 +1,33 @@ +//@ only-elf + +//@ revisions: with without + +//@ [without] build-fail +//@ [without] error-pattern:error: linking with `cc` failed +//@ [without] dont-check-compiler-stderr + +//@ [with] build-pass + +//! Ensures that linking fails when there's an undefined symbol, +//! and that it does succeed with raw-dylib. + +#![feature(raw_dylib_elf)] +#![allow(incomplete_features)] + +#[cfg_attr(with, link(name = "rawdylibbutforcats", kind = "raw-dylib"))] +#[cfg_attr(without, link(name = "rawdylibbutforcats"))] +unsafe extern "C" { + safe fn meooooooooooooooow(); +} + + +#[cfg_attr(with, link(name = "rawdylibbutfordogs", kind = "raw-dylib"))] +#[cfg_attr(without, link(name = "rawdylibbutfordogs"))] +unsafe extern "C" { + safe fn woooooooooooooooooof(); +} + +fn main() { + meooooooooooooooow(); + woooooooooooooooooof(); +} diff --git a/tests/ui/linkage-attr/raw-dylib/elf/single-symbol.rs b/tests/ui/linkage-attr/raw-dylib/elf/single-symbol.rs new file mode 100644 index 0000000000000..db8a0da0bec3e --- /dev/null +++ b/tests/ui/linkage-attr/raw-dylib/elf/single-symbol.rs @@ -0,0 +1,25 @@ +//@ only-elf + +//@ revisions: with without + +//@ [without] build-fail +//@ [without] error-pattern:error: linking with `cc` failed +//@ [without] dont-check-compiler-stderr + +//@ [with] build-pass + +//! Ensures that linking fails when there's an undefined symbol, +//! and that it does succeed with raw-dylib. + +#![feature(raw_dylib_elf)] +#![allow(incomplete_features)] + +#[cfg_attr(with, link(name = "rawdylibbutforcats", kind = "raw-dylib"))] +#[cfg_attr(without, link(name = "rawdylibbutforcats"))] +unsafe extern "C" { + safe fn meooooooooooooooow(); +} + +fn main() { + meooooooooooooooow(); +} diff --git a/tests/ui/linkage-attr/raw-dylib/elf/verbatim.rs b/tests/ui/linkage-attr/raw-dylib/elf/verbatim.rs new file mode 100644 index 0000000000000..db86d2f71da50 --- /dev/null +++ b/tests/ui/linkage-attr/raw-dylib/elf/verbatim.rs @@ -0,0 +1,25 @@ +//@ only-elf + +//@ revisions: with without + +//@ [without] build-fail +//@ [without] error-pattern:error: linking with `cc` failed +//@ [without] dont-check-compiler-stderr + +//@ [with] build-pass + +//! Ensures that linking fails when there's an undefined symbol, +//! and that it does succeed with raw-dylib, but with verbatim. + +#![feature(raw_dylib_elf)] +#![allow(incomplete_features)] + +#[cfg_attr(with, link(name = "rawdylibbutforcats", kind = "raw-dylib", modifiers = "+verbatim"))] +#[cfg_attr(without, link(name = "rawdylibbutforcats", modifiers = "+verbatim"))] +unsafe extern "C" { + safe fn meooooooooooooooow(); +} + +fn main() { + meooooooooooooooow(); +} diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/dlltool-failed.rs b/tests/ui/linkage-attr/raw-dylib/windows/dlltool-failed.rs similarity index 100% rename from tests/ui/rfcs/rfc-2627-raw-dylib/dlltool-failed.rs rename to tests/ui/linkage-attr/raw-dylib/windows/dlltool-failed.rs diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/dlltool-failed.stderr b/tests/ui/linkage-attr/raw-dylib/windows/dlltool-failed.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2627-raw-dylib/dlltool-failed.stderr rename to tests/ui/linkage-attr/raw-dylib/windows/dlltool-failed.stderr diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-invalid-format.rs b/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-invalid-format.rs similarity index 100% rename from tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-invalid-format.rs rename to tests/ui/linkage-attr/raw-dylib/windows/import-name-type-invalid-format.rs diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-invalid-format.stderr b/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-invalid-format.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-invalid-format.stderr rename to tests/ui/linkage-attr/raw-dylib/windows/import-name-type-invalid-format.stderr diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-multiple.rs b/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-multiple.rs similarity index 100% rename from tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-multiple.rs rename to tests/ui/linkage-attr/raw-dylib/windows/import-name-type-multiple.rs diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-multiple.stderr b/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-multiple.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-multiple.stderr rename to tests/ui/linkage-attr/raw-dylib/windows/import-name-type-multiple.stderr diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-unknown-value.rs b/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-unknown-value.rs similarity index 100% rename from tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-unknown-value.rs rename to tests/ui/linkage-attr/raw-dylib/windows/import-name-type-unknown-value.rs diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-unknown-value.stderr b/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-unknown-value.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-unknown-value.stderr rename to tests/ui/linkage-attr/raw-dylib/windows/import-name-type-unknown-value.stderr diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.rs b/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-unsupported-link-kind.rs similarity index 100% rename from tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.rs rename to tests/ui/linkage-attr/raw-dylib/windows/import-name-type-unsupported-link-kind.rs diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.stderr b/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-unsupported-link-kind.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.stderr rename to tests/ui/linkage-attr/raw-dylib/windows/import-name-type-unsupported-link-kind.stderr diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-x86-only.rs b/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-x86-only.rs similarity index 100% rename from tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-x86-only.rs rename to tests/ui/linkage-attr/raw-dylib/windows/import-name-type-x86-only.rs diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-x86-only.stderr b/tests/ui/linkage-attr/raw-dylib/windows/import-name-type-x86-only.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2627-raw-dylib/import-name-type-x86-only.stderr rename to tests/ui/linkage-attr/raw-dylib/windows/import-name-type-x86-only.stderr diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/invalid-dlltool.rs b/tests/ui/linkage-attr/raw-dylib/windows/invalid-dlltool.rs similarity index 100% rename from tests/ui/rfcs/rfc-2627-raw-dylib/invalid-dlltool.rs rename to tests/ui/linkage-attr/raw-dylib/windows/invalid-dlltool.rs diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/invalid-dlltool.stderr b/tests/ui/linkage-attr/raw-dylib/windows/invalid-dlltool.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2627-raw-dylib/invalid-dlltool.stderr rename to tests/ui/linkage-attr/raw-dylib/windows/invalid-dlltool.stderr diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-and-name.rs b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-and-name.rs similarity index 100% rename from tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-and-name.rs rename to tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-and-name.rs diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-and-name.stderr b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-and-name.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-and-name.stderr rename to tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-and-name.stderr diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-invalid-format.rs b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-invalid-format.rs similarity index 100% rename from tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-invalid-format.rs rename to tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-invalid-format.rs diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-invalid-format.stderr b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-invalid-format.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-invalid-format.stderr rename to tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-invalid-format.stderr diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-missing-argument.rs b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-missing-argument.rs similarity index 100% rename from tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-missing-argument.rs rename to tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-missing-argument.rs diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-missing-argument.stderr b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-missing-argument.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-missing-argument.stderr rename to tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-missing-argument.stderr diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-multiple.rs b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-multiple.rs similarity index 100% rename from tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-multiple.rs rename to tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-multiple.rs diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-multiple.stderr b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-multiple.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-multiple.stderr rename to tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-multiple.stderr diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.rs b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-not-foreign-fn.rs similarity index 100% rename from tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.rs rename to tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-not-foreign-fn.rs diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.stderr b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-not-foreign-fn.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.stderr rename to tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-not-foreign-fn.stderr diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-too-large.rs b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-too-large.rs similarity index 100% rename from tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-too-large.rs rename to tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-too-large.rs diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-too-large.stderr b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-too-large.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-too-large.stderr rename to tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-too-large.stderr diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.rs b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-too-many-arguments.rs similarity index 100% rename from tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.rs rename to tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-too-many-arguments.rs diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.stderr b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-too-many-arguments.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.stderr rename to tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-too-many-arguments.stderr diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.rs b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-unsupported-link-kind.rs similarity index 100% rename from tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.rs rename to tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-unsupported-link-kind.rs diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.stderr b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-unsupported-link-kind.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.stderr rename to tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-unsupported-link-kind.stderr diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/multiple-declarations.rs b/tests/ui/linkage-attr/raw-dylib/windows/multiple-declarations.rs similarity index 100% rename from tests/ui/rfcs/rfc-2627-raw-dylib/multiple-declarations.rs rename to tests/ui/linkage-attr/raw-dylib/windows/multiple-declarations.rs diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/multiple-declarations.stderr b/tests/ui/linkage-attr/raw-dylib/windows/multiple-declarations.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2627-raw-dylib/multiple-declarations.stderr rename to tests/ui/linkage-attr/raw-dylib/windows/multiple-declarations.stderr diff --git a/tests/ui/linkage-attr/raw-dylib/windows/raw-dylib-windows-only.elf.stderr b/tests/ui/linkage-attr/raw-dylib/windows/raw-dylib-windows-only.elf.stderr new file mode 100644 index 0000000000000..70945ed6fc0bc --- /dev/null +++ b/tests/ui/linkage-attr/raw-dylib/windows/raw-dylib-windows-only.elf.stderr @@ -0,0 +1,13 @@ +error[E0658]: link kind `raw-dylib` is unstable on ELF platforms + --> $DIR/raw-dylib-windows-only.rs:6:29 + | +LL | #[link(name = "foo", kind = "raw-dylib")] + | ^^^^^^^^^^^ + | + = note: see issue #135694 for more information + = help: add `#![feature(raw_dylib_elf)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/linkage-attr/raw-dylib/windows/raw-dylib-windows-only.rs b/tests/ui/linkage-attr/raw-dylib/windows/raw-dylib-windows-only.rs new file mode 100644 index 0000000000000..935c59b5aaa5e --- /dev/null +++ b/tests/ui/linkage-attr/raw-dylib/windows/raw-dylib-windows-only.rs @@ -0,0 +1,9 @@ +//@ revisions: elf notelf +//@ [elf] only-elf +//@ [notelf] ignore-windows +//@ [notelf] ignore-elf +//@ compile-flags: --crate-type lib +#[link(name = "foo", kind = "raw-dylib")] +//[notelf]~^ ERROR: link kind `raw-dylib` is only supported on Windows targets +//[elf]~^^ ERROR: link kind `raw-dylib` is unstable on ELF platforms +extern "C" {} diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/unsupported-abi.rs b/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.rs similarity index 100% rename from tests/ui/rfcs/rfc-2627-raw-dylib/unsupported-abi.rs rename to tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.rs diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/unsupported-abi.stderr b/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.stderr similarity index 100% rename from tests/ui/rfcs/rfc-2627-raw-dylib/unsupported-abi.stderr rename to tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.stderr diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/raw-dylib-windows-only.rs b/tests/ui/rfcs/rfc-2627-raw-dylib/raw-dylib-windows-only.rs deleted file mode 100644 index 3b982857db8dc..0000000000000 --- a/tests/ui/rfcs/rfc-2627-raw-dylib/raw-dylib-windows-only.rs +++ /dev/null @@ -1,5 +0,0 @@ -//@ ignore-windows -//@ compile-flags: --crate-type lib -#[link(name = "foo", kind = "raw-dylib")] -//~^ ERROR: link kind `raw-dylib` is only supported on Windows targets -extern "C" {} diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/raw-dylib-windows-only.stderr b/tests/ui/rfcs/rfc-2627-raw-dylib/raw-dylib-windows-only.stderr deleted file mode 100644 index ede20cb8c3f76..0000000000000 --- a/tests/ui/rfcs/rfc-2627-raw-dylib/raw-dylib-windows-only.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0455]: link kind `raw-dylib` is only supported on Windows targets - --> $DIR/raw-dylib-windows-only.rs:3:29 - | -LL | #[link(name = "foo", kind = "raw-dylib")] - | ^^^^^^^^^^^ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0455`.