From 6aa45b71b11823a3140736536a93c5eac11ceecb Mon Sep 17 00:00:00 2001 From: Richard Cobbe Date: Mon, 8 Mar 2021 12:42:54 -0800 Subject: [PATCH] Add first cut of functionality for #58713: support for #[link(kind = "raw-dylib")]. This does not yet support #[link_name] attributes on functions, the #[link_ordinal] attribute, #[link(kind = "raw-dylib")] on extern blocks in bin crates, or stdcall functions on 32-bit x86. --- .../rustc_codegen_cranelift/src/archive.rs | 9 ++ .../rustc_codegen_llvm/src/back/archive.rs | 83 ++++++++++++++++++- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 34 ++++++++ .../rustc_codegen_ssa/src/back/archive.rs | 9 ++ compiler/rustc_codegen_ssa/src/back/link.rs | 67 +++++++++++++-- compiler/rustc_codegen_ssa/src/lib.rs | 9 +- .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 52 ++++++++++++ compiler/rustc_metadata/src/native_libs.rs | 72 +++++++++++++--- compiler/rustc_middle/src/middle/cstore.rs | 7 ++ src/test/run-make/raw-dylib/Makefile | 21 +++++ src/test/run-make/raw-dylib/driver.rs | 5 ++ src/test/run-make/raw-dylib/extern_1.c | 16 ++++ src/test/run-make/raw-dylib/extern_2.c | 6 ++ src/test/run-make/raw-dylib/lib.rs | 22 +++++ src/test/run-make/raw-dylib/output.txt | 3 + .../feature-gate-raw-dylib-2.rs | 0 .../feature-gate-raw-dylib-2.stderr | 0 .../feature-gate-raw-dylib-windows-gnu.rs | 8 ++ .../feature-gate-raw-dylib-windows-gnu.stderr | 18 ++++ .../feature-gate-raw-dylib-windows-msvc.rs} | 2 + ...eature-gate-raw-dylib-windows-msvc.stderr} | 2 +- .../ui/manual/manual-link-unsupported-kind.rs | 5 ++ .../manual-link-unsupported-kind.stderr | 2 + .../rfc-2627-raw-dylib/raw-dylib-msvc-only.rs | 8 ++ .../raw-dylib-msvc-only.stderr | 17 ++++ .../raw-dylib-windows-only.rs | 7 ++ .../raw-dylib-windows-only.stderr | 17 ++++ 27 files changed, 481 insertions(+), 20 deletions(-) create mode 100644 src/test/run-make/raw-dylib/Makefile create mode 100644 src/test/run-make/raw-dylib/driver.rs create mode 100644 src/test/run-make/raw-dylib/extern_1.c create mode 100644 src/test/run-make/raw-dylib/extern_2.c create mode 100644 src/test/run-make/raw-dylib/lib.rs create mode 100644 src/test/run-make/raw-dylib/output.txt rename src/test/ui/{rfc-2627-raw-dylib => feature-gates}/feature-gate-raw-dylib-2.rs (100%) rename src/test/ui/{rfc-2627-raw-dylib => feature-gates}/feature-gate-raw-dylib-2.stderr (100%) create mode 100644 src/test/ui/feature-gates/feature-gate-raw-dylib-windows-gnu.rs create mode 100644 src/test/ui/feature-gates/feature-gate-raw-dylib-windows-gnu.stderr rename src/test/ui/{rfc-2627-raw-dylib/feature-gate-raw-dylib.rs => feature-gates/feature-gate-raw-dylib-windows-msvc.rs} (71%) rename src/test/ui/{rfc-2627-raw-dylib/feature-gate-raw-dylib.stderr => feature-gates/feature-gate-raw-dylib-windows-msvc.stderr} (88%) create mode 100644 src/test/ui/manual/manual-link-unsupported-kind.rs create mode 100644 src/test/ui/manual/manual-link-unsupported-kind.stderr create mode 100644 src/test/ui/rfc-2627-raw-dylib/raw-dylib-msvc-only.rs create mode 100644 src/test/ui/rfc-2627-raw-dylib/raw-dylib-msvc-only.stderr create mode 100644 src/test/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.rs create mode 100644 src/test/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.stderr diff --git a/compiler/rustc_codegen_cranelift/src/archive.rs b/compiler/rustc_codegen_cranelift/src/archive.rs index bd54adc53ee..22897c43e7e 100644 --- a/compiler/rustc_codegen_cranelift/src/archive.rs +++ b/compiler/rustc_codegen_cranelift/src/archive.rs @@ -254,6 +254,15 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { } } } + + fn inject_dll_import_lib( + &mut self, + _lib_name: &str, + _dll_imports: &[rustc_middle::middle::cstore::DllImport], + _tmpdir: &rustc_data_structures::temp_dir::MaybeTempDir, + ) { + bug!("injecting dll imports is not supported"); + } } impl<'a> ArArchiveBuilder<'a> { diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index 261affe2c42..64416bced31 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -8,9 +8,11 @@ use std::ptr; use std::str; use crate::llvm::archive_ro::{ArchiveRO, Child}; -use crate::llvm::{self, ArchiveKind}; +use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport}; use rustc_codegen_ssa::back::archive::{find_library, ArchiveBuilder}; use rustc_codegen_ssa::{looks_like_rust_object_file, METADATA_FILENAME}; +use rustc_data_structures::temp_dir::MaybeTempDir; +use rustc_middle::middle::cstore::DllImport; use rustc_session::Session; use rustc_span::symbol::Symbol; @@ -61,6 +63,17 @@ fn archive_config<'a>(sess: &'a Session, output: &Path, input: Option<&Path>) -> } } +/// Map machine type strings to values of LLVM's MachineTypes enum. +fn llvm_machine_type(cpu: &str) -> LLVMMachineType { + match cpu { + "x86_64" => LLVMMachineType::AMD64, + "x86" => LLVMMachineType::I386, + "aarch64" => LLVMMachineType::ARM64, + "arm" => LLVMMachineType::ARM, + _ => panic!("unsupported cpu type {}", cpu), + } +} + impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> { /// Creates a new static archive, ready for modifying the archive specified /// by `config`. @@ -175,6 +188,74 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> { self.config.sess.fatal(&format!("failed to build archive: {}", e)); } } + + fn inject_dll_import_lib( + &mut self, + lib_name: &str, + dll_imports: &[DllImport], + tmpdir: &MaybeTempDir, + ) { + let output_path = { + let mut output_path: PathBuf = tmpdir.as_ref().to_path_buf(); + output_path.push(format!("{}_imports", lib_name)); + output_path.with_extension("lib") + }; + + // we've checked for \0 characters in the library name already + let dll_name_z = CString::new(lib_name).unwrap(); + // All import names are Rust identifiers and therefore cannot contain \0 characters. + // FIXME: when support for #[link_name] implemented, ensure that import.name values don't + // have any \0 characters + let import_name_vector: Vec = dll_imports + .iter() + .map(if self.config.sess.target.arch == "x86" { + |import: &DllImport| CString::new(format!("_{}", import.name.to_string())).unwrap() + } else { + |import: &DllImport| CString::new(import.name.to_string()).unwrap() + }) + .collect(); + + let output_path_z = rustc_fs_util::path_to_c_string(&output_path); + + tracing::trace!("invoking LLVMRustWriteImportLibrary"); + tracing::trace!(" dll_name {:#?}", dll_name_z); + tracing::trace!(" output_path {}", output_path.display()); + tracing::trace!( + " import names: {}", + dll_imports.iter().map(|import| import.name.to_string()).collect::>().join(", "), + ); + + let ffi_exports: Vec = import_name_vector + .iter() + .map(|name_z| LLVMRustCOFFShortExport::from_name(name_z.as_ptr())) + .collect(); + let result = unsafe { + crate::llvm::LLVMRustWriteImportLibrary( + dll_name_z.as_ptr(), + output_path_z.as_ptr(), + ffi_exports.as_ptr(), + ffi_exports.len(), + llvm_machine_type(&self.config.sess.target.arch) as u16, + !self.config.sess.target.is_like_msvc, + ) + }; + + if result == crate::llvm::LLVMRustResult::Failure { + self.config.sess.fatal(&format!( + "Error creating import library for {}: {}", + lib_name, + llvm::last_error().unwrap_or("unknown LLVM error".to_string()) + )); + } + + self.add_archive(&output_path, |_| false).unwrap_or_else(|e| { + self.config.sess.fatal(&format!( + "failed to add native library {}: {}", + output_path.display(), + e + )); + }); + } } impl<'a> LlvmArchiveBuilder<'a> { diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 115aa74dcc4..91923251018 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -29,6 +29,31 @@ pub enum LLVMRustResult { Success, Failure, } + +// Rust version of the C struct with the same name in rustc_llvm/llvm-wrapper/RustWrapper.cpp. +#[repr(C)] +pub struct LLVMRustCOFFShortExport { + pub name: *const c_char, +} + +impl LLVMRustCOFFShortExport { + pub fn from_name(name: *const c_char) -> LLVMRustCOFFShortExport { + LLVMRustCOFFShortExport { name } + } +} + +/// Translation of LLVM's MachineTypes enum, defined in llvm\include\llvm\BinaryFormat\COFF.h. +/// +/// We include only architectures supported on Windows. +#[derive(Copy, Clone, PartialEq)] +#[repr(C)] +pub enum LLVMMachineType { + AMD64 = 0x8664, + I386 = 0x14c, + ARM64 = 0xaa64, + ARM = 0x01c0, +} + // Consts for the LLVM CallConv type, pre-cast to usize. /// LLVM CallingConv::ID. Should we wrap this? @@ -2265,6 +2290,15 @@ extern "C" { ) -> &'a mut RustArchiveMember<'a>; pub fn LLVMRustArchiveMemberFree(Member: &'a mut RustArchiveMember<'a>); + pub fn LLVMRustWriteImportLibrary( + ImportName: *const c_char, + Path: *const c_char, + Exports: *const LLVMRustCOFFShortExport, + NumExports: usize, + Machine: u16, + MinGW: bool, + ) -> LLVMRustResult; + pub fn LLVMRustSetDataLayoutFromTargetMachine(M: &'a Module, TM: &'a TargetMachine); pub fn LLVMRustBuildOperandBundleDef( diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index c197d48d4ea..63f457bb979 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -1,3 +1,5 @@ +use rustc_data_structures::temp_dir::MaybeTempDir; +use rustc_middle::middle::cstore::DllImport; use rustc_session::Session; use rustc_span::symbol::Symbol; @@ -57,4 +59,11 @@ pub trait ArchiveBuilder<'a> { fn update_symbols(&mut self); fn build(self); + + fn inject_dll_import_lib( + &mut self, + lib_name: &str, + dll_imports: &[DllImport], + tmpdir: &MaybeTempDir, + ); } diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 87eb51342d4..aeaf435e4c0 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1,9 +1,9 @@ -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_errors::Handler; use rustc_fs_util::fix_windows_verbatim_for_gcc; use rustc_hir::def_id::CrateNum; -use rustc_middle::middle::cstore::LibSource; +use rustc_middle::middle::cstore::{DllImport, LibSource}; use rustc_middle::middle::dependency_format::Linkage; use rustc_session::config::{self, CFGuard, CrateType, DebugInfo}; use rustc_session::config::{OutputFilenames, OutputType, PrintRequest}; @@ -34,6 +34,7 @@ use object::write::Object; use object::{Architecture, BinaryFormat, Endianness, FileFlags, SectionFlags, SectionKind}; use tempfile::Builder as TempFileBuilder; +use std::cmp::Ordering; use std::ffi::OsString; use std::path::{Path, PathBuf}; use std::process::{ExitStatus, Output, Stdio}; @@ -343,6 +344,12 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>( } } + for (raw_dylib_name, raw_dylib_imports) in + collate_raw_dylibs(&codegen_results.crate_info.used_libraries) + { + ab.inject_dll_import_lib(&raw_dylib_name, &raw_dylib_imports, tmpdir); + } + // After adding all files to the archive, we need to update the // symbol table of the archive. ab.update_symbols(); @@ -524,6 +531,57 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>( } } +/// 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, +/// then the CodegenResults value contains one NativeLib instance for each block. However, the +/// linker appears to expect only a single import library for each library used, so we need to +/// collate the symbols together by library name before generating the import libraries. +fn collate_raw_dylibs(used_libraries: &[NativeLib]) -> Vec<(String, Vec)> { + let mut dylib_table: FxHashMap> = FxHashMap::default(); + + for lib in used_libraries { + if lib.kind == NativeLibKind::RawDylib { + let name = lib.name.unwrap_or_else(|| + bug!("`link` attribute with kind = \"raw-dylib\" and no name should have caused error earlier") + ); + let name = if matches!(lib.verbatim, Some(true)) { + name.to_string() + } else { + format!("{}.dll", name) + }; + dylib_table + .entry(name) + .or_default() + .extend(lib.dll_imports.iter().map(|import| import.name)); + } + } + + // FIXME: when we add support for ordinals, fix this to propagate ordinals. Also figure out + // what we should do if we have two DllImport values with the same name but different + // ordinals. + let mut result = dylib_table + .into_iter() + .map(|(lib_name, imported_names)| { + let mut names = imported_names + .iter() + .map(|name| DllImport { name: *name, ordinal: None }) + .collect::>(); + names.sort_unstable_by(|a: &DllImport, b: &DllImport| { + match a.name.as_str().cmp(&b.name.as_str()) { + Ordering::Equal => a.ordinal.cmp(&b.ordinal), + x => x, + } + }); + (lib_name, names) + }) + .collect::>(); + result.sort_unstable_by(|a: &(String, Vec), b: &(String, Vec)| { + a.0.cmp(&b.0) + }); + result +} + /// Create a static archive. /// /// This is essentially the same thing as an rlib, but it also involves adding all of the upstream @@ -2302,10 +2360,7 @@ fn add_upstream_native_libraries( // already included them when we included the rust library // previously NativeLibKind::Static { bundle: None | Some(true), .. } => {} - NativeLibKind::RawDylib => { - // FIXME(#58713): Proper handling for raw dylibs. - bug!("raw_dylib feature not yet implemented"); - } + NativeLibKind::RawDylib => {} } } } diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 12da3d9e155..48171ccd2fd 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -110,11 +110,18 @@ pub struct NativeLib { pub name: Option, pub cfg: Option, pub verbatim: Option, + pub dll_imports: Vec, } impl From<&cstore::NativeLib> for NativeLib { fn from(lib: &cstore::NativeLib) -> Self { - NativeLib { kind: lib.kind, name: lib.name, cfg: lib.cfg.clone(), verbatim: lib.verbatim } + NativeLib { + kind: lib.kind, + name: lib.name, + cfg: lib.cfg.clone(), + verbatim: lib.verbatim, + dll_imports: lib.dll_imports.clone(), + } } } diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 548b3471ba7..9b757eb40c1 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -6,6 +6,7 @@ #include "llvm/IR/Instructions.h" #include "llvm/IR/Intrinsics.h" #include "llvm/Object/Archive.h" +#include "llvm/Object/COFFImportFile.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Bitcode/BitcodeWriterPass.h" #include "llvm/Support/Signals.h" @@ -1722,3 +1723,54 @@ extern "C" LLVMValueRef LLVMRustBuildMaxNum(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS) { return wrap(unwrap(B)->CreateMaxNum(unwrap(LHS),unwrap(RHS))); } + +// This struct contains all necessary info about a symbol exported from a DLL. +// At the moment, it's just the symbol's name, but we use a separate struct to +// make it easier to add other information like ordinal later. +struct LLVMRustCOFFShortExport { + const char* name; +}; + +// Machine must be a COFF machine type, as defined in PE specs. +extern "C" LLVMRustResult LLVMRustWriteImportLibrary( + const char* ImportName, + const char* Path, + const LLVMRustCOFFShortExport* Exports, + size_t NumExports, + uint16_t Machine, + bool MinGW) +{ + std::vector ConvertedExports; + ConvertedExports.reserve(NumExports); + + for (size_t i = 0; i < NumExports; ++i) { + ConvertedExports.push_back(llvm::object::COFFShortExport{ + Exports[i].name, // Name + std::string{}, // ExtName + std::string{}, // SymbolName + std::string{}, // AliasTarget + 0, // Ordinal + false, // Noname + false, // Data + false, // Private + false // Constant + }); + } + + auto Error = llvm::object::writeImportLibrary( + ImportName, + Path, + ConvertedExports, + static_cast(Machine), + MinGW); + if (Error) { + std::string errorString; + llvm::raw_string_ostream stream(errorString); + stream << Error; + stream.flush(); + LLVMRustSetLastError(errorString.c_str()); + return LLVMRustResult::Failure; + } else { + return LLVMRustResult::Success; + } +} diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index bc342119efb..cd4c394ae14 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -3,7 +3,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::itemlikevisit::ItemLikeVisitor; -use rustc_middle::middle::cstore::NativeLib; +use rustc_middle::middle::cstore::{DllImport, NativeLib}; use rustc_middle::ty::TyCtxt; use rustc_session::parse::feature_err; use rustc_session::utils::NativeLibKind; @@ -33,8 +33,8 @@ struct Collector<'tcx> { impl ItemLikeVisitor<'tcx> for Collector<'tcx> { fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) { - let abi = match it.kind { - hir::ItemKind::ForeignMod { abi, .. } => abi, + let (abi, foreign_mod_items) = match it.kind { + hir::ItemKind::ForeignMod { abi, items } => (abi, items), _ => return, }; @@ -57,6 +57,7 @@ impl ItemLikeVisitor<'tcx> for Collector<'tcx> { foreign_module: Some(it.def_id.to_def_id()), wasm_import_module: None, verbatim: None, + dll_imports: Vec::new(), }; let mut kind_specified = false; @@ -196,6 +197,27 @@ impl ItemLikeVisitor<'tcx> for Collector<'tcx> { .span_label(m.span, "missing `name` argument") .emit(); } + + if lib.kind == NativeLibKind::RawDylib { + match abi { + Abi::C { .. } => (), + Abi::Cdecl => (), + _ => { + if sess.target.arch == "x86" { + sess.span_fatal( + it.span, + r#"`#[link(kind = "raw-dylib")]` only supports C and Cdecl ABIs"#, + ); + } + } + }; + lib.dll_imports.extend( + foreign_mod_items + .iter() + .map(|child_item| DllImport { name: child_item.ident.name, ordinal: None }), + ); + } + self.register_native_lib(Some(m.span), lib); } } @@ -253,15 +275,42 @@ impl Collector<'tcx> { ) .emit(); } - if lib.kind == NativeLibKind::RawDylib && !self.tcx.features().raw_dylib { - feature_err( - &self.tcx.sess.parse_sess, - sym::raw_dylib, - span.unwrap_or(rustc_span::DUMMY_SP), - "kind=\"raw-dylib\" is unstable", - ) - .emit(); + // this just unwraps lib.name; we already established that it isn't empty above. + if let (NativeLibKind::RawDylib, Some(lib_name)) = (lib.kind, lib.name) { + let span = match span { + Some(s) => s, + None => { + bug!("raw-dylib libraries are not supported on the command line"); + } + }; + + if !self.tcx.sess.target.options.is_like_windows { + self.tcx.sess.span_fatal( + span, + "`#[link(...)]` with `kind = \"raw-dylib\"` only supported on Windows", + ); + } else if !self.tcx.sess.target.options.is_like_msvc { + self.tcx.sess.span_warn( + span, + "`#[link(...)]` with `kind = \"raw-dylib\"` not supported on windows-gnu", + ); + } + + if lib_name.as_str().contains('\0') { + self.tcx.sess.span_err(span, "library name may not contain NUL characters"); + } + + if !self.tcx.features().raw_dylib { + feature_err( + &self.tcx.sess.parse_sess, + sym::raw_dylib, + span, + "kind=\"raw-dylib\" is unstable", + ) + .emit(); + } } + self.libs.push(lib); } @@ -337,6 +386,7 @@ impl Collector<'tcx> { foreign_module: None, wasm_import_module: None, verbatim: passed_lib.verbatim, + dll_imports: Vec::new(), }; self.register_native_lib(None, lib); } else { diff --git a/compiler/rustc_middle/src/middle/cstore.rs b/compiler/rustc_middle/src/middle/cstore.rs index dd3b0a40d69..df578708931 100644 --- a/compiler/rustc_middle/src/middle/cstore.rs +++ b/compiler/rustc_middle/src/middle/cstore.rs @@ -95,6 +95,13 @@ pub struct NativeLib { pub foreign_module: Option, pub wasm_import_module: Option, pub verbatim: Option, + pub dll_imports: Vec, +} + +#[derive(Clone, Debug, Encodable, Decodable, HashStable)] +pub struct DllImport { + pub name: Symbol, + pub ordinal: Option, } #[derive(Clone, TyEncodable, TyDecodable, HashStable, Debug)] diff --git a/src/test/run-make/raw-dylib/Makefile b/src/test/run-make/raw-dylib/Makefile new file mode 100644 index 00000000000..7ce46fd9331 --- /dev/null +++ b/src/test/run-make/raw-dylib/Makefile @@ -0,0 +1,21 @@ +# Test the behavior of #[link(.., kind = "raw-dylib")] on windows-msvc + +# only-windows +# only-msvc + +-include ../../run-make-fulldeps/tools.mk + +all: + $(call COMPILE_OBJ,"$(TMPDIR)"/extern_1.obj,extern_1.c) + $(call COMPILE_OBJ,"$(TMPDIR)"/extern_2.obj,extern_2.c) + $(CC) "$(TMPDIR)"/extern_1.obj -link -dll -out:"$(TMPDIR)"/extern_1.dll + $(CC) "$(TMPDIR)"/extern_2.obj -link -dll -out:"$(TMPDIR)"/extern_2.dll + $(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs + $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)" + "$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt + +ifdef RUSTC_BLESS_TEST + cp "$(TMPDIR)"/output.txt output.txt +else + $(DIFF) output.txt "$(TMPDIR)"/output.txt +endif diff --git a/src/test/run-make/raw-dylib/driver.rs b/src/test/run-make/raw-dylib/driver.rs new file mode 100644 index 00000000000..4059ede11fc --- /dev/null +++ b/src/test/run-make/raw-dylib/driver.rs @@ -0,0 +1,5 @@ +extern crate raw_dylib_test; + +fn main() { + raw_dylib_test::library_function(); +} diff --git a/src/test/run-make/raw-dylib/extern_1.c b/src/test/run-make/raw-dylib/extern_1.c new file mode 100644 index 00000000000..72737c086eb --- /dev/null +++ b/src/test/run-make/raw-dylib/extern_1.c @@ -0,0 +1,16 @@ +#include + +__declspec(dllexport) void extern_fn_1() { + printf("extern_fn_1\n"); + fflush(stdout); +} + +__declspec(dllexport) void extern_fn_2() { + printf("extern_fn_2; didn't get the rename\n"); + fflush(stdout); +} + +__declspec(dllexport) void extern_fn_with_long_name() { + printf("extern_fn_with_long_name; got the rename\n"); + fflush(stdout); +} diff --git a/src/test/run-make/raw-dylib/extern_2.c b/src/test/run-make/raw-dylib/extern_2.c new file mode 100644 index 00000000000..ae87fc3f821 --- /dev/null +++ b/src/test/run-make/raw-dylib/extern_2.c @@ -0,0 +1,6 @@ +#include + +__declspec(dllexport) void extern_fn_3() { + printf("extern_fn_3\n"); + fflush(stdout); +} diff --git a/src/test/run-make/raw-dylib/lib.rs b/src/test/run-make/raw-dylib/lib.rs new file mode 100644 index 00000000000..d8e6301f38e --- /dev/null +++ b/src/test/run-make/raw-dylib/lib.rs @@ -0,0 +1,22 @@ +#![feature(raw_dylib, native_link_modifiers, native_link_modifiers_verbatim)] + +#[link(name = "extern_1.dll", kind = "raw-dylib", modifiers = "+verbatim")] +extern { + fn extern_fn_1(); +} + +#[link(name = "extern_2", kind = "raw-dylib")] +extern { + fn extern_fn_3(); +} + +pub fn library_function() { + #[link(name = "extern_1", kind = "raw-dylib")] + extern { fn extern_fn_2(); } + + unsafe { + extern_fn_1(); + extern_fn_2(); + extern_fn_3(); + } +} diff --git a/src/test/run-make/raw-dylib/output.txt b/src/test/run-make/raw-dylib/output.txt new file mode 100644 index 00000000000..7800cba1872 --- /dev/null +++ b/src/test/run-make/raw-dylib/output.txt @@ -0,0 +1,3 @@ +extern_fn_1 +extern_fn_2; didn't get the rename +extern_fn_3 diff --git a/src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib-2.rs b/src/test/ui/feature-gates/feature-gate-raw-dylib-2.rs similarity index 100% rename from src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib-2.rs rename to src/test/ui/feature-gates/feature-gate-raw-dylib-2.rs diff --git a/src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib-2.stderr b/src/test/ui/feature-gates/feature-gate-raw-dylib-2.stderr similarity index 100% rename from src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib-2.stderr rename to src/test/ui/feature-gates/feature-gate-raw-dylib-2.stderr diff --git a/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-gnu.rs b/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-gnu.rs new file mode 100644 index 00000000000..33f9c539313 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-gnu.rs @@ -0,0 +1,8 @@ +// gate-test-raw_dylib +// only-windows-gnu +#[link(name = "foo", kind = "raw-dylib")] +//~^ ERROR: kind="raw-dylib" is unstable +//~| WARNING: `#[link(...)]` with `kind = "raw-dylib"` not supported on windows-gnu +extern "C" {} + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-gnu.stderr b/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-gnu.stderr new file mode 100644 index 00000000000..14dfadf4126 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-gnu.stderr @@ -0,0 +1,18 @@ +warning: `#[link(...)]` with `kind = "raw-dylib"` not supported on windows-gnu + --> $DIR/feature-gate-raw-dylib-windows-gnu.rs:3:1 + | +LL | #[link(name = "foo", kind = "raw-dylib")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0658]: kind="raw-dylib" is unstable + --> $DIR/feature-gate-raw-dylib-windows-gnu.rs:3:1 + | +LL | #[link(name = "foo", kind = "raw-dylib")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #58713 for more information + = help: add `#![feature(raw_dylib)]` to the crate attributes to enable + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib.rs b/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-msvc.rs similarity index 71% rename from src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib.rs rename to src/test/ui/feature-gates/feature-gate-raw-dylib-windows-msvc.rs index 29edd0f9ef9..49de24ea9ab 100644 --- a/src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib.rs +++ b/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-msvc.rs @@ -1,3 +1,5 @@ +// gate-test-raw_dylib +// only-windows-msvc #[link(name = "foo", kind = "raw-dylib")] //~^ ERROR: kind="raw-dylib" is unstable extern "C" {} diff --git a/src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib.stderr b/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-msvc.stderr similarity index 88% rename from src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib.stderr rename to src/test/ui/feature-gates/feature-gate-raw-dylib-windows-msvc.stderr index a670b6c6c2a..11988080812 100644 --- a/src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib.stderr +++ b/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-msvc.stderr @@ -1,5 +1,5 @@ error[E0658]: kind="raw-dylib" is unstable - --> $DIR/feature-gate-raw-dylib.rs:1:1 + --> $DIR/feature-gate-raw-dylib-windows-msvc.rs:3:1 | LL | #[link(name = "foo", kind = "raw-dylib")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/manual/manual-link-unsupported-kind.rs b/src/test/ui/manual/manual-link-unsupported-kind.rs new file mode 100644 index 00000000000..34814db593f --- /dev/null +++ b/src/test/ui/manual/manual-link-unsupported-kind.rs @@ -0,0 +1,5 @@ +// compile-flags:-l raw-dylib=foo +// error-pattern: unknown library kind `raw-dylib`, expected one of dylib, framework, or static + +fn main() { +} diff --git a/src/test/ui/manual/manual-link-unsupported-kind.stderr b/src/test/ui/manual/manual-link-unsupported-kind.stderr new file mode 100644 index 00000000000..acb4463cb04 --- /dev/null +++ b/src/test/ui/manual/manual-link-unsupported-kind.stderr @@ -0,0 +1,2 @@ +error: unknown library kind `raw-dylib`, expected one of dylib, framework, or static + diff --git a/src/test/ui/rfc-2627-raw-dylib/raw-dylib-msvc-only.rs b/src/test/ui/rfc-2627-raw-dylib/raw-dylib-msvc-only.rs new file mode 100644 index 00000000000..e9690f03f45 --- /dev/null +++ b/src/test/ui/rfc-2627-raw-dylib/raw-dylib-msvc-only.rs @@ -0,0 +1,8 @@ +// only-windows-gnu +// check-pass +// compile-flags: --crate-type lib +#![feature(raw_dylib)] +//~^ WARNING: the feature `raw_dylib` is incomplete +#[link(name = "foo", kind = "raw-dylib")] +//~^ WARNING: `#[link(...)]` with `kind = "raw-dylib"` not supported on windows-gnu +extern "C" {} diff --git a/src/test/ui/rfc-2627-raw-dylib/raw-dylib-msvc-only.stderr b/src/test/ui/rfc-2627-raw-dylib/raw-dylib-msvc-only.stderr new file mode 100644 index 00000000000..6e24112b3c3 --- /dev/null +++ b/src/test/ui/rfc-2627-raw-dylib/raw-dylib-msvc-only.stderr @@ -0,0 +1,17 @@ +warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/raw-dylib-msvc-only.rs:4:12 + | +LL | #![feature(raw_dylib)] + | ^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #58713 for more information + +warning: `#[link(...)]` with `kind = "raw-dylib"` not supported on windows-gnu + --> $DIR/raw-dylib-msvc-only.rs:6:1 + | +LL | #[link(name = "foo", kind = "raw-dylib")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: 2 warnings emitted + diff --git a/src/test/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.rs b/src/test/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.rs new file mode 100644 index 00000000000..7a5d7ac2934 --- /dev/null +++ b/src/test/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.rs @@ -0,0 +1,7 @@ +// ignore-windows +// compile-flags: --crate-type lib +#![feature(raw_dylib)] +//~^ WARNING: the feature `raw_dylib` is incomplete +#[link(name = "foo", kind = "raw-dylib")] +//~^ ERROR: `#[link(...)]` with `kind = "raw-dylib"` only supported on Windows +extern "C" {} diff --git a/src/test/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.stderr b/src/test/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.stderr new file mode 100644 index 00000000000..f3879b63f91 --- /dev/null +++ b/src/test/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.stderr @@ -0,0 +1,17 @@ +warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/raw-dylib-windows-only.rs:3:12 + | +LL | #![feature(raw_dylib)] + | ^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #58713 for more information + +error: `#[link(...)]` with `kind = "raw-dylib"` only supported on Windows + --> $DIR/raw-dylib-windows-only.rs:5:1 + | +LL | #[link(name = "foo", kind = "raw-dylib")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted +