blob: fdb768836b1d7bbc8b07abc5953b56764c50af62 [file] [log] [blame]
Stephen Craneba090d12017-05-09 15:44:35 -07001// Copyright 2017 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package cc
16
17import (
Stephen Craneba090d12017-05-09 15:44:35 -070018 "android/soong/android"
19)
20
21// LTO (link-time optimization) allows the compiler to optimize and generate
22// code for the entire module at link time, rather than per-compilation
23// unit. LTO is required for Clang CFI and other whole-program optimization
24// techniques. LTO also allows cross-compilation unit optimizations that should
25// result in faster and smaller code, at the expense of additional compilation
26// time.
27//
28// To properly build a module with LTO, the module and all recursive static
29// dependencies should be compiled with -flto which directs the compiler to emit
30// bitcode rather than native object files. These bitcode files are then passed
31// by the linker to the LLVM plugin for compilation at link time. Static
32// dependencies not built as bitcode will still function correctly but cannot be
33// optimized at link time and may not be compatible with features that require
34// LTO, such as CFI.
35//
36// This file adds support to soong to automatically propogate LTO options to a
37// new variant of all static dependencies for each module with LTO enabled.
38
39type LTOProperties struct {
40 // Lto must violate capitialization style for acronyms so that it can be
41 // referred to in blueprint files as "lto"
Yi Kong244bf072017-08-29 11:10:09 +080042 Lto struct {
43 Full *bool `android:"arch_variant"`
44 Thin *bool `android:"arch_variant"`
45 } `android:"arch_variant"`
46 LTODep bool `blueprint:"mutated"`
Stephen Craneba090d12017-05-09 15:44:35 -070047}
48
49type lto struct {
50 Properties LTOProperties
51}
52
53func (lto *lto) props() []interface{} {
54 return []interface{}{&lto.Properties}
55}
56
57func (lto *lto) begin(ctx BaseModuleContext) {
58}
59
60func (lto *lto) deps(ctx BaseModuleContext, deps Deps) Deps {
61 return deps
62}
63
64func (lto *lto) flags(ctx BaseModuleContext, flags Flags) Flags {
Yi Kong244bf072017-08-29 11:10:09 +080065 if lto.LTO() {
66 var ltoFlag string
67 if Bool(lto.Properties.Lto.Thin) {
68 ltoFlag = "-flto=thin"
69 } else {
70 ltoFlag = "-flto"
71 }
72
73 flags.CFlags = append(flags.CFlags, ltoFlag)
74 flags.LdFlags = append(flags.LdFlags, ltoFlag)
Stephen Cranef5b9b952017-06-30 19:03:36 -070075 if ctx.Device() {
76 // Work around bug in Clang that doesn't pass correct emulated
77 // TLS option to target
78 flags.LdFlags = append(flags.LdFlags, "-Wl,-plugin-opt,-emulated-tls")
79 }
Stephen Craneba090d12017-05-09 15:44:35 -070080 flags.ArFlags = append(flags.ArFlags, " --plugin ${config.LLVMGoldPlugin}")
81 }
82 return flags
83}
84
85// Can be called with a null receiver
86func (lto *lto) LTO() bool {
87 if lto == nil {
88 return false
89 }
90
Yi Kong244bf072017-08-29 11:10:09 +080091 full := Bool(lto.Properties.Lto.Full)
92 thin := Bool(lto.Properties.Lto.Thin)
93 return full || thin
Stephen Craneba090d12017-05-09 15:44:35 -070094}
95
96// Propagate lto requirements down from binaries
97func ltoDepsMutator(mctx android.TopDownMutatorContext) {
98 if c, ok := mctx.Module().(*Module); ok && c.lto.LTO() {
Yi Kong244bf072017-08-29 11:10:09 +080099 full := Bool(c.lto.Properties.Lto.Full)
100 thin := Bool(c.lto.Properties.Lto.Thin)
101 if full && thin {
102 mctx.PropertyErrorf("LTO", "FullLTO and ThinLTO are mutually exclusive")
103 }
104
Colin Crossd11fcda2017-10-23 17:59:01 -0700105 mctx.VisitDepsDepthFirst(func(m android.Module) {
Stephen Craneba090d12017-05-09 15:44:35 -0700106 tag := mctx.OtherModuleDependencyTag(m)
107 switch tag {
108 case staticDepTag, staticExportDepTag, lateStaticDepTag, wholeStaticDepTag, objDepTag, reuseObjTag:
109 if cc, ok := m.(*Module); ok && cc.lto != nil {
110 cc.lto.Properties.LTODep = true
111 }
112 }
113 })
114 }
115}
116
117// Create lto variants for modules that need them
118func ltoMutator(mctx android.BottomUpMutatorContext) {
119 if c, ok := mctx.Module().(*Module); ok && c.lto != nil {
120 if c.lto.LTO() {
121 mctx.SetDependencyVariation("lto")
122 } else if c.lto.Properties.LTODep {
123 modules := mctx.CreateVariations("", "lto")
Yi Kong244bf072017-08-29 11:10:09 +0800124 modules[0].(*Module).lto.Properties.Lto.Full = boolPtr(false)
125 modules[0].(*Module).lto.Properties.Lto.Thin = boolPtr(false)
Stephen Craneba090d12017-05-09 15:44:35 -0700126 modules[0].(*Module).lto.Properties.LTODep = false
127 modules[1].(*Module).lto.Properties.LTODep = false
128 modules[1].(*Module).Properties.PreventInstall = true
129 modules[1].(*Module).Properties.HideFromMake = true
130 }
131 c.lto.Properties.LTODep = false
132 }
133}