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