10
10
11
11
//! A helper class for dealing with static archives
12
12
13
- use std:: env;
14
13
use std:: ffi:: { CString , CStr , OsString } ;
15
- use std:: fs:: { self , File } ;
16
- use std:: io:: prelude:: * ;
17
14
use std:: io;
18
15
use std:: mem;
19
16
use std:: path:: { Path , PathBuf } ;
20
- use std:: process:: { Command , Output , Stdio } ;
21
17
use std:: ptr;
22
18
use std:: str;
23
19
24
20
use libc;
25
21
use llvm:: archive_ro:: { ArchiveRO , Child } ;
26
22
use llvm:: { self , ArchiveKind } ;
27
23
use rustc:: session:: Session ;
28
- use rustc_back:: tempdir:: TempDir ;
29
24
30
25
pub struct ArchiveConfig < ' a > {
31
26
pub sess : & ' a Session ,
@@ -41,7 +36,6 @@ pub struct ArchiveConfig<'a> {
41
36
#[ must_use = "must call build() to finish building the archive" ]
42
37
pub struct ArchiveBuilder < ' a > {
43
38
config : ArchiveConfig < ' a > ,
44
- work_dir : TempDir ,
45
39
removals : Vec < String > ,
46
40
additions : Vec < Addition > ,
47
41
should_update_symbols : bool ,
@@ -55,17 +49,10 @@ enum Addition {
55
49
} ,
56
50
Archive {
57
51
archive : ArchiveRO ,
58
- archive_name : String ,
59
52
skip : Box < FnMut ( & str ) -> bool > ,
60
53
} ,
61
54
}
62
55
63
- enum Action < ' a > {
64
- Remove ( & ' a [ String ] ) ,
65
- AddObjects ( & ' a [ & ' a PathBuf ] , bool ) ,
66
- UpdateSymbols ,
67
- }
68
-
69
56
pub fn find_library ( name : & str , search_paths : & [ PathBuf ] , sess : & Session )
70
57
-> PathBuf {
71
58
// On Windows, static libraries sometimes show up as libfoo.a and other
@@ -102,7 +89,6 @@ impl<'a> ArchiveBuilder<'a> {
102
89
pub fn new ( config : ArchiveConfig < ' a > ) -> ArchiveBuilder < ' a > {
103
90
ArchiveBuilder {
104
91
config : config,
105
- work_dir : TempDir :: new ( "rsar" ) . unwrap ( ) ,
106
92
removals : Vec :: new ( ) ,
107
93
additions : Vec :: new ( ) ,
108
94
should_update_symbols : false ,
@@ -148,7 +134,7 @@ impl<'a> ArchiveBuilder<'a> {
148
134
pub fn add_native_library ( & mut self , name : & str ) {
149
135
let location = find_library ( name, & self . config . lib_search_paths ,
150
136
self . config . sess ) ;
151
- self . add_archive ( & location, name , |_| false ) . unwrap_or_else ( |e| {
137
+ self . add_archive ( & location, |_| false ) . unwrap_or_else ( |e| {
152
138
self . config . sess . fatal ( & format ! ( "failed to add native library {}: {}" ,
153
139
location. to_string_lossy( ) , e) ) ;
154
140
} ) ;
@@ -172,14 +158,14 @@ impl<'a> ArchiveBuilder<'a> {
172
158
let metadata_filename =
173
159
self . config . sess . cstore . metadata_filename ( ) . to_owned ( ) ;
174
160
175
- self . add_archive ( rlib, & name [ .. ] , move |fname : & str | {
161
+ self . add_archive ( rlib, move |fname : & str | {
176
162
let skip_obj = lto && fname. starts_with ( & obj_start)
177
163
&& fname. ends_with ( ".o" ) ;
178
164
skip_obj || fname. ends_with ( bc_ext) || fname == metadata_filename
179
165
} )
180
166
}
181
167
182
- fn add_archive < F > ( & mut self , archive : & Path , name : & str , skip : F )
168
+ fn add_archive < F > ( & mut self , archive : & Path , skip : F )
183
169
-> io:: Result < ( ) >
184
170
where F : FnMut ( & str ) -> bool + ' static
185
171
{
@@ -190,7 +176,6 @@ impl<'a> ArchiveBuilder<'a> {
190
176
} ;
191
177
self . additions . push ( Addition :: Archive {
192
178
archive : archive,
193
- archive_name : name. to_string ( ) ,
194
179
skip : Box :: new ( skip) ,
195
180
} ) ;
196
181
Ok ( ( ) )
@@ -214,234 +199,23 @@ impl<'a> ArchiveBuilder<'a> {
214
199
/// Combine the provided files, rlibs, and native libraries into a single
215
200
/// `Archive`.
216
201
pub fn build ( & mut self ) {
217
- let res = match self . llvm_archive_kind ( ) {
218
- Some ( kind) => self . build_with_llvm ( kind) ,
219
- None => self . build_with_ar_cmd ( ) ,
220
- } ;
221
- if let Err ( e) = res {
222
- self . config . sess . fatal ( & format ! ( "failed to build archive: {}" , e) ) ;
223
- }
224
- }
225
-
226
- pub fn llvm_archive_kind ( & self ) -> Option < ArchiveKind > {
227
- if unsafe { llvm:: LLVMVersionMinor ( ) < 7 } {
228
- return None
229
- }
230
-
231
- // Currently LLVM only supports writing archives in the 'gnu' format.
232
- match & self . config . sess . target . target . options . archive_format [ ..] {
233
- "gnu" => Some ( ArchiveKind :: K_GNU ) ,
234
- "mips64" => Some ( ArchiveKind :: K_MIPS64 ) ,
235
- "bsd" => Some ( ArchiveKind :: K_BSD ) ,
236
- "coff" => Some ( ArchiveKind :: K_COFF ) ,
237
- _ => None ,
238
- }
239
- }
240
-
241
- pub fn using_llvm ( & self ) -> bool {
242
- self . llvm_archive_kind ( ) . is_some ( )
243
- }
244
-
245
- fn build_with_ar_cmd ( & mut self ) -> io:: Result < ( ) > {
246
- let removals = mem:: replace ( & mut self . removals , Vec :: new ( ) ) ;
247
- let additions = mem:: replace ( & mut self . additions , Vec :: new ( ) ) ;
248
- let should_update_symbols = mem:: replace ( & mut self . should_update_symbols ,
249
- false ) ;
250
-
251
- // Don't use fs::copy because libs may be installed as read-only and we
252
- // want to modify this archive, so we use `io::copy` to not preserve
253
- // permission bits.
254
- if let Some ( ref s) = self . config . src {
255
- io:: copy ( & mut File :: open ( s) ?,
256
- & mut File :: create ( & self . config . dst ) ?) ?;
257
- }
258
-
259
- if removals. len ( ) > 0 {
260
- self . run ( None , Action :: Remove ( & removals) ) ;
261
- }
262
-
263
- let mut members = Vec :: new ( ) ;
264
- for addition in additions {
265
- match addition {
266
- Addition :: File { path, name_in_archive } => {
267
- let dst = self . work_dir . path ( ) . join ( & name_in_archive) ;
268
- fs:: copy ( & path, & dst) ?;
269
- members. push ( PathBuf :: from ( name_in_archive) ) ;
270
- }
271
- Addition :: Archive { archive, archive_name, mut skip } => {
272
- self . add_archive_members ( & mut members, archive,
273
- & archive_name, & mut * skip) ?;
274
- }
275
- }
276
- }
277
-
278
- // Get an absolute path to the destination, so `ar` will work even
279
- // though we run it from `self.work_dir`.
280
- let mut objects = Vec :: new ( ) ;
281
- let mut total_len = self . config . dst . to_string_lossy ( ) . len ( ) ;
282
-
283
- if members. is_empty ( ) {
284
- if should_update_symbols {
285
- self . run ( Some ( self . work_dir . path ( ) ) , Action :: UpdateSymbols ) ;
286
- }
287
- return Ok ( ( ) )
288
- }
289
-
290
- // Don't allow the total size of `args` to grow beyond 32,000 bytes.
291
- // Windows will raise an error if the argument string is longer than
292
- // 32,768, and we leave a bit of extra space for the program name.
293
- const ARG_LENGTH_LIMIT : usize = 32_000 ;
294
-
295
- for member_name in & members {
296
- let len = member_name. to_string_lossy ( ) . len ( ) ;
297
-
298
- // `len + 1` to account for the space that's inserted before each
299
- // argument. (Windows passes command-line arguments as a single
300
- // string, not an array of strings.)
301
- if total_len + len + 1 > ARG_LENGTH_LIMIT {
302
- // Add the archive members seen so far, without updating the
303
- // symbol table.
304
- self . run ( Some ( self . work_dir . path ( ) ) ,
305
- Action :: AddObjects ( & objects, false ) ) ;
306
-
307
- objects. clear ( ) ;
308
- total_len = self . config . dst . to_string_lossy ( ) . len ( ) ;
309
- }
310
-
311
- objects. push ( member_name) ;
312
- total_len += len + 1 ;
313
- }
314
-
315
- // Add the remaining archive members, and update the symbol table if
316
- // necessary.
317
- self . run ( Some ( self . work_dir . path ( ) ) ,
318
- Action :: AddObjects ( & objects, should_update_symbols) ) ;
319
- Ok ( ( ) )
320
- }
321
-
322
- fn add_archive_members ( & mut self , members : & mut Vec < PathBuf > ,
323
- archive : ArchiveRO , name : & str ,
324
- skip : & mut FnMut ( & str ) -> bool ) -> io:: Result < ( ) > {
325
- // Next, we must rename all of the inputs to "guaranteed unique names".
326
- // We write each file into `self.work_dir` under its new unique name.
327
- // The reason for this renaming is that archives are keyed off the name
328
- // of the files, so if two files have the same name they will override
329
- // one another in the archive (bad).
330
- //
331
- // We skip any files explicitly desired for skipping, and we also skip
332
- // all SYMDEF files as these are just magical placeholders which get
333
- // re-created when we make a new archive anyway.
334
- for file in archive. iter ( ) {
335
- let file = file. map_err ( string_to_io_error) ?;
336
- if !is_relevant_child ( & file) {
337
- continue
338
- }
339
- let filename = file. name ( ) . unwrap ( ) ;
340
- if skip ( filename) {
341
- continue
202
+ let kind = match self . llvm_archive_kind ( ) {
203
+ Ok ( kind) => kind,
204
+ Err ( kind) => {
205
+ self . config . sess . fatal ( & format ! ( "Don't know how to build archive of type: {}" ,
206
+ kind) ) ;
342
207
}
343
- let filename = Path :: new ( filename) . file_name ( ) . unwrap ( )
344
- . to_str ( ) . unwrap ( ) ;
345
-
346
- // Archives on unix systems typically do not have slashes in
347
- // filenames as the `ar` utility generally only uses the last
348
- // component of a path for the filename list in the archive. On
349
- // Windows, however, archives assembled with `lib.exe` will preserve
350
- // the full path to the file that was placed in the archive,
351
- // including path separators.
352
- //
353
- // The code below is munging paths so it'll go wrong pretty quickly
354
- // if there's some unexpected slashes in the filename, so here we
355
- // just chop off everything but the filename component. Note that
356
- // this can cause duplicate filenames, but that's also handled below
357
- // as well.
358
- let filename = Path :: new ( filename) . file_name ( ) . unwrap ( )
359
- . to_str ( ) . unwrap ( ) ;
360
-
361
- // An archive can contain files of the same name multiple times, so
362
- // we need to be sure to not have them overwrite one another when we
363
- // extract them. Consequently we need to find a truly unique file
364
- // name for us!
365
- let mut new_filename = String :: new ( ) ;
366
- for n in 0 .. {
367
- let n = if n == 0 { String :: new ( ) } else { format ! ( "-{}" , n) } ;
368
- new_filename = format ! ( "r{}-{}-{}" , n, name, filename) ;
369
-
370
- // LLDB (as mentioned in back::link) crashes on filenames of
371
- // exactly
372
- // 16 bytes in length. If we're including an object file with
373
- // exactly 16-bytes of characters, give it some prefix so
374
- // that it's not 16 bytes.
375
- new_filename = if new_filename. len ( ) == 16 {
376
- format ! ( "lldb-fix-{}" , new_filename)
377
- } else {
378
- new_filename
379
- } ;
380
-
381
- let present = members. iter ( ) . filter_map ( |p| {
382
- p. file_name ( ) . and_then ( |f| f. to_str ( ) )
383
- } ) . any ( |s| s == new_filename) ;
384
- if !present {
385
- break
386
- }
387
- }
388
- let dst = self . work_dir . path ( ) . join ( & new_filename) ;
389
- File :: create ( & dst) ?. write_all ( file. data ( ) ) ?;
390
- members. push ( PathBuf :: from ( new_filename) ) ;
391
- }
392
- Ok ( ( ) )
393
- }
394
-
395
- fn run ( & self , cwd : Option < & Path > , action : Action ) -> Output {
396
- let abs_dst = env:: current_dir ( ) . unwrap ( ) . join ( & self . config . dst ) ;
397
- let ar = & self . config . ar_prog ;
398
- let mut cmd = Command :: new ( ar) ;
399
- cmd. env ( "PATH" , & self . config . command_path ) ;
400
- cmd. stdout ( Stdio :: piped ( ) ) . stderr ( Stdio :: piped ( ) ) ;
401
- self . prepare_ar_action ( & mut cmd, & abs_dst, action) ;
402
- info ! ( "{:?}" , cmd) ;
208
+ } ;
403
209
404
- if let Some ( p) = cwd {
405
- cmd. current_dir ( p) ;
406
- info ! ( "inside {:?}" , p. display( ) ) ;
210
+ if let Err ( e) = self . build_with_llvm ( kind) {
211
+ self . config . sess . fatal ( & format ! ( "failed to build archive: {}" , e) ) ;
407
212
}
408
213
409
- let sess = & self . config . sess ;
410
- match cmd. spawn ( ) {
411
- Ok ( prog) => {
412
- let o = prog. wait_with_output ( ) . unwrap ( ) ;
413
- if !o. status . success ( ) {
414
- sess. struct_err ( & format ! ( "{:?} failed with: {}" , cmd, o. status) )
415
- . note ( & format ! ( "stdout ---\n {}" ,
416
- str :: from_utf8( & o. stdout) . unwrap( ) ) )
417
- . note ( & format ! ( "stderr ---\n {}" ,
418
- str :: from_utf8( & o. stderr) . unwrap( ) ) )
419
- . emit ( ) ;
420
- sess. abort_if_errors ( ) ;
421
- }
422
- o
423
- } ,
424
- Err ( e) => {
425
- sess. fatal ( & format ! ( "could not exec `{}`: {}" ,
426
- self . config. ar_prog, e) ) ;
427
- }
428
- }
429
214
}
430
215
431
- fn prepare_ar_action ( & self , cmd : & mut Command , dst : & Path , action : Action ) {
432
- match action {
433
- Action :: Remove ( files) => {
434
- cmd. arg ( "d" ) . arg ( dst) . args ( files) ;
435
- }
436
- Action :: AddObjects ( objs, update_symbols) => {
437
- cmd. arg ( if update_symbols { "crs" } else { "crS" } )
438
- . arg ( dst)
439
- . args ( objs) ;
440
- }
441
- Action :: UpdateSymbols => {
442
- cmd. arg ( "s" ) . arg ( dst) ;
443
- }
444
- }
216
+ fn llvm_archive_kind ( & self ) -> Result < ArchiveKind , & str > {
217
+ let kind = & self . config . sess . target . target . options . archive_format [ ..] ;
218
+ kind. parse ( ) . map_err ( |_| kind)
445
219
}
446
220
447
221
fn build_with_llvm ( & mut self , kind : ArchiveKind ) -> io:: Result < ( ) > {
@@ -480,7 +254,7 @@ impl<'a> ArchiveBuilder<'a> {
480
254
strings. push ( path) ;
481
255
strings. push ( name) ;
482
256
}
483
- Addition :: Archive { archive, archive_name : _ , mut skip } => {
257
+ Addition :: Archive { archive, mut skip } => {
484
258
for child in archive. iter ( ) {
485
259
let child = child. map_err ( string_to_io_error) ?;
486
260
if !is_relevant_child ( & child) {
0 commit comments