Always use ar_archive_writer for import libs
This commit is contained in:
parent
27b93da8de
commit
0156eb57a1
10 changed files with 100 additions and 190 deletions
|
@ -205,9 +205,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ar_archive_writer"
|
name = "ar_archive_writer"
|
||||||
version = "0.3.3"
|
version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3f2bcb7cf51decfbbfc7ef476e28b0775b13e5eb1190f8b7df145cd53d4f4374"
|
checksum = "de11a9d32db3327f981143bdf699ade4d637c6887b13b97e6e91a9154666963c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"object 0.36.2",
|
"object 0.36.2",
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,13 +1,6 @@
|
||||||
use std::borrow::Borrow;
|
|
||||||
use std::fs;
|
|
||||||
use std::path::Path;
|
|
||||||
|
|
||||||
use ar_archive_writer::{COFFShortExport, MachineTypes};
|
|
||||||
use rustc_codegen_ssa::back::archive::{
|
use rustc_codegen_ssa::back::archive::{
|
||||||
create_mingw_dll_import_lib, ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder,
|
ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER,
|
||||||
DEFAULT_OBJECT_READER,
|
|
||||||
};
|
};
|
||||||
use rustc_codegen_ssa::common::is_mingw_gnu_toolchain;
|
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
|
|
||||||
pub(crate) struct ArArchiveBuilderBuilder;
|
pub(crate) struct ArArchiveBuilderBuilder;
|
||||||
|
@ -16,78 +9,4 @@ impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
|
||||||
fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a> {
|
fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a> {
|
||||||
Box::new(ArArchiveBuilder::new(sess, &DEFAULT_OBJECT_READER))
|
Box::new(ArArchiveBuilder::new(sess, &DEFAULT_OBJECT_READER))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_dll_import_lib(
|
|
||||||
&self,
|
|
||||||
sess: &Session,
|
|
||||||
lib_name: &str,
|
|
||||||
import_name_and_ordinal_vector: Vec<(String, Option<u16>)>,
|
|
||||||
output_path: &Path,
|
|
||||||
) {
|
|
||||||
if is_mingw_gnu_toolchain(&sess.target) {
|
|
||||||
// The binutils linker used on -windows-gnu targets cannot read the import
|
|
||||||
// libraries generated by LLVM: in our attempts, the linker produced an .EXE
|
|
||||||
// that loaded but crashed with an AV upon calling one of the imported
|
|
||||||
// functions. Therefore, use binutils to create the import library instead,
|
|
||||||
// by writing a .DEF file to the temp dir and calling binutils's dlltool.
|
|
||||||
create_mingw_dll_import_lib(
|
|
||||||
sess,
|
|
||||||
lib_name,
|
|
||||||
import_name_and_ordinal_vector,
|
|
||||||
output_path,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
let mut file =
|
|
||||||
match fs::OpenOptions::new().write(true).create_new(true).open(&output_path) {
|
|
||||||
Ok(file) => file,
|
|
||||||
Err(error) => {
|
|
||||||
sess.dcx().fatal(format!(
|
|
||||||
"failed to create import library file `{path}`: {error}",
|
|
||||||
path = output_path.display(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let machine = match sess.target.arch.borrow() {
|
|
||||||
"x86" => MachineTypes::I386,
|
|
||||||
"x86_64" => MachineTypes::AMD64,
|
|
||||||
"arm" => MachineTypes::ARMNT,
|
|
||||||
"aarch64" => MachineTypes::ARM64,
|
|
||||||
_ => {
|
|
||||||
sess.dcx().fatal(format!(
|
|
||||||
"unsupported target architecture `{arch}`",
|
|
||||||
arch = sess.target.arch,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let exports = import_name_and_ordinal_vector
|
|
||||||
.iter()
|
|
||||||
.map(|(name, ordinal)| COFFShortExport {
|
|
||||||
name: name.to_string(),
|
|
||||||
ext_name: None,
|
|
||||||
symbol_name: None,
|
|
||||||
alias_target: None,
|
|
||||||
ordinal: ordinal.unwrap_or(0),
|
|
||||||
noname: ordinal.is_some(),
|
|
||||||
data: false,
|
|
||||||
private: false,
|
|
||||||
constant: false,
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
if let Err(error) = ar_archive_writer::write_import_library(
|
|
||||||
&mut file,
|
|
||||||
lib_name,
|
|
||||||
&exports,
|
|
||||||
machine,
|
|
||||||
!sess.target.is_like_msvc,
|
|
||||||
) {
|
|
||||||
sess.dcx().fatal(format!(
|
|
||||||
"failed to create import library `{path}`: `{error}`",
|
|
||||||
path = output_path.display(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
#![warn(unused_lifetimes)]
|
#![warn(unused_lifetimes)]
|
||||||
// tidy-alphabetical-end
|
// tidy-alphabetical-end
|
||||||
|
|
||||||
extern crate ar_archive_writer;
|
|
||||||
extern crate jobserver;
|
extern crate jobserver;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate rustc_middle;
|
extern crate rustc_middle;
|
||||||
|
|
|
@ -5,9 +5,6 @@ codegen_llvm_dynamic_linking_with_lto =
|
||||||
.note = only 'staticlib', 'bin', and 'cdylib' outputs are supported with LTO
|
.note = only 'staticlib', 'bin', and 'cdylib' outputs are supported with LTO
|
||||||
|
|
||||||
|
|
||||||
codegen_llvm_error_creating_import_library =
|
|
||||||
Error creating import library for {$lib_name}: {$error}
|
|
||||||
|
|
||||||
codegen_llvm_fixed_x18_invalid_arch = the `-Zfixed-x18` flag is not supported on the `{$arch}` architecture
|
codegen_llvm_fixed_x18_invalid_arch = the `-Zfixed-x18` flag is not supported on the `{$arch}` architecture
|
||||||
|
|
||||||
codegen_llvm_from_llvm_diag = {$message}
|
codegen_llvm_from_llvm_diag = {$message}
|
||||||
|
|
|
@ -5,17 +5,13 @@ use std::path::{Path, PathBuf};
|
||||||
use std::{io, mem, ptr, str};
|
use std::{io, mem, ptr, str};
|
||||||
|
|
||||||
use rustc_codegen_ssa::back::archive::{
|
use rustc_codegen_ssa::back::archive::{
|
||||||
create_mingw_dll_import_lib, try_extract_macho_fat_archive, ArArchiveBuilder,
|
try_extract_macho_fat_archive, ArArchiveBuilder, ArchiveBuildFailure, ArchiveBuilder,
|
||||||
ArchiveBuildFailure, ArchiveBuilder, ArchiveBuilderBuilder, ObjectReader, UnknownArchiveKind,
|
ArchiveBuilderBuilder, ObjectReader, UnknownArchiveKind, DEFAULT_OBJECT_READER,
|
||||||
DEFAULT_OBJECT_READER,
|
|
||||||
};
|
};
|
||||||
use rustc_codegen_ssa::common;
|
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use tracing::trace;
|
|
||||||
|
|
||||||
use crate::errors::ErrorCreatingImportLibrary;
|
|
||||||
use crate::llvm::archive_ro::{ArchiveRO, Child};
|
use crate::llvm::archive_ro::{ArchiveRO, Child};
|
||||||
use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport};
|
use crate::llvm::{self, ArchiveKind};
|
||||||
|
|
||||||
/// Helper for adding many files to an archive.
|
/// Helper for adding many files to an archive.
|
||||||
#[must_use = "must call build() to finish building the archive"]
|
#[must_use = "must call build() to finish building the archive"]
|
||||||
|
@ -44,18 +40,6 @@ fn is_relevant_child(c: &Child<'_>) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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,
|
|
||||||
"arm64ec" => LLVMMachineType::ARM64EC,
|
|
||||||
"arm" => LLVMMachineType::ARM,
|
|
||||||
_ => panic!("unsupported cpu type {cpu}"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> ArchiveBuilder for LlvmArchiveBuilder<'a> {
|
impl<'a> ArchiveBuilder for LlvmArchiveBuilder<'a> {
|
||||||
fn add_archive(
|
fn add_archive(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -116,78 +100,6 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
|
||||||
Box::new(ArArchiveBuilder::new(sess, &LLVM_OBJECT_READER))
|
Box::new(ArArchiveBuilder::new(sess, &LLVM_OBJECT_READER))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_dll_import_lib(
|
|
||||||
&self,
|
|
||||||
sess: &Session,
|
|
||||||
lib_name: &str,
|
|
||||||
import_name_and_ordinal_vector: Vec<(String, Option<u16>)>,
|
|
||||||
output_path: &Path,
|
|
||||||
) {
|
|
||||||
if common::is_mingw_gnu_toolchain(&sess.target) {
|
|
||||||
// The binutils linker used on -windows-gnu targets cannot read the import
|
|
||||||
// libraries generated by LLVM: in our attempts, the linker produced an .EXE
|
|
||||||
// that loaded but crashed with an AV upon calling one of the imported
|
|
||||||
// functions. Therefore, use binutils to create the import library instead,
|
|
||||||
// by writing a .DEF file to the temp dir and calling binutils's dlltool.
|
|
||||||
create_mingw_dll_import_lib(
|
|
||||||
sess,
|
|
||||||
lib_name,
|
|
||||||
import_name_and_ordinal_vector,
|
|
||||||
output_path,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// we've checked for \0 characters in the library name already
|
|
||||||
let dll_name_z = CString::new(lib_name).unwrap();
|
|
||||||
|
|
||||||
let output_path_z = rustc_fs_util::path_to_c_string(&output_path);
|
|
||||||
|
|
||||||
trace!("invoking LLVMRustWriteImportLibrary");
|
|
||||||
trace!(" dll_name {:#?}", dll_name_z);
|
|
||||||
trace!(" output_path {}", output_path.display());
|
|
||||||
trace!(
|
|
||||||
" import names: {}",
|
|
||||||
import_name_and_ordinal_vector
|
|
||||||
.iter()
|
|
||||||
.map(|(name, _ordinal)| name.clone())
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join(", "),
|
|
||||||
);
|
|
||||||
|
|
||||||
// All import names are Rust identifiers and therefore cannot contain \0 characters.
|
|
||||||
// FIXME: when support for #[link_name] is implemented, ensure that the import names
|
|
||||||
// still don't contain any \0 characters. Also need to check that the names don't
|
|
||||||
// contain substrings like " @" or "NONAME" that are keywords or otherwise reserved
|
|
||||||
// in definition files.
|
|
||||||
let cstring_import_name_and_ordinal_vector: Vec<(CString, Option<u16>)> =
|
|
||||||
import_name_and_ordinal_vector
|
|
||||||
.into_iter()
|
|
||||||
.map(|(name, ordinal)| (CString::new(name).unwrap(), ordinal))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let ffi_exports: Vec<LLVMRustCOFFShortExport> = cstring_import_name_and_ordinal_vector
|
|
||||||
.iter()
|
|
||||||
.map(|(name_z, ordinal)| LLVMRustCOFFShortExport::new(name_z.as_ptr(), *ordinal))
|
|
||||||
.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(&sess.target.arch) as u16,
|
|
||||||
!sess.target.is_like_msvc,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
if result == crate::llvm::LLVMRustResult::Failure {
|
|
||||||
sess.dcx().emit_fatal(ErrorCreatingImportLibrary {
|
|
||||||
lib_name,
|
|
||||||
error: llvm::last_error().unwrap_or("unknown LLVM error".to_string()),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The object crate doesn't know how to get symbols for LLVM bitcode and COFF bigobj files.
|
// The object crate doesn't know how to get symbols for LLVM bitcode and COFF bigobj files.
|
||||||
|
|
|
@ -39,13 +39,6 @@ pub(crate) enum PossibleFeature<'a> {
|
||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
|
||||||
#[diag(codegen_llvm_error_creating_import_library)]
|
|
||||||
pub(crate) struct ErrorCreatingImportLibrary<'a> {
|
|
||||||
pub lib_name: &'a str,
|
|
||||||
pub error: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(codegen_llvm_symbol_already_defined)]
|
#[diag(codegen_llvm_symbol_already_defined)]
|
||||||
pub(crate) struct SymbolAlreadyDefined<'a> {
|
pub(crate) struct SymbolAlreadyDefined<'a> {
|
||||||
|
|
|
@ -5,7 +5,7 @@ edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# tidy-alphabetical-start
|
# tidy-alphabetical-start
|
||||||
ar_archive_writer = "0.3.3"
|
ar_archive_writer = "0.4.0"
|
||||||
arrayvec = { version = "0.7", default-features = false }
|
arrayvec = { version = "0.7", default-features = false }
|
||||||
bitflags = "2.4.1"
|
bitflags = "2.4.1"
|
||||||
cc = "1.0.90"
|
cc = "1.0.90"
|
||||||
|
|
|
@ -32,6 +32,9 @@ codegen_ssa_dlltool_fail_import_library =
|
||||||
codegen_ssa_error_calling_dlltool =
|
codegen_ssa_error_calling_dlltool =
|
||||||
Error calling dlltool '{$dlltool_path}': {$error}
|
Error calling dlltool '{$dlltool_path}': {$error}
|
||||||
|
|
||||||
|
codegen_ssa_error_creating_import_library =
|
||||||
|
Error creating import library for {$lib_name}: {$error}
|
||||||
|
|
||||||
codegen_ssa_error_creating_remark_dir = failed to create remark directory: {$error}
|
codegen_ssa_error_creating_remark_dir = failed to create remark directory: {$error}
|
||||||
|
|
||||||
codegen_ssa_error_writing_def_file =
|
codegen_ssa_error_writing_def_file =
|
||||||
|
|
|
@ -5,7 +5,9 @@ use std::fs::{self, File};
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use ar_archive_writer::{write_archive_to_stream, ArchiveKind, NewArchiveMember};
|
use ar_archive_writer::{
|
||||||
|
write_archive_to_stream, ArchiveKind, COFFShortExport, MachineTypes, NewArchiveMember,
|
||||||
|
};
|
||||||
pub use ar_archive_writer::{ObjectReader, DEFAULT_OBJECT_READER};
|
pub use ar_archive_writer::{ObjectReader, DEFAULT_OBJECT_READER};
|
||||||
use object::read::archive::ArchiveFile;
|
use object::read::archive::ArchiveFile;
|
||||||
use object::read::macho::FatArch;
|
use object::read::macho::FatArch;
|
||||||
|
@ -14,11 +16,15 @@ use rustc_data_structures::memmap::Mmap;
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use rustc_span::symbol::Symbol;
|
use rustc_span::symbol::Symbol;
|
||||||
use tempfile::Builder as TempFileBuilder;
|
use tempfile::Builder as TempFileBuilder;
|
||||||
|
use tracing::trace;
|
||||||
|
|
||||||
use super::metadata::search_for_section;
|
use super::metadata::search_for_section;
|
||||||
|
use crate::common;
|
||||||
// Re-exporting for rustc_codegen_llvm::back::archive
|
// Re-exporting for rustc_codegen_llvm::back::archive
|
||||||
pub use crate::errors::{ArchiveBuildFailure, ExtractBundledLibsError, UnknownArchiveKind};
|
pub use crate::errors::{ArchiveBuildFailure, ExtractBundledLibsError, UnknownArchiveKind};
|
||||||
use crate::errors::{DlltoolFailImportLibrary, ErrorCallingDllTool, ErrorWritingDEFFile};
|
use crate::errors::{
|
||||||
|
DlltoolFailImportLibrary, ErrorCallingDllTool, ErrorCreatingImportLibrary, ErrorWritingDEFFile,
|
||||||
|
};
|
||||||
|
|
||||||
pub trait ArchiveBuilderBuilder {
|
pub trait ArchiveBuilderBuilder {
|
||||||
fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a>;
|
fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a>;
|
||||||
|
@ -34,7 +40,81 @@ pub trait ArchiveBuilderBuilder {
|
||||||
lib_name: &str,
|
lib_name: &str,
|
||||||
import_name_and_ordinal_vector: Vec<(String, Option<u16>)>,
|
import_name_and_ordinal_vector: Vec<(String, Option<u16>)>,
|
||||||
output_path: &Path,
|
output_path: &Path,
|
||||||
);
|
) {
|
||||||
|
if common::is_mingw_gnu_toolchain(&sess.target) {
|
||||||
|
// The binutils linker used on -windows-gnu targets cannot read the import
|
||||||
|
// libraries generated by LLVM: in our attempts, the linker produced an .EXE
|
||||||
|
// that loaded but crashed with an AV upon calling one of the imported
|
||||||
|
// functions. Therefore, use binutils to create the import library instead,
|
||||||
|
// by writing a .DEF file to the temp dir and calling binutils's dlltool.
|
||||||
|
create_mingw_dll_import_lib(
|
||||||
|
sess,
|
||||||
|
lib_name,
|
||||||
|
import_name_and_ordinal_vector,
|
||||||
|
output_path,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
trace!("creating import library");
|
||||||
|
trace!(" dll_name {:#?}", lib_name);
|
||||||
|
trace!(" output_path {}", output_path.display());
|
||||||
|
trace!(
|
||||||
|
" import names: {}",
|
||||||
|
import_name_and_ordinal_vector
|
||||||
|
.iter()
|
||||||
|
.map(|(name, _ordinal)| name.clone())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(", "),
|
||||||
|
);
|
||||||
|
|
||||||
|
// All import names are Rust identifiers and therefore cannot contain \0 characters.
|
||||||
|
// FIXME: when support for #[link_name] is implemented, ensure that the import names
|
||||||
|
// still don't contain any \0 characters. Also need to check that the names don't
|
||||||
|
// contain substrings like " @" or "NONAME" that are keywords or otherwise reserved
|
||||||
|
// in definition files.
|
||||||
|
|
||||||
|
let mut file = match fs::File::create_new(&output_path) {
|
||||||
|
Ok(file) => file,
|
||||||
|
Err(error) => sess
|
||||||
|
.dcx()
|
||||||
|
.emit_fatal(ErrorCreatingImportLibrary { lib_name, error: error.to_string() }),
|
||||||
|
};
|
||||||
|
|
||||||
|
let exports = import_name_and_ordinal_vector
|
||||||
|
.iter()
|
||||||
|
.map(|(name, ordinal)| COFFShortExport {
|
||||||
|
name: name.to_string(),
|
||||||
|
ext_name: None,
|
||||||
|
symbol_name: None,
|
||||||
|
alias_target: None,
|
||||||
|
ordinal: ordinal.unwrap_or(0),
|
||||||
|
noname: ordinal.is_some(),
|
||||||
|
data: false,
|
||||||
|
private: false,
|
||||||
|
constant: false,
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let machine = match &*sess.target.arch {
|
||||||
|
"x86_64" => MachineTypes::AMD64,
|
||||||
|
"x86" => MachineTypes::I386,
|
||||||
|
"aarch64" => MachineTypes::ARM64,
|
||||||
|
"arm64ec" => MachineTypes::ARM64EC,
|
||||||
|
"arm" => MachineTypes::ARMNT,
|
||||||
|
cpu => panic!("unsupported cpu type {cpu}"),
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(error) = ar_archive_writer::write_import_library(
|
||||||
|
&mut file,
|
||||||
|
lib_name,
|
||||||
|
&exports,
|
||||||
|
machine,
|
||||||
|
!sess.target.is_like_msvc,
|
||||||
|
/*comdat=*/ false,
|
||||||
|
) {
|
||||||
|
sess.dcx()
|
||||||
|
.emit_fatal(ErrorCreatingImportLibrary { lib_name, error: error.to_string() });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn extract_bundled_libs<'a>(
|
fn extract_bundled_libs<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
|
|
|
@ -1060,3 +1060,10 @@ pub struct CompilerBuiltinsCannotCall {
|
||||||
pub caller: String,
|
pub caller: String,
|
||||||
pub callee: String,
|
pub callee: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(codegen_ssa_error_creating_import_library)]
|
||||||
|
pub(crate) struct ErrorCreatingImportLibrary<'a> {
|
||||||
|
pub lib_name: &'a str,
|
||||||
|
pub error: String,
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue