1
- use crate :: core:: compiler:: { BuildOutput , CompileKind , CompileTarget , CrateType } ;
2
- use crate :: core:: { Dependency , TargetKind , Workspace } ;
1
+ use crate :: core:: compiler:: { BuildOutput , CompileKind , CompileMode , CompileTarget , CrateType } ;
2
+ use crate :: core:: { Dependency , Target , TargetKind , Workspace } ;
3
3
use crate :: util:: config:: { Config , StringList , TargetConfig } ;
4
4
use crate :: util:: { CargoResult , CargoResultExt , ProcessBuilder , Rustc } ;
5
5
use cargo_platform:: { Cfg , CfgExpr } ;
@@ -49,41 +49,73 @@ pub struct TargetInfo {
49
49
pub enum FileFlavor {
50
50
/// Not a special file type.
51
51
Normal ,
52
- /// Like `Normal`, but not directly executable
52
+ /// Like `Normal`, but not directly executable.
53
+ /// For example, a `.wasm` file paired with the "normal" `.js` file.
53
54
Auxiliary ,
54
55
/// Something you can link against (e.g., a library).
55
- Linkable { rmeta : bool } ,
56
+ Linkable ,
57
+ /// An `.rmeta` Rust metadata file.
58
+ Rmeta ,
56
59
/// Piece of external debug information (e.g., `.dSYM`/`.pdb` file).
57
60
DebugInfo ,
58
61
}
59
62
60
63
/// Type of each file generated by a Unit.
64
+ #[ derive( Debug ) ]
61
65
pub struct FileType {
62
66
/// The kind of file.
63
67
pub flavor : FileFlavor ,
68
+ /// The crate-type that generates this file.
69
+ ///
70
+ /// `None` for things that aren't associated with a specific crate type,
71
+ /// for example `rmeta` files.
72
+ pub crate_type : Option < CrateType > ,
64
73
/// The suffix for the file (for example, `.rlib`).
65
74
/// This is an empty string for executables on Unix-like platforms.
66
75
suffix : String ,
67
76
/// The prefix for the file (for example, `lib`).
68
77
/// This is an empty string for things like executables.
69
78
prefix : String ,
70
- /// Flag to convert hyphen to underscore.
71
- ///
72
- /// wasm bin targets will generate two files in deps such as
73
- /// "web-stuff.js" and "web_stuff.wasm". Note the different usages of "-"
74
- /// and "_". This flag indicates that the stem "web-stuff" should be
75
- /// converted to "web_stuff".
79
+ /// Flag to convert hyphen to underscore when uplifting.
76
80
should_replace_hyphens : bool ,
77
81
}
78
82
79
83
impl FileType {
80
- pub fn filename ( & self , stem : & str ) -> String {
81
- let stem = if self . should_replace_hyphens {
82
- stem. replace ( "-" , "_" )
84
+ /// The filename for this FileType crated by rustc.
85
+ pub fn output_filename ( & self , target : & Target , metadata : Option < & str > ) -> String {
86
+ match metadata {
87
+ Some ( metadata) => format ! (
88
+ "{}{}-{}{}" ,
89
+ self . prefix,
90
+ target. crate_name( ) ,
91
+ metadata,
92
+ self . suffix
93
+ ) ,
94
+ None => format ! ( "{}{}{}" , self . prefix, target. crate_name( ) , self . suffix) ,
95
+ }
96
+ }
97
+
98
+ /// The filename for this FileType that Cargo should use when "uplifting"
99
+ /// it to the destination directory.
100
+ pub fn uplift_filename ( & self , target : & Target ) -> String {
101
+ let name = if self . should_replace_hyphens {
102
+ target. crate_name ( )
83
103
} else {
84
- stem . to_string ( )
104
+ target . name ( ) . to_string ( )
85
105
} ;
86
- format ! ( "{}{}{}" , self . prefix, stem, self . suffix)
106
+ format ! ( "{}{}{}" , self . prefix, name, self . suffix)
107
+ }
108
+
109
+ /// Creates a new instance representing a `.rmeta` file.
110
+ pub fn new_rmeta ( ) -> FileType {
111
+ // Note that even binaries use the `lib` prefix.
112
+ FileType {
113
+ flavor : FileFlavor :: Rmeta ,
114
+ crate_type : None ,
115
+ suffix : ".rmeta" . to_string ( ) ,
116
+ prefix : "lib" . to_string ( ) ,
117
+ should_replace_hyphens : true ,
118
+ }
87
119
}
88
120
}
89
121
@@ -232,11 +264,10 @@ impl TargetInfo {
232
264
/// Returns the list of file types generated by the given crate type.
233
265
///
234
266
/// Returns `None` if the target does not support the given crate type.
235
- pub fn file_types (
267
+ fn file_types (
236
268
& self ,
237
269
crate_type : & CrateType ,
238
270
flavor : FileFlavor ,
239
- kind : & TargetKind ,
240
271
target_triple : & str ,
241
272
) -> CargoResult < Option < Vec < FileType > > > {
242
273
let crate_type = if * crate_type == CrateType :: Lib {
@@ -262,67 +293,109 @@ impl TargetInfo {
262
293
suffix: suffix. clone( ) ,
263
294
prefix: prefix. clone( ) ,
264
295
flavor,
265
- should_replace_hyphens: false ,
296
+ crate_type: Some ( crate_type. clone( ) ) ,
297
+ should_replace_hyphens: crate_type != CrateType :: Bin ,
266
298
} ] ;
267
299
268
- // See rust-lang/cargo#4500.
269
- if target_triple. ends_with ( "-windows-msvc" )
270
- && ( crate_type == CrateType :: Dylib || crate_type == CrateType :: Cdylib )
271
- && suffix == ".dll"
272
- {
273
- ret. push ( FileType {
274
- suffix : ".dll.lib" . to_string ( ) ,
275
- prefix : prefix. clone ( ) ,
276
- flavor : FileFlavor :: Normal ,
277
- should_replace_hyphens : false ,
278
- } )
279
- } else if target_triple. ends_with ( "windows-gnu" )
280
- && ( crate_type == CrateType :: Dylib || crate_type == CrateType :: Cdylib )
281
- && suffix == ".dll"
282
- {
283
- // LD can link DLL directly, but LLD requires the import library.
284
- ret. push ( FileType {
285
- suffix : ".dll.a" . to_string ( ) ,
286
- prefix : "lib" . to_string ( ) ,
287
- flavor : FileFlavor :: Normal ,
288
- should_replace_hyphens : false ,
289
- } )
300
+ // Window shared library import/export files.
301
+ if crate_type. is_dynamic ( ) {
302
+ if target_triple. ends_with ( "-windows-msvc" ) {
303
+ assert ! ( suffix == ".dll" ) ;
304
+ // See https://docs.microsoft.com/en-us/cpp/build/reference/working-with-import-libraries-and-export-files
305
+ // for more information about DLL import/export files.
306
+ ret. push ( FileType {
307
+ suffix : ".dll.lib" . to_string ( ) ,
308
+ prefix : prefix. clone ( ) ,
309
+ flavor : FileFlavor :: Auxiliary ,
310
+ crate_type : Some ( crate_type. clone ( ) ) ,
311
+ should_replace_hyphens : true ,
312
+ } ) ;
313
+ // NOTE: lld does not produce these
314
+ ret. push ( FileType {
315
+ suffix : ".dll.exp" . to_string ( ) ,
316
+ prefix : prefix. clone ( ) ,
317
+ flavor : FileFlavor :: Auxiliary ,
318
+ crate_type : Some ( crate_type. clone ( ) ) ,
319
+ should_replace_hyphens : true ,
320
+ } ) ;
321
+ } else if target_triple. ends_with ( "windows-gnu" ) {
322
+ assert ! ( suffix == ".dll" ) ;
323
+ // See https://cygwin.com/cygwin-ug-net/dll.html for more
324
+ // information about GNU import libraries.
325
+ // LD can link DLL directly, but LLD requires the import library.
326
+ ret. push ( FileType {
327
+ suffix : ".dll.a" . to_string ( ) ,
328
+ prefix : "lib" . to_string ( ) ,
329
+ flavor : FileFlavor :: Auxiliary ,
330
+ crate_type : Some ( crate_type. clone ( ) ) ,
331
+ should_replace_hyphens : true ,
332
+ } )
333
+ }
290
334
}
291
335
292
- // See rust-lang/cargo#4535.
293
336
if target_triple. starts_with ( "wasm32-" ) && crate_type == CrateType :: Bin && suffix == ".js" {
337
+ // emscripten binaries generate a .js file, which loads a .wasm
338
+ // file.
294
339
ret. push ( FileType {
295
340
suffix : ".wasm" . to_string ( ) ,
296
341
prefix : prefix. clone ( ) ,
297
342
flavor : FileFlavor :: Auxiliary ,
343
+ crate_type : Some ( crate_type. clone ( ) ) ,
344
+ // Name `foo-bar` will generate a `foo_bar.js` and
345
+ // `foo_bar.wasm`. Cargo will translate the underscore and
346
+ // copy `foo_bar.js` to `foo-bar.js`. However, the wasm
347
+ // filename is embedded in the .js file with an underscore, so
348
+ // it should not contain hyphens.
298
349
should_replace_hyphens : true ,
299
- } )
350
+ } ) ;
351
+ // And a map file for debugging. This is only emitted with debug=2
352
+ // (-g4 for emcc).
353
+ ret. push ( FileType {
354
+ suffix : ".wasm.map" . to_string ( ) ,
355
+ prefix : prefix. clone ( ) ,
356
+ flavor : FileFlavor :: DebugInfo ,
357
+ crate_type : Some ( crate_type. clone ( ) ) ,
358
+ should_replace_hyphens : true ,
359
+ } ) ;
300
360
}
301
361
302
- // See rust-lang/cargo#4490, rust-lang/cargo#4960.
303
- // Only uplift debuginfo for binaries.
304
- // - Tests are run directly from `target/debug/deps/` with the
305
- // metadata hash still in the filename.
306
- // - Examples are only uplifted for apple because the symbol file
307
- // needs to match the executable file name to be found (i.e., it
308
- // needs to remove the hash in the filename). On Windows, the path
309
- // to the .pdb with the hash is embedded in the executable.
362
+ // Handle separate debug files.
310
363
let is_apple = target_triple. contains ( "-apple-" ) ;
311
- if * kind == TargetKind :: Bin || ( * kind == TargetKind :: ExampleBin && is_apple) {
364
+ if matches ! (
365
+ crate_type,
366
+ CrateType :: Bin | CrateType :: Dylib | CrateType :: Cdylib | CrateType :: ProcMacro
367
+ ) {
312
368
if is_apple {
369
+ let suffix = if crate_type == CrateType :: Bin {
370
+ ".dSYM" . to_string ( )
371
+ } else {
372
+ ".dylib.dSYM" . to_string ( )
373
+ } ;
313
374
ret. push ( FileType {
314
- suffix : ".dSYM" . to_string ( ) ,
375
+ suffix,
315
376
prefix : prefix. clone ( ) ,
316
377
flavor : FileFlavor :: DebugInfo ,
378
+ crate_type : Some ( crate_type. clone ( ) ) ,
379
+ // macOS tools like lldb use all sorts of magic to locate
380
+ // dSYM files. See https://lldb.llvm.org/use/symbols.html
381
+ // for some details. It seems like a `.dSYM` located next
382
+ // to the executable with the same name is one method. The
383
+ // dSYM should have the same hyphens as the executable for
384
+ // the names to match.
317
385
should_replace_hyphens : false ,
318
386
} )
319
387
} else if target_triple. ends_with ( "-msvc" ) {
320
388
ret. push ( FileType {
321
389
suffix : ".pdb" . to_string ( ) ,
322
390
prefix : prefix. clone ( ) ,
323
391
flavor : FileFlavor :: DebugInfo ,
324
- // rustc calls the linker with underscores, and the
325
- // filename is embedded in the executable.
392
+ crate_type : Some ( crate_type. clone ( ) ) ,
393
+ // The absolute path to the pdb file is embedded in the
394
+ // executable. If the exe/pdb pair is moved to another
395
+ // machine, then debuggers will look in the same directory
396
+ // of the exe with the original pdb filename. Since the
397
+ // original name contains underscores, they need to be
398
+ // preserved.
326
399
should_replace_hyphens : true ,
327
400
} )
328
401
}
@@ -353,6 +426,62 @@ impl TargetInfo {
353
426
& mut output. lines ( ) ,
354
427
) ?)
355
428
}
429
+
430
+ /// Returns all the file types generated by rustc for the given mode/target_kind.
431
+ ///
432
+ /// The first value is a Vec of file types generated, the second value is
433
+ /// a list of CrateTypes that are not supported by the given target.
434
+ pub fn rustc_outputs (
435
+ & self ,
436
+ mode : CompileMode ,
437
+ target_kind : & TargetKind ,
438
+ target_triple : & str ,
439
+ ) -> CargoResult < ( Vec < FileType > , Vec < CrateType > ) > {
440
+ match mode {
441
+ CompileMode :: Build => self . calc_rustc_outputs ( target_kind, target_triple) ,
442
+ CompileMode :: Test | CompileMode :: Bench => {
443
+ match self . file_types ( & CrateType :: Bin , FileFlavor :: Normal , target_triple) ? {
444
+ Some ( fts) => Ok ( ( fts, Vec :: new ( ) ) ) ,
445
+ None => Ok ( ( Vec :: new ( ) , vec ! [ CrateType :: Bin ] ) ) ,
446
+ }
447
+ }
448
+ CompileMode :: Check { .. } => Ok ( ( vec ! [ FileType :: new_rmeta( ) ] , Vec :: new ( ) ) ) ,
449
+ CompileMode :: Doc { .. } | CompileMode :: Doctest | CompileMode :: RunCustomBuild => {
450
+ panic ! ( "asked for rustc output for non-rustc mode" )
451
+ }
452
+ }
453
+ }
454
+
455
+ fn calc_rustc_outputs (
456
+ & self ,
457
+ target_kind : & TargetKind ,
458
+ target_triple : & str ,
459
+ ) -> CargoResult < ( Vec < FileType > , Vec < CrateType > ) > {
460
+ let mut unsupported = Vec :: new ( ) ;
461
+ let mut result = Vec :: new ( ) ;
462
+ let crate_types = target_kind. rustc_crate_types ( ) ;
463
+ for crate_type in & crate_types {
464
+ let flavor = if crate_type. is_linkable ( ) {
465
+ FileFlavor :: Linkable
466
+ } else {
467
+ FileFlavor :: Normal
468
+ } ;
469
+ let file_types = self . file_types ( & crate_type, flavor, target_triple) ?;
470
+ match file_types {
471
+ Some ( types) => {
472
+ result. extend ( types) ;
473
+ }
474
+ None => {
475
+ unsupported. push ( crate_type. clone ( ) ) ;
476
+ }
477
+ }
478
+ }
479
+ if !result. is_empty ( ) && !crate_types. iter ( ) . any ( |ct| ct. requires_upstream_objects ( ) ) {
480
+ // Only add rmeta if pipelining.
481
+ result. push ( FileType :: new_rmeta ( ) ) ;
482
+ }
483
+ Ok ( ( result, unsupported) )
484
+ }
356
485
}
357
486
358
487
/// Takes rustc output (using specialized command line args), and calculates the file prefix and
@@ -537,9 +666,7 @@ pub struct RustcTargetData {
537
666
host_info : TargetInfo ,
538
667
539
668
/// Build information for targets that we're building for. This will be
540
- /// empty if the `--target` flag is not passed, and currently also only ever
541
- /// has at most one entry, but eventually we'd like to support multi-target
542
- /// builds with Cargo.
669
+ /// empty if the `--target` flag is not passed.
543
670
target_config : HashMap < CompileTarget , TargetConfig > ,
544
671
target_info : HashMap < CompileTarget , TargetInfo > ,
545
672
}
0 commit comments