| // Copyright 2017 Google Inc. All rights reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package cc |
| |
| import ( |
| "android/soong/android" |
| ) |
| |
| // LTO (link-time optimization) allows the compiler to optimize and generate |
| // code for the entire module at link time, rather than per-compilation |
| // unit. LTO is required for Clang CFI and other whole-program optimization |
| // techniques. LTO also allows cross-compilation unit optimizations that should |
| // result in faster and smaller code, at the expense of additional compilation |
| // time. |
| // |
| // To properly build a module with LTO, the module and all recursive static |
| // dependencies should be compiled with -flto which directs the compiler to emit |
| // bitcode rather than native object files. These bitcode files are then passed |
| // by the linker to the LLVM plugin for compilation at link time. Static |
| // dependencies not built as bitcode will still function correctly but cannot be |
| // optimized at link time and may not be compatible with features that require |
| // LTO, such as CFI. |
| // |
| // This file adds support to soong to automatically propogate LTO options to a |
| // new variant of all static dependencies for each module with LTO enabled. |
| |
| type LTOProperties struct { |
| // Lto must violate capitialization style for acronyms so that it can be |
| // referred to in blueprint files as "lto" |
| Lto struct { |
| Full *bool `android:"arch_variant"` |
| Thin *bool `android:"arch_variant"` |
| } `android:"arch_variant"` |
| LTODep bool `blueprint:"mutated"` |
| } |
| |
| type lto struct { |
| Properties LTOProperties |
| } |
| |
| func (lto *lto) props() []interface{} { |
| return []interface{}{<o.Properties} |
| } |
| |
| func (lto *lto) begin(ctx BaseModuleContext) { |
| } |
| |
| func (lto *lto) deps(ctx BaseModuleContext, deps Deps) Deps { |
| return deps |
| } |
| |
| func (lto *lto) flags(ctx BaseModuleContext, flags Flags) Flags { |
| if lto.LTO() { |
| var ltoFlag string |
| if Bool(lto.Properties.Lto.Thin) { |
| ltoFlag = "-flto=thin" |
| } else { |
| ltoFlag = "-flto" |
| } |
| |
| flags.CFlags = append(flags.CFlags, ltoFlag) |
| flags.LdFlags = append(flags.LdFlags, ltoFlag) |
| if ctx.Device() { |
| // Work around bug in Clang that doesn't pass correct emulated |
| // TLS option to target |
| flags.LdFlags = append(flags.LdFlags, "-Wl,-plugin-opt,-emulated-tls") |
| } |
| flags.ArFlags = append(flags.ArFlags, " --plugin ${config.LLVMGoldPlugin}") |
| } |
| return flags |
| } |
| |
| // Can be called with a null receiver |
| func (lto *lto) LTO() bool { |
| if lto == nil { |
| return false |
| } |
| |
| full := Bool(lto.Properties.Lto.Full) |
| thin := Bool(lto.Properties.Lto.Thin) |
| return full || thin |
| } |
| |
| // Propagate lto requirements down from binaries |
| func ltoDepsMutator(mctx android.TopDownMutatorContext) { |
| if c, ok := mctx.Module().(*Module); ok && c.lto.LTO() { |
| full := Bool(c.lto.Properties.Lto.Full) |
| thin := Bool(c.lto.Properties.Lto.Thin) |
| if full && thin { |
| mctx.PropertyErrorf("LTO", "FullLTO and ThinLTO are mutually exclusive") |
| } |
| |
| mctx.VisitDepsDepthFirst(func(m android.Module) { |
| tag := mctx.OtherModuleDependencyTag(m) |
| switch tag { |
| case staticDepTag, staticExportDepTag, lateStaticDepTag, wholeStaticDepTag, objDepTag, reuseObjTag: |
| if cc, ok := m.(*Module); ok && cc.lto != nil { |
| cc.lto.Properties.LTODep = true |
| } |
| } |
| }) |
| } |
| } |
| |
| // Create lto variants for modules that need them |
| func ltoMutator(mctx android.BottomUpMutatorContext) { |
| if c, ok := mctx.Module().(*Module); ok && c.lto != nil { |
| if c.lto.LTO() { |
| mctx.SetDependencyVariation("lto") |
| } else if c.lto.Properties.LTODep { |
| modules := mctx.CreateVariations("", "lto") |
| modules[0].(*Module).lto.Properties.Lto.Full = boolPtr(false) |
| modules[0].(*Module).lto.Properties.Lto.Thin = boolPtr(false) |
| modules[0].(*Module).lto.Properties.LTODep = false |
| modules[1].(*Module).lto.Properties.LTODep = false |
| modules[1].(*Module).Properties.PreventInstall = true |
| modules[1].(*Module).Properties.HideFromMake = true |
| } |
| c.lto.Properties.LTODep = false |
| } |
| } |