Skip to content

Commit daaae25

Browse files
committed
Auto merge of #98989 - dpaoliello:rawdylibbin, r=michaelwoerister
Enable raw-dylib for bin crates Fixes #93842 When `raw-dylib` is used in a `bin` crate, we need to collect all of the `raw-dylib` functions, generate the import library and add that to the linker command line. I also changed the tests so that 1) the C++ dlls are created after the Rust dlls, thus there is no chance of accidentally using them in the Rust linking process and 2) disabled generating import libraries when building with MSVC.
2 parents a867059 + 1f33785 commit daaae25

File tree

11 files changed

+108
-53
lines changed

11 files changed

+108
-53
lines changed

Diff for: compiler/rustc_codegen_cranelift/src/archive.rs

+9-5
Original file line numberDiff line numberDiff line change
@@ -204,12 +204,16 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
204204
any_members
205205
}
206206

207-
fn inject_dll_import_lib(
208-
&mut self,
207+
fn sess(&self) -> &Session {
208+
self.sess
209+
}
210+
211+
fn create_dll_import_lib(
212+
_sess: &Session,
209213
_lib_name: &str,
210214
_dll_imports: &[rustc_session::cstore::DllImport],
211-
_tmpdir: &rustc_data_structures::temp_dir::MaybeTempDir,
212-
) {
213-
bug!("injecting dll imports is not supported");
215+
_tmpdir: &Path,
216+
) -> PathBuf {
217+
bug!("creating dll imports is not supported");
214218
}
215219
}

Diff for: compiler/rustc_codegen_gcc/src/archive.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ use std::path::{Path, PathBuf};
44
use rustc_codegen_ssa::back::archive::ArchiveBuilder;
55
use rustc_session::Session;
66

7-
use rustc_data_structures::temp_dir::MaybeTempDir;
87
use rustc_session::cstore::DllImport;
98

109
struct ArchiveConfig<'a> {
@@ -177,7 +176,16 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
177176
any_members
178177
}
179178

180-
fn inject_dll_import_lib(&mut self, _lib_name: &str, _dll_imports: &[DllImport], _tmpdir: &MaybeTempDir) {
179+
fn sess(&self) -> &Session {
180+
self.config.sess
181+
}
182+
183+
fn create_dll_import_lib(
184+
_sess: &Session,
185+
_lib_name: &str,
186+
_dll_imports: &[DllImport],
187+
_tmpdir: &Path,
188+
) -> PathBuf {
181189
unimplemented!();
182190
}
183191
}

Diff for: compiler/rustc_codegen_llvm/src/back/archive.rs

+20-24
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ use std::str;
1111
use crate::llvm::archive_ro::{ArchiveRO, Child};
1212
use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport};
1313
use rustc_codegen_ssa::back::archive::ArchiveBuilder;
14-
use rustc_data_structures::temp_dir::MaybeTempDir;
1514
use rustc_session::cstore::{DllCallingConvention, DllImport};
1615
use rustc_session::Session;
1716

@@ -96,19 +95,23 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
9695
}
9796
}
9897

99-
fn inject_dll_import_lib(
100-
&mut self,
98+
fn sess(&self) -> &Session {
99+
self.sess
100+
}
101+
102+
fn create_dll_import_lib(
103+
sess: &Session,
101104
lib_name: &str,
102105
dll_imports: &[DllImport],
103-
tmpdir: &MaybeTempDir,
104-
) {
106+
tmpdir: &Path,
107+
) -> PathBuf {
105108
let output_path = {
106-
let mut output_path: PathBuf = tmpdir.as_ref().to_path_buf();
109+
let mut output_path: PathBuf = tmpdir.to_path_buf();
107110
output_path.push(format!("{}_imports", lib_name));
108111
output_path.with_extension("lib")
109112
};
110113

111-
let target = &self.sess.target;
114+
let target = &sess.target;
112115
let mingw_gnu_toolchain = target.vendor == "pc"
113116
&& target.os == "windows"
114117
&& target.env == "gnu"
@@ -117,7 +120,7 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
117120
let import_name_and_ordinal_vector: Vec<(String, Option<u16>)> = dll_imports
118121
.iter()
119122
.map(|import: &DllImport| {
120-
if self.sess.target.arch == "x86" {
123+
if sess.target.arch == "x86" {
121124
(
122125
LlvmArchiveBuilder::i686_decorated_name(import, mingw_gnu_toolchain),
123126
import.ordinal,
@@ -134,8 +137,7 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
134137
// that loaded but crashed with an AV upon calling one of the imported
135138
// functions. Therefore, use binutils to create the import library instead,
136139
// by writing a .DEF file to the temp dir and calling binutils's dlltool.
137-
let def_file_path =
138-
tmpdir.as_ref().join(format!("{}_imports", lib_name)).with_extension("def");
140+
let def_file_path = tmpdir.join(format!("{}_imports", lib_name)).with_extension("def");
139141

140142
let def_file_content = format!(
141143
"EXPORTS\n{}",
@@ -154,11 +156,11 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
154156
match std::fs::write(&def_file_path, def_file_content) {
155157
Ok(_) => {}
156158
Err(e) => {
157-
self.sess.fatal(&format!("Error writing .DEF file: {}", e));
159+
sess.fatal(&format!("Error writing .DEF file: {}", e));
158160
}
159161
};
160162

161-
let dlltool = find_binutils_dlltool(self.sess);
163+
let dlltool = find_binutils_dlltool(sess);
162164
let result = std::process::Command::new(dlltool)
163165
.args([
164166
"-d",
@@ -172,9 +174,9 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
172174

173175
match result {
174176
Err(e) => {
175-
self.sess.fatal(&format!("Error calling dlltool: {}", e));
177+
sess.fatal(&format!("Error calling dlltool: {}", e));
176178
}
177-
Ok(output) if !output.status.success() => self.sess.fatal(&format!(
179+
Ok(output) if !output.status.success() => sess.fatal(&format!(
178180
"Dlltool could not create import library: {}\n{}",
179181
String::from_utf8_lossy(&output.stdout),
180182
String::from_utf8_lossy(&output.stderr)
@@ -220,27 +222,21 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
220222
output_path_z.as_ptr(),
221223
ffi_exports.as_ptr(),
222224
ffi_exports.len(),
223-
llvm_machine_type(&self.sess.target.arch) as u16,
224-
!self.sess.target.is_like_msvc,
225+
llvm_machine_type(&sess.target.arch) as u16,
226+
!sess.target.is_like_msvc,
225227
)
226228
};
227229

228230
if result == crate::llvm::LLVMRustResult::Failure {
229-
self.sess.fatal(&format!(
231+
sess.fatal(&format!(
230232
"Error creating import library for {}: {}",
231233
lib_name,
232234
llvm::last_error().unwrap_or("unknown LLVM error".to_string())
233235
));
234236
}
235237
};
236238

237-
self.add_archive(&output_path, |_| false).unwrap_or_else(|e| {
238-
self.sess.fatal(&format!(
239-
"failed to add native library {}: {}",
240-
output_path.display(),
241-
e
242-
));
243-
});
239+
output_path
244240
}
245241
}
246242

Diff for: compiler/rustc_codegen_ssa/src/back/archive.rs

+28-1
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,37 @@ pub trait ArchiveBuilder<'a> {
5151

5252
fn build(self) -> bool;
5353

54+
fn sess(&self) -> &Session;
55+
56+
/// Creates a DLL Import Library <https://docs.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-creation#creating-an-import-library>.
57+
/// and returns the path on disk to that import library.
58+
/// This functions doesn't take `self` so that it can be called from
59+
/// `linker_with_args`, which is specialized on `ArchiveBuilder` but
60+
/// doesn't take or create an instance of that type.
61+
fn create_dll_import_lib(
62+
sess: &Session,
63+
lib_name: &str,
64+
dll_imports: &[DllImport],
65+
tmpdir: &Path,
66+
) -> PathBuf;
67+
68+
/// Creates a DLL Import Library <https://docs.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-creation#creating-an-import-library>
69+
/// and adds it to the current compilation's set of archives.
5470
fn inject_dll_import_lib(
5571
&mut self,
5672
lib_name: &str,
5773
dll_imports: &[DllImport],
5874
tmpdir: &MaybeTempDir,
59-
);
75+
) {
76+
let output_path =
77+
Self::create_dll_import_lib(self.sess(), lib_name, dll_imports, tmpdir.as_ref());
78+
79+
self.add_archive(&output_path, |_| false).unwrap_or_else(|e| {
80+
self.sess().fatal(&format!(
81+
"failed to add native library {}: {}",
82+
output_path.display(),
83+
e
84+
));
85+
});
86+
}
6087
}

Diff for: compiler/rustc_codegen_ssa/src/back/link.rs

+20-7
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(
120120
&out_filename,
121121
codegen_results,
122122
path.as_ref(),
123-
);
123+
)?;
124124
}
125125
}
126126
if sess.opts.json_artifact_notifications {
@@ -650,7 +650,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
650650
out_filename: &Path,
651651
codegen_results: &CodegenResults,
652652
tmpdir: &Path,
653-
) {
653+
) -> Result<(), ErrorGuaranteed> {
654654
info!("preparing {:?} to {:?}", crate_type, out_filename);
655655
let (linker_path, flavor) = linker_and_flavor(sess);
656656
let mut cmd = linker_with_args::<B>(
@@ -661,7 +661,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
661661
tmpdir,
662662
out_filename,
663663
codegen_results,
664-
);
664+
)?;
665665

666666
linker::disable_localization(&mut cmd);
667667

@@ -1000,6 +1000,8 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
10001000
(Strip::None, _) => {}
10011001
}
10021002
}
1003+
1004+
Ok(())
10031005
}
10041006

10051007
// Temporarily support both -Z strip and -C strip
@@ -1848,7 +1850,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
18481850
tmpdir: &Path,
18491851
out_filename: &Path,
18501852
codegen_results: &CodegenResults,
1851-
) -> Command {
1853+
) -> Result<Command, ErrorGuaranteed> {
18521854
let crt_objects_fallback = crt_objects_fallback(sess, crate_type);
18531855
let cmd = &mut *super::linker::get_linker(
18541856
sess,
@@ -1955,6 +1957,18 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
19551957
add_upstream_native_libraries(cmd, sess, codegen_results);
19561958
}
19571959

1960+
// Link with the import library generated for any raw-dylib functions.
1961+
for (raw_dylib_name, raw_dylib_imports) in
1962+
collate_raw_dylibs(sess, &codegen_results.crate_info.used_libraries)?
1963+
{
1964+
cmd.add_object(&B::create_dll_import_lib(
1965+
sess,
1966+
&raw_dylib_name,
1967+
&raw_dylib_imports,
1968+
tmpdir,
1969+
));
1970+
}
1971+
19581972
// Library linking above uses some global state for things like `-Bstatic`/`-Bdynamic` to make
19591973
// command line shorter, reset it to default here before adding more libraries.
19601974
cmd.reset_per_library_state();
@@ -1998,7 +2012,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
19982012
// to it and remove the option.
19992013
add_post_link_args(cmd, sess, flavor);
20002014

2001-
cmd.take_cmd()
2015+
Ok(cmd.take_cmd())
20022016
}
20032017

20042018
fn add_order_independent_options(
@@ -2227,8 +2241,7 @@ fn add_local_native_libraries(
22272241
}
22282242
}
22292243
NativeLibKind::RawDylib => {
2230-
// FIXME(#58713): Proper handling for raw dylibs.
2231-
bug!("raw_dylib feature not yet implemented");
2244+
// Ignore RawDylib here, they are handled separately in linker_with_args().
22322245
}
22332246
}
22342247
}

Diff for: src/test/run-make-fulldeps/tools.mk

+1-1
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ NATIVE_STATICLIB = $(TMPDIR)/$(call NATIVE_STATICLIB_FILE,$(1))
9090
OUT_EXE=-Fe:`cygpath -w $(TMPDIR)/$(call BIN,$(1))` \
9191
-Fo:`cygpath -w $(TMPDIR)/$(1).obj`
9292
else
93-
COMPILE_OBJ = $(CC) -c -o $(1) $(2)
93+
COMPILE_OBJ = $(CC) -v -c -o $(1) $(2)
9494
COMPILE_OBJ_CXX = $(CXX) -c -o $(1) $(2)
9595
NATIVE_STATICLIB_FILE = lib$(1).a
9696
NATIVE_STATICLIB = $(call STATICLIB,$(1))

Diff for: src/test/run-make/raw-dylib-alt-calling-convention/Makefile

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@
66
-include ../../run-make-fulldeps/tools.mk
77

88
all:
9+
$(RUSTC) --crate-type lib --crate-name raw_dylib_alt_calling_convention_test lib.rs
10+
$(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
911
$(call COMPILE_OBJ,"$(TMPDIR)"/extern.obj,extern.c)
1012
ifdef IS_MSVC
11-
$(CC) "$(TMPDIR)"/extern.obj -link -dll -out:"$(TMPDIR)"/extern.dll
13+
$(CC) "$(TMPDIR)"/extern.obj -link -dll -out:"$(TMPDIR)"/extern.dll -noimplib
1214
else
1315
$(CC) "$(TMPDIR)"/extern.obj -shared -o "$(TMPDIR)"/extern.dll
1416
endif
15-
$(RUSTC) --crate-type lib --crate-name raw_dylib_alt_calling_convention_test lib.rs
16-
$(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
1717
"$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt
1818

1919
ifdef RUSTC_BLESS_TEST

Diff for: src/test/run-make/raw-dylib-c/Makefile

+7-4
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,24 @@
55
-include ../../run-make-fulldeps/tools.mk
66

77
all:
8+
$(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs
9+
$(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
10+
$(RUSTC) --crate-type bin --crate-name raw_dylib_test_bin lib.rs
811
$(call COMPILE_OBJ,"$(TMPDIR)"/extern_1.obj,extern_1.c)
912
$(call COMPILE_OBJ,"$(TMPDIR)"/extern_2.obj,extern_2.c)
1013
ifdef IS_MSVC
11-
$(CC) "$(TMPDIR)"/extern_1.obj -link -dll -out:"$(TMPDIR)"/extern_1.dll
12-
$(CC) "$(TMPDIR)"/extern_2.obj -link -dll -out:"$(TMPDIR)"/extern_2.dll
14+
$(CC) "$(TMPDIR)"/extern_1.obj -link -dll -out:"$(TMPDIR)"/extern_1.dll -noimplib
15+
$(CC) "$(TMPDIR)"/extern_2.obj -link -dll -out:"$(TMPDIR)"/extern_2.dll -noimplib
1316
else
1417
$(CC) "$(TMPDIR)"/extern_1.obj -shared -o "$(TMPDIR)"/extern_1.dll
1518
$(CC) "$(TMPDIR)"/extern_2.obj -shared -o "$(TMPDIR)"/extern_2.dll
1619
endif
17-
$(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs
18-
$(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
1920
"$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt
21+
"$(TMPDIR)"/raw_dylib_test_bin > "$(TMPDIR)"/output_bin.txt
2022

2123
ifdef RUSTC_BLESS_TEST
2224
cp "$(TMPDIR)"/output.txt output.txt
2325
else
2426
$(DIFF) output.txt "$(TMPDIR)"/output.txt
27+
$(DIFF) output.txt "$(TMPDIR)"/output_bin.txt
2528
endif

Diff for: src/test/run-make/raw-dylib-c/lib.rs

+4
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,7 @@ pub fn library_function() {
2020
extern_fn_3();
2121
}
2222
}
23+
24+
fn main() {
25+
library_function();
26+
}

Diff for: src/test/run-make/raw-dylib-link-ordinal/Makefile

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@
55
-include ../../run-make-fulldeps/tools.mk
66

77
all:
8+
$(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs
9+
$(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
810
$(call COMPILE_OBJ,"$(TMPDIR)"/exporter.obj,exporter.c)
911
ifdef IS_MSVC
10-
$(CC) "$(TMPDIR)"/exporter.obj exporter.def -link -dll -out:"$(TMPDIR)"/exporter.dll
12+
$(CC) "$(TMPDIR)"/exporter.obj exporter.def -link -dll -out:"$(TMPDIR)"/exporter.dll -noimplib
1113
else
1214
$(CC) "$(TMPDIR)"/exporter.obj exporter.def -shared -o "$(TMPDIR)"/exporter.dll
1315
endif
14-
$(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs
15-
$(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
1616
"$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt
1717

1818
ifdef RUSTC_BLESS_TEST

Diff for: src/test/run-make/raw-dylib-stdcall-ordinal/Makefile

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@
66
-include ../../run-make-fulldeps/tools.mk
77

88
all:
9+
$(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs
10+
$(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
911
$(call COMPILE_OBJ,"$(TMPDIR)"/exporter.obj,exporter.c)
1012
ifdef IS_MSVC
11-
$(CC) "$(TMPDIR)"/exporter.obj exporter-msvc.def -link -dll -out:"$(TMPDIR)"/exporter.dll
13+
$(CC) "$(TMPDIR)"/exporter.obj exporter-msvc.def -link -dll -out:"$(TMPDIR)"/exporter.dll -noimplib
1214
else
1315
$(CC) "$(TMPDIR)"/exporter.obj exporter-gnu.def -shared -o "$(TMPDIR)"/exporter.dll
1416
endif
15-
$(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs
16-
$(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
1717
"$(TMPDIR)"/driver > "$(TMPDIR)"/actual_output.txt
1818

1919
ifdef RUSTC_BLESS_TEST

0 commit comments

Comments
 (0)