mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
Auto merge of #84171 - ricobbe:raw-dylib-via-llvm, r=petrochenkov
Partial support for raw-dylib linkage First cut of functionality for issue #58713: add support for `#[link(kind = "raw-dylib")]` on `extern` blocks in lib crates compiled to .rlib files. Does not yet support `#[link_name]` attributes on functions, or the `#[link_ordinal]` attribute, or `#[link(kind = "raw-dylib")]` on `extern` blocks in bin crates; I intend to publish subsequent PRs to fill those gaps. It's also not yet clear whether this works for functions in `extern "stdcall"` blocks; I also intend to investigate that shortly and make any necessary changes as a follow-on PR. This implementation calls out to an LLVM function to construct the actual `.idata` sections as temporary `.lib` files on disk and then links those into the generated .rlib.
This commit is contained in:
commit
9a576175cc
@ -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> {
|
||||
|
@ -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<CString> = 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::<Vec<_>>().join(", "),
|
||||
);
|
||||
|
||||
let ffi_exports: Vec<LLVMRustCOFFShortExport> = 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> {
|
||||
|
@ -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(
|
||||
|
@ -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,
|
||||
);
|
||||
}
|
||||
|
@ -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<DllImport>)> {
|
||||
let mut dylib_table: FxHashMap<String, FxHashSet<Symbol>> = 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::<Vec<_>>();
|
||||
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::<Vec<_>>();
|
||||
result.sort_unstable_by(|a: &(String, Vec<DllImport>), b: &(String, Vec<DllImport>)| {
|
||||
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
|
||||
@ -2303,10 +2361,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 => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -110,11 +110,18 @@ pub struct NativeLib {
|
||||
pub name: Option<Symbol>,
|
||||
pub cfg: Option<ast::MetaItem>,
|
||||
pub verbatim: Option<bool>,
|
||||
pub dll_imports: Vec<cstore::DllImport>,
|
||||
}
|
||||
|
||||
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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<llvm::object::COFFShortExport> 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<llvm::COFF::MachineTypes>(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;
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -95,6 +95,13 @@ pub struct NativeLib {
|
||||
pub foreign_module: Option<DefId>,
|
||||
pub wasm_import_module: Option<Symbol>,
|
||||
pub verbatim: Option<bool>,
|
||||
pub dll_imports: Vec<DllImport>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Encodable, Decodable, HashStable)]
|
||||
pub struct DllImport {
|
||||
pub name: Symbol,
|
||||
pub ordinal: Option<u16>,
|
||||
}
|
||||
|
||||
#[derive(Clone, TyEncodable, TyDecodable, HashStable, Debug)]
|
||||
|
21
src/test/run-make/raw-dylib/Makefile
Normal file
21
src/test/run-make/raw-dylib/Makefile
Normal file
@ -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
|
5
src/test/run-make/raw-dylib/driver.rs
Normal file
5
src/test/run-make/raw-dylib/driver.rs
Normal file
@ -0,0 +1,5 @@
|
||||
extern crate raw_dylib_test;
|
||||
|
||||
fn main() {
|
||||
raw_dylib_test::library_function();
|
||||
}
|
16
src/test/run-make/raw-dylib/extern_1.c
Normal file
16
src/test/run-make/raw-dylib/extern_1.c
Normal file
@ -0,0 +1,16 @@
|
||||
#include <stdio.h>
|
||||
|
||||
__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);
|
||||
}
|
6
src/test/run-make/raw-dylib/extern_2.c
Normal file
6
src/test/run-make/raw-dylib/extern_2.c
Normal file
@ -0,0 +1,6 @@
|
||||
#include <stdio.h>
|
||||
|
||||
__declspec(dllexport) void extern_fn_3() {
|
||||
printf("extern_fn_3\n");
|
||||
fflush(stdout);
|
||||
}
|
22
src/test/run-make/raw-dylib/lib.rs
Normal file
22
src/test/run-make/raw-dylib/lib.rs
Normal file
@ -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();
|
||||
}
|
||||
}
|
3
src/test/run-make/raw-dylib/output.txt
Normal file
3
src/test/run-make/raw-dylib/output.txt
Normal file
@ -0,0 +1,3 @@
|
||||
extern_fn_1
|
||||
extern_fn_2; didn't get the rename
|
||||
extern_fn_3
|
@ -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() {}
|
@ -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 <https://github.com/rust-lang/rust/issues/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`.
|
@ -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" {}
|
@ -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")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
5
src/test/ui/manual/manual-link-unsupported-kind.rs
Normal file
5
src/test/ui/manual/manual-link-unsupported-kind.rs
Normal file
@ -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() {
|
||||
}
|
2
src/test/ui/manual/manual-link-unsupported-kind.stderr
Normal file
2
src/test/ui/manual/manual-link-unsupported-kind.stderr
Normal file
@ -0,0 +1,2 @@
|
||||
error: unknown library kind `raw-dylib`, expected one of dylib, framework, or static
|
||||
|
8
src/test/ui/rfc-2627-raw-dylib/raw-dylib-msvc-only.rs
Normal file
8
src/test/ui/rfc-2627-raw-dylib/raw-dylib-msvc-only.rs
Normal file
@ -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" {}
|
17
src/test/ui/rfc-2627-raw-dylib/raw-dylib-msvc-only.stderr
Normal file
17
src/test/ui/rfc-2627-raw-dylib/raw-dylib-msvc-only.stderr
Normal file
@ -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 <https://github.com/rust-lang/rust/issues/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
|
||||
|
7
src/test/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.rs
Normal file
7
src/test/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.rs
Normal file
@ -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" {}
|
17
src/test/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.stderr
Normal file
17
src/test/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.stderr
Normal file
@ -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 <https://github.com/rust-lang/rust/issues/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
|
||||
|
Loading…
Reference in New Issue
Block a user