| // 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", imageMutator).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.TopDown("sanitize_runtime_deps", sanitizerRuntimeDepsMutator()) |
| |
| 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 |
| RuntimeLibs []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 |
| protoOutParams []string // Flags that modify the output of proto generated 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 |
| ProtoRoot 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 |
| ArGoldPlugin bool // Whether LLVM gold plugin option is passed to llvm-ar |
| } |
| |
| 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"` |
| AndroidMkRuntimeLibs []string `blueprint:"mutated"` |
| HideFromMake bool `blueprint:"mutated"` |
| PreventInstall bool `blueprint:"mutated"` |
| |
| UseVndk bool `blueprint:"mutated"` |
| |
| // *.logtags files, to combine together in order to generate the /system/etc/event-log-tags |
| // file |
| Logtags []string |
| |
| // Make this module available when building for recovery |
| Recovery_available *bool |
| |
| InRecovery 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. |
| // |
| // 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. |
| // |
| // Nothing happens if BOARD_VNDK_VERSION isn't set in the BoardConfig.mk |
| Vendor_available *bool |
| |
| // whether this module is capable of being loaded with other instance |
| // (possibly an older version) of the same module in the same process. |
| // Currently, a shared library that is a member of VNDK (vndk: {enabled: true}) |
| // can be double loaded in a vendor process if the library is also a |
| // (direct and indirect) dependency of an LLNDK library. Such libraries must be |
| // explicitly marked as `double_loadable: true` by the owner, or the dependency |
| // from the LLNDK lib should be cut if the lib is not designed to be double loaded. |
| Double_loadable *bool |
| } |
| |
| type ModuleContextIntf interface { |
| static() bool |
| staticBinary() bool |
| clang() bool |
| toolchain() config.Toolchain |
| useSdk() bool |
| sdkVersion() string |
| useVndk() bool |
| isVndk() bool |
| isVndkSp() bool |
| isVndkExt() bool |
| inRecovery() bool |
| createVndkSourceAbiDump() bool |
| selectedStl() string |
| baseModuleName() string |
| getVndkExtendsModuleName() string |
| isPgoCompile() bool |
| } |
| |
| 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, deps PathDeps) 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} |
| vndkExtDepTag = dependencyTag{name: "vndk extends", library: true} |
| runtimeDepTag = dependencyTag{name: "runtime lib"} |
| ) |
| |
| // 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 |
| |
| // 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. depsInLinkOrder stores the proper ordering of all of the transitive |
| // deps of this module |
| depsInLinkOrder android.Paths |
| |
| // only non-nil when this is a shared library that reuses the objects of a static library |
| staticVariant *Module |
| } |
| |
| func (c *Module) Init() android.Module { |
| c.AddProperties(&c.Properties, &c.VendorProperties) |
| 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 { |
| return c.Properties.UseVndk |
| } |
| |
| func (c *Module) isVndk() bool { |
| if vndkdep := c.vndkdep; vndkdep != nil { |
| return vndkdep.isVndk() |
| } |
| return false |
| } |
| |
| func (c *Module) isPgoCompile() bool { |
| if pgo := c.pgo; pgo != nil { |
| return pgo.Properties.PgoCompile |
| } |
| return false |
| } |
| |
| func (c *Module) isVndkSp() bool { |
| if vndkdep := c.vndkdep; vndkdep != nil { |
| return vndkdep.isVndkSp() |
| } |
| return false |
| } |
| |
| func (c *Module) isVndkExt() bool { |
| if vndkdep := c.vndkdep; vndkdep != nil { |
| return vndkdep.isVndkExt() |
| } |
| return false |
| } |
| |
| func (c *Module) getVndkExtendsModuleName() string { |
| if vndkdep := c.vndkdep; vndkdep != nil { |
| return vndkdep.getVndkExtendsModuleName() |
| } |
| return "" |
| } |
| |
| // 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) |
| } |
| |
| func (c *Module) inRecovery() bool { |
| return c.Properties.InRecovery || c.ModuleBase.InstallInRecovery() |
| } |
| |
| func (c *Module) onlyInRecovery() bool { |
| return c.ModuleBase.InstallInRecovery() |
| } |
| |
| type baseModuleContext struct { |
| android.BaseContext |
| moduleContextImpl |
| } |
| |
| type depsContext struct { |
| android.BottomUpMutatorContext |
| moduleContextImpl |
| } |
| |
| type moduleContext struct { |
| android.ModuleContext |
| moduleContextImpl |
| } |
| |
| func (ctx *moduleContext) SocSpecific() bool { |
| return ctx.ModuleContext.SocSpecific() || |
| (ctx.mod.hasVendorVariant() && ctx.mod.useVndk() && !ctx.mod.isVndk()) |
| } |
| |
| 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() && !ctx.inRecovery() { |
| return String(ctx.mod.Properties.Sdk_version) != "" |
| } |
| return false |
| } |
| |
| func (ctx *moduleContextImpl) sdkVersion() string { |
| if ctx.ctx.Device() { |
| if ctx.useVndk() { |
| vndk_ver := ctx.ctx.DeviceConfig().VndkVersion() |
| if vndk_ver == "current" { |
| platform_vndk_ver := ctx.ctx.DeviceConfig().PlatformVndkVersion() |
| if inList(platform_vndk_ver, ctx.ctx.Config().PlatformVersionCombinedCodenames()) { |
| return "current" |
| } |
| return platform_vndk_ver |
| } |
| return vndk_ver |
| } |
| return String(ctx.mod.Properties.Sdk_version) |
| } |
| return "" |
| } |
| |
| func (ctx *moduleContextImpl) useVndk() bool { |
| return ctx.mod.useVndk() |
| } |
| |
| func (ctx *moduleContextImpl) isVndk() bool { |
| return ctx.mod.isVndk() |
| } |
| |
| func (ctx *moduleContextImpl) isPgoCompile() bool { |
| return ctx.mod.isPgoCompile() |
| } |
| |
| func (ctx *moduleContextImpl) isVndkSp() bool { |
| return ctx.mod.isVndkSp() |
| } |
| |
| func (ctx *moduleContextImpl) isVndkExt() bool { |
| return ctx.mod.isVndkExt() |
| } |
| |
| func (ctx *moduleContextImpl) inRecovery() bool { |
| return ctx.mod.inRecovery() |
| } |
| |
| // Create source abi dumps if the module belongs to the list of VndkLibraries. |
| func (ctx *moduleContextImpl) createVndkSourceAbiDump() bool { |
| skipAbiChecks := ctx.ctx.Config().IsEnvTrue("SKIP_ABI_CHECKS") |
| isVariantOnProductionDevice := true |
| sanitize := ctx.mod.sanitize |
| if sanitize != nil { |
| isVariantOnProductionDevice = sanitize.isVariantOnProductionDevice() |
| } |
| vendorAvailable := Bool(ctx.mod.VendorProperties.Vendor_available) |
| return !skipAbiChecks && isVariantOnProductionDevice && ctx.ctx.Device() && ((ctx.useVndk() && ctx.isVndk() && vendorAvailable) || 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 (ctx *moduleContextImpl) getVndkExtendsModuleName() string { |
| return ctx.mod.getVndkExtendsModuleName() |
| } |
| |
| 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 = <o{} |
| 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. |
| // Note that directSharedDeps should be the analogous static library for each shared lib dep |
| func orderDeps(directStaticDeps []android.Path, directSharedDeps []android.Path, allTransitiveDeps 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 directStaticDeps { |
| orderedAllDeps = append(orderedAllDeps, dep) |
| orderedAllDeps = append(orderedAllDeps, allTransitiveDeps[dep]...) |
| } |
| for _, dep := range directSharedDeps { |
| orderedAllDeps = append(orderedAllDeps, dep) |
| orderedAllDeps = append(orderedAllDeps, allTransitiveDeps[dep]...) |
| } |
| |
| orderedAllDeps = android.LastUniquePaths(orderedAllDeps) |
| |
| // We don't want to add any new dependencies into directStaticDeps (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 directStaticDeps |
| _, orderedDeclaredDeps = android.FilterPathList(orderedAllDeps, directStaticDeps) |
| |
| return orderedAllDeps, orderedDeclaredDeps |
| } |
| |
| func orderStaticModuleDeps(module *Module, staticDeps []*Module, sharedDeps []*Module) (results []android.Path) { |
| // convert Module to Path |
| allTransitiveDeps := make(map[android.Path][]android.Path, len(staticDeps)) |
| staticDepFiles := []android.Path{} |
| for _, dep := range staticDeps { |
| allTransitiveDeps[dep.outputFile.Path()] = dep.depsInLinkOrder |
| staticDepFiles = append(staticDepFiles, dep.outputFile.Path()) |
| } |
| sharedDepFiles := []android.Path{} |
| for _, sharedDep := range sharedDeps { |
| staticAnalogue := sharedDep.staticVariant |
| if staticAnalogue != nil { |
| allTransitiveDeps[staticAnalogue.outputFile.Path()] = staticAnalogue.depsInLinkOrder |
| sharedDepFiles = append(sharedDepFiles, staticAnalogue.outputFile.Path()) |
| } |
| } |
| |
| // reorder the dependencies based on transitive dependencies |
| module.depsInLinkOrder, results = orderDeps(staticDepFiles, sharedDepFiles, allTransitiveDeps) |
| |
| return results |
| } |
| |
| func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { |
| ctx := &moduleContext{ |
| ModuleContext: actx, |
| moduleContextImpl: moduleContextImpl{ |
| mod: c, |
| }, |
| } |
| ctx.ctx = ctx |
| |
| deps := c.depsToPaths(ctx) |
| if ctx.Failed() { |
| return |
| } |
| |
| flags := Flags{ |
| Toolchain: c.toolchain(ctx), |
| Clang: c.clang(ctx), |
| } |
| if c.compiler != nil { |
| flags = c.compiler.compilerFlags(ctx, flags, deps) |
| } |
| 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) |
| |
| 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) |
| deps.RuntimeLibs = android.LastUniqueStrings(deps.RuntimeLibs) |
| |
| 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 if (ctx.Platform() || ctx.ProductSpecific()) && inList(entry, vendorPublicLibraries) { |
| vendorPublicLib := entry + vendorPublicLibrarySuffix |
| if actx.OtherModuleExists(vendorPublicLib) { |
| nonvariantLibs = append(nonvariantLibs, vendorPublicLib) |
| } else { |
| // This can happen if vendor_public_library module is defined in a |
| // namespace that isn't visible to the current module. In that case, |
| // link to the original library. |
| nonvariantLibs = append(nonvariantLibs, entry) |
| } |
| } 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.AddVariationDependencies([]blueprint.Variation{{"link", "shared"}}, runtimeDepTag, |
| deps.RuntimeLibs...) |
| |
| 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...) |
| |
| if vndkdep := c.vndkdep; vndkdep != nil { |
| if vndkdep.isVndkExt() { |
| baseModuleMode := vendorMode |
| if actx.DeviceConfig().VndkVersion() == "" { |
| baseModuleMode = coreMode |
| } |
| actx.AddVariationDependencies([]blueprint.Variation{ |
| {"image", baseModuleMode}, {"link", "shared"}}, vndkExtDepTag, |
| vndkdep.getVndkExtendsModuleName()) |
| } |
| } |
| } |
| |
| 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 { |
| 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, tag dependencyTag) { |
| 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, tag) |
| } |
| return |
| } |
| if String(from.Properties.Sdk_version) == "" { |
| // Platform code can link to anything |
| return |
| } |
| if from.inRecovery() { |
| // Recovery code is not NDK |
| return |
| } |
| if _, ok := to.linker.(*toolchainLibraryDecorator); ok { |
| // These are always allowed |
| 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. |
| |
| // Current can link against anything. |
| if String(from.Properties.Sdk_version) != "current" { |
| // Otherwise we need to check. |
| 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") |
| } else { |
| fromApi, err := strconv.Atoi(String(from.Properties.Sdk_version)) |
| if err != nil { |
| ctx.PropertyErrorf("sdk_version", |
| "Invalid sdk_version value (must be int or current): %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 or current): %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)) |
| } |
| } |
| } |
| |
| // Also check that the two STL choices are compatible. |
| fromStl := from.stl.Properties.SelectedStl |
| toStl := to.stl.Properties.SelectedStl |
| if fromStl == "" || toStl == "" { |
| // Libraries that don't use the STL are unrestricted. |
| } else if fromStl == "ndk_system" || toStl == "ndk_system" { |
| // We can be permissive with the system "STL" since it is only the C++ |
| // ABI layer, but in the future we should make sure that everyone is |
| // using either libc++ or nothing. |
| } else if getNdkStlFamily(ctx, from) != getNdkStlFamily(ctx, to) { |
| ctx.ModuleErrorf("uses %q and depends on %q which uses incompatible %q", |
| from.stl.Properties.SelectedStl, ctx.OtherModuleName(to), |
| to.stl.Properties.SelectedStl) |
| } |
| } |
| |
| // Tests whether the dependent library is okay to be double loaded inside a single process. |
| // If a library is a member of VNDK and at the same time dependencies of an LLNDK library, |
| // it is subject to be double loaded. Such lib should be explicitly marked as double_loaded: true |
| // or as vndk-sp (vndk: { enabled: true, support_system_process: true}). |
| func checkDoubleLoadableLibries(ctx android.ModuleContext, from *Module, to *Module) { |
| if _, ok := from.linker.(*libraryDecorator); !ok { |
| return |
| } |
| |
| if inList(ctx.ModuleName(), llndkLibraries) || |
| (from.useVndk() && Bool(from.VendorProperties.Double_loadable)) { |
| _, depIsLlndk := to.linker.(*llndkStubDecorator) |
| depIsVndkSp := false |
| if to.vndkdep != nil && to.vndkdep.isVndkSp() { |
| depIsVndkSp = true |
| } |
| depIsVndk := false |
| if to.vndkdep != nil && to.vndkdep.isVndk() { |
| depIsVndk = true |
| } |
| depIsDoubleLoadable := Bool(to.VendorProperties.Double_loadable) |
| if !depIsLlndk && !depIsVndkSp && !depIsDoubleLoadable && depIsVndk { |
| ctx.ModuleErrorf("links VNDK library %q that isn't double_loadable.", |
| ctx.OtherModuleName(to)) |
| } |
| } |
| } |
| |
| // Convert dependencies to paths. Returns a PathDeps containing paths |
| func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { |
| var depPaths PathDeps |
| |
| directStaticDeps := []*Module{} |
| directSharedDeps := []*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 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.GeneratedDeps()...) |
| 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.GeneratedDeps()...) |
| // 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) |
| } |
| } |
| 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 { |
| c.staticVariant = ccDep |
| 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, t) |
| checkDoubleLoadableLibries(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() |
| directSharedDeps = append(directSharedDeps, ccDep) |
| 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()) |
| } |
| |
| makeLibName := func(depName string) string { |
| libName := strings.TrimSuffix(depName, llndkLibrarySuffix) |
| libName = strings.TrimSuffix(libName, vendorPublicLibrarySuffix) |
| libName = strings.TrimPrefix(libName, "prebuilt_") |
| isLLndk := inList(libName, llndkLibraries) |
| isVendorPublicLib := inList(libName, vendorPublicLibraries) |
| 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. |
| return libName + vendorSuffix |
| } else if (ctx.Platform() || ctx.ProductSpecific()) && isVendorPublicLib { |
| return libName + vendorPublicLibrarySuffix |
| } else if ccDep.inRecovery() && !ccDep.onlyInRecovery() { |
| return libName + recoverySuffix |
| } else { |
| return libName |
| } |
| } |
| |
| // Export the shared libs to Make. |
| switch depTag { |
| case sharedDepTag, sharedExportDepTag, lateSharedDepTag: |
| // 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(depName)) |
| case runtimeDepTag: |
| c.Properties.AndroidMkRuntimeLibs = append( |
| c.Properties.AndroidMkRuntimeLibs, makeLibName(depName)) |
| } |
| }) |
| |
| // use the ordered dependencies as this module's dependencies |
| depPaths.StaticLibs = append(depPaths.StaticLibs, orderStaticModuleDeps(c, directStaticDeps, directSharedDeps)...) |
| |
| // 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) InstallInRecovery() bool { |
| return c.inRecovery() |
| } |
| |
| 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{}, |
| &MoreBaseLinkerProperties{}, |
| &LibraryProperties{}, |
| &FlagExporterProperties{}, |
| &BinaryLinkerProperties{}, |
| &TestProperties{}, |
| &TestBinaryProperties{}, |
| &StlProperties{}, |
| &SanitizeProperties{}, |
| &StripProperties{}, |
| &InstallerProperties{}, |
| &TidyProperties{}, |
| &CoverageProperties{}, |
| &SAbiProperties{}, |
| &VndkProperties{}, |
| <OProperties{}, |
| &PgoProperties{}, |
| &android.ProtoProperties{}, |
| ) |
| |
| android.InitDefaultsModule(module) |
| |
| return module |
| } |
| |
| 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" |
| |
| recoveryMode = "recovery" |
| ) |
| |
| 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...) |
| } |
| } |
| |
| func squashRecoverySrcs(m *Module) { |
| if lib, ok := m.compiler.(*libraryDecorator); ok { |
| lib.baseCompiler.Properties.Srcs = append(lib.baseCompiler.Properties.Srcs, |
| lib.baseCompiler.Properties.Target.Recovery.Srcs...) |
| |
| lib.baseCompiler.Properties.Exclude_srcs = append(lib.baseCompiler.Properties.Exclude_srcs, |
| lib.baseCompiler.Properties.Target.Recovery.Exclude_srcs...) |
| } |
| } |
| |
| func imageMutator(mctx android.BottomUpMutatorContext) { |
| if mctx.Os() != android.Android { |
| return |
| } |
| |
| if genrule, ok := mctx.Module().(*genrule.Module); ok { |
| if props, ok := genrule.Extra.(*GenruleExtraProperties); ok { |
| var coreVariantNeeded bool = false |
| var vendorVariantNeeded bool = false |
| var recoveryVariantNeeded bool = false |
| if mctx.DeviceConfig().VndkVersion() == "" { |
| coreVariantNeeded = true |
| } else if Bool(props.Vendor_available) { |
| coreVariantNeeded = true |
| vendorVariantNeeded = true |
| } else if mctx.SocSpecific() || mctx.DeviceSpecific() { |
| vendorVariantNeeded = true |
| } else { |
| coreVariantNeeded = true |
| } |
| if Bool(props.Recovery_available) { |
| recoveryVariantNeeded = true |
| } |
| |
| var variants []string |
| if coreVariantNeeded { |
| variants = append(variants, coreMode) |
| } |
| if vendorVariantNeeded { |
| variants = append(variants, vendorMode) |
| } |
| if recoveryVariantNeeded { |
| variants = append(variants, recoveryMode) |
| } |
| mctx.CreateVariations(variants...) |
| } |
| } |
| |
| m, ok := mctx.Module().(*Module) |
| if !ok { |
| return |
| } |
| |
| // Sanity check |
| vendorSpecific := mctx.SocSpecific() || mctx.DeviceSpecific() |
| |
| if m.VendorProperties.Vendor_available != nil && vendorSpecific { |
| mctx.PropertyErrorf("vendor_available", |
| "doesn't make sense at the same time as `vendor: true`, `proprietary: true`, or `device_specific:true`") |
| return |
| } |
| |
| if vndkdep := m.vndkdep; vndkdep != nil { |
| if vndkdep.isVndk() { |
| if vendorSpecific { |
| if !vndkdep.isVndkExt() { |
| mctx.PropertyErrorf("vndk", |
| "must set `extends: \"...\"` to vndk extension") |
| return |
| } |
| } else { |
| if vndkdep.isVndkExt() { |
| mctx.PropertyErrorf("vndk", |
| "must set `vendor: true` to set `extends: %q`", |
| m.getVndkExtendsModuleName()) |
| return |
| } |
| if m.VendorProperties.Vendor_available == nil { |
| mctx.PropertyErrorf("vndk", |
| "vendor_available must be set to either true or false when `vndk: {enabled: true}`") |
| return |
| } |
| } |
| } else { |
| if vndkdep.isVndkSp() { |
| mctx.PropertyErrorf("vndk", |
| "must set `enabled: true` to set `support_system_process: true`") |
| return |
| } |
| if vndkdep.isVndkExt() { |
| mctx.PropertyErrorf("vndk", |
| "must set `enabled: true` to set `extends: %q`", |
| m.getVndkExtendsModuleName()) |
| return |
| } |
| } |
| } |
| |
| var coreVariantNeeded bool = false |
| var vendorVariantNeeded bool = false |
| var recoveryVariantNeeded bool = false |
| |
| if mctx.DeviceConfig().VndkVersion() == "" { |
| // If the device isn't compiling against the VNDK, we always |
| // use the core mode. |
| coreVariantNeeded = true |
| } 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. |
| vendorVariantNeeded = true |
| } else if _, ok := m.linker.(*llndkHeadersDecorator); ok { |
| // ... and LL-NDK headers as well |
| vendorVariantNeeded = true |
| } else if _, ok := m.linker.(*vndkPrebuiltLibraryDecorator); ok { |
| // Make vendor variants only for the versions in BOARD_VNDK_VERSION and |
| // PRODUCT_EXTRA_VNDK_VERSIONS. |
| vendorVariantNeeded = true |
| } else if m.hasVendorVariant() && !vendorSpecific { |
| // This will be available in both /system and /vendor |
| // or a /system directory that is available to vendor. |
| coreVariantNeeded = true |
| vendorVariantNeeded = true |
| } else if vendorSpecific && String(m.Properties.Sdk_version) == "" { |
| // This will be available in /vendor (or /odm) only |
| vendorVariantNeeded = true |
| } 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. |
| coreVariantNeeded = true |
| } |
| |
| if Bool(m.Properties.Recovery_available) { |
| recoveryVariantNeeded = true |
| } |
| |
| if m.ModuleBase.InstallInRecovery() { |
| recoveryVariantNeeded = true |
| coreVariantNeeded = false |
| } |
| |
| var variants []string |
| if coreVariantNeeded { |
| variants = append(variants, coreMode) |
| } |
| if vendorVariantNeeded { |
| variants = append(variants, vendorMode) |
| } |
| if recoveryVariantNeeded { |
| variants = append(variants, recoveryMode) |
| } |
| mod := mctx.CreateVariations(variants...) |
| for i, v := range variants { |
| if v == vendorMode { |
| m := mod[i].(*Module) |
| m.Properties.UseVndk = true |
| squashVendorSrcs(m) |
| } else if v == recoveryMode { |
| m := mod[i].(*Module) |
| m.Properties.InRecovery = true |
| squashRecoverySrcs(m) |
| } |
| } |
| } |
| |
| func getCurrentNdkPrebuiltVersion(ctx DepsContext) string { |
| if ctx.Config().PlatformSdkVersionInt() > config.NdkMaxPrebuiltVersionInt { |
| return strconv.Itoa(config.NdkMaxPrebuiltVersionInt) |
| } |
| return ctx.Config().PlatformSdkVersion() |
| } |
| |
| var Bool = proptools.Bool |
| var BoolDefault = proptools.BoolDefault |
| var BoolPtr = proptools.BoolPtr |
| var String = proptools.String |
| var StringPtr = proptools.StringPtr |