Skip to content

Commit 3a1ef50

Browse files
committed
Support raw-dylib functions being used inside inlined functions
1 parent 758f196 commit 3a1ef50

File tree

12 files changed

+146
-7
lines changed

12 files changed

+146
-7
lines changed

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

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
3838
_lib_name: &str,
3939
_dll_imports: &[rustc_session::cstore::DllImport],
4040
_tmpdir: &Path,
41+
_is_direct_dependency: bool,
4142
) -> PathBuf {
4243
bug!("creating dll imports is not supported");
4344
}

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

+1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
4747
_lib_name: &str,
4848
_dll_imports: &[DllImport],
4949
_tmpdir: &Path,
50+
_is_direct_dependency: bool,
5051
) -> PathBuf {
5152
unimplemented!();
5253
}

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

+5-2
Original file line numberDiff line numberDiff line change
@@ -165,10 +165,12 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
165165
lib_name: &str,
166166
dll_imports: &[DllImport],
167167
tmpdir: &Path,
168+
is_direct_dependency: bool,
168169
) -> PathBuf {
170+
let name_suffix = if is_direct_dependency { "_imports" } else { "_imports_indirect" };
169171
let output_path = {
170172
let mut output_path: PathBuf = tmpdir.to_path_buf();
171-
output_path.push(format!("{}_imports", lib_name));
173+
output_path.push(format!("{}{}", lib_name, name_suffix));
172174
output_path.with_extension("lib")
173175
};
174176

@@ -195,7 +197,8 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
195197
// that loaded but crashed with an AV upon calling one of the imported
196198
// functions. Therefore, use binutils to create the import library instead,
197199
// by writing a .DEF file to the temp dir and calling binutils's dlltool.
198-
let def_file_path = tmpdir.join(format!("{}_imports", lib_name)).with_extension("def");
200+
let def_file_path =
201+
tmpdir.join(format!("{}{}", lib_name, name_suffix)).with_extension("def");
199202

200203
let def_file_content = format!(
201204
"EXPORTS\n{}",

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

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ pub trait ArchiveBuilderBuilder {
2525
lib_name: &str,
2626
dll_imports: &[DllImport],
2727
tmpdir: &Path,
28+
is_direct_dependency: bool,
2829
) -> PathBuf;
2930

3031
fn extract_bundled_libs(

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

+36-5
Original file line numberDiff line numberDiff line change
@@ -391,13 +391,14 @@ fn link_rlib<'a>(
391391
}
392392

393393
for (raw_dylib_name, raw_dylib_imports) in
394-
collate_raw_dylibs(sess, &codegen_results.crate_info.used_libraries)?
394+
collate_raw_dylibs(sess, codegen_results.crate_info.used_libraries.iter())?
395395
{
396396
let output_path = archive_builder_builder.create_dll_import_lib(
397397
sess,
398398
&raw_dylib_name,
399399
&raw_dylib_imports,
400400
tmpdir.as_ref(),
401+
true,
401402
);
402403

403404
ab.add_archive(&output_path, Box::new(|_| false)).unwrap_or_else(|error| {
@@ -449,9 +450,9 @@ fn link_rlib<'a>(
449450
/// then the CodegenResults value contains one NativeLib instance for each block. However, the
450451
/// linker appears to expect only a single import library for each library used, so we need to
451452
/// collate the symbols together by library name before generating the import libraries.
452-
fn collate_raw_dylibs(
453-
sess: &Session,
454-
used_libraries: &[NativeLib],
453+
fn collate_raw_dylibs<'a, 'b>(
454+
sess: &'a Session,
455+
used_libraries: impl IntoIterator<Item = &'b NativeLib>,
455456
) -> Result<Vec<(String, Vec<DllImport>)>, ErrorGuaranteed> {
456457
// Use index maps to preserve original order of imports and libraries.
457458
let mut dylib_table = FxIndexMap::<String, FxIndexMap<Symbol, &DllImport>>::default();
@@ -2068,13 +2069,43 @@ fn linker_with_args<'a>(
20682069

20692070
// Link with the import library generated for any raw-dylib functions.
20702071
for (raw_dylib_name, raw_dylib_imports) in
2071-
collate_raw_dylibs(sess, &codegen_results.crate_info.used_libraries)?
2072+
collate_raw_dylibs(sess, codegen_results.crate_info.used_libraries.iter())?
2073+
{
2074+
cmd.add_object(&archive_builder_builder.create_dll_import_lib(
2075+
sess,
2076+
&raw_dylib_name,
2077+
&raw_dylib_imports,
2078+
tmpdir,
2079+
true,
2080+
));
2081+
}
2082+
// As with add_upstream_native_libraries, we need to add the upstream raw-dylib symbols in case
2083+
// they are used within inlined functions or instantiated generic functions. We do this *after*
2084+
// handling the raw-dylib symbols in the current crate to make sure that those are chosen first
2085+
// by the linker.
2086+
let (_, dependency_linkage) = codegen_results
2087+
.crate_info
2088+
.dependency_formats
2089+
.iter()
2090+
.find(|(ty, _)| *ty == crate_type)
2091+
.expect("failed to find crate type in dependency format list");
2092+
let native_libraries_from_nonstatics = codegen_results
2093+
.crate_info
2094+
.native_libraries
2095+
.iter()
2096+
.filter_map(|(cnum, libraries)| {
2097+
(dependency_linkage[cnum.as_usize() - 1] != Linkage::Static).then(|| libraries)
2098+
})
2099+
.flatten();
2100+
for (raw_dylib_name, raw_dylib_imports) in
2101+
collate_raw_dylibs(sess, native_libraries_from_nonstatics)?
20722102
{
20732103
cmd.add_object(&archive_builder_builder.create_dll_import_lib(
20742104
sess,
20752105
&raw_dylib_name,
20762106
&raw_dylib_imports,
20772107
tmpdir,
2108+
false,
20782109
));
20792110
}
20802111

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Regression test for calling an inline function that uses a raw-dylib function.
2+
3+
# only-windows
4+
5+
include ../../run-make-fulldeps/tools.mk
6+
7+
all:
8+
$(RUSTC) --crate-type dylib --crate-name raw_dylib_test lib.rs -C prefer-dynamic
9+
$(RUSTC) --crate-type dylib --crate-name raw_dylib_test_wrapper lib_wrapper.rs -C prefer-dynamic
10+
$(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)" -C prefer-dynamic
11+
# Make sure we don't find an import to the functions we expect to be inlined.
12+
"$(LLVM_BIN_DIR)"/llvm-objdump -p $(TMPDIR)/driver.exe | $(CGREP) -v -e "inline_library_function"
13+
"$(LLVM_BIN_DIR)"/llvm-objdump -p $(TMPDIR)/driver.exe | $(CGREP) -v -e "inline_library_function_calls_inline"
14+
# Make sure we do find an import to the functions we expect to be imported.
15+
"$(LLVM_BIN_DIR)"/llvm-objdump -p $(TMPDIR)/driver.exe | $(CGREP) -e "library_function"
16+
$(call COMPILE_OBJ,"$(TMPDIR)"/extern_1.obj,extern_1.c)
17+
$(call COMPILE_OBJ,"$(TMPDIR)"/extern_2.obj,extern_2.c)
18+
ifdef IS_MSVC
19+
$(CC) "$(TMPDIR)"/extern_1.obj -link -dll -out:"$(TMPDIR)"/extern_1.dll -noimplib
20+
$(CC) "$(TMPDIR)"/extern_2.obj -link -dll -out:"$(TMPDIR)"/extern_2.dll -noimplib
21+
else
22+
$(CC) "$(TMPDIR)"/extern_1.obj -shared -o "$(TMPDIR)"/extern_1.dll
23+
$(CC) "$(TMPDIR)"/extern_2.obj -shared -o "$(TMPDIR)"/extern_2.dll
24+
endif
25+
$(call RUN,driver) > "$(TMPDIR)"/output.txt
26+
27+
ifdef RUSTC_BLESS_TEST
28+
cp "$(TMPDIR)"/output.txt output.txt
29+
else
30+
$(DIFF) output.txt "$(TMPDIR)"/output.txt
31+
endif
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#![feature(raw_dylib)]
2+
3+
extern crate raw_dylib_test;
4+
extern crate raw_dylib_test_wrapper;
5+
6+
#[link(name = "extern_2", kind = "raw-dylib")]
7+
extern {
8+
fn extern_fn_2();
9+
}
10+
11+
fn main() {
12+
// NOTE: The inlined call to `extern_fn_2` links against the function in extern_2.dll instead
13+
// of extern_1.dll since raw-dylib symbols from the current crate are passed to the linker
14+
// first, so any ambiguous names will prefer the current crate's definition.
15+
raw_dylib_test::inline_library_function();
16+
raw_dylib_test::library_function();
17+
raw_dylib_test_wrapper::inline_library_function_calls_inline();
18+
unsafe {
19+
extern_fn_2();
20+
}
21+
}
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#include <stdio.h>
2+
3+
__declspec(dllexport) void extern_fn_1() {
4+
printf("extern_fn_1\n");
5+
fflush(stdout);
6+
}
7+
8+
__declspec(dllexport) void extern_fn_2() {
9+
printf("extern_fn_2 in extern_1\n");
10+
fflush(stdout);
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#include <stdio.h>
2+
3+
__declspec(dllexport) void extern_fn_2() {
4+
printf("extern_fn_2 in extern_2\n");
5+
fflush(stdout);
6+
}
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#![feature(raw_dylib)]
2+
3+
#[link(name = "extern_1", kind = "raw-dylib")]
4+
extern {
5+
fn extern_fn_1();
6+
fn extern_fn_2();
7+
}
8+
9+
#[inline]
10+
pub fn inline_library_function() {
11+
unsafe {
12+
extern_fn_1();
13+
extern_fn_2();
14+
}
15+
}
16+
17+
pub fn library_function() {
18+
unsafe {
19+
extern_fn_2();
20+
}
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
extern crate raw_dylib_test;
2+
3+
#[inline]
4+
pub fn inline_library_function_calls_inline() {
5+
raw_dylib_test::inline_library_function();
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
extern_fn_1
2+
extern_fn_2 in extern_2
3+
extern_fn_2 in extern_1
4+
extern_fn_1
5+
extern_fn_2 in extern_2
6+
extern_fn_2 in extern_2

0 commit comments

Comments
 (0)