Skip to content

Commit 92d6d33

Browse files
committed
Add support for raw-dylib
1 parent 395181c commit 92d6d33

File tree

8 files changed

+159
-91
lines changed

8 files changed

+159
-91
lines changed

Cargo.lock

Lines changed: 12 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ cranelift-object = { version = "0.110.1" }
1717
target-lexicon = "0.12.0"
1818
gimli = { version = "0.28", default-features = false, features = ["write"]}
1919
object = { version = "0.36", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
20+
ar_archive_writer = "0.3.2"
2021

2122
indexmap = "2.0.0"
2223
libloading = { version = "0.8.0", optional = true }

build_system/tests.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ const BASE_SYSROOT_SUITE: &[TestCase] = &[
106106
]);
107107
runner.run_out_command("gen_block_iterate", &[]);
108108
}),
109+
TestCase::build_bin_and_run("aot.raw-dylib", "example/raw-dylib.rs", &[]),
109110
];
110111

111112
pub(crate) static RAND_REPO: GitRepo = GitRepo::github(

config.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ aot.issue-59326
4545
aot.polymorphize_coroutine
4646
aot.neon
4747
aot.gen_block_iterate
48+
aot.raw-dylib
4849

4950
testsuite.extended_sysroot
5051
test.rust-random/rand

example/raw-dylib.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Tests the raw-dylib feature for Windows.
2+
// https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute
3+
4+
fn main() {
5+
#[cfg(windows)]
6+
{
7+
#[link(name = "kernel32", kind = "raw-dylib")]
8+
extern "C" {
9+
fn GetModuleFileNameA(module: *mut std::ffi::c_void, filename: *mut u8, size: u32) -> u32;
10+
}
11+
12+
// Get the filename of the current executable....
13+
let mut buffer = [0u8; 1024];
14+
let size = unsafe { GetModuleFileNameA(core::ptr::null_mut(), buffer.as_mut_ptr(), buffer.len() as u32) };
15+
if size == 0 {
16+
eprintln!("failed to get module file name: {}", std::io::Error::last_os_error());
17+
return;
18+
} else {
19+
// ...and make sure that it matches the test name.
20+
let filename = std::ffi::CStr::from_bytes_with_nul(&buffer[..size as usize + 1]).unwrap();
21+
assert!(filename.to_str().unwrap().ends_with("raw-dylib.exe"));
22+
}
23+
}
24+
}

patches/0029-stdlib-rawdylib-processprng.patch

Lines changed: 0 additions & 47 deletions
This file was deleted.

patches/0030-stdlib-Revert-use-raw-dylib-for-Windows-futex-APIs.patch

Lines changed: 0 additions & 37 deletions
This file was deleted.

src/archive.rs

Lines changed: 120 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
1+
use std::borrow::Borrow;
2+
use std::fmt::Write;
3+
use std::fs;
14
use std::path::{Path, PathBuf};
25

6+
use ar_archive_writer::{COFFShortExport, MachineTypes};
37
use rustc_codegen_ssa::back::archive::{
48
ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER,
59
};
10+
use rustc_session::cstore::{DllCallingConvention, DllImport, PeImportNameType};
611
use rustc_session::Session;
712

813
pub(crate) struct ArArchiveBuilderBuilder;
@@ -15,11 +20,121 @@ impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
1520
fn create_dll_import_lib(
1621
&self,
1722
sess: &Session,
18-
_lib_name: &str,
19-
_dll_imports: &[rustc_session::cstore::DllImport],
20-
_tmpdir: &Path,
21-
_is_direct_dependency: bool,
23+
lib_name: &str,
24+
dll_imports: &[DllImport],
25+
tmpdir: &Path,
26+
is_direct_dependency: bool,
2227
) -> PathBuf {
23-
sess.dcx().fatal("raw-dylib is not yet supported by rustc_codegen_cranelift");
28+
let name_suffix = if is_direct_dependency { "_imports" } else { "_imports_indirect" };
29+
let output_path = tmpdir.join(format!("{lib_name}{name_suffix}.lib"));
30+
31+
let mut file = match fs::OpenOptions::new().write(true).create_new(true).open(&output_path)
32+
{
33+
Ok(file) => file,
34+
Err(error) => {
35+
sess.dcx().fatal(format!(
36+
"failed to create import library file `{path}`: {error}",
37+
path = output_path.display(),
38+
));
39+
}
40+
};
41+
42+
let machine = match sess.target.arch.borrow() {
43+
"x86" => MachineTypes::I386,
44+
"x86_64" => MachineTypes::AMD64,
45+
"arm" => MachineTypes::ARMNT,
46+
"aarch64" => MachineTypes::ARM64,
47+
_ => {
48+
sess.dcx().fatal(format!(
49+
"unsupported target architecture `{arch}`",
50+
arch = sess.target.arch,
51+
));
52+
}
53+
};
54+
55+
let exports = dll_imports
56+
.iter()
57+
.map(|import| {
58+
let name = if machine == MachineTypes::I386 {
59+
i686_decorated_name(import, !sess.target.is_like_msvc)
60+
} else {
61+
import.name.to_string()
62+
};
63+
COFFShortExport {
64+
name,
65+
ext_name: None,
66+
symbol_name: None,
67+
alias_target: None,
68+
ordinal: import.ordinal().unwrap_or(0),
69+
noname: import.ordinal().is_some(),
70+
data: false,
71+
private: false,
72+
constant: false,
73+
}
74+
})
75+
.collect::<Vec<_>>();
76+
77+
if let Err(error) = ar_archive_writer::write_import_library(
78+
&mut file,
79+
lib_name,
80+
&exports,
81+
machine,
82+
!sess.target.is_like_msvc,
83+
) {
84+
sess.dcx().fatal(format!(
85+
"failed to create import library `{path}`: `{error}`",
86+
path = output_path.display(),
87+
));
88+
}
89+
90+
output_path
2491
}
2592
}
93+
94+
fn i686_decorated_name(dll_import: &DllImport, mingw: bool) -> String {
95+
let name = dll_import.name.as_str();
96+
97+
let (add_prefix, add_suffix) = match dll_import.import_name_type {
98+
Some(PeImportNameType::NoPrefix) => (false, true),
99+
Some(PeImportNameType::Undecorated) => (false, false),
100+
_ => (true, true),
101+
};
102+
103+
// Worst case: +1 for prefix, +4 for suffix (@@__).
104+
let mut decorated_name = String::with_capacity(name.len() + 5);
105+
106+
let prefix = if add_prefix && dll_import.is_fn {
107+
match dll_import.calling_convention {
108+
DllCallingConvention::C | DllCallingConvention::Vectorcall(_) => None,
109+
DllCallingConvention::Stdcall(_) => (!mingw
110+
|| dll_import.import_name_type == Some(PeImportNameType::Decorated))
111+
.then_some('_'),
112+
DllCallingConvention::Fastcall(_) => Some('@'),
113+
}
114+
} else if !dll_import.is_fn && !mingw {
115+
// For static variables, prefix with '_' on MSVC.
116+
Some('_')
117+
} else {
118+
None
119+
};
120+
if let Some(prefix) = prefix {
121+
decorated_name.push(prefix);
122+
}
123+
124+
decorated_name.push_str(name);
125+
126+
if add_suffix && dll_import.is_fn {
127+
match dll_import.calling_convention {
128+
DllCallingConvention::C => {}
129+
DllCallingConvention::Stdcall(arg_list_size)
130+
| DllCallingConvention::Fastcall(arg_list_size) => {
131+
write!(&mut decorated_name, "@{arg_list_size}").unwrap();
132+
}
133+
DllCallingConvention::Vectorcall(arg_list_size) => {
134+
write!(&mut decorated_name, "@@{arg_list_size}").unwrap();
135+
}
136+
}
137+
}
138+
139+
decorated_name
140+
}

0 commit comments

Comments
 (0)