platform_build_soong/cc/cc.go

1438 lines
42 KiB
Go
Raw Normal View History

// Copyright 2015 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
// This file contains the module types for compiling C/C++ for Android, and converts the properties
// into the flags and filenames necessary to pass to the compiler. The final creation of the rules
// is handled in builder.go
import (
"strconv"
"strings"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
"android/soong/android"
"android/soong/cc/config"
"android/soong/genrule"
)
func init() {
android.RegisterModuleType("cc_defaults", defaultsFactory)
android.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
ctx.BottomUp("image", vendorMutator).Parallel()
ctx.BottomUp("link", linkageMutator).Parallel()
ctx.BottomUp("vndk", vndkMutator).Parallel()
ctx.BottomUp("ndk_api", ndkApiMutator).Parallel()
ctx.BottomUp("test_per_src", testPerSrcMutator).Parallel()
ctx.BottomUp("begin", beginMutator).Parallel()
})
android.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
ctx.TopDown("asan_deps", sanitizerDepsMutator(asan))
ctx.BottomUp("asan", sanitizerMutator(asan)).Parallel()
ctx.TopDown("cfi_deps", sanitizerDepsMutator(cfi))
ctx.BottomUp("cfi", sanitizerMutator(cfi)).Parallel()
ctx.TopDown("tsan_deps", sanitizerDepsMutator(tsan))
ctx.BottomUp("tsan", sanitizerMutator(tsan)).Parallel()
ctx.BottomUp("coverage", coverageLinkingMutator).Parallel()
ctx.TopDown("vndk_deps", sabiDepsMutator)
ctx.TopDown("lto_deps", ltoDepsMutator)
ctx.BottomUp("lto", ltoMutator).Parallel()
})
pctx.Import("android/soong/cc/config")
}
type Deps struct {
SharedLibs, LateSharedLibs []string
StaticLibs, LateStaticLibs, WholeStaticLibs []string
HeaderLibs []string
ReexportSharedLibHeaders, ReexportStaticLibHeaders, ReexportHeaderLibHeaders []string
ObjFiles []string
GeneratedSources []string
GeneratedHeaders []string
ReexportGeneratedHeaders []string
CrtBegin, CrtEnd string
LinkerScript string
}
type PathDeps struct {
// Paths to .so files
SharedLibs, LateSharedLibs android.Paths
// Paths to the dependencies to use for .so files (.so.toc files)
SharedLibsDeps, LateSharedLibsDeps android.Paths
// Paths to .a files
StaticLibs, LateStaticLibs, WholeStaticLibs android.Paths
// Paths to .o files
Objs Objects
StaticLibObjs Objects
WholeStaticLibObjs Objects
// Paths to generated source files
GeneratedSources android.Paths
GeneratedHeaders android.Paths
Flags, ReexportedFlags []string
ReexportedFlagsDeps android.Paths
// Paths to crt*.o files
CrtBegin, CrtEnd android.OptionalPath
LinkerScript android.OptionalPath
}
type Flags struct {
GlobalFlags []string // Flags that apply to C, C++, and assembly source files
ArFlags []string // Flags that apply to ar
AsFlags []string // Flags that apply to assembly source files
CFlags []string // Flags that apply to C and C++ source files
ToolingCFlags []string // Flags that apply to C and C++ source files parsed by clang LibTooling tools
ConlyFlags []string // Flags that apply to C source files
CppFlags []string // Flags that apply to C++ source files
ToolingCppFlags []string // Flags that apply to C++ source files parsed by clang LibTooling tools
YaccFlags []string // Flags that apply to Yacc source files
protoFlags []string // Flags that apply to proto source files
aidlFlags []string // Flags that apply to aidl source files
rsFlags []string // Flags that apply to renderscript source files
LdFlags []string // Flags that apply to linker command lines
libFlags []string // Flags to add libraries early to the link order
TidyFlags []string // Flags that apply to clang-tidy
SAbiFlags []string // Flags that apply to header-abi-dumper
YasmFlags []string // Flags that apply to yasm assembly source files
// Global include flags that apply to C, C++, and assembly source files
// These must be after any module include flags, which will be in GlobalFlags.
SystemIncludeFlags []string
Toolchain config.Toolchain
Clang bool
Tidy bool
Coverage bool
SAbiDump bool
RequiredInstructionSet string
DynamicLinker string
CFlagsDeps android.Paths // Files depended on by compiler flags
LdFlagsDeps android.Paths // Files depended on by linker flags
GroupStaticLibs bool
}
type ObjectLinkerProperties struct {
// names of other cc_object modules to link into this module using partial linking
Objs []string `android:"arch_variant"`
// if set, add an extra objcopy --prefix-symbols= step
Prefix_symbols *string
}
// Properties used to compile all C or C++ modules
type BaseProperties struct {
// compile module with clang instead of gcc
Clang *bool `android:"arch_variant"`
// Minimum sdk version supported when compiling against the ndk
Sdk_version *string
AndroidMkSharedLibs []string `blueprint:"mutated"`
HideFromMake bool `blueprint:"mutated"`
PreventInstall bool `blueprint:"mutated"`
UseVndk bool `blueprint:"mutated"`
}
type VendorProperties struct {
// whether this module should be allowed to be directly depended by other
// modules with `vendor: true`, `proprietary: true`, or `vendor_available:true`.
// If set to true, two variants will be built separately, one like
// normal, and the other limited to the set of libraries and headers
// that are exposed to /vendor modules.
Split /system and /vendor modules, allow multi-installation Nothing changes if BOARD_VNDK_VERSION isn't set. When the VNDK is enabled (BOARD_VNDK_VERSION in Make), this will split /system and /vendor modules into two different variant spaces that can't link to each other. There are a few interfaces between the two variant spaces: The `llndk_library` stubs will be available in the /vendor variant, but won't be installed, so at runtime the /system variant will be used. Setting `vendor_available: true` will split a module into both variants. The /system (or "core") variant will compile just like today. The /vendor ("vendor") variant will compile against everything else in the vendor space (so LL-NDK instead of libc/liblog/etc). There will be two copies of these libraries installed onto the final device. Since the available runtime interfaces for vendor modules may be reduced, and your dependencies may not expose their private interfaces, we allow the vendor variants to reduce their compilation set, and export a different set of headers: cc_library { name: "libfoo", srcs: ["common.cpp", "private_impl.cpp"], export_include_dirs: ["include"], target: { vendor: { export_include_dirs: ["include_vndk"], exclude_srcs: ["private_impl.cpp"], srcs: ["vendor_only.cpp"], }, }, } So the "core" variant would compile with both "common.cpp" and "private_impl.cpp", and export "include". The "vendor" variant would compile "common.cpp" and "vendor_only.cpp", and export "include_vndk". Bug: 36426473 Bug: 36079834 Test: out/soong/build.ninja, out/soong/Android- only changes due to _core addition and .llndk -> .vendor Test: attempt to compile with BOARD_VNDK_VERSION:=current Change-Id: Idef28764043bf6c33dc0d2e7e2026c38867ff769
2017-04-06 21:43:22 +02:00
//
// The vendor variant may be used with a different (newer) /system,
// so it shouldn't have any unversioned runtime dependencies, or
// make assumptions about the system that may not be true in the
// future.
//
// If set to false, this module becomes inaccessible from /vendor modules.
//
// Default value is true when vndk: {enabled: true} or vendor: true.
//
Split /system and /vendor modules, allow multi-installation Nothing changes if BOARD_VNDK_VERSION isn't set. When the VNDK is enabled (BOARD_VNDK_VERSION in Make), this will split /system and /vendor modules into two different variant spaces that can't link to each other. There are a few interfaces between the two variant spaces: The `llndk_library` stubs will be available in the /vendor variant, but won't be installed, so at runtime the /system variant will be used. Setting `vendor_available: true` will split a module into both variants. The /system (or "core") variant will compile just like today. The /vendor ("vendor") variant will compile against everything else in the vendor space (so LL-NDK instead of libc/liblog/etc). There will be two copies of these libraries installed onto the final device. Since the available runtime interfaces for vendor modules may be reduced, and your dependencies may not expose their private interfaces, we allow the vendor variants to reduce their compilation set, and export a different set of headers: cc_library { name: "libfoo", srcs: ["common.cpp", "private_impl.cpp"], export_include_dirs: ["include"], target: { vendor: { export_include_dirs: ["include_vndk"], exclude_srcs: ["private_impl.cpp"], srcs: ["vendor_only.cpp"], }, }, } So the "core" variant would compile with both "common.cpp" and "private_impl.cpp", and export "include". The "vendor" variant would compile "common.cpp" and "vendor_only.cpp", and export "include_vndk". Bug: 36426473 Bug: 36079834 Test: out/soong/build.ninja, out/soong/Android- only changes due to _core addition and .llndk -> .vendor Test: attempt to compile with BOARD_VNDK_VERSION:=current Change-Id: Idef28764043bf6c33dc0d2e7e2026c38867ff769
2017-04-06 21:43:22 +02:00
// Nothing happens if BOARD_VNDK_VERSION isn't set in the BoardConfig.mk
Vendor_available *bool
}
type UnusedProperties struct {
Tags []string
}
type ModuleContextIntf interface {
static() bool
staticBinary() bool
clang() bool
toolchain() config.Toolchain
useSdk() bool
sdkVersion() string
useVndk() bool
isVndk() bool
isVndkSp() bool
createVndkSourceAbiDump() bool
selectedStl() string
baseModuleName() string
}
type ModuleContext interface {
android.ModuleContext
ModuleContextIntf
}
type BaseModuleContext interface {
android.BaseContext
ModuleContextIntf
}
type DepsContext interface {
android.BottomUpMutatorContext
ModuleContextIntf
}
type feature interface {
begin(ctx BaseModuleContext)
deps(ctx DepsContext, deps Deps) Deps
flags(ctx ModuleContext, flags Flags) Flags
props() []interface{}
}
type compiler interface {
compilerInit(ctx BaseModuleContext)
compilerDeps(ctx DepsContext, deps Deps) Deps
compilerFlags(ctx ModuleContext, flags Flags) Flags
compilerProps() []interface{}
appendCflags([]string)
appendAsflags([]string)
compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects
}
type linker interface {
linkerInit(ctx BaseModuleContext)
linkerDeps(ctx DepsContext, deps Deps) Deps
linkerFlags(ctx ModuleContext, flags Flags) Flags
linkerProps() []interface{}
link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path
appendLdflags([]string)
}
type installer interface {
installerProps() []interface{}
install(ctx ModuleContext, path android.Path)
inData() bool
inSanitizerDir() bool
hostToolPath() android.OptionalPath
}
type dependencyTag struct {
blueprint.BaseDependencyTag
name string
library bool
reexportFlags bool
}
var (
sharedDepTag = dependencyTag{name: "shared", library: true}
sharedExportDepTag = dependencyTag{name: "shared", library: true, reexportFlags: true}
lateSharedDepTag = dependencyTag{name: "late shared", library: true}
staticDepTag = dependencyTag{name: "static", library: true}
staticExportDepTag = dependencyTag{name: "static", library: true, reexportFlags: true}
lateStaticDepTag = dependencyTag{name: "late static", library: true}
wholeStaticDepTag = dependencyTag{name: "whole static", library: true, reexportFlags: true}
headerDepTag = dependencyTag{name: "header", library: true}
headerExportDepTag = dependencyTag{name: "header", library: true, reexportFlags: true}
genSourceDepTag = dependencyTag{name: "gen source"}
genHeaderDepTag = dependencyTag{name: "gen header"}
genHeaderExportDepTag = dependencyTag{name: "gen header", reexportFlags: true}
objDepTag = dependencyTag{name: "obj"}
crtBeginDepTag = dependencyTag{name: "crtbegin"}
crtEndDepTag = dependencyTag{name: "crtend"}
linkerScriptDepTag = dependencyTag{name: "linker script"}
reuseObjTag = dependencyTag{name: "reuse objects"}
ndkStubDepTag = dependencyTag{name: "ndk stub", library: true}
ndkLateStubDepTag = dependencyTag{name: "ndk late stub", library: true}
)
// Module contains the properties and members used by all C/C++ module types, and implements
// the blueprint.Module interface. It delegates to compiler, linker, and installer interfaces
// to construct the output file. Behavior can be customized with a Customizer interface
type Module struct {
android.ModuleBase
android.DefaultableModuleBase
Properties BaseProperties
VendorProperties VendorProperties
unused UnusedProperties
// initialize before calling Init
hod android.HostOrDeviceSupported
multilib android.Multilib
// delegates, initialize before calling Init
features []feature
compiler compiler
linker linker
installer installer
stl *stl
sanitize *sanitize
coverage *coverage
sabi *sabi
vndkdep *vndkdep
lto *lto
pgo *pgo
androidMkSharedLibDeps []string
outputFile android.OptionalPath
cachedToolchain config.Toolchain
subAndroidMkOnce map[subAndroidMkProvider]bool
// Flags used to compile this module
flags Flags
// When calling a linker, if module A depends on module B, then A must precede B in its command
// line invocation. staticDepsInLinkOrder stores the proper ordering of all of the transitive
// deps of this module
staticDepsInLinkOrder android.Paths
}
func (c *Module) Init() android.Module {
c.AddProperties(&c.Properties, &c.VendorProperties, &c.unused)
if c.compiler != nil {
c.AddProperties(c.compiler.compilerProps()...)
}
if c.linker != nil {
c.AddProperties(c.linker.linkerProps()...)
}
if c.installer != nil {
c.AddProperties(c.installer.installerProps()...)
}
if c.stl != nil {
c.AddProperties(c.stl.props()...)
}
if c.sanitize != nil {
c.AddProperties(c.sanitize.props()...)
}
if c.coverage != nil {
c.AddProperties(c.coverage.props()...)
}
if c.sabi != nil {
c.AddProperties(c.sabi.props()...)
}
if c.vndkdep != nil {
c.AddProperties(c.vndkdep.props()...)
}
if c.lto != nil {
c.AddProperties(c.lto.props()...)
}
if c.pgo != nil {
c.AddProperties(c.pgo.props()...)
}
for _, feature := range c.features {
c.AddProperties(feature.props()...)
}
android.InitAndroidArchModule(c, c.hod, c.multilib)
android.InitDefaultableModule(c)
return c
}
// Returns true for dependency roots (binaries)
// TODO(ccross): also handle dlopenable libraries
func (c *Module) isDependencyRoot() bool {
if root, ok := c.linker.(interface {
isDependencyRoot() bool
}); ok {
return root.isDependencyRoot()
}
return false
}
func (c *Module) useVndk() bool {
Split /system and /vendor modules, allow multi-installation Nothing changes if BOARD_VNDK_VERSION isn't set. When the VNDK is enabled (BOARD_VNDK_VERSION in Make), this will split /system and /vendor modules into two different variant spaces that can't link to each other. There are a few interfaces between the two variant spaces: The `llndk_library` stubs will be available in the /vendor variant, but won't be installed, so at runtime the /system variant will be used. Setting `vendor_available: true` will split a module into both variants. The /system (or "core") variant will compile just like today. The /vendor ("vendor") variant will compile against everything else in the vendor space (so LL-NDK instead of libc/liblog/etc). There will be two copies of these libraries installed onto the final device. Since the available runtime interfaces for vendor modules may be reduced, and your dependencies may not expose their private interfaces, we allow the vendor variants to reduce their compilation set, and export a different set of headers: cc_library { name: "libfoo", srcs: ["common.cpp", "private_impl.cpp"], export_include_dirs: ["include"], target: { vendor: { export_include_dirs: ["include_vndk"], exclude_srcs: ["private_impl.cpp"], srcs: ["vendor_only.cpp"], }, }, } So the "core" variant would compile with both "common.cpp" and "private_impl.cpp", and export "include". The "vendor" variant would compile "common.cpp" and "vendor_only.cpp", and export "include_vndk". Bug: 36426473 Bug: 36079834 Test: out/soong/build.ninja, out/soong/Android- only changes due to _core addition and .llndk -> .vendor Test: attempt to compile with BOARD_VNDK_VERSION:=current Change-Id: Idef28764043bf6c33dc0d2e7e2026c38867ff769
2017-04-06 21:43:22 +02:00
return c.Properties.UseVndk
}
func (c *Module) isVndk() bool {
if c.vndkdep != nil {
return c.vndkdep.isVndk()
}
return false
}
// Returns true only when this module is configured to have core and vendor
// variants.
func (c *Module) hasVendorVariant() bool {
return c.isVndk() || Bool(c.VendorProperties.Vendor_available)
}
type baseModuleContext struct {
android.BaseContext
moduleContextImpl
}
type depsContext struct {
android.BottomUpMutatorContext
moduleContextImpl
}
type moduleContext struct {
android.ModuleContext
moduleContextImpl
}
func (ctx *moduleContext) InstallOnVendorPartition() bool {
return ctx.ModuleContext.InstallOnVendorPartition() || (ctx.mod.useVndk() && !ctx.mod.isVndk())
Split /system and /vendor modules, allow multi-installation Nothing changes if BOARD_VNDK_VERSION isn't set. When the VNDK is enabled (BOARD_VNDK_VERSION in Make), this will split /system and /vendor modules into two different variant spaces that can't link to each other. There are a few interfaces between the two variant spaces: The `llndk_library` stubs will be available in the /vendor variant, but won't be installed, so at runtime the /system variant will be used. Setting `vendor_available: true` will split a module into both variants. The /system (or "core") variant will compile just like today. The /vendor ("vendor") variant will compile against everything else in the vendor space (so LL-NDK instead of libc/liblog/etc). There will be two copies of these libraries installed onto the final device. Since the available runtime interfaces for vendor modules may be reduced, and your dependencies may not expose their private interfaces, we allow the vendor variants to reduce their compilation set, and export a different set of headers: cc_library { name: "libfoo", srcs: ["common.cpp", "private_impl.cpp"], export_include_dirs: ["include"], target: { vendor: { export_include_dirs: ["include_vndk"], exclude_srcs: ["private_impl.cpp"], srcs: ["vendor_only.cpp"], }, }, } So the "core" variant would compile with both "common.cpp" and "private_impl.cpp", and export "include". The "vendor" variant would compile "common.cpp" and "vendor_only.cpp", and export "include_vndk". Bug: 36426473 Bug: 36079834 Test: out/soong/build.ninja, out/soong/Android- only changes due to _core addition and .llndk -> .vendor Test: attempt to compile with BOARD_VNDK_VERSION:=current Change-Id: Idef28764043bf6c33dc0d2e7e2026c38867ff769
2017-04-06 21:43:22 +02:00
}
type moduleContextImpl struct {
mod *Module
ctx BaseModuleContext
}
func (ctx *moduleContextImpl) clang() bool {
return ctx.mod.clang(ctx.ctx)
}
func (ctx *moduleContextImpl) toolchain() config.Toolchain {
return ctx.mod.toolchain(ctx.ctx)
}
func (ctx *moduleContextImpl) static() bool {
return ctx.mod.static()
}
func (ctx *moduleContextImpl) staticBinary() bool {
if static, ok := ctx.mod.linker.(interface {
staticBinary() bool
}); ok {
return static.staticBinary()
}
return false
}
func (ctx *moduleContextImpl) useSdk() bool {
if ctx.ctx.Device() && !ctx.useVndk() {
return String(ctx.mod.Properties.Sdk_version) != ""
}
return false
}
func (ctx *moduleContextImpl) sdkVersion() string {
if ctx.ctx.Device() {
if ctx.useVndk() {
return "current"
} else {
return String(ctx.mod.Properties.Sdk_version)
}
}
return ""
}
func (ctx *moduleContextImpl) isVndk() bool {
return ctx.mod.isVndk()
}
func (ctx *moduleContextImpl) useVndk() bool {
return ctx.mod.useVndk()
}
func (ctx *moduleContextImpl) isVndkSp() bool {
if vndk := ctx.mod.vndkdep; vndk != nil {
return vndk.isVndkSp()
}
return false
}
// Create source abi dumps if the module belongs to the list of VndkLibraries.
func (ctx *moduleContextImpl) createVndkSourceAbiDump() bool {
return ctx.ctx.Device() && ((ctx.useVndk() && ctx.isVndk()) || inList(ctx.baseModuleName(), llndkLibraries))
}
func (ctx *moduleContextImpl) selectedStl() string {
if stl := ctx.mod.stl; stl != nil {
return stl.Properties.SelectedStl
}
return ""
}
func (ctx *moduleContextImpl) baseModuleName() string {
return ctx.mod.ModuleBase.BaseModuleName()
}
func newBaseModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Module {
return &Module{
hod: hod,
multilib: multilib,
}
}
func newModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Module {
module := newBaseModule(hod, multilib)
module.features = []feature{
&tidyFeature{},
}
module.stl = &stl{}
module.sanitize = &sanitize{}
module.coverage = &coverage{}
module.sabi = &sabi{}
module.vndkdep = &vndkdep{}
module.lto = &lto{}
module.pgo = &pgo{}
return module
}
func (c *Module) Prebuilt() *android.Prebuilt {
if p, ok := c.linker.(prebuiltLinkerInterface); ok {
return p.prebuilt()
}
return nil
}
func (c *Module) Name() string {
name := c.ModuleBase.Name()
if p, ok := c.linker.(interface {
Name(string) string
}); ok {
name = p.Name(name)
}
return name
}
// orderDeps reorders dependencies into a list such that if module A depends on B, then
// A will precede B in the resultant list.
// This is convenient for passing into a linker.
func orderDeps(directDeps []android.Path, transitiveDeps map[android.Path][]android.Path) (orderedAllDeps []android.Path, orderedDeclaredDeps []android.Path) {
// If A depends on B, then
// Every list containing A will also contain B later in the list
// So, after concatenating all lists, the final instance of B will have come from the same
// original list as the final instance of A
// So, the final instance of B will be later in the concatenation than the final A
// So, keeping only the final instance of A and of B ensures that A is earlier in the output
// list than B
for _, dep := range directDeps {
orderedAllDeps = append(orderedAllDeps, dep)
orderedAllDeps = append(orderedAllDeps, transitiveDeps[dep]...)
}
orderedAllDeps = android.LastUniquePaths(orderedAllDeps)
// We don't want to add any new dependencies into directDeps (to allow the caller to
// intentionally exclude or replace any unwanted transitive dependencies), so we limit the
// resultant list to only what the caller has chosen to include in directDeps
_, orderedDeclaredDeps = android.FilterPathList(orderedAllDeps, directDeps)
return orderedAllDeps, orderedDeclaredDeps
}
func orderStaticModuleDeps(module *Module, deps []*Module) (results []android.Path) {
// make map of transitive dependencies
transitiveStaticDepNames := make(map[android.Path][]android.Path, len(deps))
for _, dep := range deps {
transitiveStaticDepNames[dep.outputFile.Path()] = dep.staticDepsInLinkOrder
}
// get the output file for each declared dependency
depFiles := []android.Path{}
for _, dep := range deps {
depFiles = append(depFiles, dep.outputFile.Path())
}
// reorder the dependencies based on transitive dependencies
module.staticDepsInLinkOrder, results = orderDeps(depFiles, transitiveStaticDepNames)
return results
}
func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
ctx := &moduleContext{
ModuleContext: actx,
moduleContextImpl: moduleContextImpl{
mod: c,
},
}
ctx.ctx = ctx
flags := Flags{
Toolchain: c.toolchain(ctx),
Clang: c.clang(ctx),
}
if c.compiler != nil {
flags = c.compiler.compilerFlags(ctx, flags)
}
if c.linker != nil {
flags = c.linker.linkerFlags(ctx, flags)
}
if c.stl != nil {
flags = c.stl.flags(ctx, flags)
}
if c.sanitize != nil {
flags = c.sanitize.flags(ctx, flags)
}
if c.coverage != nil {
flags = c.coverage.flags(ctx, flags)
}
if c.lto != nil {
flags = c.lto.flags(ctx, flags)
}
if c.pgo != nil {
flags = c.pgo.flags(ctx, flags)
}
for _, feature := range c.features {
flags = feature.flags(ctx, flags)
}
if ctx.Failed() {
return
}
flags.CFlags, _ = filterList(flags.CFlags, config.IllegalFlags)
flags.CppFlags, _ = filterList(flags.CppFlags, config.IllegalFlags)
flags.ConlyFlags, _ = filterList(flags.ConlyFlags, config.IllegalFlags)
deps := c.depsToPaths(ctx)
if ctx.Failed() {
return
}
flags.GlobalFlags = append(flags.GlobalFlags, deps.Flags...)
c.flags = flags
// We need access to all the flags seen by a source file.
if c.sabi != nil {
flags = c.sabi.flags(ctx, flags)
}
// Optimization to reduce size of build.ninja
// Replace the long list of flags for each file with a module-local variable
ctx.Variable(pctx, "cflags", strings.Join(flags.CFlags, " "))
ctx.Variable(pctx, "cppflags", strings.Join(flags.CppFlags, " "))
ctx.Variable(pctx, "asflags", strings.Join(flags.AsFlags, " "))
flags.CFlags = []string{"$cflags"}
flags.CppFlags = []string{"$cppflags"}
flags.AsFlags = []string{"$asflags"}
var objs Objects
if c.compiler != nil {
objs = c.compiler.compile(ctx, flags, deps)
if ctx.Failed() {
return
}
}
if c.linker != nil {
outputFile := c.linker.link(ctx, flags, deps, objs)
if ctx.Failed() {
return
}
c.outputFile = android.OptionalPathForPath(outputFile)
}
if c.installer != nil && !c.Properties.PreventInstall && c.outputFile.Valid() {
c.installer.install(ctx, c.outputFile.Path())
if ctx.Failed() {
return
}
}
}
func (c *Module) toolchain(ctx BaseModuleContext) config.Toolchain {
if c.cachedToolchain == nil {
c.cachedToolchain = config.FindToolchain(ctx.Os(), ctx.Arch())
}
return c.cachedToolchain
}
func (c *Module) begin(ctx BaseModuleContext) {
if c.compiler != nil {
c.compiler.compilerInit(ctx)
}
if c.linker != nil {
c.linker.linkerInit(ctx)
}
if c.stl != nil {
c.stl.begin(ctx)
}
if c.sanitize != nil {
c.sanitize.begin(ctx)
}
if c.coverage != nil {
c.coverage.begin(ctx)
}
if c.sabi != nil {
c.sabi.begin(ctx)
}
if c.vndkdep != nil {
c.vndkdep.begin(ctx)
}
if c.lto != nil {
c.lto.begin(ctx)
}
if c.pgo != nil {
c.pgo.begin(ctx)
}
for _, feature := range c.features {
feature.begin(ctx)
}
if ctx.useSdk() {
version, err := normalizeNdkApiLevel(ctx, ctx.sdkVersion(), ctx.Arch())
if err != nil {
ctx.PropertyErrorf("sdk_version", err.Error())
}
c.Properties.Sdk_version = StringPtr(version)
}
}
func (c *Module) deps(ctx DepsContext) Deps {
deps := Deps{}
if c.compiler != nil {
deps = c.compiler.compilerDeps(ctx, deps)
}
// Add the PGO dependency (the clang_rt.profile runtime library), which
// sometimes depends on symbols from libgcc, before libgcc gets added
// in linkerDeps().
if c.pgo != nil {
deps = c.pgo.deps(ctx, deps)
}
if c.linker != nil {
deps = c.linker.linkerDeps(ctx, deps)
}
if c.stl != nil {
deps = c.stl.deps(ctx, deps)
}
if c.sanitize != nil {
deps = c.sanitize.deps(ctx, deps)
}
if c.coverage != nil {
deps = c.coverage.deps(ctx, deps)
}
if c.sabi != nil {
deps = c.sabi.deps(ctx, deps)
}
if c.vndkdep != nil {
deps = c.vndkdep.deps(ctx, deps)
}
if c.lto != nil {
deps = c.lto.deps(ctx, deps)
}
for _, feature := range c.features {
deps = feature.deps(ctx, deps)
}
deps.WholeStaticLibs = android.LastUniqueStrings(deps.WholeStaticLibs)
deps.StaticLibs = android.LastUniqueStrings(deps.StaticLibs)
deps.LateStaticLibs = android.LastUniqueStrings(deps.LateStaticLibs)
deps.SharedLibs = android.LastUniqueStrings(deps.SharedLibs)
deps.LateSharedLibs = android.LastUniqueStrings(deps.LateSharedLibs)
deps.HeaderLibs = android.LastUniqueStrings(deps.HeaderLibs)
for _, lib := range deps.ReexportSharedLibHeaders {
if !inList(lib, deps.SharedLibs) {
ctx.PropertyErrorf("export_shared_lib_headers", "Shared library not in shared_libs: '%s'", lib)
}
}
for _, lib := range deps.ReexportStaticLibHeaders {
if !inList(lib, deps.StaticLibs) {
ctx.PropertyErrorf("export_static_lib_headers", "Static library not in static_libs: '%s'", lib)
}
}
for _, lib := range deps.ReexportHeaderLibHeaders {
if !inList(lib, deps.HeaderLibs) {
ctx.PropertyErrorf("export_header_lib_headers", "Header library not in header_libs: '%s'", lib)
}
}
for _, gen := range deps.ReexportGeneratedHeaders {
if !inList(gen, deps.GeneratedHeaders) {
ctx.PropertyErrorf("export_generated_headers", "Generated header module not in generated_headers: '%s'", gen)
}
}
return deps
}
func (c *Module) beginMutator(actx android.BottomUpMutatorContext) {
ctx := &baseModuleContext{
BaseContext: actx,
moduleContextImpl: moduleContextImpl{
mod: c,
},
}
ctx.ctx = ctx
c.begin(ctx)
}
func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) {
if !c.Enabled() {
return
}
ctx := &depsContext{
BottomUpMutatorContext: actx,
moduleContextImpl: moduleContextImpl{
mod: c,
},
}
ctx.ctx = ctx
deps := c.deps(ctx)
variantNdkLibs := []string{}
variantLateNdkLibs := []string{}
if ctx.Os() == android.Android {
version := ctx.sdkVersion()
// rewriteNdkLibs takes a list of names of shared libraries and scans it for three types
// of names:
//
// 1. Name of an NDK library that refers to a prebuilt module.
// For each of these, it adds the name of the prebuilt module (which will be in
// prebuilts/ndk) to the list of nonvariant libs.
// 2. Name of an NDK library that refers to an ndk_library module.
// For each of these, it adds the name of the ndk_library module to the list of
// variant libs.
// 3. Anything else (so anything that isn't an NDK library).
// It adds these to the nonvariantLibs list.
//
// The caller can then know to add the variantLibs dependencies differently from the
// nonvariantLibs
rewriteNdkLibs := func(list []string) (nonvariantLibs []string, variantLibs []string) {
variantLibs = []string{}
nonvariantLibs = []string{}
for _, entry := range list {
if ctx.useSdk() && inList(entry, ndkPrebuiltSharedLibraries) {
if !inList(entry, ndkMigratedLibs) {
nonvariantLibs = append(nonvariantLibs, entry+".ndk."+version)
} else {
variantLibs = append(variantLibs, entry+ndkLibrarySuffix)
}
} else if ctx.useVndk() && inList(entry, llndkLibraries) {
nonvariantLibs = append(nonvariantLibs, entry+llndkLibrarySuffix)
} else {
nonvariantLibs = append(nonvariantLibs, entry)
}
}
return nonvariantLibs, variantLibs
}
deps.SharedLibs, variantNdkLibs = rewriteNdkLibs(deps.SharedLibs)
deps.LateSharedLibs, variantLateNdkLibs = rewriteNdkLibs(deps.LateSharedLibs)
deps.ReexportSharedLibHeaders, _ = rewriteNdkLibs(deps.ReexportSharedLibHeaders)
}
for _, lib := range deps.HeaderLibs {
depTag := headerDepTag
if inList(lib, deps.ReexportHeaderLibHeaders) {
depTag = headerExportDepTag
}
actx.AddVariationDependencies(nil, depTag, lib)
}
actx.AddVariationDependencies([]blueprint.Variation{{"link", "static"}}, wholeStaticDepTag,
deps.WholeStaticLibs...)
for _, lib := range deps.StaticLibs {
depTag := staticDepTag
if inList(lib, deps.ReexportStaticLibHeaders) {
depTag = staticExportDepTag
}
actx.AddVariationDependencies([]blueprint.Variation{{"link", "static"}}, depTag, lib)
}
actx.AddVariationDependencies([]blueprint.Variation{{"link", "static"}}, lateStaticDepTag,
deps.LateStaticLibs...)
for _, lib := range deps.SharedLibs {
depTag := sharedDepTag
if inList(lib, deps.ReexportSharedLibHeaders) {
depTag = sharedExportDepTag
}
actx.AddVariationDependencies([]blueprint.Variation{{"link", "shared"}}, depTag, lib)
}
actx.AddVariationDependencies([]blueprint.Variation{{"link", "shared"}}, lateSharedDepTag,
deps.LateSharedLibs...)
actx.AddDependency(c, genSourceDepTag, deps.GeneratedSources...)
for _, gen := range deps.GeneratedHeaders {
depTag := genHeaderDepTag
if inList(gen, deps.ReexportGeneratedHeaders) {
depTag = genHeaderExportDepTag
}
actx.AddDependency(c, depTag, gen)
}
actx.AddDependency(c, objDepTag, deps.ObjFiles...)
if deps.CrtBegin != "" {
actx.AddDependency(c, crtBeginDepTag, deps.CrtBegin)
}
if deps.CrtEnd != "" {
actx.AddDependency(c, crtEndDepTag, deps.CrtEnd)
}
if deps.LinkerScript != "" {
actx.AddDependency(c, linkerScriptDepTag, deps.LinkerScript)
}
version := ctx.sdkVersion()
actx.AddVariationDependencies([]blueprint.Variation{
{"ndk_api", version}, {"link", "shared"}}, ndkStubDepTag, variantNdkLibs...)
actx.AddVariationDependencies([]blueprint.Variation{
{"ndk_api", version}, {"link", "shared"}}, ndkLateStubDepTag, variantLateNdkLibs...)
}
func beginMutator(ctx android.BottomUpMutatorContext) {
if c, ok := ctx.Module().(*Module); ok && c.Enabled() {
c.beginMutator(ctx)
}
}
func (c *Module) clang(ctx BaseModuleContext) bool {
clang := Bool(c.Properties.Clang)
if c.Properties.Clang == nil {
if ctx.Host() {
clang = true
}
if ctx.Device() && ctx.AConfig().DeviceUsesClang() {
clang = true
}
}
if !c.toolchain(ctx).ClangSupported() {
clang = false
}
return clang
}
// Whether a module can link to another module, taking into
// account NDK linking.
func checkLinkType(ctx android.ModuleContext, from *Module, to *Module) {
if from.Target().Os != android.Android {
// Host code is not restricted
return
}
if from.Properties.UseVndk {
// Though vendor code is limited by the vendor mutator,
// each vendor-available module needs to check
// link-type for VNDK.
if from.vndkdep != nil {
from.vndkdep.vndkCheckLinkType(ctx, to)
}
return
}
if String(from.Properties.Sdk_version) == "" {
// Platform code can link to anything
return
}
if _, ok := to.linker.(*toolchainLibraryDecorator); ok {
// These are always allowed
return
}
if _, ok := to.linker.(*ndkPrebuiltLibraryLinker); ok {
// These are allowed, but they don't set sdk_version
return
}
if _, ok := to.linker.(*ndkPrebuiltStlLinker); ok {
// These are allowed, but they don't set sdk_version
return
}
if _, ok := to.linker.(*stubDecorator); ok {
// These aren't real libraries, but are the stub shared libraries that are included in
// the NDK.
return
}
if String(to.Properties.Sdk_version) == "" {
// NDK code linking to platform code is never okay.
ctx.ModuleErrorf("depends on non-NDK-built library %q",
ctx.OtherModuleName(to))
}
// At this point we know we have two NDK libraries, but we need to
// check that we're not linking against anything built against a higher
// API level, as it is only valid to link against older or equivalent
// APIs.
if String(from.Properties.Sdk_version) == "current" {
// Current can link against anything.
return
} else if String(to.Properties.Sdk_version) == "current" {
// Current can't be linked against by anything else.
ctx.ModuleErrorf("links %q built against newer API version %q",
ctx.OtherModuleName(to), "current")
}
fromApi, err := strconv.Atoi(String(from.Properties.Sdk_version))
if err != nil {
ctx.PropertyErrorf("sdk_version",
"Invalid sdk_version value (must be int): %q",
String(from.Properties.Sdk_version))
}
toApi, err := strconv.Atoi(String(to.Properties.Sdk_version))
if err != nil {
ctx.PropertyErrorf("sdk_version",
"Invalid sdk_version value (must be int): %q",
String(to.Properties.Sdk_version))
}
if toApi > fromApi {
ctx.ModuleErrorf("links %q built against newer API version %q",
ctx.OtherModuleName(to), String(to.Properties.Sdk_version))
}
}
// Convert dependencies to paths. Returns a PathDeps containing paths
func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
var depPaths PathDeps
directStaticDeps := []*Module{}
ctx.VisitDirectDeps(func(dep android.Module) {
depName := ctx.OtherModuleName(dep)
depTag := ctx.OtherModuleDependencyTag(dep)
ccDep, _ := dep.(*Module)
if ccDep == nil {
// handling for a few module types that aren't cc Module but that are also supported
switch depTag {
case android.DefaultsDepTag, android.SourceDepTag:
// Nothing to do
case genSourceDepTag:
if genRule, ok := dep.(genrule.SourceFileGenerator); ok {
depPaths.GeneratedSources = append(depPaths.GeneratedSources,
genRule.GeneratedSourceFiles()...)
} else {
ctx.ModuleErrorf("module %q is not a gensrcs or genrule", depName)
}
// Support exported headers from a generated_sources dependency
fallthrough
case genHeaderDepTag, genHeaderExportDepTag:
if genRule, ok := dep.(genrule.SourceFileGenerator); ok {
depPaths.GeneratedHeaders = append(depPaths.GeneratedHeaders,
genRule.GeneratedSourceFiles()...)
flags := includeDirsToFlags(genRule.GeneratedHeaderDirs())
depPaths.Flags = append(depPaths.Flags, flags)
if depTag == genHeaderExportDepTag {
depPaths.ReexportedFlags = append(depPaths.ReexportedFlags, flags)
depPaths.ReexportedFlagsDeps = append(depPaths.ReexportedFlagsDeps,
genRule.GeneratedSourceFiles()...)
// Add these re-exported flags to help header-abi-dumper to infer the abi exported by a library.
c.sabi.Properties.ReexportedIncludeFlags = append(c.sabi.Properties.ReexportedIncludeFlags, flags)
}
} else {
ctx.ModuleErrorf("module %q is not a genrule", depName)
}
case linkerScriptDepTag:
if genRule, ok := dep.(genrule.SourceFileGenerator); ok {
files := genRule.GeneratedSourceFiles()
if len(files) == 1 {
depPaths.LinkerScript = android.OptionalPathForPath(files[0])
} else if len(files) > 1 {
ctx.ModuleErrorf("module %q can only generate a single file if used for a linker script", depName)
}
} else {
ctx.ModuleErrorf("module %q is not a genrule", depName)
}
default:
ctx.ModuleErrorf("depends on non-cc module %q", depName)
}
return
}
if dep.Target().Os != ctx.Os() {
ctx.ModuleErrorf("OS mismatch between %q and %q", ctx.ModuleName(), depName)
return
}
if dep.Target().Arch.ArchType != ctx.Arch().ArchType {
ctx.ModuleErrorf("Arch mismatch between %q and %q", ctx.ModuleName(), depName)
return
}
// re-exporting flags
if depTag == reuseObjTag {
if l, ok := ccDep.compiler.(libraryInterface); ok {
objs, flags, deps := l.reuseObjs()
depPaths.Objs = depPaths.Objs.Append(objs)
depPaths.ReexportedFlags = append(depPaths.ReexportedFlags, flags...)
depPaths.ReexportedFlagsDeps = append(depPaths.ReexportedFlagsDeps, deps...)
return
}
}
if t, ok := depTag.(dependencyTag); ok && t.library {
if i, ok := ccDep.linker.(exportedFlagsProducer); ok {
flags := i.exportedFlags()
deps := i.exportedFlagsDeps()
depPaths.Flags = append(depPaths.Flags, flags...)
depPaths.GeneratedHeaders = append(depPaths.GeneratedHeaders, deps...)
if t.reexportFlags {
depPaths.ReexportedFlags = append(depPaths.ReexportedFlags, flags...)
depPaths.ReexportedFlagsDeps = append(depPaths.ReexportedFlagsDeps, deps...)
// Add these re-exported flags to help header-abi-dumper to infer the abi exported by a library.
// Re-exported shared library headers must be included as well since they can help us with type information
// about template instantiations (instantiated from their headers).
c.sabi.Properties.ReexportedIncludeFlags = append(c.sabi.Properties.ReexportedIncludeFlags, flags...)
}
}
checkLinkType(ctx, c, ccDep)
}
var ptr *android.Paths
var depPtr *android.Paths
linkFile := ccDep.outputFile
depFile := android.OptionalPath{}
switch depTag {
case ndkStubDepTag, sharedDepTag, sharedExportDepTag:
ptr = &depPaths.SharedLibs
depPtr = &depPaths.SharedLibsDeps
depFile = ccDep.linker.(libraryInterface).toc()
case lateSharedDepTag, ndkLateStubDepTag:
ptr = &depPaths.LateSharedLibs
depPtr = &depPaths.LateSharedLibsDeps
depFile = ccDep.linker.(libraryInterface).toc()
case staticDepTag, staticExportDepTag:
ptr = nil
directStaticDeps = append(directStaticDeps, ccDep)
case lateStaticDepTag:
ptr = &depPaths.LateStaticLibs
case wholeStaticDepTag:
ptr = &depPaths.WholeStaticLibs
staticLib, ok := ccDep.linker.(libraryInterface)
if !ok || !staticLib.static() {
ctx.ModuleErrorf("module %q not a static library", depName)
return
}
if missingDeps := staticLib.getWholeStaticMissingDeps(); missingDeps != nil {
postfix := " (required by " + ctx.OtherModuleName(dep) + ")"
for i := range missingDeps {
missingDeps[i] += postfix
}
ctx.AddMissingDependencies(missingDeps)
}
depPaths.WholeStaticLibObjs = depPaths.WholeStaticLibObjs.Append(staticLib.objs())
case headerDepTag:
// Nothing
case objDepTag:
depPaths.Objs.objFiles = append(depPaths.Objs.objFiles, linkFile.Path())
case crtBeginDepTag:
depPaths.CrtBegin = linkFile
case crtEndDepTag:
depPaths.CrtEnd = linkFile
}
switch depTag {
case staticDepTag, staticExportDepTag, lateStaticDepTag:
staticLib, ok := ccDep.linker.(libraryInterface)
if !ok || !staticLib.static() {
ctx.ModuleErrorf("module %q not a static library", depName)
return
}
// When combining coverage files for shared libraries and executables, coverage files
// in static libraries act as if they were whole static libraries. The same goes for
// source based Abi dump files.
depPaths.StaticLibObjs.coverageFiles = append(depPaths.StaticLibObjs.coverageFiles,
staticLib.objs().coverageFiles...)
depPaths.StaticLibObjs.sAbiDumpFiles = append(depPaths.StaticLibObjs.sAbiDumpFiles,
staticLib.objs().sAbiDumpFiles...)
}
if ptr != nil {
if !linkFile.Valid() {
ctx.ModuleErrorf("module %q missing output file", depName)
return
}
*ptr = append(*ptr, linkFile.Path())
}
if depPtr != nil {
dep := depFile
if !dep.Valid() {
dep = linkFile
}
*depPtr = append(*depPtr, dep.Path())
}
// Export the shared libs to Make.
switch depTag {
case sharedDepTag, sharedExportDepTag, lateSharedDepTag:
libName := strings.TrimSuffix(depName, llndkLibrarySuffix)
libName = strings.TrimPrefix(libName, "prebuilt_")
isLLndk := inList(libName, llndkLibraries)
var makeLibName string
bothVendorAndCoreVariantsExist := ccDep.hasVendorVariant() || isLLndk
if c.useVndk() && bothVendorAndCoreVariantsExist {
// The vendor module in Make will have been renamed to not conflict with the core
// module, so update the dependency name here accordingly.
makeLibName = libName + vendorSuffix
} else {
makeLibName = libName
}
// Note: the order of libs in this list is not important because
// they merely serve as Make dependencies and do not affect this lib itself.
c.Properties.AndroidMkSharedLibs = append(c.Properties.AndroidMkSharedLibs, makeLibName)
}
})
// use the ordered dependencies as this module's dependencies
depPaths.StaticLibs = append(depPaths.StaticLibs, orderStaticModuleDeps(c, directStaticDeps)...)
// Dedup exported flags from dependencies
depPaths.Flags = android.FirstUniqueStrings(depPaths.Flags)
depPaths.GeneratedHeaders = android.FirstUniquePaths(depPaths.GeneratedHeaders)
depPaths.ReexportedFlags = android.FirstUniqueStrings(depPaths.ReexportedFlags)
depPaths.ReexportedFlagsDeps = android.FirstUniquePaths(depPaths.ReexportedFlagsDeps)
if c.sabi != nil {
c.sabi.Properties.ReexportedIncludeFlags = android.FirstUniqueStrings(c.sabi.Properties.ReexportedIncludeFlags)
}
return depPaths
}
func (c *Module) InstallInData() bool {
if c.installer == nil {
return false
}
return c.installer.inData()
}
func (c *Module) InstallInSanitizerDir() bool {
if c.installer == nil {
return false
}
if c.sanitize != nil && c.sanitize.inSanitizerDir() {
return true
}
return c.installer.inSanitizerDir()
}
func (c *Module) HostToolPath() android.OptionalPath {
if c.installer == nil {
return android.OptionalPath{}
}
return c.installer.hostToolPath()
}
func (c *Module) IntermPathForModuleOut() android.OptionalPath {
return c.outputFile
}
func (c *Module) Srcs() android.Paths {
if c.outputFile.Valid() {
return android.Paths{c.outputFile.Path()}
}
return android.Paths{}
}
func (c *Module) static() bool {
if static, ok := c.linker.(interface {
static() bool
}); ok {
return static.static()
}
return false
}
//
// Defaults
//
type Defaults struct {
android.ModuleBase
android.DefaultsModuleBase
}
func (*Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) {
}
func (d *Defaults) DepsMutator(ctx android.BottomUpMutatorContext) {
}
func defaultsFactory() android.Module {
return DefaultsFactory()
}
func DefaultsFactory(props ...interface{}) android.Module {
module := &Defaults{}
module.AddProperties(props...)
module.AddProperties(
&BaseProperties{},
&VendorProperties{},
&BaseCompilerProperties{},
&BaseLinkerProperties{},
&LibraryProperties{},
&FlagExporterProperties{},
&BinaryLinkerProperties{},
&TestProperties{},
&TestBinaryProperties{},
&UnusedProperties{},
&StlProperties{},
&SanitizeProperties{},
&StripProperties{},
&InstallerProperties{},
&TidyProperties{},
&CoverageProperties{},
&SAbiProperties{},
&VndkProperties{},
&LTOProperties{},
&PgoProperties{},
)
android.InitDefaultsModule(module)
return module
}
Split /system and /vendor modules, allow multi-installation Nothing changes if BOARD_VNDK_VERSION isn't set. When the VNDK is enabled (BOARD_VNDK_VERSION in Make), this will split /system and /vendor modules into two different variant spaces that can't link to each other. There are a few interfaces between the two variant spaces: The `llndk_library` stubs will be available in the /vendor variant, but won't be installed, so at runtime the /system variant will be used. Setting `vendor_available: true` will split a module into both variants. The /system (or "core") variant will compile just like today. The /vendor ("vendor") variant will compile against everything else in the vendor space (so LL-NDK instead of libc/liblog/etc). There will be two copies of these libraries installed onto the final device. Since the available runtime interfaces for vendor modules may be reduced, and your dependencies may not expose their private interfaces, we allow the vendor variants to reduce their compilation set, and export a different set of headers: cc_library { name: "libfoo", srcs: ["common.cpp", "private_impl.cpp"], export_include_dirs: ["include"], target: { vendor: { export_include_dirs: ["include_vndk"], exclude_srcs: ["private_impl.cpp"], srcs: ["vendor_only.cpp"], }, }, } So the "core" variant would compile with both "common.cpp" and "private_impl.cpp", and export "include". The "vendor" variant would compile "common.cpp" and "vendor_only.cpp", and export "include_vndk". Bug: 36426473 Bug: 36079834 Test: out/soong/build.ninja, out/soong/Android- only changes due to _core addition and .llndk -> .vendor Test: attempt to compile with BOARD_VNDK_VERSION:=current Change-Id: Idef28764043bf6c33dc0d2e7e2026c38867ff769
2017-04-06 21:43:22 +02:00
const (
// coreMode is the variant used for framework-private libraries, or
// SDK libraries. (which framework-private libraries can use)
coreMode = "core"
// vendorMode is the variant used for /vendor code that compiles
// against the VNDK.
vendorMode = "vendor"
)
func squashVendorSrcs(m *Module) {
if lib, ok := m.compiler.(*libraryDecorator); ok {
lib.baseCompiler.Properties.Srcs = append(lib.baseCompiler.Properties.Srcs,
lib.baseCompiler.Properties.Target.Vendor.Srcs...)
lib.baseCompiler.Properties.Exclude_srcs = append(lib.baseCompiler.Properties.Exclude_srcs,
lib.baseCompiler.Properties.Target.Vendor.Exclude_srcs...)
}
}
Split /system and /vendor modules, allow multi-installation Nothing changes if BOARD_VNDK_VERSION isn't set. When the VNDK is enabled (BOARD_VNDK_VERSION in Make), this will split /system and /vendor modules into two different variant spaces that can't link to each other. There are a few interfaces between the two variant spaces: The `llndk_library` stubs will be available in the /vendor variant, but won't be installed, so at runtime the /system variant will be used. Setting `vendor_available: true` will split a module into both variants. The /system (or "core") variant will compile just like today. The /vendor ("vendor") variant will compile against everything else in the vendor space (so LL-NDK instead of libc/liblog/etc). There will be two copies of these libraries installed onto the final device. Since the available runtime interfaces for vendor modules may be reduced, and your dependencies may not expose their private interfaces, we allow the vendor variants to reduce their compilation set, and export a different set of headers: cc_library { name: "libfoo", srcs: ["common.cpp", "private_impl.cpp"], export_include_dirs: ["include"], target: { vendor: { export_include_dirs: ["include_vndk"], exclude_srcs: ["private_impl.cpp"], srcs: ["vendor_only.cpp"], }, }, } So the "core" variant would compile with both "common.cpp" and "private_impl.cpp", and export "include". The "vendor" variant would compile "common.cpp" and "vendor_only.cpp", and export "include_vndk". Bug: 36426473 Bug: 36079834 Test: out/soong/build.ninja, out/soong/Android- only changes due to _core addition and .llndk -> .vendor Test: attempt to compile with BOARD_VNDK_VERSION:=current Change-Id: Idef28764043bf6c33dc0d2e7e2026c38867ff769
2017-04-06 21:43:22 +02:00
func vendorMutator(mctx android.BottomUpMutatorContext) {
if mctx.Os() != android.Android {
return
}
if genrule, ok := mctx.Module().(*genrule.Module); ok {
if props, ok := genrule.Extra.(*VendorProperties); ok {
if !mctx.DeviceConfig().CompileVndk() {
mctx.CreateVariations(coreMode)
} else if Bool(props.Vendor_available) {
mctx.CreateVariations(coreMode, vendorMode)
} else if mctx.InstallOnVendorPartition() {
mctx.CreateVariations(vendorMode)
} else {
mctx.CreateVariations(coreMode)
}
}
}
Split /system and /vendor modules, allow multi-installation Nothing changes if BOARD_VNDK_VERSION isn't set. When the VNDK is enabled (BOARD_VNDK_VERSION in Make), this will split /system and /vendor modules into two different variant spaces that can't link to each other. There are a few interfaces between the two variant spaces: The `llndk_library` stubs will be available in the /vendor variant, but won't be installed, so at runtime the /system variant will be used. Setting `vendor_available: true` will split a module into both variants. The /system (or "core") variant will compile just like today. The /vendor ("vendor") variant will compile against everything else in the vendor space (so LL-NDK instead of libc/liblog/etc). There will be two copies of these libraries installed onto the final device. Since the available runtime interfaces for vendor modules may be reduced, and your dependencies may not expose their private interfaces, we allow the vendor variants to reduce their compilation set, and export a different set of headers: cc_library { name: "libfoo", srcs: ["common.cpp", "private_impl.cpp"], export_include_dirs: ["include"], target: { vendor: { export_include_dirs: ["include_vndk"], exclude_srcs: ["private_impl.cpp"], srcs: ["vendor_only.cpp"], }, }, } So the "core" variant would compile with both "common.cpp" and "private_impl.cpp", and export "include". The "vendor" variant would compile "common.cpp" and "vendor_only.cpp", and export "include_vndk". Bug: 36426473 Bug: 36079834 Test: out/soong/build.ninja, out/soong/Android- only changes due to _core addition and .llndk -> .vendor Test: attempt to compile with BOARD_VNDK_VERSION:=current Change-Id: Idef28764043bf6c33dc0d2e7e2026c38867ff769
2017-04-06 21:43:22 +02:00
m, ok := mctx.Module().(*Module)
if !ok {
return
}
// Sanity check
if m.VendorProperties.Vendor_available != nil && mctx.InstallOnVendorPartition() {
Split /system and /vendor modules, allow multi-installation Nothing changes if BOARD_VNDK_VERSION isn't set. When the VNDK is enabled (BOARD_VNDK_VERSION in Make), this will split /system and /vendor modules into two different variant spaces that can't link to each other. There are a few interfaces between the two variant spaces: The `llndk_library` stubs will be available in the /vendor variant, but won't be installed, so at runtime the /system variant will be used. Setting `vendor_available: true` will split a module into both variants. The /system (or "core") variant will compile just like today. The /vendor ("vendor") variant will compile against everything else in the vendor space (so LL-NDK instead of libc/liblog/etc). There will be two copies of these libraries installed onto the final device. Since the available runtime interfaces for vendor modules may be reduced, and your dependencies may not expose their private interfaces, we allow the vendor variants to reduce their compilation set, and export a different set of headers: cc_library { name: "libfoo", srcs: ["common.cpp", "private_impl.cpp"], export_include_dirs: ["include"], target: { vendor: { export_include_dirs: ["include_vndk"], exclude_srcs: ["private_impl.cpp"], srcs: ["vendor_only.cpp"], }, }, } So the "core" variant would compile with both "common.cpp" and "private_impl.cpp", and export "include". The "vendor" variant would compile "common.cpp" and "vendor_only.cpp", and export "include_vndk". Bug: 36426473 Bug: 36079834 Test: out/soong/build.ninja, out/soong/Android- only changes due to _core addition and .llndk -> .vendor Test: attempt to compile with BOARD_VNDK_VERSION:=current Change-Id: Idef28764043bf6c33dc0d2e7e2026c38867ff769
2017-04-06 21:43:22 +02:00
mctx.PropertyErrorf("vendor_available",
"doesn't make sense at the same time as `vendor: true` or `proprietary: true`")
return
}
if vndk := m.vndkdep; vndk != nil {
if vndk.isVndk() && m.VendorProperties.Vendor_available == nil {
mctx.PropertyErrorf("vndk",
"vendor_available must be set to either true or false when `vndk: {enabled: true}`")
return
}
if !vndk.isVndk() && vndk.isVndkSp() {
mctx.PropertyErrorf("vndk",
"must set `enabled: true` to set `support_system_process: true`")
return
}
}
Split /system and /vendor modules, allow multi-installation Nothing changes if BOARD_VNDK_VERSION isn't set. When the VNDK is enabled (BOARD_VNDK_VERSION in Make), this will split /system and /vendor modules into two different variant spaces that can't link to each other. There are a few interfaces between the two variant spaces: The `llndk_library` stubs will be available in the /vendor variant, but won't be installed, so at runtime the /system variant will be used. Setting `vendor_available: true` will split a module into both variants. The /system (or "core") variant will compile just like today. The /vendor ("vendor") variant will compile against everything else in the vendor space (so LL-NDK instead of libc/liblog/etc). There will be two copies of these libraries installed onto the final device. Since the available runtime interfaces for vendor modules may be reduced, and your dependencies may not expose their private interfaces, we allow the vendor variants to reduce their compilation set, and export a different set of headers: cc_library { name: "libfoo", srcs: ["common.cpp", "private_impl.cpp"], export_include_dirs: ["include"], target: { vendor: { export_include_dirs: ["include_vndk"], exclude_srcs: ["private_impl.cpp"], srcs: ["vendor_only.cpp"], }, }, } So the "core" variant would compile with both "common.cpp" and "private_impl.cpp", and export "include". The "vendor" variant would compile "common.cpp" and "vendor_only.cpp", and export "include_vndk". Bug: 36426473 Bug: 36079834 Test: out/soong/build.ninja, out/soong/Android- only changes due to _core addition and .llndk -> .vendor Test: attempt to compile with BOARD_VNDK_VERSION:=current Change-Id: Idef28764043bf6c33dc0d2e7e2026c38867ff769
2017-04-06 21:43:22 +02:00
if !mctx.DeviceConfig().CompileVndk() {
// If the device isn't compiling against the VNDK, we always
// use the core mode.
mctx.CreateVariations(coreMode)
} else if _, ok := m.linker.(*llndkStubDecorator); ok {
// LL-NDK stubs only exist in the vendor variant, since the
// real libraries will be used in the core variant.
mctx.CreateVariations(vendorMode)
} else if _, ok := m.linker.(*llndkHeadersDecorator); ok {
// ... and LL-NDK headers as well
mctx.CreateVariations(vendorMode)
} else if m.hasVendorVariant() {
Split /system and /vendor modules, allow multi-installation Nothing changes if BOARD_VNDK_VERSION isn't set. When the VNDK is enabled (BOARD_VNDK_VERSION in Make), this will split /system and /vendor modules into two different variant spaces that can't link to each other. There are a few interfaces between the two variant spaces: The `llndk_library` stubs will be available in the /vendor variant, but won't be installed, so at runtime the /system variant will be used. Setting `vendor_available: true` will split a module into both variants. The /system (or "core") variant will compile just like today. The /vendor ("vendor") variant will compile against everything else in the vendor space (so LL-NDK instead of libc/liblog/etc). There will be two copies of these libraries installed onto the final device. Since the available runtime interfaces for vendor modules may be reduced, and your dependencies may not expose their private interfaces, we allow the vendor variants to reduce their compilation set, and export a different set of headers: cc_library { name: "libfoo", srcs: ["common.cpp", "private_impl.cpp"], export_include_dirs: ["include"], target: { vendor: { export_include_dirs: ["include_vndk"], exclude_srcs: ["private_impl.cpp"], srcs: ["vendor_only.cpp"], }, }, } So the "core" variant would compile with both "common.cpp" and "private_impl.cpp", and export "include". The "vendor" variant would compile "common.cpp" and "vendor_only.cpp", and export "include_vndk". Bug: 36426473 Bug: 36079834 Test: out/soong/build.ninja, out/soong/Android- only changes due to _core addition and .llndk -> .vendor Test: attempt to compile with BOARD_VNDK_VERSION:=current Change-Id: Idef28764043bf6c33dc0d2e7e2026c38867ff769
2017-04-06 21:43:22 +02:00
// This will be available in both /system and /vendor
// or a /system directory that is available to vendor.
Split /system and /vendor modules, allow multi-installation Nothing changes if BOARD_VNDK_VERSION isn't set. When the VNDK is enabled (BOARD_VNDK_VERSION in Make), this will split /system and /vendor modules into two different variant spaces that can't link to each other. There are a few interfaces between the two variant spaces: The `llndk_library` stubs will be available in the /vendor variant, but won't be installed, so at runtime the /system variant will be used. Setting `vendor_available: true` will split a module into both variants. The /system (or "core") variant will compile just like today. The /vendor ("vendor") variant will compile against everything else in the vendor space (so LL-NDK instead of libc/liblog/etc). There will be two copies of these libraries installed onto the final device. Since the available runtime interfaces for vendor modules may be reduced, and your dependencies may not expose their private interfaces, we allow the vendor variants to reduce their compilation set, and export a different set of headers: cc_library { name: "libfoo", srcs: ["common.cpp", "private_impl.cpp"], export_include_dirs: ["include"], target: { vendor: { export_include_dirs: ["include_vndk"], exclude_srcs: ["private_impl.cpp"], srcs: ["vendor_only.cpp"], }, }, } So the "core" variant would compile with both "common.cpp" and "private_impl.cpp", and export "include". The "vendor" variant would compile "common.cpp" and "vendor_only.cpp", and export "include_vndk". Bug: 36426473 Bug: 36079834 Test: out/soong/build.ninja, out/soong/Android- only changes due to _core addition and .llndk -> .vendor Test: attempt to compile with BOARD_VNDK_VERSION:=current Change-Id: Idef28764043bf6c33dc0d2e7e2026c38867ff769
2017-04-06 21:43:22 +02:00
mod := mctx.CreateVariations(coreMode, vendorMode)
vendor := mod[1].(*Module)
vendor.Properties.UseVndk = true
squashVendorSrcs(vendor)
} else if mctx.InstallOnVendorPartition() && String(m.Properties.Sdk_version) == "" {
Split /system and /vendor modules, allow multi-installation Nothing changes if BOARD_VNDK_VERSION isn't set. When the VNDK is enabled (BOARD_VNDK_VERSION in Make), this will split /system and /vendor modules into two different variant spaces that can't link to each other. There are a few interfaces between the two variant spaces: The `llndk_library` stubs will be available in the /vendor variant, but won't be installed, so at runtime the /system variant will be used. Setting `vendor_available: true` will split a module into both variants. The /system (or "core") variant will compile just like today. The /vendor ("vendor") variant will compile against everything else in the vendor space (so LL-NDK instead of libc/liblog/etc). There will be two copies of these libraries installed onto the final device. Since the available runtime interfaces for vendor modules may be reduced, and your dependencies may not expose their private interfaces, we allow the vendor variants to reduce their compilation set, and export a different set of headers: cc_library { name: "libfoo", srcs: ["common.cpp", "private_impl.cpp"], export_include_dirs: ["include"], target: { vendor: { export_include_dirs: ["include_vndk"], exclude_srcs: ["private_impl.cpp"], srcs: ["vendor_only.cpp"], }, }, } So the "core" variant would compile with both "common.cpp" and "private_impl.cpp", and export "include". The "vendor" variant would compile "common.cpp" and "vendor_only.cpp", and export "include_vndk". Bug: 36426473 Bug: 36079834 Test: out/soong/build.ninja, out/soong/Android- only changes due to _core addition and .llndk -> .vendor Test: attempt to compile with BOARD_VNDK_VERSION:=current Change-Id: Idef28764043bf6c33dc0d2e7e2026c38867ff769
2017-04-06 21:43:22 +02:00
// This will be available in /vendor only
mod := mctx.CreateVariations(vendorMode)
vendor := mod[0].(*Module)
vendor.Properties.UseVndk = true
squashVendorSrcs(vendor)
Split /system and /vendor modules, allow multi-installation Nothing changes if BOARD_VNDK_VERSION isn't set. When the VNDK is enabled (BOARD_VNDK_VERSION in Make), this will split /system and /vendor modules into two different variant spaces that can't link to each other. There are a few interfaces between the two variant spaces: The `llndk_library` stubs will be available in the /vendor variant, but won't be installed, so at runtime the /system variant will be used. Setting `vendor_available: true` will split a module into both variants. The /system (or "core") variant will compile just like today. The /vendor ("vendor") variant will compile against everything else in the vendor space (so LL-NDK instead of libc/liblog/etc). There will be two copies of these libraries installed onto the final device. Since the available runtime interfaces for vendor modules may be reduced, and your dependencies may not expose their private interfaces, we allow the vendor variants to reduce their compilation set, and export a different set of headers: cc_library { name: "libfoo", srcs: ["common.cpp", "private_impl.cpp"], export_include_dirs: ["include"], target: { vendor: { export_include_dirs: ["include_vndk"], exclude_srcs: ["private_impl.cpp"], srcs: ["vendor_only.cpp"], }, }, } So the "core" variant would compile with both "common.cpp" and "private_impl.cpp", and export "include". The "vendor" variant would compile "common.cpp" and "vendor_only.cpp", and export "include_vndk". Bug: 36426473 Bug: 36079834 Test: out/soong/build.ninja, out/soong/Android- only changes due to _core addition and .llndk -> .vendor Test: attempt to compile with BOARD_VNDK_VERSION:=current Change-Id: Idef28764043bf6c33dc0d2e7e2026c38867ff769
2017-04-06 21:43:22 +02:00
} else {
// This is either in /system (or similar: /data), or is a
// modules built with the NDK. Modules built with the NDK
// will be restricted using the existing link type checks.
mctx.CreateVariations(coreMode)
}
}
func getCurrentNdkPrebuiltVersion(ctx DepsContext) string {
if ctx.AConfig().PlatformSdkVersionInt() > config.NdkMaxPrebuiltVersionInt {
return strconv.Itoa(config.NdkMaxPrebuiltVersionInt)
}
return ctx.AConfig().PlatformSdkVersion()
}
var Bool = proptools.Bool
var BoolPtr = proptools.BoolPtr
var String = proptools.String
var StringPtr = proptools.StringPtr