1- use std:: collections:: HashMap ;
21use std:: fs:: File ;
32use std:: path:: { Path , PathBuf } ;
43
@@ -8,12 +7,14 @@ use rustc_codegen_ssa::{METADATA_FILENAME, RLIB_BYTECODE_EXTENSION};
87use rustc_codegen_ssa:: back:: archive:: { ArchiveBuilder , find_library} ;
98
109struct ArchiveConfig < ' a > {
11- pub sess : & ' a Session ,
12- pub dst : PathBuf ,
13- pub src : Option < PathBuf > ,
14- pub lib_search_paths : Vec < PathBuf > ,
10+ sess : & ' a Session ,
11+ dst : PathBuf ,
12+ src : Option < PathBuf > ,
13+ lib_search_paths : Vec < PathBuf > ,
14+ use_gnu_style_archive : bool ,
1515}
1616
17+ #[ derive( Debug ) ]
1718enum ArchiveEntry {
1819 FromArchive { archive_index : usize , entry_index : usize } ,
1920 File ( File ) ,
@@ -22,7 +23,9 @@ enum ArchiveEntry {
2223pub struct ArArchiveBuilder < ' a > {
2324 config : ArchiveConfig < ' a > ,
2425 src_archives : Vec < ar:: Archive < File > > ,
25- entries : HashMap < String , ArchiveEntry > ,
26+ // Don't use `HashMap` here, as the order is important. `rust.metadata.bin` must always be at
27+ // the end of an archive for linkers to not get confused.
28+ entries : Vec < ( String , ArchiveEntry ) > ,
2629 update_symbols : bool ,
2730}
2831
@@ -34,25 +37,27 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
3437 dst : output. to_path_buf ( ) ,
3538 src : input. map ( |p| p. to_path_buf ( ) ) ,
3639 lib_search_paths : archive_search_paths ( sess) ,
40+ // FIXME test for linux and System V derivatives instead
41+ use_gnu_style_archive : !sess. target . target . options . is_like_osx ,
3742 } ;
3843
3944 let ( src_archives, entries) = if let Some ( src) = & config. src {
4045 let mut archive = ar:: Archive :: new ( File :: open ( src) . unwrap ( ) ) ;
41- let mut entries = HashMap :: new ( ) ;
46+ let mut entries = Vec :: new ( ) ;
4247
4348 let mut i = 0 ;
4449 while let Some ( entry) = archive. next_entry ( ) {
4550 let entry = entry. unwrap ( ) ;
46- entries. insert (
51+ entries. push ( (
4752 String :: from_utf8 ( entry. header ( ) . identifier ( ) . to_vec ( ) ) . unwrap ( ) ,
4853 ArchiveEntry :: FromArchive { archive_index : 0 , entry_index : i } ,
49- ) ;
54+ ) ) ;
5055 i += 1 ;
5156 }
5257
5358 ( vec ! [ archive] , entries)
5459 } else {
55- ( vec ! [ ] , HashMap :: new ( ) )
60+ ( vec ! [ ] , Vec :: new ( ) )
5661 } ;
5762
5863 ArArchiveBuilder {
@@ -64,22 +69,22 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
6469 }
6570
6671 fn src_files ( & mut self ) -> Vec < String > {
67- self . entries . keys ( ) . cloned ( ) . collect ( )
72+ self . entries . iter ( ) . map ( | ( name , _ ) | name . clone ( ) ) . collect ( )
6873 }
6974
7075 fn remove_file ( & mut self , name : & str ) {
71- let file = self . entries . remove ( name ) ;
72- assert ! (
73- file . is_some ( ) ,
74- "Tried to remove file not existing in src archive" ,
75- ) ;
76+ let index = self . entries
77+ . iter ( )
78+ . position ( | ( entry_name , _ ) | entry_name == name )
79+ . expect ( "Tried to remove file not existing in src archive" ) ;
80+ self . entries . remove ( index ) ;
7681 }
7782
7883 fn add_file ( & mut self , file : & Path ) {
79- self . entries . insert (
84+ self . entries . push ( (
8085 file. file_name ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) . to_string ( ) ,
8186 ArchiveEntry :: File ( File :: open ( file) . unwrap ( ) ) ,
82- ) ;
87+ ) ) ;
8388 }
8489
8590 fn add_native_library ( & mut self , name : & str ) {
@@ -119,24 +124,44 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
119124 }
120125
121126 fn build ( mut self ) {
122- let mut builder = ar:: Builder :: new ( File :: create ( & self . config . dst ) . unwrap ( ) ) ;
127+ enum BuilderKind {
128+ Bsd ( ar:: Builder < File > ) ,
129+ Gnu ( ar:: GnuBuilder < File > ) ,
130+ }
131+
132+ let archive_file = File :: create ( & self . config . dst ) . unwrap ( ) ;
133+ let mut builder = if self . config . use_gnu_style_archive {
134+ BuilderKind :: Gnu ( ar:: GnuBuilder :: new (
135+ archive_file,
136+ self . entries . iter ( ) . map ( |( name, _) | name. as_bytes ( ) . to_vec ( ) ) . collect ( ) ,
137+ ) )
138+ } else {
139+ BuilderKind :: Bsd ( ar:: Builder :: new ( archive_file) )
140+ } ;
123141
124142 // Add all files
125143 for ( entry_name, entry) in self . entries . into_iter ( ) {
126144 match entry {
127145 ArchiveEntry :: FromArchive { archive_index, entry_index } => {
128146 let entry = self . src_archives [ archive_index] . jump_to_entry ( entry_index) . unwrap ( ) ;
129147 let orig_header = entry. header ( ) ;
148+
130149 let mut header =
131150 ar:: Header :: new ( orig_header. identifier ( ) . to_vec ( ) , orig_header. size ( ) ) ;
132151 header. set_mtime ( orig_header. mtime ( ) ) ;
133152 header. set_uid ( orig_header. uid ( ) ) ;
134153 header. set_gid ( orig_header. gid ( ) ) ;
135154 header. set_mode ( orig_header. mode ( ) ) ;
136- builder. append ( & header, entry) . unwrap ( ) ;
155+ match builder {
156+ BuilderKind :: Bsd ( ref mut builder) => builder. append ( & header, entry) . unwrap ( ) ,
157+ BuilderKind :: Gnu ( ref mut builder) => builder. append ( & header, entry) . unwrap ( ) ,
158+ }
137159 }
138160 ArchiveEntry :: File ( mut file) => {
139- builder. append_file ( entry_name. as_bytes ( ) , & mut file) . unwrap ( ) ;
161+ match builder {
162+ BuilderKind :: Bsd ( ref mut builder) => builder. append_file ( entry_name. as_bytes ( ) , & mut file) . unwrap ( ) ,
163+ BuilderKind :: Gnu ( ref mut builder) => builder. append_file ( entry_name. as_bytes ( ) , & mut file) . unwrap ( ) ,
164+ }
140165 }
141166 }
142167 }
@@ -169,10 +194,10 @@ impl<'a> ArArchiveBuilder<'a> {
169194 let entry = entry. unwrap ( ) ;
170195 let file_name = String :: from_utf8 ( entry. header ( ) . identifier ( ) . to_vec ( ) ) . unwrap ( ) ;
171196 if !skip ( & file_name) {
172- self . entries . insert (
197+ self . entries . push ( (
173198 file_name,
174199 ArchiveEntry :: FromArchive { archive_index, entry_index : i } ,
175- ) ;
200+ ) ) ;
176201 }
177202 i += 1 ;
178203 }
0 commit comments