11//! A helper class for dealing with static archives 
22
3- use  std:: ffi:: { c_char,  c_void,  CStr ,  CString ,   OsString } ; 
3+ use  std:: ffi:: { c_char,  c_void,  CStr ,  CString } ; 
44use  std:: path:: { Path ,  PathBuf } ; 
5- use  std:: { env ,   io,  mem,  ptr,  str} ; 
5+ use  std:: { io,  mem,  ptr,  str} ; 
66
77use  rustc_codegen_ssa:: back:: archive:: { 
8-     try_extract_macho_fat_archive,  ArArchiveBuilder ,  ArchiveBuildFailure ,  ArchiveBuilder , 
9-     ArchiveBuilderBuilder ,  ObjectReader ,  UnknownArchiveKind ,  DEFAULT_OBJECT_READER , 
8+     create_mingw_dll_import_lib,  try_extract_macho_fat_archive,  ArArchiveBuilder , 
9+     ArchiveBuildFailure ,  ArchiveBuilder ,  ArchiveBuilderBuilder ,  ObjectReader ,  UnknownArchiveKind , 
10+     DEFAULT_OBJECT_READER , 
1011} ; 
11- use  rustc_session :: cstore :: DllImport ; 
12+ use  rustc_codegen_ssa :: common ; 
1213use  rustc_session:: Session ; 
1314use  tracing:: trace; 
1415
15- use  crate :: common; 
16- use  crate :: errors:: { 
17-     DlltoolFailImportLibrary ,  ErrorCallingDllTool ,  ErrorCreatingImportLibrary ,  ErrorWritingDEFFile , 
18- } ; 
16+ use  crate :: errors:: ErrorCreatingImportLibrary ; 
1917use  crate :: llvm:: archive_ro:: { ArchiveRO ,  Child } ; 
2018use  crate :: llvm:: { self ,  ArchiveKind ,  LLVMMachineType ,  LLVMRustCOFFShortExport } ; 
2119
@@ -121,116 +119,21 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
121119        & self , 
122120        sess :  & Session , 
123121        lib_name :  & str , 
124-         dll_imports :  & [ DllImport ] , 
125-         tmpdir :  & Path , 
126-         is_direct_dependency :  bool , 
127-     )  -> PathBuf  { 
128-         let  name_suffix = if  is_direct_dependency {  "_imports"  }  else  {  "_imports_indirect"  } ; 
129-         let  output_path = tmpdir. join ( format ! ( "{lib_name}{name_suffix}.lib" ) ) ; 
130- 
131-         let  target = & sess. target ; 
132-         let  mingw_gnu_toolchain = common:: is_mingw_gnu_toolchain ( target) ; 
133- 
134-         let  import_name_and_ordinal_vector:  Vec < ( String ,  Option < u16 > ) >  = dll_imports
135-             . iter ( ) 
136-             . map ( |import :  & DllImport | { 
137-                 if  sess. target . arch  == "x86"  { 
138-                     ( 
139-                         common:: i686_decorated_name ( import,  mingw_gnu_toolchain,  false ) , 
140-                         import. ordinal ( ) , 
141-                     ) 
142-                 }  else  { 
143-                     ( import. name . to_string ( ) ,  import. ordinal ( ) ) 
144-                 } 
145-             } ) 
146-             . collect ( ) ; 
147- 
148-         if  mingw_gnu_toolchain { 
122+         import_name_and_ordinal_vector :  Vec < ( String ,  Option < u16 > ) > , 
123+         output_path :  & Path , 
124+     )  { 
125+         if  common:: is_mingw_gnu_toolchain ( & sess. target )  { 
149126            // The binutils linker used on -windows-gnu targets cannot read the import 
150127            // libraries generated by LLVM: in our attempts, the linker produced an .EXE 
151128            // that loaded but crashed with an AV upon calling one of the imported 
152129            // functions. Therefore, use binutils to create the import library instead, 
153130            // by writing a .DEF file to the temp dir and calling binutils's dlltool. 
154-             let  def_file_path = tmpdir. join ( format ! ( "{lib_name}{name_suffix}.def" ) ) ; 
155- 
156-             let  def_file_content = format ! ( 
157-                 "EXPORTS\n {}" , 
158-                 import_name_and_ordinal_vector
159-                     . into_iter( ) 
160-                     . map( |( name,  ordinal) | { 
161-                         match  ordinal { 
162-                             Some ( n)  => format!( "{name} @{n} NONAME" ) , 
163-                             None  => name, 
164-                         } 
165-                     } ) 
166-                     . collect:: <Vec <String >>( ) 
167-                     . join( "\n " ) 
131+             create_mingw_dll_import_lib ( 
132+                 sess, 
133+                 lib_name, 
134+                 import_name_and_ordinal_vector, 
135+                 output_path, 
168136            ) ; 
169- 
170-             match  std:: fs:: write ( & def_file_path,  def_file_content)  { 
171-                 Ok ( _)  => { } 
172-                 Err ( e)  => { 
173-                     sess. dcx ( ) . emit_fatal ( ErrorWritingDEFFile  {  error :  e } ) ; 
174-                 } 
175-             } ; 
176- 
177-             // --no-leading-underscore: For the `import_name_type` feature to work, we need to be 
178-             // able to control the *exact* spelling of each of the symbols that are being imported: 
179-             // hence we don't want `dlltool` adding leading underscores automatically. 
180-             let  dlltool = find_binutils_dlltool ( sess) ; 
181-             let  temp_prefix = { 
182-                 let  mut  path = PathBuf :: from ( & output_path) ; 
183-                 path. pop ( ) ; 
184-                 path. push ( lib_name) ; 
185-                 path
186-             } ; 
187-             // dlltool target architecture args from: 
188-             // https://github.com/llvm/llvm-project-release-prs/blob/llvmorg-15.0.6/llvm/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp#L69 
189-             let  ( dlltool_target_arch,  dlltool_target_bitness)  = match  sess. target . arch . as_ref ( )  { 
190-                 "x86_64"  => ( "i386:x86-64" ,  "--64" ) , 
191-                 "x86"  => ( "i386" ,  "--32" ) , 
192-                 "aarch64"  => ( "arm64" ,  "--64" ) , 
193-                 "arm"  => ( "arm" ,  "--32" ) , 
194-                 _ => panic ! ( "unsupported arch {}" ,  sess. target. arch) , 
195-             } ; 
196-             let  mut  dlltool_cmd = std:: process:: Command :: new ( & dlltool) ; 
197-             dlltool_cmd
198-                 . arg ( "-d" ) 
199-                 . arg ( def_file_path) 
200-                 . arg ( "-D" ) 
201-                 . arg ( lib_name) 
202-                 . arg ( "-l" ) 
203-                 . arg ( & output_path) 
204-                 . arg ( "-m" ) 
205-                 . arg ( dlltool_target_arch) 
206-                 . arg ( "-f" ) 
207-                 . arg ( dlltool_target_bitness) 
208-                 . arg ( "--no-leading-underscore" ) 
209-                 . arg ( "--temp-prefix" ) 
210-                 . arg ( temp_prefix) ; 
211- 
212-             match  dlltool_cmd. output ( )  { 
213-                 Err ( e)  => { 
214-                     sess. dcx ( ) . emit_fatal ( ErrorCallingDllTool  { 
215-                         dlltool_path :  dlltool. to_string_lossy ( ) , 
216-                         error :  e, 
217-                     } ) ; 
218-                 } 
219-                 // dlltool returns '0' on failure, so check for error output instead. 
220-                 Ok ( output)  if  !output. stderr . is_empty ( )  => { 
221-                     sess. dcx ( ) . emit_fatal ( DlltoolFailImportLibrary  { 
222-                         dlltool_path :  dlltool. to_string_lossy ( ) , 
223-                         dlltool_args :  dlltool_cmd
224-                             . get_args ( ) 
225-                             . map ( |arg| arg. to_string_lossy ( ) ) 
226-                             . collect :: < Vec < _ > > ( ) 
227-                             . join ( " " ) , 
228-                         stdout :  String :: from_utf8_lossy ( & output. stdout ) , 
229-                         stderr :  String :: from_utf8_lossy ( & output. stderr ) , 
230-                     } ) 
231-                 } 
232-                 _ => { } 
233-             } 
234137        }  else  { 
235138            // we've checked for \0 characters in the library name already 
236139            let  dll_name_z = CString :: new ( lib_name) . unwrap ( ) ; 
@@ -242,9 +145,9 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
242145            trace ! ( "  output_path {}" ,  output_path. display( ) ) ; 
243146            trace ! ( 
244147                "  import names: {}" , 
245-                 dll_imports 
148+                 import_name_and_ordinal_vector 
246149                    . iter( ) 
247-                     . map( |import| import . name. to_string ( ) ) 
150+                     . map( |( name ,  _ordinal ) |  name. clone ( ) ) 
248151                    . collect:: <Vec <_>>( ) 
249152                    . join( ", " ) , 
250153            ) ; 
@@ -281,9 +184,7 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
281184                    error :  llvm:: last_error ( ) . unwrap_or ( "unknown LLVM error" . to_string ( ) ) , 
282185                } ) ; 
283186            } 
284-         } ; 
285- 
286-         output_path
187+         } 
287188    } 
288189} 
289190
@@ -457,39 +358,3 @@ impl<'a> LlvmArchiveBuilder<'a> {
457358fn  string_to_io_error ( s :  String )  -> io:: Error  { 
458359    io:: Error :: new ( io:: ErrorKind :: Other ,  format ! ( "bad archive: {s}" ) ) 
459360} 
460- 
461- fn  find_binutils_dlltool ( sess :  & Session )  -> OsString  { 
462-     assert ! ( sess. target. options. is_like_windows && !sess. target. options. is_like_msvc) ; 
463-     if  let  Some ( dlltool_path)  = & sess. opts . cg . dlltool  { 
464-         return  dlltool_path. clone ( ) . into_os_string ( ) ; 
465-     } 
466- 
467-     let  tool_name:  OsString  = if  sess. host . options . is_like_windows  { 
468-         // If we're compiling on Windows, always use "dlltool.exe". 
469-         "dlltool.exe" 
470-     }  else  { 
471-         // On other platforms, use the architecture-specific name. 
472-         match  sess. target . arch . as_ref ( )  { 
473-             "x86_64"  => "x86_64-w64-mingw32-dlltool" , 
474-             "x86"  => "i686-w64-mingw32-dlltool" , 
475-             "aarch64"  => "aarch64-w64-mingw32-dlltool" , 
476- 
477-             // For non-standard architectures (e.g., aarch32) fallback to "dlltool". 
478-             _ => "dlltool" , 
479-         } 
480-     } 
481-     . into ( ) ; 
482- 
483-     // NOTE: it's not clear how useful it is to explicitly search PATH. 
484-     for  dir in  env:: split_paths ( & env:: var_os ( "PATH" ) . unwrap_or_default ( ) )  { 
485-         let  full_path = dir. join ( & tool_name) ; 
486-         if  full_path. is_file ( )  { 
487-             return  full_path. into_os_string ( ) ; 
488-         } 
489-     } 
490- 
491-     // The user didn't specify the location of the dlltool binary, and we weren't able 
492-     // to find the appropriate one on the PATH. Just return the name of the tool 
493-     // and let the invocation fail with a hopefully useful error message. 
494-     tool_name
495- } 
0 commit comments