1- use std:: env;
21use std:: error:: Error ;
3- use std:: ffi:: OsString ;
42use std:: fs:: { self , File } ;
53use std:: io:: { self , BufWriter , Write } ;
64use std:: path:: { Path , PathBuf } ;
@@ -23,13 +21,9 @@ use tracing::trace;
2321use super :: metadata:: { create_compressed_metadata_file, search_for_section} ;
2422use super :: rmeta_link;
2523use super :: symbol_edit:: apply_hide;
26- use crate :: common;
2724// Public for ArchiveBuilderBuilder::extract_bundled_libs
2825pub use crate :: errors:: ExtractBundledLibsError ;
29- use crate :: errors:: {
30- ArchiveBuildFailure , DlltoolFailImportLibrary , ErrorCallingDllTool , ErrorCreatingImportLibrary ,
31- ErrorWritingDEFFile , UnknownArchiveKind ,
32- } ;
26+ use crate :: errors:: { ArchiveBuildFailure , ErrorCreatingImportLibrary , UnknownArchiveKind } ;
3327
3428/// An item to be included in an import library.
3529/// This is a slimmed down version of `COFFShortExport` from `ar-archive-writer`.
@@ -86,66 +80,57 @@ pub trait ArchiveBuilderBuilder {
8680 items : Vec < ImportLibraryItem > ,
8781 output_path : & Path ,
8882 ) {
89- if common:: is_mingw_gnu_toolchain ( & sess. target ) {
90- // The binutils linker used on -windows-gnu targets cannot read the import
91- // libraries generated by LLVM: in our attempts, the linker produced an .EXE
92- // that loaded but crashed with an AV upon calling one of the imported
93- // functions. Therefore, use binutils to create the import library instead,
94- // by writing a .DEF file to the temp dir and calling binutils's dlltool.
95- create_mingw_dll_import_lib ( sess, lib_name, items, output_path) ;
96- } else {
97- trace ! ( "creating import library" ) ;
98- trace ! ( " dll_name {:#?}" , lib_name) ;
99- trace ! ( " output_path {}" , output_path. display( ) ) ;
100- trace ! (
101- " import names: {}" ,
102- items
103- . iter( )
104- . map( |ImportLibraryItem { name, .. } | name. clone( ) )
105- . collect:: <Vec <_>>( )
106- . join( ", " ) ,
107- ) ;
108-
109- // All import names are Rust identifiers and therefore cannot contain \0 characters.
110- // FIXME: when support for #[link_name] is implemented, ensure that the import names
111- // still don't contain any \0 characters. Also need to check that the names don't
112- // contain substrings like " @" or "NONAME" that are keywords or otherwise reserved
113- // in definition files.
114-
115- let mut file = match fs:: File :: create_new ( & output_path) {
116- Ok ( file) => file,
117- Err ( error) => sess
118- . dcx ( )
119- . emit_fatal ( ErrorCreatingImportLibrary { lib_name, error : error. to_string ( ) } ) ,
120- } ;
83+ trace ! ( "creating import library" ) ;
84+ trace ! ( " dll_name {:#?}" , lib_name) ;
85+ trace ! ( " output_path {}" , output_path. display( ) ) ;
86+ trace ! (
87+ " import names: {}" ,
88+ items
89+ . iter( )
90+ . map( |ImportLibraryItem { name, .. } | name. clone( ) )
91+ . collect:: <Vec <_>>( )
92+ . join( ", " ) ,
93+ ) ;
94+
95+ // All import names are Rust identifiers and therefore cannot contain \0 characters.
96+ // FIXME: when support for #[link_name] is implemented, ensure that the import names
97+ // still don't contain any \0 characters. Also need to check that the names don't
98+ // contain substrings like " @" or "NONAME" that are keywords or otherwise reserved
99+ // in definition files.
100+
101+ let mut file = match fs:: File :: create_new ( & output_path) {
102+ Ok ( file) => file,
103+ Err ( error) => sess
104+ . dcx ( )
105+ . emit_fatal ( ErrorCreatingImportLibrary { lib_name, error : error. to_string ( ) } ) ,
106+ } ;
121107
122- let exports =
123- items. into_iter ( ) . map ( |item| item. into_coff_short_export ( sess) ) . collect :: < Vec < _ > > ( ) ;
124- let machine = match & sess. target . arch {
125- Arch :: X86_64 => MachineTypes :: AMD64 ,
126- Arch :: X86 => MachineTypes :: I386 ,
127- Arch :: AArch64 => MachineTypes :: ARM64 ,
128- Arch :: Arm64EC => MachineTypes :: ARM64EC ,
129- Arch :: Arm => MachineTypes :: ARMNT ,
130- cpu => panic ! ( "unsupported cpu type {cpu}" ) ,
131- } ;
108+ let exports =
109+ items. into_iter ( ) . map ( |item| item. into_coff_short_export ( sess) ) . collect :: < Vec < _ > > ( ) ;
110+ let machine = match & sess. target . arch {
111+ Arch :: X86_64 => MachineTypes :: AMD64 ,
112+ Arch :: X86 => MachineTypes :: I386 ,
113+ Arch :: AArch64 => MachineTypes :: ARM64 ,
114+ Arch :: Arm64EC => MachineTypes :: ARM64EC ,
115+ Arch :: Arm => MachineTypes :: ARMNT ,
116+ cpu => panic ! ( "unsupported cpu type {cpu}" ) ,
117+ } ;
132118
133- if let Err ( error) = ar_archive_writer:: write_import_library (
134- & mut file,
135- lib_name,
136- & exports,
137- machine,
138- !sess. target . is_like_msvc ,
139- // Enable compatibility with MSVC's `/WHOLEARCHIVE` flag.
140- // Without this flag a duplicate symbol error would be emitted
141- // when linking a rust staticlib using `/WHOLEARCHIVE`.
142- // See #129020
143- true ,
144- & [ ] ,
145- ) {
146- sess. dcx ( )
147- . emit_fatal ( ErrorCreatingImportLibrary { lib_name, error : error. to_string ( ) } ) ;
148- }
119+ if let Err ( error) = ar_archive_writer:: write_import_library (
120+ & mut file,
121+ lib_name,
122+ & exports,
123+ machine,
124+ !sess. target . is_like_msvc ,
125+ // Enable compatibility with MSVC's `/WHOLEARCHIVE` flag.
126+ // Without this flag a duplicate symbol error would be emitted
127+ // when linking a rust staticlib using `/WHOLEARCHIVE`.
128+ // See #129020
129+ true ,
130+ & [ ] ,
131+ ) {
132+ sess. dcx ( )
133+ . emit_fatal ( ErrorCreatingImportLibrary { lib_name, error : error. to_string ( ) } ) ;
149134 }
150135 }
151136
@@ -186,129 +171,6 @@ pub trait ArchiveBuilderBuilder {
186171 }
187172}
188173
189- fn create_mingw_dll_import_lib (
190- sess : & Session ,
191- lib_name : & str ,
192- items : Vec < ImportLibraryItem > ,
193- output_path : & Path ,
194- ) {
195- let def_file_path = output_path. with_extension ( "def" ) ;
196-
197- let def_file_content = format ! (
198- "EXPORTS\n {}" ,
199- items
200- . into_iter( )
201- . map( |ImportLibraryItem { name, ordinal, .. } | {
202- match ordinal {
203- Some ( n) => format!( "{name} @{n} NONAME" ) ,
204- None => name,
205- }
206- } )
207- . collect:: <Vec <String >>( )
208- . join( "\n " )
209- ) ;
210-
211- match std:: fs:: write ( & def_file_path, def_file_content) {
212- Ok ( _) => { }
213- Err ( e) => {
214- sess. dcx ( ) . emit_fatal ( ErrorWritingDEFFile { error : e } ) ;
215- }
216- } ;
217-
218- // --no-leading-underscore: For the `import_name_type` feature to work, we need to be
219- // able to control the *exact* spelling of each of the symbols that are being imported:
220- // hence we don't want `dlltool` adding leading underscores automatically.
221- let dlltool = find_binutils_dlltool ( sess) ;
222- // temp_prefix doesn't handle paths with spaces so
223- // use a relative path and set the current working directory
224- let cwd = output_path. parent ( ) . unwrap_or ( output_path) ;
225- let temp_prefix = lib_name;
226- // dlltool target architecture args from:
227- // https://github.com/llvm/llvm-project-release-prs/blob/llvmorg-15.0.6/llvm/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp#L69
228- let ( dlltool_target_arch, dlltool_target_bitness) = match & sess. target . arch {
229- Arch :: X86_64 => ( "i386:x86-64" , "--64" ) ,
230- Arch :: X86 => ( "i386" , "--32" ) ,
231- Arch :: AArch64 => ( "arm64" , "--64" ) ,
232- Arch :: Arm => ( "arm" , "--32" ) ,
233- arch => panic ! ( "unsupported arch {arch}" ) ,
234- } ;
235- let mut dlltool_cmd = std:: process:: Command :: new ( & dlltool) ;
236- dlltool_cmd
237- . arg ( "-d" )
238- . arg ( def_file_path)
239- . arg ( "-D" )
240- . arg ( lib_name)
241- . arg ( "-l" )
242- . arg ( & output_path)
243- . arg ( "-m" )
244- . arg ( dlltool_target_arch)
245- . arg ( "-f" )
246- . arg ( dlltool_target_bitness)
247- . arg ( "--no-leading-underscore" )
248- . arg ( "--temp-prefix" )
249- . arg ( temp_prefix)
250- . current_dir ( cwd) ;
251-
252- match dlltool_cmd. output ( ) {
253- Err ( e) => {
254- sess. dcx ( ) . emit_fatal ( ErrorCallingDllTool {
255- dlltool_path : dlltool. to_string_lossy ( ) ,
256- error : e,
257- } ) ;
258- }
259- // dlltool returns '0' on failure, so check for error output instead.
260- Ok ( output) if !output. stderr . is_empty ( ) => {
261- sess. dcx ( ) . emit_fatal ( DlltoolFailImportLibrary {
262- dlltool_path : dlltool. to_string_lossy ( ) ,
263- dlltool_args : dlltool_cmd
264- . get_args ( )
265- . map ( |arg| arg. to_string_lossy ( ) )
266- . collect :: < Vec < _ > > ( )
267- . join ( " " ) ,
268- stdout : String :: from_utf8_lossy ( & output. stdout ) ,
269- stderr : String :: from_utf8_lossy ( & output. stderr ) ,
270- } )
271- }
272- _ => { }
273- }
274- }
275-
276- fn find_binutils_dlltool ( sess : & Session ) -> OsString {
277- assert ! ( sess. target. options. is_like_windows && !sess. target. options. is_like_msvc) ;
278- if let Some ( dlltool_path) = & sess. opts . cg . dlltool {
279- return dlltool_path. clone ( ) . into_os_string ( ) ;
280- }
281-
282- let tool_name: OsString = if sess. host . options . is_like_windows {
283- // If we're compiling on Windows, always use "dlltool.exe".
284- "dlltool.exe"
285- } else {
286- // On other platforms, use the architecture-specific name.
287- match sess. target . arch {
288- Arch :: X86_64 => "x86_64-w64-mingw32-dlltool" ,
289- Arch :: X86 => "i686-w64-mingw32-dlltool" ,
290- Arch :: AArch64 => "aarch64-w64-mingw32-dlltool" ,
291-
292- // For non-standard architectures (e.g., aarch32) fallback to "dlltool".
293- _ => "dlltool" ,
294- }
295- }
296- . into ( ) ;
297-
298- // NOTE: it's not clear how useful it is to explicitly search PATH.
299- for dir in env:: split_paths ( & env:: var_os ( "PATH" ) . unwrap_or_default ( ) ) {
300- let full_path = dir. join ( & tool_name) ;
301- if full_path. is_file ( ) {
302- return full_path. into_os_string ( ) ;
303- }
304- }
305-
306- // The user didn't specify the location of the dlltool binary, and we weren't able
307- // to find the appropriate one on the PATH. Just return the name of the tool
308- // and let the invocation fail with a hopefully useful error message.
309- tool_name
310- }
311-
312174pub enum AddArchiveKind < ' a > {
313175 Rlib ( /*skip*/ & ' a dyn Fn ( & str , ArchiveEntryKind ) -> bool ) ,
314176 Other ,
0 commit comments