Support raw-dylib functions being used inside inlined functions
This commit is contained in:
parent
758f19645b
commit
3a1ef50b34
12 changed files with 146 additions and 7 deletions
|
@ -38,6 +38,7 @@ impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
|
||||||
_lib_name: &str,
|
_lib_name: &str,
|
||||||
_dll_imports: &[rustc_session::cstore::DllImport],
|
_dll_imports: &[rustc_session::cstore::DllImport],
|
||||||
_tmpdir: &Path,
|
_tmpdir: &Path,
|
||||||
|
_is_direct_dependency: bool,
|
||||||
) -> PathBuf {
|
) -> PathBuf {
|
||||||
bug!("creating dll imports is not supported");
|
bug!("creating dll imports is not supported");
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,7 @@ impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
|
||||||
_lib_name: &str,
|
_lib_name: &str,
|
||||||
_dll_imports: &[DllImport],
|
_dll_imports: &[DllImport],
|
||||||
_tmpdir: &Path,
|
_tmpdir: &Path,
|
||||||
|
_is_direct_dependency: bool,
|
||||||
) -> PathBuf {
|
) -> PathBuf {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
|
@ -165,10 +165,12 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
|
||||||
lib_name: &str,
|
lib_name: &str,
|
||||||
dll_imports: &[DllImport],
|
dll_imports: &[DllImport],
|
||||||
tmpdir: &Path,
|
tmpdir: &Path,
|
||||||
|
is_direct_dependency: bool,
|
||||||
) -> PathBuf {
|
) -> PathBuf {
|
||||||
|
let name_suffix = if is_direct_dependency { "_imports" } else { "_imports_indirect" };
|
||||||
let output_path = {
|
let output_path = {
|
||||||
let mut output_path: PathBuf = tmpdir.to_path_buf();
|
let mut output_path: PathBuf = tmpdir.to_path_buf();
|
||||||
output_path.push(format!("{}_imports", lib_name));
|
output_path.push(format!("{}{}", lib_name, name_suffix));
|
||||||
output_path.with_extension("lib")
|
output_path.with_extension("lib")
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -195,7 +197,8 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
|
||||||
// that loaded but crashed with an AV upon calling one of the imported
|
// that loaded but crashed with an AV upon calling one of the imported
|
||||||
// functions. Therefore, use binutils to create the import library instead,
|
// functions. Therefore, use binutils to create the import library instead,
|
||||||
// by writing a .DEF file to the temp dir and calling binutils's dlltool.
|
// by writing a .DEF file to the temp dir and calling binutils's dlltool.
|
||||||
let def_file_path = tmpdir.join(format!("{}_imports", lib_name)).with_extension("def");
|
let def_file_path =
|
||||||
|
tmpdir.join(format!("{}{}", lib_name, name_suffix)).with_extension("def");
|
||||||
|
|
||||||
let def_file_content = format!(
|
let def_file_content = format!(
|
||||||
"EXPORTS\n{}",
|
"EXPORTS\n{}",
|
||||||
|
|
|
@ -25,6 +25,7 @@ pub trait ArchiveBuilderBuilder {
|
||||||
lib_name: &str,
|
lib_name: &str,
|
||||||
dll_imports: &[DllImport],
|
dll_imports: &[DllImport],
|
||||||
tmpdir: &Path,
|
tmpdir: &Path,
|
||||||
|
is_direct_dependency: bool,
|
||||||
) -> PathBuf;
|
) -> PathBuf;
|
||||||
|
|
||||||
fn extract_bundled_libs(
|
fn extract_bundled_libs(
|
||||||
|
|
|
@ -391,13 +391,14 @@ fn link_rlib<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
for (raw_dylib_name, raw_dylib_imports) in
|
for (raw_dylib_name, raw_dylib_imports) in
|
||||||
collate_raw_dylibs(sess, &codegen_results.crate_info.used_libraries)?
|
collate_raw_dylibs(sess, codegen_results.crate_info.used_libraries.iter())?
|
||||||
{
|
{
|
||||||
let output_path = archive_builder_builder.create_dll_import_lib(
|
let output_path = archive_builder_builder.create_dll_import_lib(
|
||||||
sess,
|
sess,
|
||||||
&raw_dylib_name,
|
&raw_dylib_name,
|
||||||
&raw_dylib_imports,
|
&raw_dylib_imports,
|
||||||
tmpdir.as_ref(),
|
tmpdir.as_ref(),
|
||||||
|
true,
|
||||||
);
|
);
|
||||||
|
|
||||||
ab.add_archive(&output_path, Box::new(|_| false)).unwrap_or_else(|error| {
|
ab.add_archive(&output_path, Box::new(|_| false)).unwrap_or_else(|error| {
|
||||||
|
@ -449,9 +450,9 @@ fn link_rlib<'a>(
|
||||||
/// then the CodegenResults value contains one NativeLib instance for each block. However, the
|
/// 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
|
/// 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.
|
/// collate the symbols together by library name before generating the import libraries.
|
||||||
fn collate_raw_dylibs(
|
fn collate_raw_dylibs<'a, 'b>(
|
||||||
sess: &Session,
|
sess: &'a Session,
|
||||||
used_libraries: &[NativeLib],
|
used_libraries: impl IntoIterator<Item = &'b NativeLib>,
|
||||||
) -> Result<Vec<(String, Vec<DllImport>)>, ErrorGuaranteed> {
|
) -> Result<Vec<(String, Vec<DllImport>)>, ErrorGuaranteed> {
|
||||||
// Use index maps to preserve original order of imports and libraries.
|
// Use index maps to preserve original order of imports and libraries.
|
||||||
let mut dylib_table = FxIndexMap::<String, FxIndexMap<Symbol, &DllImport>>::default();
|
let mut dylib_table = FxIndexMap::<String, FxIndexMap<Symbol, &DllImport>>::default();
|
||||||
|
@ -2068,13 +2069,43 @@ fn linker_with_args<'a>(
|
||||||
|
|
||||||
// Link with the import library generated for any raw-dylib functions.
|
// Link with the import library generated for any raw-dylib functions.
|
||||||
for (raw_dylib_name, raw_dylib_imports) in
|
for (raw_dylib_name, raw_dylib_imports) in
|
||||||
collate_raw_dylibs(sess, &codegen_results.crate_info.used_libraries)?
|
collate_raw_dylibs(sess, codegen_results.crate_info.used_libraries.iter())?
|
||||||
{
|
{
|
||||||
cmd.add_object(&archive_builder_builder.create_dll_import_lib(
|
cmd.add_object(&archive_builder_builder.create_dll_import_lib(
|
||||||
sess,
|
sess,
|
||||||
&raw_dylib_name,
|
&raw_dylib_name,
|
||||||
&raw_dylib_imports,
|
&raw_dylib_imports,
|
||||||
tmpdir,
|
tmpdir,
|
||||||
|
true,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
// As with add_upstream_native_libraries, we need to add the upstream raw-dylib symbols in case
|
||||||
|
// they are used within inlined functions or instantiated generic functions. We do this *after*
|
||||||
|
// handling the raw-dylib symbols in the current crate to make sure that those are chosen first
|
||||||
|
// by the linker.
|
||||||
|
let (_, dependency_linkage) = codegen_results
|
||||||
|
.crate_info
|
||||||
|
.dependency_formats
|
||||||
|
.iter()
|
||||||
|
.find(|(ty, _)| *ty == crate_type)
|
||||||
|
.expect("failed to find crate type in dependency format list");
|
||||||
|
let native_libraries_from_nonstatics = codegen_results
|
||||||
|
.crate_info
|
||||||
|
.native_libraries
|
||||||
|
.iter()
|
||||||
|
.filter_map(|(cnum, libraries)| {
|
||||||
|
(dependency_linkage[cnum.as_usize() - 1] != Linkage::Static).then(|| libraries)
|
||||||
|
})
|
||||||
|
.flatten();
|
||||||
|
for (raw_dylib_name, raw_dylib_imports) in
|
||||||
|
collate_raw_dylibs(sess, native_libraries_from_nonstatics)?
|
||||||
|
{
|
||||||
|
cmd.add_object(&archive_builder_builder.create_dll_import_lib(
|
||||||
|
sess,
|
||||||
|
&raw_dylib_name,
|
||||||
|
&raw_dylib_imports,
|
||||||
|
tmpdir,
|
||||||
|
false,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
31
src/test/run-make/raw-dylib-inline-cross-dylib/Makefile
Normal file
31
src/test/run-make/raw-dylib-inline-cross-dylib/Makefile
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
# Regression test for calling an inline function that uses a raw-dylib function.
|
||||||
|
|
||||||
|
# only-windows
|
||||||
|
|
||||||
|
include ../../run-make-fulldeps/tools.mk
|
||||||
|
|
||||||
|
all:
|
||||||
|
$(RUSTC) --crate-type dylib --crate-name raw_dylib_test lib.rs -C prefer-dynamic
|
||||||
|
$(RUSTC) --crate-type dylib --crate-name raw_dylib_test_wrapper lib_wrapper.rs -C prefer-dynamic
|
||||||
|
$(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)" -C prefer-dynamic
|
||||||
|
# Make sure we don't find an import to the functions we expect to be inlined.
|
||||||
|
"$(LLVM_BIN_DIR)"/llvm-objdump -p $(TMPDIR)/driver.exe | $(CGREP) -v -e "inline_library_function"
|
||||||
|
"$(LLVM_BIN_DIR)"/llvm-objdump -p $(TMPDIR)/driver.exe | $(CGREP) -v -e "inline_library_function_calls_inline"
|
||||||
|
# Make sure we do find an import to the functions we expect to be imported.
|
||||||
|
"$(LLVM_BIN_DIR)"/llvm-objdump -p $(TMPDIR)/driver.exe | $(CGREP) -e "library_function"
|
||||||
|
$(call COMPILE_OBJ,"$(TMPDIR)"/extern_1.obj,extern_1.c)
|
||||||
|
$(call COMPILE_OBJ,"$(TMPDIR)"/extern_2.obj,extern_2.c)
|
||||||
|
ifdef IS_MSVC
|
||||||
|
$(CC) "$(TMPDIR)"/extern_1.obj -link -dll -out:"$(TMPDIR)"/extern_1.dll -noimplib
|
||||||
|
$(CC) "$(TMPDIR)"/extern_2.obj -link -dll -out:"$(TMPDIR)"/extern_2.dll -noimplib
|
||||||
|
else
|
||||||
|
$(CC) "$(TMPDIR)"/extern_1.obj -shared -o "$(TMPDIR)"/extern_1.dll
|
||||||
|
$(CC) "$(TMPDIR)"/extern_2.obj -shared -o "$(TMPDIR)"/extern_2.dll
|
||||||
|
endif
|
||||||
|
$(call RUN,driver) > "$(TMPDIR)"/output.txt
|
||||||
|
|
||||||
|
ifdef RUSTC_BLESS_TEST
|
||||||
|
cp "$(TMPDIR)"/output.txt output.txt
|
||||||
|
else
|
||||||
|
$(DIFF) output.txt "$(TMPDIR)"/output.txt
|
||||||
|
endif
|
21
src/test/run-make/raw-dylib-inline-cross-dylib/driver.rs
Normal file
21
src/test/run-make/raw-dylib-inline-cross-dylib/driver.rs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#![feature(raw_dylib)]
|
||||||
|
|
||||||
|
extern crate raw_dylib_test;
|
||||||
|
extern crate raw_dylib_test_wrapper;
|
||||||
|
|
||||||
|
#[link(name = "extern_2", kind = "raw-dylib")]
|
||||||
|
extern {
|
||||||
|
fn extern_fn_2();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// NOTE: The inlined call to `extern_fn_2` links against the function in extern_2.dll instead
|
||||||
|
// of extern_1.dll since raw-dylib symbols from the current crate are passed to the linker
|
||||||
|
// first, so any ambiguous names will prefer the current crate's definition.
|
||||||
|
raw_dylib_test::inline_library_function();
|
||||||
|
raw_dylib_test::library_function();
|
||||||
|
raw_dylib_test_wrapper::inline_library_function_calls_inline();
|
||||||
|
unsafe {
|
||||||
|
extern_fn_2();
|
||||||
|
}
|
||||||
|
}
|
11
src/test/run-make/raw-dylib-inline-cross-dylib/extern_1.c
Normal file
11
src/test/run-make/raw-dylib-inline-cross-dylib/extern_1.c
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#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 in extern_1\n");
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
__declspec(dllexport) void extern_fn_2() {
|
||||||
|
printf("extern_fn_2 in extern_2\n");
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
21
src/test/run-make/raw-dylib-inline-cross-dylib/lib.rs
Normal file
21
src/test/run-make/raw-dylib-inline-cross-dylib/lib.rs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#![feature(raw_dylib)]
|
||||||
|
|
||||||
|
#[link(name = "extern_1", kind = "raw-dylib")]
|
||||||
|
extern {
|
||||||
|
fn extern_fn_1();
|
||||||
|
fn extern_fn_2();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn inline_library_function() {
|
||||||
|
unsafe {
|
||||||
|
extern_fn_1();
|
||||||
|
extern_fn_2();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn library_function() {
|
||||||
|
unsafe {
|
||||||
|
extern_fn_2();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
extern crate raw_dylib_test;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn inline_library_function_calls_inline() {
|
||||||
|
raw_dylib_test::inline_library_function();
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
extern_fn_1
|
||||||
|
extern_fn_2 in extern_2
|
||||||
|
extern_fn_2 in extern_1
|
||||||
|
extern_fn_1
|
||||||
|
extern_fn_2 in extern_2
|
||||||
|
extern_fn_2 in extern_2
|
Loading…
Add table
Add a link
Reference in a new issue