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