| // 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 ( |
| "fmt" |
| "strconv" |
| "strings" |
| |
| "github.com/google/blueprint" |
| "github.com/google/blueprint/proptools" |
| |
| "android/soong" |
| "android/soong/android" |
| "android/soong/cc/config" |
| "android/soong/genrule" |
| ) |
| |
| func init() { |
| soong.RegisterModuleType("cc_defaults", defaultsFactory) |
| |
| // LinkageMutator must be registered after common.ArchMutator, but that is guaranteed by |
| // the Go initialization order because this package depends on common, so common's init |
| // functions will run first. |
| android.RegisterBottomUpMutator("link", linkageMutator).Parallel() |
| android.RegisterBottomUpMutator("ndk_api", ndkApiMutator).Parallel() |
| android.RegisterBottomUpMutator("test_per_src", testPerSrcMutator).Parallel() |
| android.RegisterBottomUpMutator("begin", beginMutator).Parallel() |
| android.RegisterBottomUpMutator("deps", depsMutator).Parallel() |
| |
| android.RegisterTopDownMutator("asan_deps", sanitizerDepsMutator(asan)) |
| android.RegisterBottomUpMutator("asan", sanitizerMutator(asan)).Parallel() |
| |
| android.RegisterTopDownMutator("tsan_deps", sanitizerDepsMutator(tsan)) |
| android.RegisterBottomUpMutator("tsan", sanitizerMutator(tsan)).Parallel() |
| |
| pctx.Import("android/soong/cc/config") |
| } |
| |
| type Deps struct { |
| SharedLibs, LateSharedLibs []string |
| StaticLibs, LateStaticLibs, WholeStaticLibs []string |
| |
| ReexportSharedLibHeaders, ReexportStaticLibHeaders []string |
| |
| ObjFiles []string |
| |
| GeneratedSources []string |
| GeneratedHeaders []string |
| |
| CrtBegin, CrtEnd string |
| } |
| |
| type PathDeps struct { |
| SharedLibs, LateSharedLibs android.Paths |
| StaticLibs, LateStaticLibs, WholeStaticLibs android.Paths |
| |
| ObjFiles android.Paths |
| WholeStaticLibObjFiles android.Paths |
| |
| GeneratedSources android.Paths |
| GeneratedHeaders android.Paths |
| |
| Flags, ReexportedFlags []string |
| |
| CrtBegin, CrtEnd android.OptionalPath |
| } |
| |
| type Flags struct { |
| GlobalFlags []string // Flags that apply to C, C++, and assembly source files |
| AsFlags []string // Flags that apply to assembly source files |
| CFlags []string // Flags that apply to C and C++ source files |
| ConlyFlags []string // Flags that apply to C source files |
| CppFlags []string // Flags that apply to C++ source files |
| YaccFlags []string // Flags that apply to Yacc source files |
| LdFlags []string // Flags that apply to linker command lines |
| libFlags []string // Flags to add libraries early to the link order |
| |
| Toolchain config.Toolchain |
| Clang bool |
| |
| RequiredInstructionSet string |
| DynamicLinker string |
| |
| CFlagsDeps android.Paths // Files depended on by compiler flags |
| } |
| |
| type ObjectLinkerProperties struct { |
| // names of other cc_object modules to link into this module using partial linking |
| Objs []string `android:"arch_variant"` |
| } |
| |
| // 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 |
| |
| // don't insert default compiler flags into asflags, cflags, |
| // cppflags, conlyflags, ldflags, or include_dirs |
| No_default_compiler_flags *bool |
| |
| AndroidMkSharedLibs []string `blueprint:"mutated"` |
| HideFromMake bool `blueprint:"mutated"` |
| } |
| |
| type UnusedProperties struct { |
| Native_coverage *bool |
| Tags []string |
| } |
| |
| type ModuleContextIntf interface { |
| static() bool |
| staticBinary() bool |
| clang() bool |
| toolchain() config.Toolchain |
| noDefaultCompilerFlags() bool |
| sdk() bool |
| sdkVersion() string |
| selectedStl() string |
| } |
| |
| type ModuleContext interface { |
| android.ModuleContext |
| ModuleContextIntf |
| } |
| |
| type BaseModuleContext interface { |
| android.BaseContext |
| ModuleContextIntf |
| } |
| |
| type CustomizerFlagsContext interface { |
| BaseModuleContext |
| AppendCflags(...string) |
| AppendLdflags(...string) |
| AppendAsflags(...string) |
| } |
| |
| type Customizer interface { |
| Flags(CustomizerFlagsContext) |
| Properties() []interface{} |
| } |
| |
| type feature interface { |
| begin(ctx BaseModuleContext) |
| deps(ctx BaseModuleContext, deps Deps) Deps |
| flags(ctx ModuleContext, flags Flags) Flags |
| props() []interface{} |
| } |
| |
| type compiler interface { |
| compilerInit(ctx BaseModuleContext) |
| compilerDeps(ctx BaseModuleContext, deps Deps) Deps |
| compilerFlags(ctx ModuleContext, flags Flags) Flags |
| compilerProps() []interface{} |
| |
| appendCflags([]string) |
| appendAsflags([]string) |
| compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Paths |
| } |
| |
| type linker interface { |
| linkerInit(ctx BaseModuleContext) |
| linkerDeps(ctx BaseModuleContext, deps Deps) Deps |
| linkerFlags(ctx ModuleContext, flags Flags) Flags |
| linkerProps() []interface{} |
| |
| link(ctx ModuleContext, flags Flags, deps PathDeps, objFiles android.Paths) android.Path |
| appendLdflags([]string) |
| } |
| |
| type installer interface { |
| installerProps() []interface{} |
| install(ctx ModuleContext, path android.Path) |
| inData() bool |
| } |
| |
| 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} |
| genSourceDepTag = dependencyTag{name: "gen source"} |
| genHeaderDepTag = dependencyTag{name: "gen header"} |
| objDepTag = dependencyTag{name: "obj"} |
| crtBeginDepTag = dependencyTag{name: "crtbegin"} |
| crtEndDepTag = dependencyTag{name: "crtend"} |
| 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.DefaultableModule |
| |
| Properties BaseProperties |
| unused UnusedProperties |
| |
| // initialize before calling Init |
| hod android.HostOrDeviceSupported |
| multilib android.Multilib |
| |
| // delegates, initialize before calling Init |
| Customizer Customizer |
| features []feature |
| compiler compiler |
| linker linker |
| installer installer |
| stl *stl |
| sanitize *sanitize |
| |
| androidMkSharedLibDeps []string |
| |
| outputFile android.OptionalPath |
| |
| cachedToolchain config.Toolchain |
| |
| subAndroidMkOnce map[subAndroidMkProvider]bool |
| } |
| |
| func (c *Module) Init() (blueprint.Module, []interface{}) { |
| props := []interface{}{&c.Properties, &c.unused} |
| if c.Customizer != nil { |
| props = append(props, c.Customizer.Properties()...) |
| } |
| if c.compiler != nil { |
| props = append(props, c.compiler.compilerProps()...) |
| } |
| if c.linker != nil { |
| props = append(props, c.linker.linkerProps()...) |
| } |
| if c.installer != nil { |
| props = append(props, c.installer.installerProps()...) |
| } |
| if c.stl != nil { |
| props = append(props, c.stl.props()...) |
| } |
| if c.sanitize != nil { |
| props = append(props, c.sanitize.props()...) |
| } |
| for _, feature := range c.features { |
| props = append(props, feature.props()...) |
| } |
| |
| _, props = android.InitAndroidArchModule(c, c.hod, c.multilib, props...) |
| |
| return android.InitDefaultableModule(c, c, props...) |
| } |
| |
| // 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 |
| } |
| |
| type baseModuleContext struct { |
| android.BaseContext |
| moduleContextImpl |
| } |
| |
| type moduleContext struct { |
| android.ModuleContext |
| moduleContextImpl |
| } |
| |
| type moduleContextImpl struct { |
| mod *Module |
| ctx BaseModuleContext |
| } |
| |
| func (ctx *moduleContextImpl) AppendCflags(flags ...string) { |
| CheckBadCompilerFlags(ctx.ctx, "", flags) |
| ctx.mod.compiler.appendCflags(flags) |
| } |
| |
| func (ctx *moduleContextImpl) AppendAsflags(flags ...string) { |
| CheckBadCompilerFlags(ctx.ctx, "", flags) |
| ctx.mod.compiler.appendAsflags(flags) |
| } |
| |
| func (ctx *moduleContextImpl) AppendLdflags(flags ...string) { |
| CheckBadLinkerFlags(ctx.ctx, "", flags) |
| ctx.mod.linker.appendLdflags(flags) |
| } |
| |
| 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 { |
| if static, ok := ctx.mod.linker.(interface { |
| static() bool |
| }); ok { |
| return static.static() |
| } |
| return false |
| } |
| |
| func (ctx *moduleContextImpl) staticBinary() bool { |
| if static, ok := ctx.mod.linker.(interface { |
| staticBinary() bool |
| }); ok { |
| return static.staticBinary() |
| } |
| return false |
| } |
| |
| func (ctx *moduleContextImpl) noDefaultCompilerFlags() bool { |
| return Bool(ctx.mod.Properties.No_default_compiler_flags) |
| } |
| |
| func (ctx *moduleContextImpl) sdk() bool { |
| if ctx.ctx.Device() { |
| return ctx.mod.Properties.Sdk_version != "" |
| } |
| return false |
| } |
| |
| func (ctx *moduleContextImpl) sdkVersion() string { |
| if ctx.ctx.Device() { |
| return ctx.mod.Properties.Sdk_version |
| } |
| return "" |
| } |
| |
| func (ctx *moduleContextImpl) selectedStl() string { |
| if stl := ctx.mod.stl; stl != nil { |
| return stl.Properties.SelectedStl |
| } |
| return "" |
| } |
| |
| 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.stl = &stl{} |
| module.sanitize = &sanitize{} |
| return module |
| } |
| |
| func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { |
| ctx := &moduleContext{ |
| ModuleContext: actx, |
| moduleContextImpl: moduleContextImpl{ |
| mod: c, |
| }, |
| } |
| ctx.ctx = ctx |
| |
| if c.Customizer != nil { |
| c.Customizer.Flags(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) |
| } |
| 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) |
| |
| // 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"} |
| |
| deps := c.depsToPaths(ctx) |
| if ctx.Failed() { |
| return |
| } |
| |
| flags.GlobalFlags = append(flags.GlobalFlags, deps.Flags...) |
| |
| var objFiles android.Paths |
| if c.compiler != nil { |
| objFiles = c.compiler.compile(ctx, flags, deps) |
| if ctx.Failed() { |
| return |
| } |
| } |
| |
| if c.linker != nil { |
| outputFile := c.linker.link(ctx, flags, deps, objFiles) |
| if ctx.Failed() { |
| return |
| } |
| c.outputFile = android.OptionalPathForPath(outputFile) |
| |
| if c.installer != nil { |
| c.installer.install(ctx, outputFile) |
| 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) |
| } |
| for _, feature := range c.features { |
| feature.begin(ctx) |
| } |
| if ctx.sdk() { |
| version, err := normalizeNdkApiLevel(ctx.sdkVersion(), ctx.Arch()) |
| if err != nil { |
| ctx.PropertyErrorf("sdk_version", err.Error()) |
| } |
| c.Properties.Sdk_version = strconv.Itoa(version) |
| } |
| } |
| |
| func (c *Module) deps(ctx BaseModuleContext) Deps { |
| deps := Deps{} |
| |
| if c.compiler != nil { |
| deps = c.compiler.compilerDeps(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) |
| } |
| for _, feature := range c.features { |
| deps = feature.deps(ctx, deps) |
| } |
| |
| deps.WholeStaticLibs = lastUniqueElements(deps.WholeStaticLibs) |
| deps.StaticLibs = lastUniqueElements(deps.StaticLibs) |
| deps.LateStaticLibs = lastUniqueElements(deps.LateStaticLibs) |
| deps.SharedLibs = lastUniqueElements(deps.SharedLibs) |
| deps.LateSharedLibs = lastUniqueElements(deps.LateSharedLibs) |
| |
| 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) |
| } |
| } |
| |
| 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) { |
| ctx := &baseModuleContext{ |
| BaseContext: actx, |
| moduleContextImpl: moduleContextImpl{ |
| mod: c, |
| }, |
| } |
| ctx.ctx = ctx |
| |
| deps := c.deps(ctx) |
| |
| c.Properties.AndroidMkSharedLibs = append(c.Properties.AndroidMkSharedLibs, deps.SharedLibs...) |
| c.Properties.AndroidMkSharedLibs = append(c.Properties.AndroidMkSharedLibs, deps.LateSharedLibs...) |
| |
| variantNdkLibs := []string{} |
| variantLateNdkLibs := []string{} |
| if ctx.sdk() { |
| version := ctx.sdkVersion() |
| |
| // Rewrites the names of shared libraries into the names of the NDK |
| // libraries where appropriate. This returns two slices. |
| // |
| // The first is a list of non-variant shared libraries (either rewritten |
| // NDK libraries to the modules in prebuilts/ndk, or not rewritten |
| // because they are not NDK libraries). |
| // |
| // The second is a list of ndk_library modules. These need to be |
| // separated because they are a variation dependency and must be added |
| // in a different manner. |
| rewriteNdkLibs := func(list []string) ([]string, []string) { |
| variantLibs := []string{} |
| nonvariantLibs := []string{} |
| for _, entry := range list { |
| if inList(entry, ndkPrebuiltSharedLibraries) { |
| if !inList(entry, ndkMigratedLibs) { |
| nonvariantLibs = append(nonvariantLibs, entry+".ndk."+version) |
| } else { |
| variantLibs = append(variantLibs, entry+ndkLibrarySuffix) |
| } |
| } else { |
| nonvariantLibs = append(variantLibs, entry) |
| } |
| } |
| return nonvariantLibs, variantLibs |
| } |
| |
| deps.SharedLibs, variantNdkLibs = rewriteNdkLibs(deps.SharedLibs) |
| deps.LateSharedLibs, variantLateNdkLibs = rewriteNdkLibs(deps.LateSharedLibs) |
| } |
| |
| 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...) |
| actx.AddDependency(c, genHeaderDepTag, deps.GeneratedHeaders...) |
| |
| actx.AddDependency(c, objDepTag, deps.ObjFiles...) |
| |
| if deps.CrtBegin != "" { |
| actx.AddDependency(c, crtBeginDepTag, deps.CrtBegin) |
| } |
| if deps.CrtEnd != "" { |
| actx.AddDependency(c, crtEndDepTag, deps.CrtEnd) |
| } |
| |
| 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 depsMutator(ctx android.BottomUpMutatorContext) { |
| if c, ok := ctx.Module().(*Module); ok && c.Enabled() { |
| c.depsMutator(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 |
| } |
| |
| // Convert dependencies to paths. Returns a PathDeps containing paths |
| func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { |
| var depPaths PathDeps |
| |
| // Whether a module can link to another module, taking into |
| // account NDK linking. |
| checkLinkType := func(from, to *Module) { |
| if from.Target().Os != android.Android { |
| // Host code is not restricted |
| return |
| } |
| if 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 don't set sdk_version |
| return |
| } |
| if _, ok := to.linker.(*ndkPrebuiltStlLinker); ok { |
| // These are allowed, but 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 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)) |
| } |
| |
| // All 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 from.Properties.Sdk_version == "current" { |
| // Current can link against anything. |
| return |
| } else if 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(from.Properties.Sdk_version) |
| if err != nil { |
| ctx.PropertyErrorf("sdk_version", |
| "Invalid sdk_version value (must be int): %q", |
| from.Properties.Sdk_version) |
| } |
| toApi, err := strconv.Atoi(to.Properties.Sdk_version) |
| if err != nil { |
| ctx.PropertyErrorf("sdk_version", |
| "Invalid sdk_version value (must be int): %q", |
| to.Properties.Sdk_version) |
| } |
| |
| if toApi > fromApi { |
| ctx.ModuleErrorf("links %q built against newer API version %q", |
| ctx.OtherModuleName(to), to.Properties.Sdk_version) |
| } |
| } |
| |
| ctx.VisitDirectDeps(func(m blueprint.Module) { |
| name := ctx.OtherModuleName(m) |
| tag := ctx.OtherModuleDependencyTag(m) |
| |
| a, _ := m.(android.Module) |
| if a == nil { |
| ctx.ModuleErrorf("module %q not an android module", name) |
| return |
| } |
| |
| cc, _ := m.(*Module) |
| if cc == nil { |
| switch tag { |
| case android.DefaultsDepTag: |
| case genSourceDepTag: |
| if genRule, ok := m.(genrule.SourceFileGenerator); ok { |
| depPaths.GeneratedSources = append(depPaths.GeneratedSources, |
| genRule.GeneratedSourceFiles()...) |
| } else { |
| ctx.ModuleErrorf("module %q is not a gensrcs or genrule", name) |
| } |
| case genHeaderDepTag: |
| if genRule, ok := m.(genrule.SourceFileGenerator); ok { |
| depPaths.GeneratedHeaders = append(depPaths.GeneratedHeaders, |
| genRule.GeneratedSourceFiles()...) |
| depPaths.Flags = append(depPaths.Flags, |
| includeDirsToFlags(android.Paths{genRule.GeneratedHeaderDir()})) |
| } else { |
| ctx.ModuleErrorf("module %q is not a genrule", name) |
| } |
| default: |
| ctx.ModuleErrorf("depends on non-cc module %q", name) |
| } |
| return |
| } |
| |
| if !a.Enabled() { |
| ctx.ModuleErrorf("depends on disabled module %q", name) |
| return |
| } |
| |
| if a.Target().Os != ctx.Os() { |
| ctx.ModuleErrorf("OS mismatch between %q and %q", ctx.ModuleName(), name) |
| return |
| } |
| |
| if a.Target().Arch.ArchType != ctx.Arch().ArchType { |
| ctx.ModuleErrorf("Arch mismatch between %q and %q", ctx.ModuleName(), name) |
| return |
| } |
| |
| if !cc.outputFile.Valid() { |
| ctx.ModuleErrorf("module %q missing output file", name) |
| return |
| } |
| |
| if tag == reuseObjTag { |
| depPaths.ObjFiles = append(depPaths.ObjFiles, |
| cc.compiler.(libraryInterface).reuseObjs()...) |
| return |
| } |
| |
| if t, ok := tag.(dependencyTag); ok && t.library { |
| if i, ok := cc.linker.(exportedFlagsProducer); ok { |
| flags := i.exportedFlags() |
| depPaths.Flags = append(depPaths.Flags, flags...) |
| |
| if t.reexportFlags { |
| depPaths.ReexportedFlags = append(depPaths.ReexportedFlags, flags...) |
| } |
| } |
| |
| checkLinkType(c, cc) |
| } |
| |
| var depPtr *android.Paths |
| |
| switch tag { |
| case ndkStubDepTag, sharedDepTag, sharedExportDepTag: |
| depPtr = &depPaths.SharedLibs |
| case lateSharedDepTag, ndkLateStubDepTag: |
| depPtr = &depPaths.LateSharedLibs |
| case staticDepTag, staticExportDepTag: |
| depPtr = &depPaths.StaticLibs |
| case lateStaticDepTag: |
| depPtr = &depPaths.LateStaticLibs |
| case wholeStaticDepTag: |
| depPtr = &depPaths.WholeStaticLibs |
| staticLib, ok := cc.linker.(libraryInterface) |
| if !ok || !staticLib.static() { |
| ctx.ModuleErrorf("module %q not a static library", name) |
| return |
| } |
| |
| if missingDeps := staticLib.getWholeStaticMissingDeps(); missingDeps != nil { |
| postfix := " (required by " + ctx.OtherModuleName(m) + ")" |
| for i := range missingDeps { |
| missingDeps[i] += postfix |
| } |
| ctx.AddMissingDependencies(missingDeps) |
| } |
| depPaths.WholeStaticLibObjFiles = |
| append(depPaths.WholeStaticLibObjFiles, staticLib.objs()...) |
| case objDepTag: |
| depPtr = &depPaths.ObjFiles |
| case crtBeginDepTag: |
| depPaths.CrtBegin = cc.outputFile |
| case crtEndDepTag: |
| depPaths.CrtEnd = cc.outputFile |
| default: |
| panic(fmt.Errorf("unknown dependency tag: %s", tag)) |
| } |
| |
| if depPtr != nil { |
| *depPtr = append(*depPtr, cc.outputFile.Path()) |
| } |
| }) |
| |
| return depPaths |
| } |
| |
| func (c *Module) InstallInData() bool { |
| if c.installer == nil { |
| return false |
| } |
| return c.installer.inData() |
| } |
| |
| // |
| // Defaults |
| // |
| type Defaults struct { |
| android.ModuleBase |
| android.DefaultsModule |
| } |
| |
| func (*Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) { |
| } |
| |
| func defaultsFactory() (blueprint.Module, []interface{}) { |
| return DefaultsFactory() |
| } |
| |
| func DefaultsFactory(props ...interface{}) (blueprint.Module, []interface{}) { |
| module := &Defaults{} |
| |
| props = append(props, |
| &BaseProperties{}, |
| &BaseCompilerProperties{}, |
| &BaseLinkerProperties{}, |
| &LibraryProperties{}, |
| &FlagExporterProperties{}, |
| &BinaryLinkerProperties{}, |
| &TestProperties{}, |
| &TestBinaryProperties{}, |
| &UnusedProperties{}, |
| &StlProperties{}, |
| &SanitizeProperties{}, |
| &StripProperties{}, |
| ) |
| |
| _, props = android.InitAndroidArchModule(module, android.HostAndDeviceDefault, |
| android.MultilibDefault, props...) |
| |
| return android.InitDefaultsModule(module, module, props...) |
| } |
| |
| // lastUniqueElements returns all unique elements of a slice, keeping the last copy of each |
| // modifies the slice contents in place, and returns a subslice of the original slice |
| func lastUniqueElements(list []string) []string { |
| totalSkip := 0 |
| for i := len(list) - 1; i >= totalSkip; i-- { |
| skip := 0 |
| for j := i - 1; j >= totalSkip; j-- { |
| if list[i] == list[j] { |
| skip++ |
| } else { |
| list[j+skip] = list[j] |
| } |
| } |
| totalSkip += skip |
| } |
| return list[totalSkip:] |
| } |
| |
| var Bool = proptools.Bool |