blob: f496772446fa8604988bd41cfbf16c81d8128af0 [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 (
18 "github.com/google/blueprint"
19
20 "android/soong/android"
21)
22
23// LTO (link-time optimization) allows the compiler to optimize and generate
24// code for the entire module at link time, rather than per-compilation
25// unit. LTO is required for Clang CFI and other whole-program optimization
26// techniques. LTO also allows cross-compilation unit optimizations that should
27// result in faster and smaller code, at the expense of additional compilation
28// time.
29//
30// To properly build a module with LTO, the module and all recursive static
31// dependencies should be compiled with -flto which directs the compiler to emit
32// bitcode rather than native object files. These bitcode files are then passed
33// by the linker to the LLVM plugin for compilation at link time. Static
34// dependencies not built as bitcode will still function correctly but cannot be
35// optimized at link time and may not be compatible with features that require
36// LTO, such as CFI.
37//
38// This file adds support to soong to automatically propogate LTO options to a
39// new variant of all static dependencies for each module with LTO enabled.
40
41type LTOProperties struct {
42 // Lto must violate capitialization style for acronyms so that it can be
43 // referred to in blueprint files as "lto"
44 Lto *bool `android:"arch_variant"`
45 LTODep bool `blueprint:"mutated"`
46}
47
48type lto struct {
49 Properties LTOProperties
50}
51
52func (lto *lto) props() []interface{} {
53 return []interface{}{&lto.Properties}
54}
55
56func (lto *lto) begin(ctx BaseModuleContext) {
57}
58
59func (lto *lto) deps(ctx BaseModuleContext, deps Deps) Deps {
60 return deps
61}
62
63func (lto *lto) flags(ctx BaseModuleContext, flags Flags) Flags {
64 if Bool(lto.Properties.Lto) {
65 flags.CFlags = append(flags.CFlags, "-flto")
66 flags.LdFlags = append(flags.LdFlags, "-flto")
Stephen Cranef5b9b952017-06-30 19:03:36 -070067 if ctx.Device() {
68 // Work around bug in Clang that doesn't pass correct emulated
69 // TLS option to target
70 flags.LdFlags = append(flags.LdFlags, "-Wl,-plugin-opt,-emulated-tls")
71 }
Stephen Craneba090d12017-05-09 15:44:35 -070072 flags.ArFlags = append(flags.ArFlags, " --plugin ${config.LLVMGoldPlugin}")
73 }
74 return flags
75}
76
77// Can be called with a null receiver
78func (lto *lto) LTO() bool {
79 if lto == nil {
80 return false
81 }
82
83 return Bool(lto.Properties.Lto)
84}
85
86// Propagate lto requirements down from binaries
87func ltoDepsMutator(mctx android.TopDownMutatorContext) {
88 if c, ok := mctx.Module().(*Module); ok && c.lto.LTO() {
89 mctx.VisitDepsDepthFirst(func(m blueprint.Module) {
90 tag := mctx.OtherModuleDependencyTag(m)
91 switch tag {
92 case staticDepTag, staticExportDepTag, lateStaticDepTag, wholeStaticDepTag, objDepTag, reuseObjTag:
93 if cc, ok := m.(*Module); ok && cc.lto != nil {
94 cc.lto.Properties.LTODep = true
95 }
96 }
97 })
98 }
99}
100
101// Create lto variants for modules that need them
102func ltoMutator(mctx android.BottomUpMutatorContext) {
103 if c, ok := mctx.Module().(*Module); ok && c.lto != nil {
104 if c.lto.LTO() {
105 mctx.SetDependencyVariation("lto")
106 } else if c.lto.Properties.LTODep {
107 modules := mctx.CreateVariations("", "lto")
108 modules[0].(*Module).lto.Properties.Lto = boolPtr(false)
109 modules[1].(*Module).lto.Properties.Lto = boolPtr(true)
110 modules[0].(*Module).lto.Properties.LTODep = false
111 modules[1].(*Module).lto.Properties.LTODep = false
112 modules[1].(*Module).Properties.PreventInstall = true
113 modules[1].(*Module).Properties.HideFromMake = true
114 }
115 c.lto.Properties.LTODep = false
116 }
117}