1
1
use crate :: core:: compiler:: { Context , Unit } ;
2
2
use crate :: core:: interning:: InternedString ;
3
3
use crate :: core:: profiles;
4
+ use crate :: core:: TargetKind ;
4
5
use crate :: util:: errors:: CargoResult ;
5
6
use std:: collections:: hash_map:: { Entry , HashMap } ;
6
7
@@ -26,7 +27,7 @@ pub enum Lto {
26
27
pub fn generate ( cx : & mut Context < ' _ , ' _ > ) -> CargoResult < ( ) > {
27
28
let mut map = HashMap :: new ( ) ;
28
29
for unit in cx. bcx . roots . iter ( ) {
29
- calculate ( cx, & mut map, unit, false ) ?;
30
+ calculate ( cx, & mut map, unit, Lto :: None ) ?;
30
31
}
31
32
cx. lto = map;
32
33
Ok ( ( ) )
@@ -36,34 +37,49 @@ fn calculate(
36
37
cx : & Context < ' _ , ' _ > ,
37
38
map : & mut HashMap < Unit , Lto > ,
38
39
unit : & Unit ,
39
- require_bitcode : bool ,
40
+ lto_for_deps : Lto ,
40
41
) -> CargoResult < ( ) > {
41
- let ( lto, require_bitcode_for_deps ) = if unit. target . for_host ( ) {
42
+ let ( lto, lto_for_deps ) = if unit. target . for_host ( ) {
42
43
// Disable LTO for host builds since we only really want to perform LTO
43
44
// for the final binary, and LTO on plugins/build scripts/proc macros is
44
45
// largely not desired.
45
- ( Lto :: None , false )
46
- } else if unit. target . can_lto ( ) {
47
- // Otherwise if this target can perform LTO then we're going to read the
48
- // LTO value out of the profile. Note that we ignore `require_bitcode`
46
+ ( Lto :: None , Lto :: None )
47
+ } else if unit. target . is_linkable ( ) {
48
+ // A "linkable" target is one that produces and rlib or dylib in this
49
+ // case. In this scenario we cannot pass `-Clto` to the compiler because
50
+ // that is an invalid request, this is simply a dependency. What we do,
51
+ // however, is respect the request for whatever dependencies need to
52
+ // have.
53
+ //
54
+ // Here if no LTO is requested then we keep it turned off. Otherwise LTO
55
+ // is requested in some form, which means ideally we need just what's
56
+ // requested, nothing else. It's possible, though, to have libraries
57
+ // which are both a cdylib and and rlib, for example, which means that
58
+ // object files are getting sent to the linker. That means that we need
59
+ // to fully embed bitcode rather than simply generating just bitcode.
60
+ let has_non_linkable_lib = match unit. target . kind ( ) {
61
+ TargetKind :: Lib ( kinds) => kinds. iter ( ) . any ( |k| !k. is_linkable ( ) ) ,
62
+ _ => true ,
63
+ } ;
64
+ match lto_for_deps {
65
+ Lto :: None => ( Lto :: None , Lto :: None ) ,
66
+ _ if has_non_linkable_lib => ( Lto :: EmbedBitcode , Lto :: EmbedBitcode ) ,
67
+ other => ( other, other) ,
68
+ }
69
+ } else {
70
+ // Otherwise this target can perform LTO and we're going to read the
71
+ // LTO value out of the profile. Note that we ignore `lto_for_deps`
49
72
// here because if a unit depends on another unit than can LTO this
50
73
// isn't a rustc-level dependency but rather a Cargo-level dependency.
51
74
// For example this is an integration test depending on a binary.
52
75
match unit. profile . lto {
53
76
profiles:: Lto :: Named ( s) => match s. as_str ( ) {
54
- "n" | "no" | "off" => ( Lto :: Run ( Some ( s) ) , false ) ,
55
- _ => ( Lto :: Run ( Some ( s) ) , true ) ,
77
+ "n" | "no" | "off" => ( Lto :: Run ( Some ( s) ) , Lto :: None ) ,
78
+ _ => ( Lto :: Run ( Some ( s) ) , Lto :: OnlyBitcode ) ,
56
79
} ,
57
- profiles:: Lto :: Bool ( true ) => ( Lto :: Run ( None ) , true ) ,
58
- profiles:: Lto :: Bool ( false ) => ( Lto :: None , false ) ,
80
+ profiles:: Lto :: Bool ( true ) => ( Lto :: Run ( None ) , Lto :: OnlyBitcode ) ,
81
+ profiles:: Lto :: Bool ( false ) => ( Lto :: None , Lto :: None ) ,
59
82
}
60
- } else if require_bitcode {
61
- // Otherwise we're a dependency of something, an rlib. This means that
62
- // if our parent required bitcode of some kind then we need to generate
63
- // bitcode.
64
- ( Lto :: OnlyBitcode , true )
65
- } else {
66
- ( Lto :: None , false )
67
83
} ;
68
84
69
85
match map. entry ( unit. clone ( ) ) {
@@ -93,14 +109,12 @@ fn calculate(
93
109
// either only-objects or only-bitcode we have to embed both in
94
110
// rlibs (used for different compilations), so we switch to
95
111
// embedding bitcode.
96
- ( Lto :: OnlyBitcode , Lto :: None )
97
- | ( Lto :: OnlyBitcode , Lto :: EmbedBitcode )
98
- | ( Lto :: None , Lto :: OnlyBitcode )
99
- | ( Lto :: None , Lto :: EmbedBitcode ) => Lto :: EmbedBitcode ,
112
+ ( Lto :: OnlyBitcode , Lto :: None ) | ( Lto :: None , Lto :: OnlyBitcode ) => Lto :: EmbedBitcode ,
100
113
101
- // Currently this variant is never calculated above, so no need
102
- // to handle this case.
103
- ( Lto :: EmbedBitcode , _) => unreachable ! ( ) ,
114
+ // Once a target has requested bitcode embedding that's the
115
+ // maximal amount of work that can be done, so we just keep
116
+ // doing that work.
117
+ ( Lto :: EmbedBitcode , _) | ( _, Lto :: EmbedBitcode ) => Lto :: EmbedBitcode ,
104
118
} ;
105
119
// No need to recurse if we calculated the same value as before.
106
120
if result == * v. get ( ) {
@@ -111,7 +125,7 @@ fn calculate(
111
125
}
112
126
113
127
for dep in cx. unit_deps ( unit) {
114
- calculate ( cx, map, & dep. unit , require_bitcode_for_deps ) ?;
128
+ calculate ( cx, map, & dep. unit , lto_for_deps ) ?;
115
129
}
116
130
Ok ( ( ) )
117
131
}
0 commit comments