@@ -308,71 +308,144 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
308
308
}
309
309
310
310
/// Get the metadata for a target in a specific profile
311
+ /// We build to the path: "{filename}-{target_metadata}"
312
+ /// We use a linking step to link/copy to a predictable filename
313
+ /// like `target/debug/libfoo.{a,so,rlib}` and such.
311
314
pub fn target_metadata ( & self , unit : & Unit ) -> Option < Metadata > {
312
- let metadata = unit. target . metadata ( ) ;
315
+ // No metadata for dylibs because of a couple issues
316
+ // - OSX encodes the dylib name in the executable
317
+ // - Windows rustc multiple files of which we can't easily link all of them
318
+ //
319
+ // Two expeptions
320
+ // 1) Upstream dependencies (we aren't exporting + need to resolve name conflict)
321
+ // 2) __CARGO_DEFAULT_LIB_METADATA env var
322
+ //
323
+ // Note, though, that the compiler's build system at least wants
324
+ // path dependencies (eg libstd) to have hashes in filenames. To account for
325
+ // that we have an extra hack here which reads the
326
+ // `__CARGO_DEFAULT_METADATA` environment variable and creates a
327
+ // hash in the filename if that's present.
328
+ //
329
+ // This environment variable should not be relied on! It's
330
+ // just here for rustbuild. We need a more principled method
331
+ // doing this eventually.
332
+ if !unit. profile . test &&
333
+ unit. target . is_dylib ( ) &&
334
+ unit. pkg . package_id ( ) . source_id ( ) . is_path ( ) &&
335
+ !env:: var ( "__CARGO_DEFAULT_LIB_METADATA" ) . is_ok ( ) {
336
+ return None ;
337
+ }
338
+
339
+ let metadata = unit. target . metadata ( ) . cloned ( ) . map ( |mut m| {
340
+ if let Some ( features) = self . resolve . features ( unit. pkg . package_id ( ) ) {
341
+ let mut feat_vec: Vec < & String > = features. iter ( ) . collect ( ) ;
342
+ feat_vec. sort ( ) ;
343
+ for feat in feat_vec {
344
+ m. mix ( feat) ;
345
+ }
346
+ }
347
+ m. mix ( unit. profile ) ;
348
+ m
349
+ } ) ;
350
+ let mut pkg_metadata = {
351
+ let mut m = unit. pkg . generate_metadata ( ) ;
352
+ if let Some ( features) = self . resolve . features ( unit. pkg . package_id ( ) ) {
353
+ let mut feat_vec: Vec < & String > = features. iter ( ) . collect ( ) ;
354
+ feat_vec. sort ( ) ;
355
+ for feat in feat_vec {
356
+ m. mix ( feat) ;
357
+ }
358
+ }
359
+ m. mix ( unit. profile ) ;
360
+ m
361
+ } ;
362
+
313
363
if unit. target . is_lib ( ) && unit. profile . test {
314
364
// Libs and their tests are built in parallel, so we need to make
315
365
// sure that their metadata is different.
316
- metadata. cloned ( ) . map ( |mut m| {
366
+ metadata. map ( |mut m| {
317
367
m. mix ( & "test" ) ;
318
368
m
319
369
} )
320
370
} else if unit. target . is_bin ( ) && unit. profile . test {
321
371
// Make sure that the name of this test executable doesn't
322
372
// conflict with a library that has the same name and is
323
373
// being tested
324
- let mut metadata = unit. pkg . generate_metadata ( ) ;
325
- metadata. mix ( & format ! ( "bin-{}" , unit. target. name( ) ) ) ;
326
- Some ( metadata)
374
+ pkg_metadata. mix ( & format ! ( "bin-{}" , unit. target. name( ) ) ) ;
375
+ Some ( pkg_metadata)
327
376
} else if unit. pkg . package_id ( ) . source_id ( ) . is_path ( ) &&
328
377
!unit. profile . test {
329
- // If we're not building a unit test but we're building a path
330
- // dependency, then we're likely compiling the "current package" or
331
- // some package in a workspace. In this situation we pass no
332
- // metadata by default so we'll have predictable
333
- // file names like `target/debug/libfoo.{a,so,rlib}` and such.
334
- //
335
- // Note, though, that the compiler's build system at least wants
336
- // path dependencies to have hashes in filenames. To account for
337
- // that we have an extra hack here which reads the
338
- // `__CARGO_DEFAULT_METADATA` environment variable and creates a
339
- // hash in the filename if that's present.
340
- //
341
- // This environment variable should not be relied on! It's basically
342
- // just here for rustbuild. We need a more principled method of
343
- // doing this eventually.
344
- if unit. target . is_lib ( ) {
345
- env:: var ( "__CARGO_DEFAULT_LIB_METADATA" ) . ok ( ) . map ( |meta| {
346
- let mut metadata = unit. pkg . generate_metadata ( ) ;
347
- metadata. mix ( & meta) ;
348
- metadata
349
- } )
350
- } else {
351
- None
352
- }
378
+ Some ( pkg_metadata)
353
379
} else {
354
- metadata. cloned ( )
380
+ metadata
355
381
}
356
382
}
357
383
358
- /// Returns the file stem for a given target/profile combo
384
+ /// Returns the file stem for a given target/profile combo (with metadata)
359
385
pub fn file_stem ( & self , unit : & Unit ) -> String {
360
386
match self . target_metadata ( unit) {
361
387
Some ( ref metadata) => format ! ( "{}{}" , unit. target. crate_name( ) ,
362
388
metadata. extra_filename) ,
363
- None if unit. target . allows_underscores ( ) => {
364
- unit. target . name ( ) . to_string ( )
389
+ None => self . bin_stem ( unit) ,
390
+ }
391
+ }
392
+
393
+ /// Returns the bin stem for a given target (without metadata)
394
+ fn bin_stem ( & self , unit : & Unit ) -> String {
395
+ if unit. target . allows_underscores ( ) {
396
+ unit. target . name ( ) . to_string ( )
397
+ } else {
398
+ unit. target . crate_name ( )
399
+ }
400
+ }
401
+
402
+ /// Returns a tuple with the directory and name of the hard link we expect
403
+ /// our target to be copied to. Eg, file_stem may be out_dir/deps/foo-abcdef
404
+ /// and link_stem would be out_dir/foo
405
+ /// This function returns it in two parts so the caller can add prefix/suffis
406
+ /// to filename separately
407
+
408
+ /// Returns an Option because in some cases we don't want to link
409
+ /// (eg a dependent lib)
410
+ pub fn link_stem ( & self , unit : & Unit ) -> Option < ( PathBuf , String ) > {
411
+ let src_dir = self . out_dir ( unit) ;
412
+ let bin_stem = self . bin_stem ( unit) ;
413
+ let file_stem = self . file_stem ( unit) ;
414
+
415
+ // We currently only lift files up from the `deps` directory. If
416
+ // it was compiled into something like `example/` or `doc/` then
417
+ // we don't want to link it up.
418
+ if src_dir. ends_with ( "deps" ) {
419
+ // Don't lift up library dependencies
420
+ if unit. pkg . package_id ( ) != & self . current_package && !unit. target . is_bin ( ) {
421
+ None
422
+ } else {
423
+ Some ( (
424
+ src_dir. parent ( ) . unwrap ( ) . to_owned ( ) ,
425
+ if unit. profile . test { file_stem} else { bin_stem} ,
426
+ ) )
365
427
}
366
- None => unit. target . crate_name ( ) ,
428
+ } else if bin_stem == file_stem {
429
+ None
430
+ } else if src_dir. ends_with ( "examples" ) {
431
+ Some ( ( src_dir, bin_stem) )
432
+ } else if src_dir. parent ( ) . unwrap ( ) . ends_with ( "build" ) {
433
+ Some ( ( src_dir, bin_stem) )
434
+ } else {
435
+ None
367
436
}
368
437
}
369
438
370
439
/// Return the filenames that the given target for the given profile will
371
- /// generate, along with whether you can link against that file (e.g. it's a
372
- /// library).
440
+ /// generate as a list of 3-tuples (filename, link_dst, linkable)
441
+ /// filename: filename rustc compiles to. (Often has metadata suffix).
442
+ /// link_dst: Optional file to link/copy the result to (without metadata suffix)
443
+ /// linkable: Whether possible to link against file (eg it's a library)
373
444
pub fn target_filenames ( & self , unit : & Unit )
374
- -> CargoResult < Vec < ( String , bool ) > > {
445
+ -> CargoResult < Vec < ( PathBuf , Option < PathBuf > , bool ) > > {
446
+ let out_dir = self . out_dir ( unit) ;
375
447
let stem = self . file_stem ( unit) ;
448
+ let link_stem = self . link_stem ( unit) ;
376
449
let info = if unit. target . for_host ( ) {
377
450
& self . host_info
378
451
} else {
@@ -386,8 +459,11 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
386
459
let crate_type = if crate_type == "lib" { "rlib" } else { crate_type} ;
387
460
match info. crate_types . get ( crate_type) {
388
461
Some ( & Some ( ( ref prefix, ref suffix) ) ) => {
389
- ret. push ( ( format ! ( "{}{}{}" , prefix, stem, suffix) ,
390
- linkable) ) ;
462
+ let filename = out_dir. join ( format ! ( "{}{}{}" , prefix, stem, suffix) ) ;
463
+ let link_dst = link_stem. clone ( ) . map ( |( ld, ls) | {
464
+ ld. join ( format ! ( "{}{}{}" , prefix, ls, suffix) )
465
+ } ) ;
466
+ ret. push ( ( filename, link_dst, linkable) ) ;
391
467
Ok ( ( ) )
392
468
}
393
469
// not supported, don't worry about it
@@ -429,6 +505,7 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
429
505
support any of the output crate types",
430
506
unit. pkg, self . target_triple( ) ) ;
431
507
}
508
+ info ! ( "Target filenames: {:?}" , ret) ;
432
509
Ok ( ret)
433
510
}
434
511
0 commit comments