Skip to content

Partial support for raw-dylib linkage #84171

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 6, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions compiler/rustc_codegen_cranelift/src/archive.rs
Original file line number Diff line number Diff line change
@@ -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> {
83 changes: 82 additions & 1 deletion compiler/rustc_codegen_llvm/src/back/archive.rs
Original file line number Diff line number Diff line change
@@ -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> {
34 changes: 34 additions & 0 deletions compiler/rustc_codegen_llvm/src/llvm/ffi.rs
Original file line number Diff line number Diff line change
@@ -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(
9 changes: 9 additions & 0 deletions compiler/rustc_codegen_ssa/src/back/archive.rs
Original file line number Diff line number Diff line change
@@ -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,
);
}
67 changes: 61 additions & 6 deletions compiler/rustc_codegen_ssa/src/back/link.rs
Original file line number Diff line number Diff line change
@@ -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
@@ -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 => {}
}
}
}
9 changes: 8 additions & 1 deletion compiler/rustc_codegen_ssa/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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(),
}
}
}

52 changes: 52 additions & 0 deletions compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
Original file line number Diff line number Diff line change
@@ -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;
}
}
72 changes: 61 additions & 11 deletions compiler/rustc_metadata/src/native_libs.rs
Original file line number Diff line number Diff line change
@@ -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 {
7 changes: 7 additions & 0 deletions compiler/rustc_middle/src/middle/cstore.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 21 additions & 0 deletions src/test/run-make/raw-dylib/Makefile
Original file line number Diff line number Diff line change
@@ -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 changes: 5 additions & 0 deletions src/test/run-make/raw-dylib/driver.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
extern crate raw_dylib_test;

fn main() {
raw_dylib_test::library_function();
}
16 changes: 16 additions & 0 deletions src/test/run-make/raw-dylib/extern_1.c
Original file line number Diff line number Diff line change
@@ -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 changes: 6 additions & 0 deletions src/test/run-make/raw-dylib/extern_2.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include <stdio.h>

__declspec(dllexport) void extern_fn_3() {
printf("extern_fn_3\n");
fflush(stdout);
}
22 changes: 22 additions & 0 deletions src/test/run-make/raw-dylib/lib.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 3 additions & 0 deletions src/test/run-make/raw-dylib/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
extern_fn_1
extern_fn_2; didn't get the rename
extern_fn_3
Original file line number Diff line number Diff line change
@@ -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() {}
Original file line number Diff line number Diff line change
@@ -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`.
Original file line number Diff line number Diff line change
@@ -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" {}
Original file line number Diff line number Diff line change
@@ -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 changes: 5 additions & 0 deletions src/test/ui/manual/manual-link-unsupported-kind.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 2 additions & 0 deletions src/test/ui/manual/manual-link-unsupported-kind.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: unknown library kind `raw-dylib`, expected one of dylib, framework, or static

8 changes: 8 additions & 0 deletions src/test/ui/rfc-2627-raw-dylib/raw-dylib-msvc-only.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 17 additions & 0 deletions src/test/ui/rfc-2627-raw-dylib/raw-dylib-msvc-only.stderr
Original file line number Diff line number Diff line change
@@ -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 changes: 7 additions & 0 deletions src/test/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 17 additions & 0 deletions src/test/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.stderr
Original file line number Diff line number Diff line change
@@ -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