11use std:: collections:: HashMap ;
22use std:: fs:: File ;
3- use std:: path:: PathBuf ;
3+ use std:: path:: { Path , PathBuf } ;
44
55use crate :: prelude:: * ;
66
7+ use rustc_codegen_ssa:: { METADATA_FILENAME , RLIB_BYTECODE_EXTENSION } ;
8+ use rustc_codegen_ssa:: back:: archive:: { ArchiveBuilder , find_library} ;
9+
710pub struct ArchiveConfig < ' a > {
811 pub sess : & ' a Session ,
912 pub dst : PathBuf ,
1013 pub src : Option < PathBuf > ,
1114 pub lib_search_paths : Vec < PathBuf > ,
1215}
1316
14- pub struct ArchiveBuilder < ' a > {
15- cfg : ArchiveConfig < ' a > ,
17+ pub struct ArArchiveBuilder < ' a > {
18+ config : ArchiveConfig < ' a > ,
1619 src_archive : Option < ar:: Archive < File > > ,
1720 src_entries : HashMap < String , usize > ,
1821 builder : ar:: Builder < File > ,
1922 update_symbols : bool ,
2023}
2124
22- impl < ' a > ArchiveBuilder < ' a > {
23- pub fn new ( cfg : ArchiveConfig < ' a > ) -> Self {
25+ impl < ' a > ArchiveBuilder < ' a > for ArArchiveBuilder < ' a > {
26+ fn new ( sess : & ' a Session , output : & Path , input : Option < & Path > ) -> Self {
27+ use rustc_codegen_ssa:: back:: link:: archive_search_paths;
28+ let cfg = ArchiveConfig {
29+ sess,
30+ dst : output. to_path_buf ( ) ,
31+ src : input. map ( |p| p. to_path_buf ( ) ) ,
32+ lib_search_paths : archive_search_paths ( sess) ,
33+ } ;
34+
2435 let ( src_archive, src_entries) = if let Some ( src) = & cfg. src {
2536 let mut archive = ar:: Archive :: new ( File :: open ( src) . unwrap ( ) ) ;
2637 let mut entries = HashMap :: new ( ) ;
@@ -42,32 +53,68 @@ impl<'a> ArchiveBuilder<'a> {
4253
4354 let builder = ar:: Builder :: new ( File :: create ( & cfg. dst ) . unwrap ( ) ) ;
4455
45- ArchiveBuilder {
46- cfg,
56+ ArArchiveBuilder {
57+ config : cfg,
4758 src_archive,
4859 src_entries,
4960 builder,
5061 update_symbols : false ,
5162 }
5263 }
5364
54- pub fn src_files ( & self ) -> Vec < String > {
65+ fn src_files ( & mut self ) -> Vec < String > {
5566 self . src_entries . keys ( ) . cloned ( ) . collect ( )
5667 }
5768
58- pub fn remove_file ( & mut self , name : & str ) {
69+ fn remove_file ( & mut self , name : & str ) {
5970 let file = self . src_entries . remove ( name) ;
6071 assert ! (
6172 file. is_some( ) ,
6273 "Tried to remove file not existing in src archive" ,
6374 ) ;
6475 }
6576
66- pub fn update_symbols ( & mut self ) {
77+ fn add_file ( & mut self , file : & Path ) {
78+ self . builder . append_path ( file) . unwrap ( ) ;
79+ }
80+
81+ fn add_native_library ( & mut self , name : & str ) {
82+ let location = find_library ( name, & self . config . lib_search_paths , self . config . sess ) ;
83+ self . add_archive ( & location, |_| false ) . unwrap_or_else ( |e| {
84+ panic ! ( "failed to add native library {}: {}" , location. to_string_lossy( ) , e) ;
85+ } ) ;
86+ }
87+
88+ fn add_rlib ( & mut self , rlib : & Path , name : & str , lto : bool , skip_objects : bool ) -> std:: io:: Result < ( ) > {
89+ let obj_start = name. to_owned ( ) ;
90+
91+ self . add_archive ( rlib, move |fname : & str | {
92+ // Ignore bytecode/metadata files, no matter the name.
93+ if fname. ends_with ( RLIB_BYTECODE_EXTENSION ) || fname == METADATA_FILENAME {
94+ return true ;
95+ }
96+
97+ // Don't include Rust objects if LTO is enabled
98+ if lto && fname. starts_with ( & obj_start) && fname. ends_with ( ".o" ) {
99+ return true ;
100+ }
101+
102+ // Otherwise if this is *not* a rust object and we're skipping
103+ // objects then skip this file
104+ if skip_objects && ( !fname. starts_with ( & obj_start) || !fname. ends_with ( ".o" ) ) {
105+ return true ;
106+ }
107+
108+ // ok, don't skip this
109+ return false ;
110+ } )
111+ }
112+
113+ fn update_symbols ( & mut self ) {
67114 self . update_symbols = true ;
68115 }
69116
70- pub fn build ( mut self ) {
117+ fn build ( mut self ) {
71118 // Add files from original archive
72119 if let Some ( mut src_archive) = self . src_archive {
73120 for ( _entry_name, entry_idx) in self . src_entries . into_iter ( ) {
@@ -88,7 +135,7 @@ impl<'a> ArchiveBuilder<'a> {
88135
89136 // Run ranlib to be able to link the archive
90137 let status = std:: process:: Command :: new ( "ranlib" )
91- . arg ( self . cfg . dst )
138+ . arg ( self . config . dst )
92139 . status ( )
93140 . expect ( "Couldn't run ranlib" ) ;
94141 assert ! (
@@ -98,3 +145,28 @@ impl<'a> ArchiveBuilder<'a> {
98145 ) ;
99146 }
100147}
148+
149+ impl < ' a > ArArchiveBuilder < ' a > {
150+ fn add_archive < F > ( & mut self , archive : & Path , mut skip : F ) -> std:: io:: Result < ( ) >
151+ where F : FnMut ( & str ) -> bool + ' static
152+ {
153+ let mut archive = ar:: Archive :: new ( std:: fs:: File :: open ( archive) ?) ;
154+ while let Some ( entry) = archive. next_entry ( ) {
155+ let entry = entry?;
156+ let orig_header = entry. header ( ) ;
157+
158+ if skip ( std:: str:: from_utf8 ( orig_header. identifier ( ) ) . unwrap ( ) ) {
159+ continue ;
160+ }
161+
162+ let mut header =
163+ ar:: Header :: new ( orig_header. identifier ( ) . to_vec ( ) , orig_header. size ( ) ) ;
164+ header. set_mtime ( orig_header. mtime ( ) ) ;
165+ header. set_uid ( orig_header. uid ( ) ) ;
166+ header. set_gid ( orig_header. gid ( ) ) ;
167+ header. set_mode ( orig_header. mode ( ) ) ;
168+ self . builder . append ( & header, entry) . unwrap ( ) ;
169+ }
170+ Ok ( ( ) )
171+ }
172+ }
0 commit comments