1
1
use std:: collections:: HashMap ;
2
2
use std:: fs:: File ;
3
- use std:: path:: PathBuf ;
3
+ use std:: path:: { Path , PathBuf } ;
4
4
5
5
use crate :: prelude:: * ;
6
6
7
+ use rustc_codegen_ssa:: { METADATA_FILENAME , RLIB_BYTECODE_EXTENSION } ;
8
+ use rustc_codegen_ssa:: back:: archive:: { ArchiveBuilder , find_library} ;
9
+
7
10
pub struct ArchiveConfig < ' a > {
8
11
pub sess : & ' a Session ,
9
12
pub dst : PathBuf ,
10
13
pub src : Option < PathBuf > ,
11
14
pub lib_search_paths : Vec < PathBuf > ,
12
15
}
13
16
14
- pub struct ArchiveBuilder < ' a > {
15
- cfg : ArchiveConfig < ' a > ,
17
+ pub struct ArArchiveBuilder < ' a > {
18
+ config : ArchiveConfig < ' a > ,
16
19
src_archive : Option < ar:: Archive < File > > ,
17
20
src_entries : HashMap < String , usize > ,
18
21
builder : ar:: Builder < File > ,
19
22
update_symbols : bool ,
20
23
}
21
24
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
+
24
35
let ( src_archive, src_entries) = if let Some ( src) = & cfg. src {
25
36
let mut archive = ar:: Archive :: new ( File :: open ( src) . unwrap ( ) ) ;
26
37
let mut entries = HashMap :: new ( ) ;
@@ -42,32 +53,68 @@ impl<'a> ArchiveBuilder<'a> {
42
53
43
54
let builder = ar:: Builder :: new ( File :: create ( & cfg. dst ) . unwrap ( ) ) ;
44
55
45
- ArchiveBuilder {
46
- cfg,
56
+ ArArchiveBuilder {
57
+ config : cfg,
47
58
src_archive,
48
59
src_entries,
49
60
builder,
50
61
update_symbols : false ,
51
62
}
52
63
}
53
64
54
- pub fn src_files ( & self ) -> Vec < String > {
65
+ fn src_files ( & mut self ) -> Vec < String > {
55
66
self . src_entries . keys ( ) . cloned ( ) . collect ( )
56
67
}
57
68
58
- pub fn remove_file ( & mut self , name : & str ) {
69
+ fn remove_file ( & mut self , name : & str ) {
59
70
let file = self . src_entries . remove ( name) ;
60
71
assert ! (
61
72
file. is_some( ) ,
62
73
"Tried to remove file not existing in src archive" ,
63
74
) ;
64
75
}
65
76
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 ) {
67
114
self . update_symbols = true ;
68
115
}
69
116
70
- pub fn build ( mut self ) {
117
+ fn build ( mut self ) {
71
118
// Add files from original archive
72
119
if let Some ( mut src_archive) = self . src_archive {
73
120
for ( _entry_name, entry_idx) in self . src_entries . into_iter ( ) {
@@ -88,7 +135,7 @@ impl<'a> ArchiveBuilder<'a> {
88
135
89
136
// Run ranlib to be able to link the archive
90
137
let status = std:: process:: Command :: new ( "ranlib" )
91
- . arg ( self . cfg . dst )
138
+ . arg ( self . config . dst )
92
139
. status ( )
93
140
. expect ( "Couldn't run ranlib" ) ;
94
141
assert ! (
@@ -98,3 +145,28 @@ impl<'a> ArchiveBuilder<'a> {
98
145
) ;
99
146
}
100
147
}
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