diff options
109 files changed, 3846 insertions, 1470 deletions
diff --git a/Android.bp b/Android.bp index 25038c653..1dfac875a 100644 --- a/Android.bp +++ b/Android.bp @@ -67,6 +67,7 @@ bootstrap_go_package { "android/proto.go", "android/register.go", "android/rule_builder.go", + "android/sdk.go", "android/sh_binary.go", "android/singleton.go", "android/testing.go", @@ -171,6 +172,7 @@ bootstrap_go_package { "cc/vndk_prebuilt.go", "cc/xom.go", + "cc/cflag_artifacts.go", "cc/cmakelists.go", "cc/compdb.go", "cc/compiler.go", @@ -303,7 +305,6 @@ bootstrap_go_package { "java/jdeps_test.go", "java/kotlin_test.go", "java/plugin_test.go", - "java/robolectric_test.go", "java/sdk_test.go", ], pluginFor: ["soong_build"], @@ -332,8 +333,11 @@ bootstrap_go_package { "soong-cc-config", ], srcs: [ + "rust/config/arm_device.go", + "rust/config/arm64_device.go", "rust/config/global.go", "rust/config/toolchain.go", + "rust/config/whitelist.go", "rust/config/x86_linux_host.go", "rust/config/x86_64_device.go", ], @@ -474,6 +478,26 @@ bootstrap_go_package { pluginFor: ["soong_build"], } +bootstrap_go_package { + name: "soong-sdk", + pkgPath: "android/soong/sdk", + deps: [ + "blueprint", + "soong", + "soong-android", + "soong-apex", + "soong-cc", + "soong-java", + ], + srcs: [ + "sdk/sdk.go", + ], + testSrcs: [ + "sdk/sdk_test.go", + ], + pluginFor: ["soong_build"], +} + // // Defaults to enable various configurations of host bionic // @@ -4,3 +4,4 @@ per-file ndk_*.go, *gen_stub_libs.py = danalbert@google.com per-file clang.go,global.go = srhines@google.com, chh@google.com, pirama@google.com, yikong@google.com per-file tidy.go = srhines@google.com, chh@google.com per-file lto.go,pgo.go = srhines@google.com, pirama@google.com, yikong@google.com +per-file rust/config/whitelist.go = chh@google.com, ivanlozano@google.com, jeffv@google.com, jgalenson@google.com, srhines@google.com diff --git a/android/androidmk.go b/android/androidmk.go index 124523f4c..907134776 100644 --- a/android/androidmk.go +++ b/android/androidmk.go @@ -80,12 +80,14 @@ type AndroidMkEntries struct { footer bytes.Buffer ExtraEntries []AndroidMkExtraEntriesFunc + ExtraFooters []AndroidMkExtraFootersFunc EntryMap map[string][]string entryOrder []string } type AndroidMkExtraEntriesFunc func(entries *AndroidMkEntries) +type AndroidMkExtraFootersFunc func(w io.Writer, name, prefix, moduleDir string, entries *AndroidMkEntries) func (a *AndroidMkEntries) SetString(name, value string) { if _, ok := a.EntryMap[name]; !ok { @@ -94,6 +96,13 @@ func (a *AndroidMkEntries) SetString(name, value string) { a.EntryMap[name] = []string{value} } +func (a *AndroidMkEntries) SetPath(name string, path Path) { + if _, ok := a.EntryMap[name]; !ok { + a.entryOrder = append(a.entryOrder, name) + } + a.EntryMap[name] = []string{path.String()} +} + func (a *AndroidMkEntries) SetBoolIfTrue(name string, flag bool) { if flag { if _, ok := a.EntryMap[name]; !ok { @@ -103,6 +112,17 @@ func (a *AndroidMkEntries) SetBoolIfTrue(name string, flag bool) { } } +func (a *AndroidMkEntries) SetBool(name string, flag bool) { + if _, ok := a.EntryMap[name]; !ok { + a.entryOrder = append(a.entryOrder, name) + } + if flag { + a.EntryMap[name] = []string{"true"} + } else { + a.EntryMap[name] = []string{"false"} + } +} + func (a *AndroidMkEntries) AddStrings(name string, value ...string) { if len(value) == 0 { return @@ -254,9 +274,21 @@ func (a *AndroidMkEntries) fillInEntries(config Config, bpPath string, mod bluep // Write to footer. fmt.Fprintln(&a.footer, "include "+a.Include) + blueprintDir := filepath.Dir(bpPath) + for _, footerFunc := range a.ExtraFooters { + footerFunc(&a.footer, name, prefix, blueprintDir, a) + } } func (a *AndroidMkEntries) write(w io.Writer) { + if a.Disabled { + return + } + + if !a.OutputFile.Valid() { + return + } + w.Write(a.header.Bytes()) for _, name := range a.entryOrder { fmt.Fprintln(w, name+" := "+strings.Join(a.EntryMap[name], " ")) @@ -264,6 +296,10 @@ func (a *AndroidMkEntries) write(w io.Writer) { w.Write(a.footer.Bytes()) } +func (a *AndroidMkEntries) FooterLinesForTests() []string { + return strings.Split(string(a.footer.Bytes()), "\n") +} + func AndroidMkSingleton() Singleton { return &androidMkSingleton{} } diff --git a/android/apex.go b/android/apex.go index 99b13ab72..557febfc9 100644 --- a/android/apex.go +++ b/android/apex.go @@ -78,12 +78,23 @@ type ApexModule interface { // Return the no_apex property NoApex() bool + + // Tests if this module is available for the specified APEX or ":platform" + AvailableFor(what string) bool } type ApexProperties struct { // Whether this module should not be part of any APEX. Default is false. + // TODO(b/128708192): remove this as this is equal to apex_available: [":platform"] No_apex *bool + // Availability of this module in APEXes. Only the listed APEXes can include this module. + // "//apex_available:anyapex" is a pseudo APEX name that matches to any APEX. + // "//apex_available:platform" refers to non-APEX partitions like "system.img". + // Default is ["//apex_available:platform", "//apex_available:anyapex"]. + // TODO(b/128708192) change the default to ["//apex_available:platform"] + Apex_available []string + // Name of the apex variant that this module is mutated into ApexName string `blueprint:"mutated"` } @@ -136,15 +147,46 @@ func (m *ApexModuleBase) NoApex() bool { return proptools.Bool(m.ApexProperties.No_apex) } +const ( + availableToPlatform = "//apex_available:platform" + availableToAnyApex = "//apex_available:anyapex" +) + +func (m *ApexModuleBase) AvailableFor(what string) bool { + if len(m.ApexProperties.Apex_available) == 0 { + // apex_available defaults to ["//apex_available:platform", "//apex_available:anyapex"], + // which means 'available to everybody'. + return true + } + return InList(what, m.ApexProperties.Apex_available) || + (what != availableToPlatform && InList(availableToAnyApex, m.ApexProperties.Apex_available)) +} + +func (m *ApexModuleBase) checkApexAvailableProperty(mctx BaseModuleContext) { + for _, n := range m.ApexProperties.Apex_available { + if n == availableToPlatform || n == availableToAnyApex { + continue + } + if !mctx.OtherModuleExists(n) { + mctx.PropertyErrorf("apex_available", "%q is not a valid module name", n) + } + } +} + func (m *ApexModuleBase) CreateApexVariations(mctx BottomUpMutatorContext) []blueprint.Module { if len(m.apexVariations) > 0 { + m.checkApexAvailableProperty(mctx) sort.Strings(m.apexVariations) - variations := []string{""} // Original variation for platform + variations := []string{} + availableForPlatform := m.AvailableFor(availableToPlatform) + if availableForPlatform { + variations = append(variations, "") // Original variation for platform + } variations = append(variations, m.apexVariations...) modules := mctx.CreateVariations(variations...) for i, m := range modules { - if i == 0 { + if availableForPlatform && i == 0 { continue } m.(ApexModule).setApexName(variations[i]) diff --git a/android/arch.go b/android/arch.go index b0389560b..348b06492 100644 --- a/android/arch.go +++ b/android/arch.go @@ -854,149 +854,11 @@ func decodeMultilib(base *ModuleBase, class OsClass) (multilib, extraMultilib st } } -func filterArchStructFields(fields []reflect.StructField) (filteredFields []reflect.StructField, filtered bool) { - for _, field := range fields { - if !proptools.HasTag(field, "android", "arch_variant") { - filtered = true - continue - } - - // The arch_variant field isn't necessary past this point - // Instead of wasting space, just remove it. Go also has a - // 16-bit limit on structure name length. The name is constructed - // based on the Go source representation of the structure, so - // the tag names count towards that length. - // - // TODO: handle the uncommon case of other tags being involved - if field.Tag == `android:"arch_variant"` { - field.Tag = "" - } - - // Recurse into structs - switch field.Type.Kind() { - case reflect.Struct: - var subFiltered bool - field.Type, subFiltered = filterArchStruct(field.Type) - filtered = filtered || subFiltered - if field.Type == nil { - continue - } - case reflect.Ptr: - if field.Type.Elem().Kind() == reflect.Struct { - nestedType, subFiltered := filterArchStruct(field.Type.Elem()) - filtered = filtered || subFiltered - if nestedType == nil { - continue - } - field.Type = reflect.PtrTo(nestedType) - } - case reflect.Interface: - panic("Interfaces are not supported in arch_variant properties") - } - - filteredFields = append(filteredFields, field) - } - - return filteredFields, filtered -} - -// filterArchStruct takes a reflect.Type that is either a sturct or a pointer to a struct, and returns a reflect.Type -// that only contains the fields in the original type that have an `android:"arch_variant"` struct tag, and a bool -// that is true if the new struct type has fewer fields than the original type. If there are no fields in the -// original type with the struct tag it returns nil and true. -func filterArchStruct(prop reflect.Type) (filteredProp reflect.Type, filtered bool) { - var fields []reflect.StructField - - ptr := prop.Kind() == reflect.Ptr - if ptr { - prop = prop.Elem() - } - - for i := 0; i < prop.NumField(); i++ { - fields = append(fields, prop.Field(i)) - } - - filteredFields, filtered := filterArchStructFields(fields) - - if len(filteredFields) == 0 { - return nil, true - } - - if !filtered { - if ptr { - return reflect.PtrTo(prop), false - } - return prop, false - } - - ret := reflect.StructOf(filteredFields) - if ptr { - ret = reflect.PtrTo(ret) - } - - return ret, true -} - -// filterArchStruct takes a reflect.Type that is either a sturct or a pointer to a struct, and returns a list of -// reflect.Type that only contains the fields in the original type that have an `android:"arch_variant"` struct tag, -// and a bool that is true if the new struct type has fewer fields than the original type. If there are no fields in -// the original type with the struct tag it returns nil and true. Each returned struct type will have a maximum of -// 10 top level fields in it to attempt to avoid hitting the reflect.StructOf name length limit, although the limit -// can still be reached with a single struct field with many fields in it. -func filterArchStructSharded(prop reflect.Type) (filteredProp []reflect.Type, filtered bool) { - var fields []reflect.StructField - - ptr := prop.Kind() == reflect.Ptr - if ptr { - prop = prop.Elem() - } - - for i := 0; i < prop.NumField(); i++ { - fields = append(fields, prop.Field(i)) - } - - fields, filtered = filterArchStructFields(fields) - if !filtered { - if ptr { - return []reflect.Type{reflect.PtrTo(prop)}, false - } - return []reflect.Type{prop}, false - } - - if len(fields) == 0 { - return nil, true - } - - shards := shardFields(fields, 10) - - for _, shard := range shards { - s := reflect.StructOf(shard) - if ptr { - s = reflect.PtrTo(s) - } - filteredProp = append(filteredProp, s) - } - - return filteredProp, true -} - -func shardFields(fields []reflect.StructField, shardSize int) [][]reflect.StructField { - ret := make([][]reflect.StructField, 0, (len(fields)+shardSize-1)/shardSize) - for len(fields) > shardSize { - ret = append(ret, fields[0:shardSize]) - fields = fields[shardSize:] - } - if len(fields) > 0 { - ret = append(ret, fields) - } - return ret -} - // createArchType takes a reflect.Type that is either a struct or a pointer to a struct, and returns a list of // reflect.Type that contains the arch-variant properties inside structs for each architecture, os, target, multilib, // etc. func createArchType(props reflect.Type) []reflect.Type { - propShards, _ := filterArchStructSharded(props) + propShards, _ := proptools.FilterPropertyStructSharded(props, filterArchStruct) if len(propShards) == 0 { return nil } @@ -1095,6 +957,23 @@ func createArchType(props reflect.Type) []reflect.Type { return ret } +func filterArchStruct(field reflect.StructField, prefix string) (bool, reflect.StructField) { + if proptools.HasTag(field, "android", "arch_variant") { + // The arch_variant field isn't necessary past this point + // Instead of wasting space, just remove it. Go also has a + // 16-bit limit on structure name length. The name is constructed + // based on the Go source representation of the structure, so + // the tag names count towards that length. + // + // TODO: handle the uncommon case of other tags being involved + if field.Tag == `android:"arch_variant"` { + field.Tag = "" + } + return true, field + } + return false, field +} + var archPropTypeMap OncePer func InitArchModule(m Module) { diff --git a/android/arch_test.go b/android/arch_test.go index 0589e6c3a..11edb4f1c 100644 --- a/android/arch_test.go +++ b/android/arch_test.go @@ -17,6 +17,8 @@ package android import ( "reflect" "testing" + + "github.com/google/blueprint/proptools" ) type Named struct { @@ -219,7 +221,7 @@ func TestFilterArchStruct(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - out, filtered := filterArchStruct(reflect.TypeOf(test.in)) + out, filtered := proptools.FilterPropertyStruct(reflect.TypeOf(test.in), filterArchStruct) if filtered != test.filtered { t.Errorf("expected filtered %v, got %v", test.filtered, filtered) } diff --git a/android/config.go b/android/config.go index 209b4ded9..26c4e6ebd 100644 --- a/android/config.go +++ b/android/config.go @@ -813,7 +813,7 @@ func (c *config) ArtUseReadBarrier() bool { func (c *config) EnforceRROForModule(name string) bool { enforceList := c.productVariables.EnforceRROTargets if enforceList != nil { - if len(enforceList) == 1 && (enforceList)[0] == "*" { + if InList("*", enforceList) { return true } return InList(name, enforceList) diff --git a/android/hooks.go b/android/hooks.go index 58109961b..604cb9c28 100644 --- a/android/hooks.go +++ b/android/hooks.go @@ -30,7 +30,7 @@ type LoadHookContext interface { BaseModuleContext AppendProperties(...interface{}) PrependProperties(...interface{}) - CreateModule(blueprint.ModuleFactory, ...interface{}) + CreateModule(ModuleFactory, ...interface{}) Module } // Arch hooks are run after the module has been split into architecture variants, and can be used @@ -75,7 +75,7 @@ func (x *hooks) runArchHooks(ctx ArchHookContext, m *ModuleBase) { type InstallHookContext interface { ModuleContext - Path() OutputPath + Path() InstallPath Symlink() bool } @@ -89,11 +89,11 @@ func AddInstallHook(m blueprint.Module, hook func(InstallHookContext)) { type installHookContext struct { ModuleContext - path OutputPath + path InstallPath symlink bool } -func (x *installHookContext) Path() OutputPath { +func (x *installHookContext) Path() InstallPath { return x.path } @@ -101,7 +101,7 @@ func (x *installHookContext) Symlink() bool { return x.symlink } -func (x *hooks) runInstallHooks(ctx ModuleContext, path OutputPath, symlink bool) { +func (x *hooks) runInstallHooks(ctx ModuleContext, path InstallPath, symlink bool) { if len(x.install) > 0 { mctx := &installHookContext{ ModuleContext: ctx, diff --git a/android/module.go b/android/module.go index 8076a99ff..6988ac0d4 100644 --- a/android/module.go +++ b/android/module.go @@ -147,15 +147,17 @@ type ModuleContext interface { ExpandSource(srcFile, prop string) Path ExpandOptionalSource(srcFile *string, prop string) OptionalPath - InstallExecutable(installPath OutputPath, name string, srcPath Path, deps ...Path) OutputPath - InstallFile(installPath OutputPath, name string, srcPath Path, deps ...Path) OutputPath - InstallSymlink(installPath OutputPath, name string, srcPath OutputPath) OutputPath - InstallAbsoluteSymlink(installPath OutputPath, name string, absPath string) OutputPath + InstallExecutable(installPath InstallPath, name string, srcPath Path, deps ...Path) InstallPath + InstallFile(installPath InstallPath, name string, srcPath Path, deps ...Path) InstallPath + InstallSymlink(installPath InstallPath, name string, srcPath InstallPath) InstallPath + InstallAbsoluteSymlink(installPath InstallPath, name string, absPath string) InstallPath CheckbuildFile(srcPath Path) InstallInData() bool + InstallInTestcases() bool InstallInSanitizerDir() bool InstallInRecovery() bool + InstallInRoot() bool InstallBypassMake() bool RequiredModuleNames() []string @@ -192,8 +194,10 @@ type Module interface { Enabled() bool Target() Target InstallInData() bool + InstallInTestcases() bool InstallInSanitizerDir() bool InstallInRecovery() bool + InstallInRoot() bool InstallBypassMake() bool SkipInstall() ExportedToMake() bool @@ -832,6 +836,10 @@ func (m *ModuleBase) InstallInData() bool { return false } +func (m *ModuleBase) InstallInTestcases() bool { + return false +} + func (m *ModuleBase) InstallInSanitizerDir() bool { return false } @@ -840,6 +848,10 @@ func (m *ModuleBase) InstallInRecovery() bool { return Bool(m.commonProperties.Recovery) } +func (m *ModuleBase) InstallInRoot() bool { + return false +} + func (m *ModuleBase) InstallBypassMake() bool { return false } @@ -1177,6 +1189,12 @@ func (m *moduleContext) Variable(pctx PackageContext, name, value string) { func (m *moduleContext) Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule { + if m.config.UseGoma() && params.Pool == nil { + // When USE_GOMA=true is set and the rule is not supported by goma, restrict jobs to the + // local parallelism value + params.Pool = localPool + } + rule := m.bp.Rule(pctx.PackageContext, name, params, argNames...) if m.config.captureBuild { @@ -1504,6 +1522,10 @@ func (m *moduleContext) InstallInData() bool { return m.module.InstallInData() } +func (m *moduleContext) InstallInTestcases() bool { + return m.module.InstallInTestcases() +} + func (m *moduleContext) InstallInSanitizerDir() bool { return m.module.InstallInSanitizerDir() } @@ -1512,11 +1534,15 @@ func (m *moduleContext) InstallInRecovery() bool { return m.module.InstallInRecovery() } +func (m *moduleContext) InstallInRoot() bool { + return m.module.InstallInRoot() +} + func (m *moduleContext) InstallBypassMake() bool { return m.module.InstallBypassMake() } -func (m *moduleContext) skipInstall(fullInstallPath OutputPath) bool { +func (m *moduleContext) skipInstall(fullInstallPath InstallPath) bool { if m.module.base().commonProperties.SkipInstall { return true } @@ -1541,18 +1567,18 @@ func (m *moduleContext) skipInstall(fullInstallPath OutputPath) bool { return false } -func (m *moduleContext) InstallFile(installPath OutputPath, name string, srcPath Path, - deps ...Path) OutputPath { +func (m *moduleContext) InstallFile(installPath InstallPath, name string, srcPath Path, + deps ...Path) InstallPath { return m.installFile(installPath, name, srcPath, Cp, deps) } -func (m *moduleContext) InstallExecutable(installPath OutputPath, name string, srcPath Path, - deps ...Path) OutputPath { +func (m *moduleContext) InstallExecutable(installPath InstallPath, name string, srcPath Path, + deps ...Path) InstallPath { return m.installFile(installPath, name, srcPath, CpExecutable, deps) } -func (m *moduleContext) installFile(installPath OutputPath, name string, srcPath Path, - rule blueprint.Rule, deps []Path) OutputPath { +func (m *moduleContext) installFile(installPath InstallPath, name string, srcPath Path, + rule blueprint.Rule, deps []Path) InstallPath { fullInstallPath := installPath.Join(m, name) m.module.base().hooks.runInstallHooks(m, fullInstallPath, false) @@ -1587,7 +1613,7 @@ func (m *moduleContext) installFile(installPath OutputPath, name string, srcPath return fullInstallPath } -func (m *moduleContext) InstallSymlink(installPath OutputPath, name string, srcPath OutputPath) OutputPath { +func (m *moduleContext) InstallSymlink(installPath InstallPath, name string, srcPath InstallPath) InstallPath { fullInstallPath := installPath.Join(m, name) m.module.base().hooks.runInstallHooks(m, fullInstallPath, true) @@ -1616,7 +1642,7 @@ func (m *moduleContext) InstallSymlink(installPath OutputPath, name string, srcP // installPath/name -> absPath where absPath might be a path that is available only at runtime // (e.g. /apex/...) -func (m *moduleContext) InstallAbsoluteSymlink(installPath OutputPath, name string, absPath string) OutputPath { +func (m *moduleContext) InstallAbsoluteSymlink(installPath InstallPath, name string, absPath string) InstallPath { fullInstallPath := installPath.Join(m, name) m.module.base().hooks.runInstallHooks(m, fullInstallPath, true) diff --git a/android/mutator.go b/android/mutator.go index e76f847c9..510e63c0c 100644 --- a/android/mutator.go +++ b/android/mutator.go @@ -121,7 +121,7 @@ type TopDownMutatorContext interface { Rename(name string) - CreateModule(blueprint.ModuleFactory, ...interface{}) + CreateModule(ModuleFactory, ...interface{}) Module } type topDownMutatorContext struct { @@ -243,9 +243,10 @@ func (t *topDownMutatorContext) Rename(name string) { t.Module().base().commonProperties.DebugName = name } -func (t *topDownMutatorContext) CreateModule(factory blueprint.ModuleFactory, props ...interface{}) { +func (t *topDownMutatorContext) CreateModule(factory ModuleFactory, props ...interface{}) Module { inherited := []interface{}{&t.Module().base().commonProperties, &t.Module().base().variableProperties} - t.bp.CreateModule(factory, append(inherited, props...)...) + module := t.bp.CreateModule(ModuleFactoryAdaptor(factory), append(inherited, props...)...).(Module) + return module } func (b *bottomUpMutatorContext) MutatorName() string { diff --git a/android/notices.go b/android/notices.go index 7b61d65ba..bf273b544 100644 --- a/android/notices.go +++ b/android/notices.go @@ -60,7 +60,7 @@ func MergeNotices(ctx ModuleContext, mergedNotice WritablePath, noticePaths []Pa }) } -func BuildNoticeOutput(ctx ModuleContext, installPath OutputPath, installFilename string, +func BuildNoticeOutput(ctx ModuleContext, installPath InstallPath, installFilename string, noticePaths []Path) NoticeOutputs { // Merge all NOTICE files into one. // TODO(jungjw): We should just produce a well-formatted NOTICE.html file in a single pass. diff --git a/android/package_ctx.go b/android/package_ctx.go index 00b99ff62..548450e44 100644 --- a/android/package_ctx.go +++ b/android/package_ctx.go @@ -104,7 +104,8 @@ func (p PackageContext) PoolFunc(name string, } // RuleFunc wraps blueprint.PackageContext.RuleFunc, converting the interface{} config -// argument to a Context that supports Config(). +// argument to a Context that supports Config(), and provides a default Pool if none is +// specified. func (p PackageContext) RuleFunc(name string, f func(PackageRuleContext) blueprint.RuleParams, argNames ...string) blueprint.Rule { @@ -114,6 +115,11 @@ func (p PackageContext) RuleFunc(name string, if len(ctx.errors) > 0 { return params, ctx.errors[0] } + if ctx.Config().UseGoma() && params.Pool == nil { + // When USE_GOMA=true is set and the rule is not supported by goma, restrict jobs to the + // local parallelism value + params.Pool = localPool + } return params, nil }, argNames...) } @@ -234,10 +240,16 @@ func (p PackageContext) PrefixedExistentPathsForSourcesVariable( }) } -// AndroidStaticRule wraps blueprint.StaticRule and provides a default Pool if none is specified +// AndroidStaticRule is an alias for StaticRule. func (p PackageContext) AndroidStaticRule(name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule { - return p.AndroidRuleFunc(name, func(PackageRuleContext) blueprint.RuleParams { + return p.StaticRule(name, params, argNames...) +} + +// StaticRule wraps blueprint.StaticRule and provides a default Pool if none is specified. +func (p PackageContext) StaticRule(name string, params blueprint.RuleParams, + argNames ...string) blueprint.Rule { + return p.RuleFunc(name, func(PackageRuleContext) blueprint.RuleParams { return params }, argNames...) } @@ -245,18 +257,6 @@ func (p PackageContext) AndroidStaticRule(name string, params blueprint.RulePara // AndroidGomaStaticRule wraps blueprint.StaticRule but uses goma's parallelism if goma is enabled func (p PackageContext) AndroidGomaStaticRule(name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule { - return p.StaticRule(name, params, argNames...) -} - -func (p PackageContext) AndroidRuleFunc(name string, - f func(PackageRuleContext) blueprint.RuleParams, argNames ...string) blueprint.Rule { - return p.RuleFunc(name, func(ctx PackageRuleContext) blueprint.RuleParams { - params := f(ctx) - if ctx.Config().UseGoma() && params.Pool == nil { - // When USE_GOMA=true is set and the rule is not supported by goma, restrict jobs to the - // local parallelism value - params.Pool = localPool - } - return params - }, argNames...) + // bypass android.PackageContext.StaticRule so that Pool does not get set to local_pool. + return p.PackageContext.StaticRule(name, params, argNames...) } diff --git a/android/paths.go b/android/paths.go index 0d64a61db..8dbb08644 100644 --- a/android/paths.go +++ b/android/paths.go @@ -44,8 +44,10 @@ type ModuleInstallPathContext interface { BaseModuleContext InstallInData() bool + InstallInTestcases() bool InstallInSanitizerDir() bool InstallInRecovery() bool + InstallInRoot() bool InstallBypassMake() bool } @@ -791,7 +793,7 @@ func (p SourcePath) OverlayPath(ctx ModuleContext, path Path) OptionalPath { return OptionalPathForPath(PathForSource(ctx, relPath)) } -// OutputPath is a Path representing a file path rooted from the build directory +// OutputPath is a Path representing an intermediates file path rooted from the build directory type OutputPath struct { basePath } @@ -819,17 +821,6 @@ func PathForOutput(ctx PathContext, pathComponents ...string) OutputPath { return OutputPath{basePath{path, ctx.Config(), ""}} } -// pathForInstallInMakeDir is used by PathForModuleInstall when the module returns true -// for InstallBypassMake to produce an OutputPath that installs to $OUT_DIR instead of -// $OUT_DIR/soong. -func pathForInstallInMakeDir(ctx PathContext, pathComponents ...string) OutputPath { - path, err := validatePath(pathComponents...) - if err != nil { - reportPathError(ctx, err) - } - return OutputPath{basePath{"../" + path, ctx.Config(), ""}} -} - // PathsForOutput returns Paths rooted from buildDir func PathsForOutput(ctx PathContext, paths []string) WritablePaths { ret := make(WritablePaths, len(paths)) @@ -845,10 +836,6 @@ func (p OutputPath) String() string { return filepath.Join(p.config.buildDir, p.path) } -func (p OutputPath) RelPathString() string { - return p.path -} - // Join creates a new OutputPath with paths... joined with the current path. The // provided paths... may not use '..' to escape from the current path. func (p OutputPath) Join(ctx PathContext, paths ...string) OutputPath { @@ -1117,9 +1104,44 @@ func PathForModuleRes(ctx ModuleContext, pathComponents ...string) ModuleResPath return ModuleResPath{PathForModuleOut(ctx, "res", p)} } +// InstallPath is a Path representing a installed file path rooted from the build directory +type InstallPath struct { + basePath + + baseDir string // "../" for Make paths to convert "out/soong" to "out", "" for Soong paths +} + +func (p InstallPath) writablePath() {} + +func (p InstallPath) String() string { + return filepath.Join(p.config.buildDir, p.baseDir, p.path) +} + +// Join creates a new InstallPath with paths... joined with the current path. The +// provided paths... may not use '..' to escape from the current path. +func (p InstallPath) Join(ctx PathContext, paths ...string) InstallPath { + path, err := validatePath(paths...) + if err != nil { + reportPathError(ctx, err) + } + return p.withRel(path) +} + +func (p InstallPath) withRel(rel string) InstallPath { + p.basePath = p.basePath.withRel(rel) + return p +} + +// ToMakePath returns a new InstallPath that points to Make's install directory instead of Soong's, +// i.e. out/ instead of out/soong/. +func (p InstallPath) ToMakePath() InstallPath { + p.baseDir = "../" + return p +} + // PathForModuleInstall returns a Path representing the install path for the // module appended with paths... -func PathForModuleInstall(ctx ModuleInstallPathContext, pathComponents ...string) OutputPath { +func PathForModuleInstall(ctx ModuleInstallPathContext, pathComponents ...string) InstallPath { var outPaths []string if ctx.Device() { partition := modulePartition(ctx) @@ -1139,13 +1161,30 @@ func PathForModuleInstall(ctx ModuleInstallPathContext, pathComponents ...string outPaths = append([]string{"debug"}, outPaths...) } outPaths = append(outPaths, pathComponents...) + + path, err := validatePath(outPaths...) + if err != nil { + reportPathError(ctx, err) + } + + ret := InstallPath{basePath{path, ctx.Config(), ""}, ""} if ctx.InstallBypassMake() && ctx.Config().EmbeddedInMake() { - return pathForInstallInMakeDir(ctx, outPaths...) + ret = ret.ToMakePath() } - return PathForOutput(ctx, outPaths...) + + return ret } -func InstallPathToOnDevicePath(ctx PathContext, path OutputPath) string { +func PathForNdkInstall(ctx PathContext, paths ...string) InstallPath { + paths = append([]string{"ndk"}, paths...) + path, err := validatePath(paths...) + if err != nil { + reportPathError(ctx, err) + } + return InstallPath{basePath{path, ctx.Config(), ""}, ""} +} + +func InstallPathToOnDevicePath(ctx PathContext, path InstallPath) string { rel := Rel(ctx, PathForOutput(ctx, "target", "product", ctx.Config().DeviceName()).String(), path.String()) return "/" + rel @@ -1155,9 +1194,15 @@ func modulePartition(ctx ModuleInstallPathContext) string { var partition string if ctx.InstallInData() { partition = "data" + } else if ctx.InstallInTestcases() { + partition = "testcases" } else if ctx.InstallInRecovery() { - // the layout of recovery partion is the same as that of system partition - partition = "recovery/root/system" + if ctx.InstallInRoot() { + partition = "recovery/root" + } else { + // the layout of recovery partion is the same as that of system partition + partition = "recovery/root/system" + } } else if ctx.SocSpecific() { partition = ctx.DeviceConfig().VendorPath() } else if ctx.DeviceSpecific() { @@ -1166,6 +1211,8 @@ func modulePartition(ctx ModuleInstallPathContext) string { partition = ctx.DeviceConfig().ProductPath() } else if ctx.SystemExtSpecific() { partition = ctx.DeviceConfig().SystemExtPath() + } else if ctx.InstallInRoot() { + partition = "root" } else { partition = "system" } diff --git a/android/paths_test.go b/android/paths_test.go index f2996bff8..2e67272e0 100644 --- a/android/paths_test.go +++ b/android/paths_test.go @@ -201,8 +201,10 @@ type moduleInstallPathContextImpl struct { baseModuleContext inData bool + inTestcases bool inSanitizerDir bool inRecovery bool + inRoot bool } func (moduleInstallPathContextImpl) Fs() pathtools.FileSystem { @@ -219,6 +221,10 @@ func (m moduleInstallPathContextImpl) InstallInData() bool { return m.inData } +func (m moduleInstallPathContextImpl) InstallInTestcases() bool { + return m.inTestcases +} + func (m moduleInstallPathContextImpl) InstallInSanitizerDir() bool { return m.inSanitizerDir } @@ -227,6 +233,10 @@ func (m moduleInstallPathContextImpl) InstallInRecovery() bool { return m.inRecovery } +func (m moduleInstallPathContextImpl) InstallInRoot() bool { + return m.inRoot +} + func (m moduleInstallPathContextImpl) InstallBypassMake() bool { return false } @@ -308,6 +318,40 @@ func TestPathForModuleInstall(t *testing.T) { in: []string{"bin", "my_test"}, out: "target/product/test_device/system_ext/bin/my_test", }, + { + name: "root binary", + ctx: &moduleInstallPathContextImpl{ + baseModuleContext: baseModuleContext{ + target: deviceTarget, + }, + inRoot: true, + }, + in: []string{"my_test"}, + out: "target/product/test_device/root/my_test", + }, + { + name: "recovery binary", + ctx: &moduleInstallPathContextImpl{ + baseModuleContext: baseModuleContext{ + target: deviceTarget, + }, + inRecovery: true, + }, + in: []string{"bin/my_test"}, + out: "target/product/test_device/recovery/root/system/bin/my_test", + }, + { + name: "recovery root binary", + ctx: &moduleInstallPathContextImpl{ + baseModuleContext: baseModuleContext{ + target: deviceTarget, + }, + inRecovery: true, + inRoot: true, + }, + in: []string{"my_test"}, + out: "target/product/test_device/recovery/root/my_test", + }, { name: "system native test binary", diff --git a/android/prebuilt_etc.go b/android/prebuilt_etc.go index d29ed16f6..6c4813bd1 100644 --- a/android/prebuilt_etc.go +++ b/android/prebuilt_etc.go @@ -65,7 +65,7 @@ type PrebuiltEtc struct { installDirBase string // The base install location when soc_specific property is set to true, e.g. "firmware" for prebuilt_firmware. socInstallDirBase string - installDirPath OutputPath + installDirPath InstallPath additionalDependencies *Paths } @@ -91,7 +91,7 @@ func (p *PrebuiltEtc) SourceFilePath(ctx ModuleContext) Path { return PathForModuleSrc(ctx, String(p.properties.Src)) } -func (p *PrebuiltEtc) InstallDirPath() OutputPath { +func (p *PrebuiltEtc) InstallDirPath() InstallPath { return p.installDirPath } @@ -158,7 +158,7 @@ func (p *PrebuiltEtc) AndroidMkEntries() AndroidMkEntries { ExtraEntries: []AndroidMkExtraEntriesFunc{ func(entries *AndroidMkEntries) { entries.SetString("LOCAL_MODULE_TAGS", "optional") - entries.SetString("LOCAL_MODULE_PATH", "$(OUT_DIR)/"+p.installDirPath.RelPathString()) + entries.SetString("LOCAL_MODULE_PATH", p.installDirPath.ToMakePath().String()) entries.SetString("LOCAL_INSTALLED_MODULE_STEM", p.outputFilePath.Base()) entries.SetString("LOCAL_UNINSTALLABLE_MODULE", strconv.FormatBool(!p.Installable())) if p.additionalDependencies != nil { diff --git a/android/prebuilt_etc_test.go b/android/prebuilt_etc_test.go index 0a2c7a4f5..f675ea3c3 100644 --- a/android/prebuilt_etc_test.go +++ b/android/prebuilt_etc_test.go @@ -182,9 +182,9 @@ func TestPrebuiltUserShareInstallDirPath(t *testing.T) { `) p := ctx.ModuleForTests("foo.conf", "android_arm64_armv8-a_core").Module().(*PrebuiltEtc) - expected := "target/product/test_device/system/usr/share/bar" - if p.installDirPath.RelPathString() != expected { - t.Errorf("expected %q, got %q", expected, p.installDirPath.RelPathString()) + expected := buildDir + "/target/product/test_device/system/usr/share/bar" + if p.installDirPath.String() != expected { + t.Errorf("expected %q, got %q", expected, p.installDirPath.String()) } } @@ -199,9 +199,9 @@ func TestPrebuiltUserShareHostInstallDirPath(t *testing.T) { buildOS := BuildOs.String() p := ctx.ModuleForTests("foo.conf", buildOS+"_common").Module().(*PrebuiltEtc) - expected := filepath.Join("host", config.PrebuiltOS(), "usr", "share", "bar") - if p.installDirPath.RelPathString() != expected { - t.Errorf("expected %q, got %q", expected, p.installDirPath.RelPathString()) + expected := filepath.Join(buildDir, "host", config.PrebuiltOS(), "usr", "share", "bar") + if p.installDirPath.String() != expected { + t.Errorf("expected %q, got %q", expected, p.installDirPath.String()) } } @@ -214,14 +214,14 @@ func TestPrebuiltFontInstallDirPath(t *testing.T) { `) p := ctx.ModuleForTests("foo.conf", "android_arm64_armv8-a_core").Module().(*PrebuiltEtc) - expected := "target/product/test_device/system/fonts" - if p.installDirPath.RelPathString() != expected { - t.Errorf("expected %q, got %q", expected, p.installDirPath.RelPathString()) + expected := buildDir + "/target/product/test_device/system/fonts" + if p.installDirPath.String() != expected { + t.Errorf("expected %q, got %q", expected, p.installDirPath.String()) } } func TestPrebuiltFirmwareDirPath(t *testing.T) { - targetPath := "target/product/test_device" + targetPath := buildDir + "/target/product/test_device" tests := []struct { description string config string @@ -249,7 +249,7 @@ func TestPrebuiltFirmwareDirPath(t *testing.T) { t.Run(tt.description, func(t *testing.T) { ctx, _ := testPrebuiltEtc(t, tt.config) p := ctx.ModuleForTests("foo.conf", "android_arm64_armv8-a_core").Module().(*PrebuiltEtc) - if p.installDirPath.RelPathString() != tt.expectedPath { + if p.installDirPath.String() != tt.expectedPath { t.Errorf("expected %q, got %q", tt.expectedPath, p.installDirPath) } }) diff --git a/android/sdk.go b/android/sdk.go new file mode 100644 index 000000000..52c392f4d --- /dev/null +++ b/android/sdk.go @@ -0,0 +1,146 @@ +// Copyright (C) 2019 The Android Open Source Project +// +// 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 android + +import ( + "strings" + + "github.com/google/blueprint/proptools" +) + +// SdkAware is the interface that must be supported by any module to become a member of SDK or to be +// built with SDK +type SdkAware interface { + Module + sdkBase() *SdkBase + MakeMemberOf(sdk SdkRef) + IsInAnySdk() bool + ContainingSdk() SdkRef + MemberName() string + BuildWithSdks(sdks SdkRefs) + RequiredSdks() SdkRefs +} + +// SdkRef refers to a version of an SDK +type SdkRef struct { + Name string + Version string +} + +const ( + // currentVersion refers to the in-development version of an SDK + currentVersion = "current" +) + +// IsCurrentVersion determines if the SdkRef is referencing to an in-development version of an SDK +func (s SdkRef) IsCurrentVersion() bool { + return s.Version == currentVersion +} + +// IsCurrentVersionOf determines if the SdkRef is referencing to an in-development version of the +// specified SDK +func (s SdkRef) IsCurrentVersionOf(name string) bool { + return s.Name == name && s.IsCurrentVersion() +} + +// ParseSdkRef parses a `name#version` style string into a corresponding SdkRef struct +func ParseSdkRef(ctx BaseModuleContext, str string, property string) SdkRef { + tokens := strings.Split(str, "#") + if len(tokens) < 1 || len(tokens) > 2 { + ctx.PropertyErrorf(property, "%q does not follow name#version syntax", str) + return SdkRef{Name: "invalid sdk name", Version: "invalid sdk version"} + } + + name := tokens[0] + + version := currentVersion // If version is omitted, defaults to "current" + if len(tokens) == 2 { + version = tokens[1] + } + + return SdkRef{Name: name, Version: version} +} + +type SdkRefs []SdkRef + +func (refs SdkRefs) Contains(s SdkRef) bool { + for _, r := range refs { + if r == s { + return true + } + } + return false +} + +type sdkProperties struct { + // The SDK that this module is a member of. nil if it is not a member of any SDK + ContainingSdk *SdkRef `blueprint:"mutated"` + + // The list of SDK names and versions that are used to build this module + RequiredSdks SdkRefs `blueprint:"mutated"` + + // Name of the module that this sdk member is representing + Sdk_member_name *string +} + +// SdkBase is a struct that is expected to be included in module types to implement the SdkAware +// interface. InitSdkAwareModule should be called to initialize this struct. +type SdkBase struct { + properties sdkProperties +} + +func (s *SdkBase) sdkBase() *SdkBase { + return s +} + +// MakeMemberof sets this module to be a member of a specific SDK +func (s *SdkBase) MakeMemberOf(sdk SdkRef) { + s.properties.ContainingSdk = &sdk +} + +// IsInAnySdk returns true if this module is a member of any SDK +func (s *SdkBase) IsInAnySdk() bool { + return s.properties.ContainingSdk != nil +} + +// ContainingSdk returns the SDK that this module is a member of +func (s *SdkBase) ContainingSdk() SdkRef { + if s.properties.ContainingSdk != nil { + return *s.properties.ContainingSdk + } + return SdkRef{Name: "", Version: currentVersion} +} + +// Membername returns the name of the module that this SDK member is overriding +func (s *SdkBase) MemberName() string { + return proptools.String(s.properties.Sdk_member_name) +} + +// BuildWithSdks is used to mark that this module has to be built with the given SDK(s). +func (s *SdkBase) BuildWithSdks(sdks SdkRefs) { + s.properties.RequiredSdks = sdks +} + +// RequiredSdks returns the SDK(s) that this module has to be built with +func (s *SdkBase) RequiredSdks() SdkRefs { + return s.properties.RequiredSdks +} + +// InitSdkAwareModule initializes the SdkBase struct. This must be called by all modules including +// SdkBase. +func InitSdkAwareModule(m SdkAware) { + base := m.sdkBase() + m.AddProperties(&base.properties) +} diff --git a/android/sh_binary.go b/android/sh_binary.go index ba0c8be7d..6db9892fa 100644 --- a/android/sh_binary.go +++ b/android/sh_binary.go @@ -48,6 +48,9 @@ type shBinaryProperties struct { // Whether this module is directly installable to one of the partitions. Default: true. Installable *bool + + // install symlinks to the binary + Symlinks []string `android:"arch_variant"` } type TestProperties struct { @@ -103,6 +106,10 @@ func (s *ShBinary) Installable() bool { return s.properties.Installable == nil || Bool(s.properties.Installable) } +func (s *ShBinary) Symlinks() []string { + return s.properties.Symlinks +} + func (s *ShBinary) GenerateAndroidBuildActions(ctx ModuleContext) { s.sourceFilePath = PathForModuleSrc(ctx, String(s.properties.Src)) filename := String(s.properties.Filename) @@ -145,6 +152,9 @@ func (s *ShBinary) customAndroidMkEntries(entries *AndroidMkEntries) { entries.SetString("LOCAL_MODULE_RELATIVE_PATH", String(s.properties.Sub_dir)) entries.SetString("LOCAL_MODULE_SUFFIX", "") entries.SetString("LOCAL_MODULE_STEM", s.outputFilePath.Rel()) + if len(s.properties.Symlinks) > 0 { + entries.SetString("LOCAL_MODULE_SYMLINKS", strings.Join(s.properties.Symlinks, " ")) + } } func (s *ShTest) GenerateAndroidBuildActions(ctx ModuleContext) { diff --git a/android/singleton.go b/android/singleton.go index a59d54aa2..7f9c21606 100644 --- a/android/singleton.go +++ b/android/singleton.go @@ -127,6 +127,11 @@ func (s *singletonContextAdaptor) Variable(pctx PackageContext, name, value stri } func (s *singletonContextAdaptor) Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule { + if s.Config().UseGoma() && params.Pool == nil { + // When USE_GOMA=true is set and the rule is not supported by goma, restrict jobs to the + // local parallelism value + params.Pool = localPool + } rule := s.SingletonContext.Rule(pctx.PackageContext, name, params, argNames...) if s.Config().captureBuild { s.ruleParams[rule] = params diff --git a/android/util.go b/android/util.go index 010244209..71ded5e07 100644 --- a/android/util.go +++ b/android/util.go @@ -319,3 +319,36 @@ func SplitFileExt(name string) (string, string, string) { return root, suffix, ext } + +// ShardPaths takes a Paths, and returns a slice of Paths where each one has at most shardSize paths. +func ShardPaths(paths Paths, shardSize int) []Paths { + if len(paths) == 0 { + return nil + } + ret := make([]Paths, 0, (len(paths)+shardSize-1)/shardSize) + for len(paths) > shardSize { + ret = append(ret, paths[0:shardSize]) + paths = paths[shardSize:] + } + if len(paths) > 0 { + ret = append(ret, paths) + } + return ret +} + +// ShardStrings takes a slice of strings, and returns a slice of slices of strings where each one has at most shardSize +// elements. +func ShardStrings(s []string, shardSize int) [][]string { + if len(s) == 0 { + return nil + } + ret := make([][]string, 0, (len(s)+shardSize-1)/shardSize) + for len(s) > shardSize { + ret = append(ret, s[0:shardSize]) + s = s[shardSize:] + } + if len(s) > 0 { + ret = append(ret, s) + } + return ret +} diff --git a/android/util_test.go b/android/util_test.go index 1df1c5af5..90fefeede 100644 --- a/android/util_test.go +++ b/android/util_test.go @@ -469,3 +469,102 @@ func TestSplitFileExt(t *testing.T) { } }) } + +func Test_Shard(t *testing.T) { + type args struct { + strings []string + shardSize int + } + tests := []struct { + name string + args args + want [][]string + }{ + { + name: "empty", + args: args{ + strings: nil, + shardSize: 1, + }, + want: [][]string(nil), + }, + { + name: "single shard", + args: args{ + strings: []string{"a", "b"}, + shardSize: 2, + }, + want: [][]string{{"a", "b"}}, + }, + { + name: "single short shard", + args: args{ + strings: []string{"a", "b"}, + shardSize: 3, + }, + want: [][]string{{"a", "b"}}, + }, + { + name: "shard per input", + args: args{ + strings: []string{"a", "b", "c"}, + shardSize: 1, + }, + want: [][]string{{"a"}, {"b"}, {"c"}}, + }, + { + name: "balanced shards", + args: args{ + strings: []string{"a", "b", "c", "d"}, + shardSize: 2, + }, + want: [][]string{{"a", "b"}, {"c", "d"}}, + }, + { + name: "unbalanced shards", + args: args{ + strings: []string{"a", "b", "c"}, + shardSize: 2, + }, + want: [][]string{{"a", "b"}, {"c"}}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Run("strings", func(t *testing.T) { + if got := ShardStrings(tt.args.strings, tt.args.shardSize); !reflect.DeepEqual(got, tt.want) { + t.Errorf("ShardStrings(%v, %v) = %v, want %v", + tt.args.strings, tt.args.shardSize, got, tt.want) + } + }) + + t.Run("paths", func(t *testing.T) { + stringsToPaths := func(strings []string) Paths { + if strings == nil { + return nil + } + paths := make(Paths, len(strings)) + for i, s := range strings { + paths[i] = PathForTesting(s) + } + return paths + } + + paths := stringsToPaths(tt.args.strings) + + var want []Paths + if sWant := tt.want; sWant != nil { + want = make([]Paths, len(sWant)) + for i, w := range sWant { + want[i] = stringsToPaths(w) + } + } + + if got := ShardPaths(paths, tt.args.shardSize); !reflect.DeepEqual(got, want) { + t.Errorf("ShardPaths(%v, %v) = %v, want %v", + paths, tt.args.shardSize, got, want) + } + }) + }) + } +} diff --git a/apex/apex.go b/apex/apex.go index 23f6d3729..5f714259b 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -47,13 +47,15 @@ var ( Description: "fs_config ${out}", }, "ro_paths", "exec_paths") - injectApexDependency = pctx.StaticRule("injectApexDependency", blueprint.RuleParams{ + apexManifestRule = pctx.StaticRule("apexManifestRule", blueprint.RuleParams{ Command: `rm -f $out && ${jsonmodify} $in ` + `-a provideNativeLibs ${provideNativeLibs} ` + - `-a requireNativeLibs ${requireNativeLibs} -o $out`, + `-a requireNativeLibs ${requireNativeLibs} ` + + `${opt} ` + + `-o $out`, CommandDeps: []string{"${jsonmodify}"}, - Description: "Inject dependency into ${out}", - }, "provideNativeLibs", "requireNativeLibs") + Description: "prepare ${out}", + }, "provideNativeLibs", "requireNativeLibs", "opt") // TODO(b/113233103): make sure that file_contexts is sane, i.e., validate // against the binary policy using sefcontext_compiler -p <policy>. @@ -150,8 +152,6 @@ var ( var ( whitelistNoApex = map[string][]string{ "apex_test_build_features": []string{"libbinder"}, - "com.android.neuralnetworks": []string{"libbinder"}, - "com.android.media": []string{"libbinder"}, "com.android.media.swcodec": []string{"libbinder"}, "test_com.android.media.swcodec": []string{"libbinder"}, "com.android.vndk": []string{"libbinder"}, @@ -185,7 +185,7 @@ func init() { pctx.HostBinToolVariable("zipalign", "zipalign") pctx.HostBinToolVariable("jsonmodify", "jsonmodify") - android.RegisterModuleType("apex", apexBundleFactory) + android.RegisterModuleType("apex", BundleFactory) android.RegisterModuleType("apex_test", testApexBundleFactory) android.RegisterModuleType("apex_vndk", vndkApexBundleFactory) android.RegisterModuleType("apex_defaults", defaultsFactory) @@ -195,12 +195,14 @@ func init() { ctx.TopDown("apex_vndk_gather", apexVndkGatherMutator).Parallel() ctx.BottomUp("apex_vndk_add_deps", apexVndkAddDepsMutator).Parallel() }) - android.PostDepsMutators(func(ctx android.RegisterMutatorsContext) { - ctx.TopDown("apex_deps", apexDepsMutator) - ctx.BottomUp("apex", apexMutator).Parallel() - ctx.BottomUp("apex_flattened", apexFlattenedMutator).Parallel() - ctx.BottomUp("apex_uses", apexUsesMutator).Parallel() - }) + android.PostDepsMutators(RegisterPostDepsMutators) +} + +func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) { + ctx.TopDown("apex_deps", apexDepsMutator) + ctx.BottomUp("apex", apexMutator).Parallel() + ctx.BottomUp("apex_flattened", apexFlattenedMutator).Parallel() + ctx.BottomUp("apex_uses", apexUsesMutator).Parallel() } var ( @@ -220,12 +222,14 @@ func apexVndkGatherMutator(mctx android.TopDownMutatorContext) { if ab.IsNativeBridgeSupported() { mctx.PropertyErrorf("native_bridge_supported", "%q doesn't support native bridge binary.", mctx.ModuleType()) } - vndkVersion := proptools.StringDefault(ab.vndkProperties.Vndk_version, mctx.DeviceConfig().PlatformVndkVersion()) + + vndkVersion := proptools.String(ab.vndkProperties.Vndk_version) + vndkApexListMutex.Lock() defer vndkApexListMutex.Unlock() vndkApexList := vndkApexList(mctx.Config()) if other, ok := vndkApexList[vndkVersion]; ok { - mctx.PropertyErrorf("vndk_version", "%v is already defined in %q", vndkVersion, other.Name()) + mctx.PropertyErrorf("vndk_version", "%v is already defined in %q", vndkVersion, other.BaseModuleName()) } vndkApexList[vndkVersion] = ab } @@ -287,11 +291,14 @@ func apexMutator(mctx android.BottomUpMutatorContext) { } func apexFlattenedMutator(mctx android.BottomUpMutatorContext) { - if _, ok := mctx.Module().(*apexBundle); ok { + if ab, ok := mctx.Module().(*apexBundle); ok { if !mctx.Config().FlattenApex() || mctx.Config().UnbundledBuild() { modules := mctx.CreateLocalVariations("", "flattened") modules[0].(*apexBundle).SetFlattened(false) modules[1].(*apexBundle).SetFlattened(true) + } else { + ab.SetFlattened(true) + ab.SetFlattenedConfigValue() } } } @@ -339,8 +346,9 @@ type apexBundleProperties struct { // If unspecified, a default one is automatically generated. AndroidManifest *string `android:"path"` - // Canonical name of the APEX bundle in the manifest file. - // If unspecified, defaults to the value of name + // Canonical name of the APEX bundle. Used to determine the path to the activated APEX on + // device (/apex/<apex_name>). + // If unspecified, defaults to the value of name. Apex_name *string // Determines the file contexts file for setting security context to each file in this APEX bundle. @@ -406,9 +414,19 @@ type apexBundleProperties struct { // List of APKs to package inside APEX Apps []string - // To distinguish between flattened and non-flattened variants. - // if set true, then this variant is flattened variant. + // To distinguish between flattened and non-flattened apex. + // if set true, then output files are flattened. Flattened bool `blueprint:"mutated"` + + // if true, it means that TARGET_FLATTEN_APEX is true and + // TARGET_BUILD_APPS is false + FlattenedConfigValue bool `blueprint:"mutated"` + + // List of SDKs that are used to build this APEX. A reference to an SDK should be either + // `name#version` or `name` which is an alias for `name#current`. If left empty, `platform#current` + // is implied. This value affects all modules included in this APEX. In other words, they are + // also built with the SDKs specified here. + Uses_sdks []string } type apexTargetBundleProperties struct { @@ -535,6 +553,7 @@ type apexFile struct { type apexBundle struct { android.ModuleBase android.DefaultableModuleBase + android.SdkBase properties apexBundleProperties targetProperties apexTargetBundleProperties @@ -544,8 +563,8 @@ type apexBundle struct { bundleModuleFile android.WritablePath outputFiles map[apexPackaging]android.WritablePath - flattenedOutput android.OutputPath - installDir android.OutputPath + flattenedOutput android.InstallPath + installDir android.InstallPath prebuiltFileToDelete string @@ -566,9 +585,6 @@ type apexBundle struct { // intermediate path for apex_manifest.json manifestOut android.WritablePath - - // A config value of (TARGET_FLATTEN_APEX && !TARGET_BUILD_APPS) - flattenedConfigValue bool } func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext, @@ -737,6 +753,16 @@ func (a *apexBundle) DepsMutator(ctx android.BottomUpMutatorContext) { if cert != "" { ctx.AddDependency(ctx.Module(), certificateTag, cert) } + + // TODO(jiyong): ensure that all apexes are with non-empty uses_sdks + if len(a.properties.Uses_sdks) > 0 { + sdkRefs := []android.SdkRef{} + for _, str := range a.properties.Uses_sdks { + parsed := android.ParseSdkRef(ctx, str, "uses_sdks") + sdkRefs = append(sdkRefs, parsed) + } + a.BuildWithSdks(sdkRefs) + } } func (a *apexBundle) getCertString(ctx android.BaseModuleContext) string { @@ -773,7 +799,7 @@ func (a *apexBundle) installable() bool { func (a *apexBundle) getImageVariation(config android.DeviceConfig) string { if config.VndkVersion() != "" && proptools.Bool(a.properties.Use_vendor) { - return "vendor" + return "vendor." + config.PlatformVndkVersion() } else { return "core" } @@ -819,6 +845,20 @@ func (a *apexBundle) SetFlattened(flattened bool) { a.properties.Flattened = flattened } +func (a *apexBundle) SetFlattenedConfigValue() { + a.properties.FlattenedConfigValue = true +} + +// isFlattenedVariant returns true when the current module is the flattened +// variant of an apex that has both a flattened and an unflattened variant. +// It returns false when the current module is flattened but there is no +// unflattened variant, which occurs when ctx.Config().FlattenedApex() returns +// true. It can be used to avoid collisions between the install paths of the +// flattened and unflattened variants. +func (a *apexBundle) isFlattenedVariant() bool { + return a.properties.Flattened && !a.properties.FlattenedConfigValue +} + func getCopyManifestForNativeLibrary(ccMod *cc.Module, config android.Config, handleSpecialLibs bool) (fileToCopy android.Path, dirInApex string) { // Decide the APEX-local directory by the multilib of the library // In the future, we may query this to the module. @@ -993,7 +1033,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { return true } else if sh, ok := child.(*android.ShBinary); ok { fileToCopy, dirInApex := getCopyManifestForShBinary(sh) - filesInfo = append(filesInfo, apexFile{fileToCopy, depName, dirInApex, shBinary, sh, nil}) + filesInfo = append(filesInfo, apexFile{fileToCopy, depName, dirInApex, shBinary, sh, sh.Symlinks()}) } else if py, ok := child.(*python.Module); ok && py.HostToolPath().Valid() { fileToCopy, dirInApex := getCopyManifestForPyBinary(py) filesInfo = append(filesInfo, apexFile{fileToCopy, depName, dirInApex, pyBinary, py, nil}) @@ -1128,6 +1168,8 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { } } else if am.CanHaveApexVariants() && am.IsInstallableToApex() { ctx.ModuleErrorf("unexpected tag %q for indirect dependency %q", depTag, depName) + } else if depTag == android.DefaultsDepTag { + return false } else if am.NoApex() && !android.InList(depName, whitelistNoApex[ctx.ModuleName()]) { ctx.ModuleErrorf("tries to include no_apex module %s", depName) } @@ -1136,10 +1178,6 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { return false }) - a.flattenedConfigValue = ctx.Config().FlattenApex() && !ctx.Config().UnbundledBuild() - if a.flattenedConfigValue { - a.properties.Flattened = true - } if a.private_key_file == nil { ctx.PropertyErrorf("key", "private_key for %q could not be found", String(a.properties.Key)) return @@ -1175,6 +1213,16 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { } } + // check apex_available requirements + for _, fi := range filesInfo { + if am, ok := fi.module.(android.ApexModule); ok { + if !am.AvailableFor(ctx.ModuleName()) { + ctx.ModuleErrorf("requires %q that is not available for the APEX", fi.module.Name()) + return + } + } + } + // prepend the name of this APEX to the module names. These names will be the names of // modules that will be defined if the APEX is flattened. for i := range filesInfo { @@ -1184,18 +1232,28 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.installDir = android.PathForModuleInstall(ctx, "apex") a.filesInfo = filesInfo + // prepare apex_manifest.json a.manifestOut = android.PathForModuleOut(ctx, "apex_manifest.json") - // put dependency({provide|require}NativeLibs) in apex_manifest.json manifestSrc := android.PathForModuleSrc(ctx, proptools.StringDefault(a.properties.Manifest, "apex_manifest.json")) + + // put dependency({provide|require}NativeLibs) in apex_manifest.json provideNativeLibs = android.SortedUniqueStrings(provideNativeLibs) requireNativeLibs = android.SortedUniqueStrings(android.RemoveListFromList(requireNativeLibs, provideNativeLibs)) + + // apex name can be overridden + optCommands := []string{} + if a.properties.Apex_name != nil { + optCommands = append(optCommands, "-v name "+*a.properties.Apex_name) + } + ctx.Build(pctx, android.BuildParams{ - Rule: injectApexDependency, + Rule: apexManifestRule, Input: manifestSrc, Output: a.manifestOut, Args: map[string]string{ "provideNativeLibs": strings.Join(provideNativeLibs, " "), "requireNativeLibs": strings.Join(requireNativeLibs, " "), + "opt": strings.Join(optCommands, " "), }, }) @@ -1409,6 +1467,12 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext, apexType ap optFlags = append(optFlags, "--no_hashtree") } + if a.properties.Apex_name != nil { + // If apex_name is set, apexer can skip checking if key name matches with apex name. + // Note that apex_manifest is also mended. + optFlags = append(optFlags, "--do_not_check_keyname") + } + ctx.Build(pctx, android.BuildParams{ Rule: apexRule, Implicits: implicitInputs, @@ -1478,7 +1542,7 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext, apexType ap }) // Install to $OUT/soong/{target,host}/.../apex - if a.installable() && (!ctx.Config().FlattenApex() || apexType.zip()) && (!a.properties.Flattened || a.flattenedConfigValue) { + if a.installable() && (!ctx.Config().FlattenApex() || apexType.zip()) && !a.isFlattenedVariant() { ctx.InstallFile(a.installDir, ctx.ModuleName()+suffix, a.outputFiles[apexType]) } } @@ -1543,7 +1607,7 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, name, moduleDir string, apex } var suffix string - if a.properties.Flattened && !a.flattenedConfigValue { + if a.isFlattenedVariant() { suffix = ".flattened" } @@ -1554,14 +1618,14 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, name, moduleDir string, apex fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)") fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir) fmt.Fprintln(w, "LOCAL_MODULE :=", fi.moduleName+suffix) - // /apex/<name>/{lib|framework|...} + // /apex/<apex_name>/{lib|framework|...} pathWhenActivated := filepath.Join("$(PRODUCT_OUT)", "apex", proptools.StringDefault(a.properties.Apex_name, name), fi.installDir) if a.properties.Flattened && apexType.image() { // /system/apex/<name>/{lib|framework|...} - fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", filepath.Join("$(OUT_DIR)", - a.installDir.RelPathString(), name, fi.installDir)) - if a.flattenedConfigValue { + fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", filepath.Join(a.installDir.ToMakePath().String(), + name, fi.installDir)) + if !a.isFlattenedVariant() { fmt.Fprintln(w, "LOCAL_SOONG_SYMBOL_PATH :=", pathWhenActivated) } if len(fi.symlinks) > 0 { @@ -1643,7 +1707,7 @@ func (a *apexBundle) androidMkForType(apexType apexPackaging) android.AndroidMkD moduleNames = a.androidMkForFiles(w, name, moduleDir, apexType) } - if a.properties.Flattened && !a.flattenedConfigValue { + if a.isFlattenedVariant() { name = name + ".flattened" } @@ -1658,7 +1722,7 @@ func (a *apexBundle) androidMkForType(apexType apexPackaging) android.AndroidMkD fmt.Fprintln(w, "include $(BUILD_PHONY_PACKAGE)") fmt.Fprintln(w, "$(LOCAL_INSTALLED_MODULE): .KATI_IMPLICIT_OUTPUTS :=", a.flattenedOutput.String()) - } else if !a.properties.Flattened || a.flattenedConfigValue { + } else if !a.isFlattenedVariant() { // zip-apex is the less common type so have the name refer to the image-apex // only and use {name}.zip if you want the zip-apex if apexType == zipApex && a.apexTypes == both { @@ -1669,7 +1733,7 @@ func (a *apexBundle) androidMkForType(apexType apexPackaging) android.AndroidMkD fmt.Fprintln(w, "LOCAL_MODULE :=", name) fmt.Fprintln(w, "LOCAL_MODULE_CLASS := ETC") // do we need a new class? fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", a.outputFiles[apexType].String()) - fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", filepath.Join("$(OUT_DIR)", a.installDir.RelPathString())) + fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", a.installDir.ToMakePath().String()) fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", name+apexType.suffix()) fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE :=", !a.installable()) if len(moduleNames) > 0 { @@ -1680,7 +1744,7 @@ func (a *apexBundle) androidMkForType(apexType apexPackaging) android.AndroidMkD } if a.prebuiltFileToDelete != "" { fmt.Fprintln(w, "LOCAL_POST_INSTALL_CMD :=", "rm -rf "+ - filepath.Join("$(OUT_DIR)", a.installDir.RelPathString(), a.prebuiltFileToDelete)) + filepath.Join(a.installDir.ToMakePath().String(), a.prebuiltFileToDelete)) } fmt.Fprintln(w, "include $(BUILD_PREBUILT)") @@ -1702,6 +1766,7 @@ func newApexBundle() *apexBundle { }) android.InitAndroidMultiTargetsArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon) android.InitDefaultableModule(module) + android.InitSdkAwareModule(module) return module } @@ -1717,7 +1782,7 @@ func testApexBundleFactory() android.Module { return bundle } -func apexBundleFactory() android.Module { +func BundleFactory() android.Module { return newApexBundle() } @@ -1734,6 +1799,15 @@ func vndkApexBundleFactory() android.Module { }{ proptools.StringPtr("both"), }) + + vndkVersion := proptools.StringDefault(bundle.vndkProperties.Vndk_version, "current") + if vndkVersion == "current" { + vndkVersion = ctx.DeviceConfig().PlatformVndkVersion() + bundle.vndkProperties.Vndk_version = proptools.StringPtr(vndkVersion) + } + + // Ensure VNDK APEX mount point is formatted as com.android.vndk.v### + bundle.properties.Apex_name = proptools.StringPtr("com.android.vndk.v" + vndkVersion) }) return bundle } @@ -1773,7 +1847,7 @@ type Prebuilt struct { properties PrebuiltProperties inputApex android.Path - installDir android.OutputPath + installDir android.InstallPath installFilename string outputApex android.WritablePath } @@ -1920,7 +1994,7 @@ func (p *Prebuilt) AndroidMkEntries() android.AndroidMkEntries { Include: "$(BUILD_PREBUILT)", ExtraEntries: []android.AndroidMkExtraEntriesFunc{ func(entries *android.AndroidMkEntries) { - entries.SetString("LOCAL_MODULE_PATH", filepath.Join("$(OUT_DIR)", p.installDir.RelPathString())) + entries.SetString("LOCAL_MODULE_PATH", p.installDir.ToMakePath().String()) entries.SetString("LOCAL_MODULE_STEM", p.installFilename) entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", !p.installable()) entries.AddStrings("LOCAL_OVERRIDES_PACKAGES", p.properties.Overrides...) diff --git a/apex/apex_test.go b/apex/apex_test.go index 577cf8fe1..ddf04597f 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -92,17 +92,19 @@ func testApexContext(t *testing.T, bp string, handlers ...testCustomizer) (*andr config.TestProductVariables.CertificateOverrides = []string{"myapex_keytest:myapex.certificate.override"} config.TestProductVariables.Platform_sdk_codename = proptools.StringPtr("Q") config.TestProductVariables.Platform_sdk_final = proptools.BoolPtr(false) - config.TestProductVariables.DeviceVndkVersion = proptools.StringPtr("current") config.TestProductVariables.Platform_vndk_version = proptools.StringPtr("VER") ctx := android.NewTestArchContext() - ctx.RegisterModuleType("apex", android.ModuleFactoryAdaptor(apexBundleFactory)) + ctx.RegisterModuleType("apex", android.ModuleFactoryAdaptor(BundleFactory)) ctx.RegisterModuleType("apex_test", android.ModuleFactoryAdaptor(testApexBundleFactory)) ctx.RegisterModuleType("apex_vndk", android.ModuleFactoryAdaptor(vndkApexBundleFactory)) - ctx.RegisterModuleType("apex_key", android.ModuleFactoryAdaptor(apexKeyFactory)) + ctx.RegisterModuleType("apex_key", android.ModuleFactoryAdaptor(ApexKeyFactory)) ctx.RegisterModuleType("apex_defaults", android.ModuleFactoryAdaptor(defaultsFactory)) ctx.RegisterModuleType("prebuilt_apex", android.ModuleFactoryAdaptor(PrebuiltFactory)) + ctx.RegisterModuleType("cc_defaults", android.ModuleFactoryAdaptor(func() android.Module { + return cc.DefaultsFactory() + })) ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(cc.LibraryFactory)) ctx.RegisterModuleType("cc_library_shared", android.ModuleFactoryAdaptor(cc.LibrarySharedFactory)) ctx.RegisterModuleType("cc_library_headers", android.ModuleFactoryAdaptor(cc.LibraryHeaderFactory)) @@ -769,9 +771,9 @@ func TestApexWithRuntimeLibsDependency(t *testing.T) { // Ensure that runtime_libs dep in included ensureContains(t, copyCmds, "image.apex/lib64/libbar.so") - injectRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("injectApexDependency") - ensureListEmpty(t, names(injectRule.Args["provideNativeLibs"])) - ensureListContains(t, names(injectRule.Args["requireNativeLibs"]), "libfoo.so") + apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexManifestRule") + ensureListEmpty(t, names(apexManifestRule.Args["provideNativeLibs"])) + ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libfoo.so") } @@ -819,11 +821,11 @@ func TestApexDependencyToLLNDK(t *testing.T) { // Ensure that LLNDK dep is not included ensureNotContains(t, copyCmds, "image.apex/lib64/libbar.so") - injectRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("injectApexDependency") - ensureListEmpty(t, names(injectRule.Args["provideNativeLibs"])) + apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexManifestRule") + ensureListEmpty(t, names(apexManifestRule.Args["provideNativeLibs"])) // Ensure that LLNDK dep is required - ensureListContains(t, names(injectRule.Args["requireNativeLibs"]), "libbar.so") + ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libbar.so") } @@ -1050,8 +1052,8 @@ func TestUseVendor(t *testing.T) { inputsString := strings.Join(inputsList, " ") // ensure that the apex includes vendor variants of the direct and indirect deps - ensureContains(t, inputsString, "android_arm64_armv8-a_vendor_shared_myapex/mylib.so") - ensureContains(t, inputsString, "android_arm64_armv8-a_vendor_shared_myapex/mylib2.so") + ensureContains(t, inputsString, "android_arm64_armv8-a_vendor.VER_shared_myapex/mylib.so") + ensureContains(t, inputsString, "android_arm64_armv8-a_vendor.VER_shared_myapex/mylib2.so") // ensure that the apex does not include core variants ensureNotContains(t, inputsString, "android_arm64_armv8-a_core_shared_myapex/mylib.so") @@ -1380,6 +1382,7 @@ func TestVndkApexVersion(t *testing.T) { vndk: { enabled: true, }, + target_arch: "arm64", srcs: ["libvndk27.so"], } `, withFiles(map[string][]byte{ @@ -1439,6 +1442,37 @@ func TestVndkApexErrorWithDuplicateVersion(t *testing.T) { })) } +func TestVndkApexNameRule(t *testing.T) { + ctx, _ := testApex(t, ` + apex_vndk { + name: "myapex", + key: "myapex.key", + file_contexts: "myapex", + } + apex_vndk { + name: "myapex_v28", + key: "myapex.key", + file_contexts: "myapex", + vndk_version: "28", + } + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + }`) + + assertApexName := func(expected, moduleName string) { + bundle := ctx.ModuleForTests(moduleName, "android_common_"+moduleName).Module().(*apexBundle) + actual := proptools.String(bundle.properties.Apex_name) + if !reflect.DeepEqual(actual, expected) { + t.Errorf("Got '%v', expected '%v'", actual, expected) + } + } + + assertApexName("com.android.vndk.vVER", "myapex") + assertApexName("com.android.vndk.v28", "myapex_v28") +} + func TestVndkApexSkipsNativeBridgeSupportedModules(t *testing.T) { ctx, _ := testApex(t, ` apex_vndk { @@ -1580,34 +1614,56 @@ func TestDependenciesInApexManifest(t *testing.T) { } `) - var injectRule android.TestingBuildParams + var apexManifestRule android.TestingBuildParams var provideNativeLibs, requireNativeLibs []string - injectRule = ctx.ModuleForTests("myapex_nodep", "android_common_myapex_nodep").Rule("injectApexDependency") - provideNativeLibs = names(injectRule.Args["provideNativeLibs"]) - requireNativeLibs = names(injectRule.Args["requireNativeLibs"]) + apexManifestRule = ctx.ModuleForTests("myapex_nodep", "android_common_myapex_nodep").Rule("apexManifestRule") + provideNativeLibs = names(apexManifestRule.Args["provideNativeLibs"]) + requireNativeLibs = names(apexManifestRule.Args["requireNativeLibs"]) ensureListEmpty(t, provideNativeLibs) ensureListEmpty(t, requireNativeLibs) - injectRule = ctx.ModuleForTests("myapex_dep", "android_common_myapex_dep").Rule("injectApexDependency") - provideNativeLibs = names(injectRule.Args["provideNativeLibs"]) - requireNativeLibs = names(injectRule.Args["requireNativeLibs"]) + apexManifestRule = ctx.ModuleForTests("myapex_dep", "android_common_myapex_dep").Rule("apexManifestRule") + provideNativeLibs = names(apexManifestRule.Args["provideNativeLibs"]) + requireNativeLibs = names(apexManifestRule.Args["requireNativeLibs"]) ensureListEmpty(t, provideNativeLibs) ensureListContains(t, requireNativeLibs, "libfoo.so") - injectRule = ctx.ModuleForTests("myapex_provider", "android_common_myapex_provider").Rule("injectApexDependency") - provideNativeLibs = names(injectRule.Args["provideNativeLibs"]) - requireNativeLibs = names(injectRule.Args["requireNativeLibs"]) + apexManifestRule = ctx.ModuleForTests("myapex_provider", "android_common_myapex_provider").Rule("apexManifestRule") + provideNativeLibs = names(apexManifestRule.Args["provideNativeLibs"]) + requireNativeLibs = names(apexManifestRule.Args["requireNativeLibs"]) ensureListContains(t, provideNativeLibs, "libfoo.so") ensureListEmpty(t, requireNativeLibs) - injectRule = ctx.ModuleForTests("myapex_selfcontained", "android_common_myapex_selfcontained").Rule("injectApexDependency") - provideNativeLibs = names(injectRule.Args["provideNativeLibs"]) - requireNativeLibs = names(injectRule.Args["requireNativeLibs"]) + apexManifestRule = ctx.ModuleForTests("myapex_selfcontained", "android_common_myapex_selfcontained").Rule("apexManifestRule") + provideNativeLibs = names(apexManifestRule.Args["provideNativeLibs"]) + requireNativeLibs = names(apexManifestRule.Args["requireNativeLibs"]) ensureListContains(t, provideNativeLibs, "libfoo.so") ensureListEmpty(t, requireNativeLibs) } +func TestApexName(t *testing.T) { + ctx, _ := testApex(t, ` + apex { + name: "myapex", + key: "myapex.key", + apex_name: "com.android.myapex", + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + `) + + module := ctx.ModuleForTests("myapex", "android_common_myapex") + apexManifestRule := module.Rule("apexManifestRule") + ensureContains(t, apexManifestRule.Args["opt"], "-v name com.android.myapex") + apexRule := module.Rule("apexRule") + ensureContains(t, apexRule.Args["opt_flags"], "--do_not_check_keyname") +} + func TestNonTestApex(t *testing.T) { ctx, _ := testApex(t, ` apex { @@ -1840,8 +1896,8 @@ func TestApexInProductPartition(t *testing.T) { `) apex := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle) - expected := "target/product/test_device/product/apex" - actual := apex.installDir.RelPathString() + expected := buildDir + "/target/product/test_device/product/apex" + actual := apex.installDir.String() if actual != expected { t.Errorf("wrong install path. expected %q. actual %q", expected, actual) } @@ -2128,6 +2184,7 @@ func TestApexUsesFailsIfUseVenderMismatch(t *testing.T) { } func TestApexUsesFailsIfUseNoApex(t *testing.T) { + // 'no_apex' prevents a module to be included in an apex testApexError(t, `tries to include no_apex module mylib2`, ` apex { name: "commonapex", @@ -2158,6 +2215,7 @@ func TestApexUsesFailsIfUseNoApex(t *testing.T) { } `) + // respect 'no_apex' even with static link testApexError(t, `tries to include no_apex module mylib2`, ` apex { name: "commonapex", @@ -2188,6 +2246,86 @@ func TestApexUsesFailsIfUseNoApex(t *testing.T) { } `) + // 'no_apex' can be applied via defaults + testApexError(t, `tries to include no_apex module mylib2`, ` + apex { + name: "commonapex", + key: "myapex.key", + native_shared_libs: ["mylib"], + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + cc_library { + name: "mylib", + srcs: ["mylib.cpp"], + static_libs: ["mylib2"], + system_shared_libs: [], + stl: "none", + } + + cc_defaults { + name: "mylib2_defaults", + system_shared_libs: [], + stl: "none", + no_apex: true, + } + + cc_library { + name: "mylib2", + srcs: ["mylib.cpp"], + defaults: ["mylib2_defaults"], + } + `) +} + +func TestNoApexWorksWithWhitelist(t *testing.T) { + + testApex(t, ` + apex { + name: "myapex", + key: "myapex.key", + native_shared_libs: ["mylib"], + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + cc_library { + name: "mylib", + srcs: ["mylib.cpp"], + shared_libs: ["mylib2"], + system_shared_libs: [], + stl: "none", + } + + cc_defaults { + name: "mylib2_defaults", + system_shared_libs: [], + stl: "none", + no_apex: true, + } + + cc_library { + name: "mylib2", + srcs: ["mylib.cpp"], + defaults: ["mylib2_defaults"], + } + `, func(fs map[string][]byte, config android.Config) { + whitelistNoApex = map[string][]string{ + "myapex": []string{"mylib2"}, + } + }) +} + +func TestNoApexCanBeDependedOnViaStubs(t *testing.T) { ctx, _ := testApex(t, ` apex { name: "myapex", @@ -2220,6 +2358,7 @@ func TestApexUsesFailsIfUseNoApex(t *testing.T) { }, } + // this won't be included in "myapex", so 'no_apex' is still valid in this case. cc_library { name: "mylib3", srcs: ["mylib.cpp"], @@ -2236,7 +2375,6 @@ func TestApexUsesFailsIfUseNoApex(t *testing.T) { ensureContains(t, copyCmds, "image.apex/lib64/mylib.so") ensureNotContains(t, copyCmds, "image.apex/lib64/mylib2.so") ensureNotContains(t, copyCmds, "image.apex/lib64/mylib3.so") - } func TestErrorsIfDepsAreNotEnabled(t *testing.T) { @@ -2316,6 +2454,158 @@ func TestApexWithApps(t *testing.T) { } +func TestApexAvailable(t *testing.T) { + // libfoo is not available to myapex, but only to otherapex + testApexError(t, "requires \"libfoo\" that is not available for the APEX", ` + apex { + name: "myapex", + key: "myapex.key", + native_shared_libs: ["libfoo"], + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + apex { + name: "otherapex", + key: "otherapex.key", + native_shared_libs: ["libfoo"], + } + + apex_key { + name: "otherapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + cc_library { + name: "libfoo", + stl: "none", + system_shared_libs: [], + apex_available: ["otherapex"], + }`) + + // libbar is an indirect dep + testApexError(t, "requires \"libbar\" that is not available for the APEX", ` + apex { + name: "myapex", + key: "myapex.key", + native_shared_libs: ["libfoo"], + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + apex { + name: "otherapex", + key: "otherapex.key", + native_shared_libs: ["libfoo"], + } + + apex_key { + name: "otherapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + cc_library { + name: "libfoo", + stl: "none", + shared_libs: ["libbar"], + system_shared_libs: [], + apex_available: ["myapex", "otherapex"], + } + + cc_library { + name: "libbar", + stl: "none", + system_shared_libs: [], + apex_available: ["otherapex"], + }`) + + testApexError(t, "\"otherapex\" is not a valid module name", ` + apex { + name: "myapex", + key: "myapex.key", + native_shared_libs: ["libfoo"], + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + cc_library { + name: "libfoo", + stl: "none", + system_shared_libs: [], + apex_available: ["otherapex"], + }`) + + ctx, _ := testApex(t, ` + apex { + name: "myapex", + key: "myapex.key", + native_shared_libs: ["libfoo", "libbar"], + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + cc_library { + name: "libfoo", + stl: "none", + system_shared_libs: [], + apex_available: ["myapex"], + } + + cc_library { + name: "libbar", + stl: "none", + system_shared_libs: [], + apex_available: ["//apex_available:anyapex"], + }`) + + // check that libfoo and libbar are created only for myapex, but not for the platform + ensureListContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_core_shared_myapex") + ensureListNotContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_core_shared") + ensureListContains(t, ctx.ModuleVariantsForTests("libbar"), "android_arm64_armv8-a_core_shared_myapex") + ensureListNotContains(t, ctx.ModuleVariantsForTests("libbar"), "android_arm64_armv8-a_core_shared") + + ctx, _ = testApex(t, ` + apex { + name: "myapex", + key: "myapex.key", + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + cc_library { + name: "libfoo", + stl: "none", + system_shared_libs: [], + apex_available: ["//apex_available:platform"], + }`) + + // check that libfoo is created only for the platform + ensureListNotContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_core_shared_myapex") + ensureListContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_core_shared") +} + func TestMain(m *testing.M) { run := func() int { setUp() diff --git a/apex/key.go b/apex/key.go index 08cd45ebd..ffde315f9 100644 --- a/apex/key.go +++ b/apex/key.go @@ -27,7 +27,7 @@ import ( var String = proptools.String func init() { - android.RegisterModuleType("apex_key", apexKeyFactory) + android.RegisterModuleType("apex_key", ApexKeyFactory) android.RegisterSingletonType("apex_keys_text", apexKeysTextFactory) } @@ -53,7 +53,7 @@ type apexKeyProperties struct { Installable *bool } -func apexKeyFactory() android.Module { +func ApexKeyFactory() android.Module { module := &apexKey{} module.AddProperties(&module.properties) android.InitAndroidArchModule(module, android.HostAndDeviceDefault, android.MultilibCommon) diff --git a/build_kzip.bash b/build_kzip.bash index 5364e7f5d..1e0d48f86 100755 --- a/build_kzip.bash +++ b/build_kzip.bash @@ -1,25 +1,27 @@ -# /bin/bash -uv +#! /bin/bash -uv # # Build kzip files (source files for the indexing pipeline) for the given configuration, # merge them and place the resulting all.kzip into $DIST_DIR. # It is assumed that the current directory is the top of the source tree. -# The following enviromnet variables affect the result: -# TARGET_PRODUCT target device name, e.g., `aosp_blueline` -# TARGET_BUILD_VARIANT variant, e.g., `userdebug` -# OUT_DIR where the build is happening (./out if not specified) +# The following environment variables affect the result: +# BUILD_NUMBER build number, used to generate unique ID (will use UUID if not set) # DIST_DIR where the resulting all.kzip will be placed -# XREF_CORPUS source code repository URI, e.g., -# `android.googlesource.com/platform/superproject` +# OUT_DIR output directory (out if not specified}) +# TARGET_BUILD_VARIANT variant, e.g., `userdebug` +# TARGET_PRODUCT target device name, e.g., 'aosp_blueline' +# XREF_CORPUS source code repository URI, e.g., 'android.googlesource.com/platform/superproject' -# The extraction might fail for some source files, so run with -k -build/soong/soong_ui.bash --build-mode --all-modules --dir=$PWD -k merge_zips xref_cxx xref_java +: ${BUILD_NUMBER:=$(uuidgen)} -# We build with -k, so check that we have generated at least 100K files -# (the actual number is 180K+) -declare -r kzip_count=$(find $OUT_DIR -name '*.kzip' | wc -l) +# The extraction might fail for some source files, so run with -k and then check that +# sufficiently many files were generated. +build/soong/soong_ui.bash --build-mode --all-modules --dir=$PWD -k merge_zips xref_cxx xref_java +declare -r out="${OUT_DIR:-out}" +declare -r kzip_count=$(find "$out" -name '*.kzip' | wc -l) (($kzip_count>100000)) || { printf "Too few kzip files were generated: %d\n" $kzip_count; exit 1; } # Pack # TODO(asmundak): this should be done by soong. -declare -r allkzip=all.kzip -"${OUT_DIR:-out}/soong/host/linux-x86/bin/merge_zips" "$DIST_DIR/$allkzip" @<(find $OUT_DIR -name '*.kzip') +declare -r allkzip="$BUILD_NUMBER.kzip" +"$out/soong/host/linux-x86/bin/merge_zips" "$DIST_DIR/$allkzip" @<(find "$out" -name '*.kzip') + diff --git a/cc/androidmk.go b/cc/androidmk.go index 66dd83815..f1d329f9c 100644 --- a/cc/androidmk.go +++ b/cc/androidmk.go @@ -37,6 +37,7 @@ type AndroidMkContext interface { Os() android.OsType Host() bool useVndk() bool + vndkVersion() string static() bool inRecovery() bool } @@ -109,17 +110,7 @@ func (c *Module) AndroidMk() android.AndroidMkData { } c.subAndroidMk(&ret, c.installer) - if c.Target().NativeBridge == android.NativeBridgeEnabled { - ret.SubName += nativeBridgeSuffix - } - - if c.useVndk() && c.hasVendorVariant() { - // .vendor suffix is added only when we will have two variants: core and vendor. - // The suffix is not added for vendor-only module. - ret.SubName += vendorSuffix - } else if c.inRecovery() && !c.onlyInRecovery() { - ret.SubName += recoverySuffix - } + ret.SubName += c.Properties.SubName return ret } @@ -312,6 +303,33 @@ func (test *testBinary) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkDa androidMkWriteTestData(test.data, ctx, ret) } +func (fuzz *fuzzBinary) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) { + ctx.subAndroidMk(ret, fuzz.binaryDecorator) + + var fuzzFiles []string + for _, d := range fuzz.corpus { + rel := d.Rel() + path := d.String() + path = strings.TrimSuffix(path, rel) + fuzzFiles = append(fuzzFiles, path+":corpus/"+d.Base()) + } + + if fuzz.dictionary != nil { + path := strings.TrimSuffix(fuzz.dictionary.String(), fuzz.dictionary.Rel()) + fuzzFiles = append(fuzzFiles, path+":"+fuzz.dictionary.Base()) + } + + if len(fuzzFiles) > 0 { + ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) { + fmt.Fprintln(w, "LOCAL_TEST_DATA := "+strings.Join(fuzzFiles, " ")) + }) + } + + ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) { + fmt.Fprintln(w, "LOCAL_IS_FUZZ_TARGET := true") + }) +} + func (test *testLibrary) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) { ctx.subAndroidMk(ret, test.libraryDecorator) } @@ -332,11 +350,10 @@ func (installer *baseInstaller) AndroidMk(ctx AndroidMkContext, ret *android.And } ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) { - path := installer.path.RelPathString() - dir, file := filepath.Split(path) + path, file := filepath.Split(installer.path.ToMakePath().String()) stem, suffix, _ := android.SplitFileExt(file) fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+suffix) - fmt.Fprintln(w, "LOCAL_MODULE_PATH := $(OUT_DIR)/"+filepath.Clean(dir)) + fmt.Fprintln(w, "LOCAL_MODULE_PATH := "+path) fmt.Fprintln(w, "LOCAL_MODULE_STEM := "+stem) }) } @@ -357,7 +374,6 @@ func (c *stubDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkDa func (c *llndkStubDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) { ret.Class = "SHARED_LIBRARIES" - ret.SubName = vendorSuffix ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) { c.libraryDecorator.androidMkWriteExportedFlags(w) @@ -378,12 +394,11 @@ func (c *vndkPrebuiltLibraryDecorator) AndroidMk(ctx AndroidMkContext, ret *andr ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) { c.libraryDecorator.androidMkWriteExportedFlags(w) - path := c.path.RelPathString() - dir, file := filepath.Split(path) + path, file := filepath.Split(c.path.ToMakePath().String()) stem, suffix, ext := android.SplitFileExt(file) fmt.Fprintln(w, "LOCAL_BUILT_MODULE_STEM := $(LOCAL_MODULE)"+ext) fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+suffix) - fmt.Fprintln(w, "LOCAL_MODULE_PATH := $(OUT_DIR)/"+filepath.Clean(dir)) + fmt.Fprintln(w, "LOCAL_MODULE_PATH := "+path) fmt.Fprintln(w, "LOCAL_MODULE_STEM := "+stem) }) } diff --git a/cc/builder.go b/cc/builder.go index 42d809aa8..0760dd490 100644 --- a/cc/builder.go +++ b/cc/builder.go @@ -195,7 +195,7 @@ var ( _ = pctx.SourcePathVariable("sAbiDiffer", "prebuilts/clang-tools/${config.HostPrebuiltTag}/bin/header-abi-diff") - sAbiDiff = pctx.AndroidRuleFunc("sAbiDiff", + sAbiDiff = pctx.RuleFunc("sAbiDiff", func(ctx android.PackageRuleContext) blueprint.RuleParams { // TODO(b/78139997): Add -check-all-apis back commandStr := "($sAbiDiffer ${allowFlags} -lib ${libName} -arch ${arch} -o ${out} -new ${in} -old ${referenceDump})" @@ -224,12 +224,13 @@ var ( _ = pctx.SourcePathVariable("cxxExtractor", "prebuilts/clang-tools/${config.HostPrebuiltTag}/bin/cxx_extractor") + _ = pctx.SourcePathVariable("kytheVnames", "build/soong/vnames.json") _ = pctx.VariableFunc("kytheCorpus", func(ctx android.PackageVarContext) string { return ctx.Config().XrefCorpusName() }) kytheExtract = pctx.StaticRule("kythe", blueprint.RuleParams{ - Command: "rm -f $out && KYTHE_CORPUS=${kytheCorpus} KYTHE_OUTPUT_FILE=$out $cxxExtractor $cFlags $in ", - CommandDeps: []string{"$cxxExtractor"}, + Command: "rm -f $out && KYTHE_CORPUS=${kytheCorpus} KYTHE_OUTPUT_FILE=$out KYTHE_VNAMES=$kytheVnames $cxxExtractor $cFlags $in ", + CommandDeps: []string{"$cxxExtractor", "$kytheVnames"}, }, "cFlags") ) @@ -764,7 +765,7 @@ func TransformSharedObjectToToc(ctx android.ModuleContext, inputFile android.Pat // Generate a rule for compiling multiple .o files to a .o using ld partial linking func TransformObjsToObj(ctx android.ModuleContext, objFiles android.Paths, - flags builderFlags, outputFile android.WritablePath) { + flags builderFlags, outputFile android.WritablePath, deps android.Paths) { ldCmd := "${config.ClangBin}/clang++" @@ -773,6 +774,7 @@ func TransformObjsToObj(ctx android.ModuleContext, objFiles android.Paths, Description: "link " + outputFile.Base(), Output: outputFile, Inputs: objFiles, + Implicits: deps, Args: map[string]string{ "ldCmd": ldCmd, "ldFlags": flags.ldFlags, @@ -36,9 +36,9 @@ func init() { android.RegisterModuleType("cc_defaults", defaultsFactory) android.PreDepsMutators(func(ctx android.RegisterMutatorsContext) { + ctx.BottomUp("vndk", VndkMutator).Parallel() 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("version", VersionMutator).Parallel() @@ -200,7 +200,8 @@ type BaseProperties struct { PreventInstall bool `blueprint:"mutated"` ApexesProvidingSharedLibs []string `blueprint:"mutated"` - UseVndk bool `blueprint:"mutated"` + VndkVersion string `blueprint:"mutated"` + SubName string `blueprint:"mutated"` // *.logtags files, to combine together in order to generate the /system/etc/event-log-tags // file @@ -400,6 +401,14 @@ func StaticDepTag() dependencyTag { return staticDepTag } +func CrtBeginDepTag() dependencyTag { + return crtBeginDepTag +} + +func CrtEndDepTag() dependencyTag { + return crtEndDepTag +} + // 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 @@ -407,6 +416,7 @@ type Module struct { android.ModuleBase android.DefaultableModuleBase android.ApexModuleBase + android.SdkBase Properties BaseProperties VendorProperties VendorProperties @@ -542,10 +552,9 @@ func (c *Module) Init() android.Module { } }) android.InitAndroidArchModule(c, c.hod, c.multilib) - - android.InitDefaultableModule(c) - android.InitApexModule(c) + android.InitDefaultableModule(c) + android.InitSdkAwareModule(c) return c } @@ -562,7 +571,7 @@ func (c *Module) isDependencyRoot() bool { } func (c *Module) useVndk() bool { - return c.Properties.UseVndk + return c.Properties.VndkVersion != "" } func (c *Module) isCoverageVariant() bool { @@ -596,10 +605,7 @@ func (c *Module) isVndk() bool { } func (c *Module) vndkVersion() string { - if vndkdep := c.vndkdep; vndkdep != nil { - return vndkdep.Properties.Vndk.Version - } - return "" + return c.Properties.VndkVersion } func (c *Module) isPgoCompile() bool { @@ -1009,6 +1015,31 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { c.makeLinkType = c.getMakeLinkType(actx) + c.Properties.SubName = "" + + if c.Target().NativeBridge == android.NativeBridgeEnabled { + c.Properties.SubName += nativeBridgeSuffix + } + + if _, ok := c.linker.(*vndkPrebuiltLibraryDecorator); ok { + // .vendor suffix is added for backward compatibility with VNDK snapshot whose names with + // such suffixes are already hard-coded in prebuilts/vndk/.../Android.bp. + c.Properties.SubName += vendorSuffix + } else if _, ok := c.linker.(*llndkStubDecorator); ok || (c.useVndk() && c.hasVendorVariant()) { + // .vendor.{version} suffix is added only when we will have two variants: core and vendor. + // The suffix is not added for vendor-only module. + c.Properties.SubName += vendorSuffix + vendorVersion := actx.DeviceConfig().VndkVersion() + if vendorVersion == "current" { + vendorVersion = actx.DeviceConfig().PlatformVndkVersion() + } + if c.Properties.VndkVersion != vendorVersion { + c.Properties.SubName += "." + c.Properties.VndkVersion + } + } else if c.inRecovery() && !c.onlyInRecovery() { + c.Properties.SubName += recoverySuffix + } + ctx := &moduleContext{ ModuleContext: actx, moduleContextImpl: moduleContextImpl{ @@ -1496,9 +1527,11 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { if vndkdep := c.vndkdep; vndkdep != nil { if vndkdep.isVndkExt() { - baseModuleMode := vendorMode + var baseModuleMode string if actx.DeviceConfig().VndkVersion() == "" { baseModuleMode = coreMode + } else { + baseModuleMode = c.imageVariation() } actx.AddVariationDependencies([]blueprint.Variation{ {Mutator: "image", Variation: baseModuleMode}, @@ -1521,7 +1554,7 @@ func checkLinkType(ctx android.ModuleContext, from *Module, to *Module, tag depe // Host code is not restricted return } - if from.Properties.UseVndk { + if from.useVndk() { // Though vendor code is limited by the vendor mutator, // each vendor-available module needs to check // link-type for VNDK. @@ -1928,7 +1961,15 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { } else 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 + ret := libName + vendorSuffix + vendorVersion := ctx.DeviceConfig().VndkVersion() + if vendorVersion == "current" { + vendorVersion = ctx.DeviceConfig().PlatformVndkVersion() + } + if c.Properties.VndkVersion != vendorVersion { + ret += "." + c.Properties.VndkVersion + } + return ret } else if (ctx.Platform() || ctx.ProductSpecific()) && isVendorPublicLib { return libName + vendorPublicLibrarySuffix } else if ccDep.inRecovery() && !ccDep.onlyInRecovery() { @@ -2114,13 +2155,12 @@ func (c *Module) installable() bool { } func (c *Module) imageVariation() string { - variation := "core" if c.useVndk() { - variation = "vendor" + return vendorMode + "." + c.Properties.VndkVersion } else if c.inRecovery() { - variation = "recovery" + return recoveryMode } - return variation + return coreMode } func (c *Module) IDEInfo(dpInfo *android.IdeInfo) { @@ -2168,10 +2208,13 @@ func DefaultsFactory(props ...interface{}) android.Module { &BaseLinkerProperties{}, &ObjectLinkerProperties{}, &LibraryProperties{}, + &StaticProperties{}, + &SharedProperties{}, &FlagExporterProperties{}, &BinaryLinkerProperties{}, &TestProperties{}, &TestBinaryProperties{}, + &FuzzProperties{}, &StlProperties{}, &SanitizeProperties{}, &StripProperties{}, @@ -2186,8 +2229,8 @@ func DefaultsFactory(props ...interface{}) android.Module { &android.ProtoProperties{}, ) - android.InitDefaultsModule(module) android.InitApexModule(module) + android.InitDefaultsModule(module) return module } @@ -2197,7 +2240,7 @@ const ( // SDK libraries. (which framework-private libraries can use) coreMode = "core" - // vendorMode is the variant used for /vendor code that compiles + // vendorMode is the variant prefix used for /vendor code that compiles // against the VNDK. vendorMode = "vendor" @@ -2261,7 +2304,10 @@ func ImageMutator(mctx android.BottomUpMutatorContext) { variants = append(variants, coreMode) } if vendorVariantNeeded { - variants = append(variants, vendorMode) + variants = append(variants, vendorMode+"."+mctx.DeviceConfig().PlatformVndkVersion()) + if vndkVersion := mctx.DeviceConfig().VndkVersion(); vndkVersion != "current" { + variants = append(variants, vendorMode+"."+vndkVersion) + } } if recoveryVariantNeeded { variants = append(variants, recoveryMode) @@ -2333,9 +2379,16 @@ func ImageMutator(mctx android.BottomUpMutatorContext) { } var coreVariantNeeded bool = false - var vendorVariantNeeded bool = false var recoveryVariantNeeded bool = false + var vendorVariants []string + + platformVndkVersion := mctx.DeviceConfig().PlatformVndkVersion() + deviceVndkVersion := mctx.DeviceConfig().VndkVersion() + if deviceVndkVersion == "current" { + deviceVndkVersion = platformVndkVersion + } + if mctx.DeviceConfig().VndkVersion() == "" { // If the device isn't compiling against the VNDK, we always // use the core mode. @@ -2346,22 +2399,31 @@ func ImageMutator(mctx android.BottomUpMutatorContext) { } 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 + vendorVariants = append(vendorVariants, + platformVndkVersion, + deviceVndkVersion, + ) } else if _, ok := m.linker.(*llndkHeadersDecorator); ok { // ... and LL-NDK headers as well - vendorVariantNeeded = true - } else if _, ok := m.linker.(*vndkPrebuiltLibraryDecorator); ok { + vendorVariants = append(vendorVariants, + platformVndkVersion, + deviceVndkVersion, + ) + } else if lib, ok := m.linker.(*vndkPrebuiltLibraryDecorator); ok { // Make vendor variants only for the versions in BOARD_VNDK_VERSION and // PRODUCT_EXTRA_VNDK_VERSIONS. - vendorVariantNeeded = true + vendorVariants = append(vendorVariants, lib.version()) } 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 + vendorVariants = append(vendorVariants, platformVndkVersion) + if m.isVndk() { + vendorVariants = append(vendorVariants, deviceVndkVersion) + } } else if vendorSpecific && String(m.Properties.Sdk_version) == "" { // This will be available in /vendor (or /odm) only - vendorVariantNeeded = true + vendorVariants = append(vendorVariants, deviceVndkVersion) } else { // This is either in /system (or similar: /data), or is a // modules built with the NDK. Modules built with the NDK @@ -2390,17 +2452,17 @@ func ImageMutator(mctx android.BottomUpMutatorContext) { if coreVariantNeeded { variants = append(variants, coreMode) } - if vendorVariantNeeded { - variants = append(variants, vendorMode) + for _, variant := range android.FirstUniqueStrings(vendorVariants) { + variants = append(variants, vendorMode+"."+variant) } if recoveryVariantNeeded { variants = append(variants, recoveryMode) } mod := mctx.CreateVariations(variants...) for i, v := range variants { - if v == vendorMode { + if strings.HasPrefix(v, vendorMode+".") { m := mod[i].(*Module) - m.Properties.UseVndk = true + m.Properties.VndkVersion = strings.TrimPrefix(v, vendorMode+".") squashVendorSrcs(m) } else if v == recoveryMode { m := mod[i].(*Module) diff --git a/cc/cc_test.go b/cc/cc_test.go index c9eb42116..689aacd84 100644 --- a/cc/cc_test.go +++ b/cc/cc_test.go @@ -15,8 +15,6 @@ package cc import ( - "android/soong/android" - "fmt" "io/ioutil" "os" @@ -25,6 +23,8 @@ import ( "sort" "strings" "testing" + + "android/soong/android" ) var buildDir string @@ -53,6 +53,7 @@ func TestMain(m *testing.M) { } func testCcWithConfig(t *testing.T, bp string, config android.Config) *android.TestContext { + t.Helper() return testCcWithConfigForOs(t, bp, config, android.Android) } @@ -112,7 +113,7 @@ func testCcError(t *testing.T, pattern string, bp string) { const ( coreVariant = "android_arm64_armv8-a_core_shared" - vendorVariant = "android_arm64_armv8-a_vendor_shared" + vendorVariant = "android_arm64_armv8-a_vendor.VER_shared" recoveryVariant = "android_arm64_armv8-a_recovery_shared" ) @@ -328,8 +329,8 @@ func TestVndk(t *testing.T) { vndkCoreLib2ndPath := filepath.Join(vndkLib2ndPath, "shared", "vndk-core") vndkSpLib2ndPath := filepath.Join(vndkLib2ndPath, "shared", "vndk-sp") - variant := "android_arm64_armv8-a_vendor_shared" - variant2nd := "android_arm_armv7-a-neon_vendor_shared" + variant := "android_arm64_armv8-a_vendor.VER_shared" + variant2nd := "android_arm_armv7-a-neon_vendor.VER_shared" checkVndkSnapshot(t, ctx, "libvndk", vndkCoreLibPath, variant) checkVndkSnapshot(t, ctx, "libvndk", vndkCoreLib2ndPath, variant2nd) @@ -1343,6 +1344,8 @@ func TestMakeLinkType(t *testing.T) { assertArrayString(t, *vndkPrivateLibraries(config), []string{"libllndkprivate", "libvndkprivate"}) + vendorVariant27 := "android_arm64_armv8-a_vendor.27_shared" + tests := []struct { variant string name string @@ -1353,8 +1356,8 @@ func TestMakeLinkType(t *testing.T) { {vendorVariant, "libvndkprivate", "native:vndk_private"}, {vendorVariant, "libvendor", "native:vendor"}, {vendorVariant, "libvndkext", "native:vendor"}, - {vendorVariant, "prevndk.vndk.27.arm.binder32", "native:vndk"}, {vendorVariant, "libllndk.llndk", "native:vndk"}, + {vendorVariant27, "prevndk.vndk.27.arm.binder32", "native:vndk"}, {coreVariant, "libvndk", "native:platform"}, {coreVariant, "libvndkprivate", "native:platform"}, {coreVariant, "libllndk", "native:platform"}, @@ -1792,7 +1795,7 @@ func TestLlndkHeaders(t *testing.T) { `) // _static variant is used since _shared reuses *.o from the static variant - cc := ctx.ModuleForTests("libvendor", "android_arm_armv7-a-neon_vendor_static").Rule("cc") + cc := ctx.ModuleForTests("libvendor", "android_arm_armv7-a-neon_vendor.VER_static").Rule("cc") cflags := cc.Args["cFlags"] if !strings.Contains(cflags, "-Imy_include") { t.Errorf("cflags for libvendor must contain -Imy_include, but was %#v.", cflags) @@ -1878,7 +1881,7 @@ func TestRuntimeLibs(t *testing.T) { // runtime_libs for vendor variants have '.vendor' suffixes if the modules have both core // and vendor variants. - variant = "android_arm64_armv8-a_vendor_shared" + variant = "android_arm64_armv8-a_vendor.VER_shared" module = ctx.ModuleForTests("libvendor_available2", variant).Module().(*Module) checkRuntimeLibs(t, []string{"libvendor_available1.vendor"}, module) @@ -1894,7 +1897,7 @@ func TestExcludeRuntimeLibs(t *testing.T) { module := ctx.ModuleForTests("libvendor_available3", variant).Module().(*Module) checkRuntimeLibs(t, []string{"libvendor_available1"}, module) - variant = "android_arm64_armv8-a_vendor_shared" + variant = "android_arm64_armv8-a_vendor.VER_shared" module = ctx.ModuleForTests("libvendor_available3", variant).Module().(*Module) checkRuntimeLibs(t, nil, module) } @@ -2091,9 +2094,9 @@ func TestVendorPublicLibraries(t *testing.T) { } // test if libvendor is linked to the real shared lib - ld = ctx.ModuleForTests("libvendor", strings.Replace(variant, "_core", "_vendor", 1)).Rule("ld") + ld = ctx.ModuleForTests("libvendor", strings.Replace(variant, "_core", "_vendor.VER", 1)).Rule("ld") libflags = ld.Args["libFlags"] - stubPaths = getOutputPaths(ctx, strings.Replace(variant, "_core", "_vendor", 1), []string{"libvendorpublic"}) + stubPaths = getOutputPaths(ctx, strings.Replace(variant, "_core", "_vendor.VER", 1), []string{"libvendorpublic"}) if !strings.Contains(libflags, stubPaths[0].String()) { t.Errorf("libflags for libvendor must contain %#v, but was %#v", stubPaths[0], libflags) } @@ -2319,3 +2322,67 @@ func assertArrayString(t *testing.T, got, expected []string) { } } } + +func TestDefaults(t *testing.T) { + ctx := testCc(t, ` + cc_defaults { + name: "defaults", + srcs: ["foo.c"], + static: { + srcs: ["bar.c"], + }, + shared: { + srcs: ["baz.c"], + }, + } + + cc_library_static { + name: "libstatic", + defaults: ["defaults"], + } + + cc_library_shared { + name: "libshared", + defaults: ["defaults"], + } + + cc_library { + name: "libboth", + defaults: ["defaults"], + } + + cc_binary { + name: "binary", + defaults: ["defaults"], + }`) + + pathsToBase := func(paths android.Paths) []string { + var ret []string + for _, p := range paths { + ret = append(ret, p.Base()) + } + return ret + } + + shared := ctx.ModuleForTests("libshared", "android_arm64_armv8-a_core_shared").Rule("ld") + if g, w := pathsToBase(shared.Inputs), []string{"foo.o", "baz.o"}; !reflect.DeepEqual(w, g) { + t.Errorf("libshared ld rule wanted %q, got %q", w, g) + } + bothShared := ctx.ModuleForTests("libboth", "android_arm64_armv8-a_core_shared").Rule("ld") + if g, w := pathsToBase(bothShared.Inputs), []string{"foo.o", "baz.o"}; !reflect.DeepEqual(w, g) { + t.Errorf("libboth ld rule wanted %q, got %q", w, g) + } + binary := ctx.ModuleForTests("binary", "android_arm64_armv8-a_core").Rule("ld") + if g, w := pathsToBase(binary.Inputs), []string{"foo.o"}; !reflect.DeepEqual(w, g) { + t.Errorf("binary ld rule wanted %q, got %q", w, g) + } + + static := ctx.ModuleForTests("libstatic", "android_arm64_armv8-a_core_static").Rule("ar") + if g, w := pathsToBase(static.Inputs), []string{"foo.o", "bar.o"}; !reflect.DeepEqual(w, g) { + t.Errorf("libstatic ar rule wanted %q, got %q", w, g) + } + bothStatic := ctx.ModuleForTests("libboth", "android_arm64_armv8-a_core_static").Rule("ar") + if g, w := pathsToBase(bothStatic.Inputs), []string{"foo.o", "bar.o"}; !reflect.DeepEqual(w, g) { + t.Errorf("libboth ar rule wanted %q, got %q", w, g) + } +} diff --git a/cc/cflag_artifacts.go b/cc/cflag_artifacts.go new file mode 100644 index 000000000..9ed3876ab --- /dev/null +++ b/cc/cflag_artifacts.go @@ -0,0 +1,188 @@ +package cc + +import ( + "fmt" + "sort" + "strings" + + "github.com/google/blueprint/proptools" + + "android/soong/android" +) + +func init() { + android.RegisterSingletonType("cflag_artifacts_text", cflagArtifactsTextFactory) +} + +var ( + TrackedCFlags = []string{ + "-Wall", + "-Werror", + "-Wextra", + "-Wthread-safety", + "-O3", + } + + TrackedCFlagsDir = []string{ + "device/google/", + "vendor/google/", + } +) + +const FileBP = 50 + +// Stores output files. +type cflagArtifactsText struct { + interOutputs map[string]android.WritablePaths + outputs android.WritablePaths +} + +// allowedDir verifies if the directory/project is part of the TrackedCFlagsDir +// filter. +func allowedDir(subdir string) bool { + subdir += "/" + for _, prefix := range TrackedCFlagsDir { + if strings.HasPrefix(subdir, prefix) { + return true + } + } + return false +} + +func (s *cflagArtifactsText) genFlagFilename(flag string) string { + return fmt.Sprintf("module_cflags%s.txt", flag) +} + +// incrementFile is used to generate an output path object with the passed in flag +// and part number. +// e.g. FLAG + part # -> out/soong/cflags/module_cflags-FLAG.txt.0 +func (s *cflagArtifactsText) incrementFile(ctx android.SingletonContext, + flag string, part int) (string, android.OutputPath) { + + filename := fmt.Sprintf("%s.%d", s.genFlagFilename(flag), part) + filepath := android.PathForOutput(ctx, "cflags", filename) + s.interOutputs[flag] = append(s.interOutputs[flag], filepath) + return filename, filepath +} + +// GenCFlagArtifactParts is used to generate the build rules which produce the +// intermediary files for each desired C Flag artifact +// e.g. module_cflags-FLAG.txt.0, module_cflags-FLAG.txt.1, ... +func (s *cflagArtifactsText) GenCFlagArtifactParts(ctx android.SingletonContext, + flag string, using bool, modules []string, part int) int { + + cleanedName := strings.Replace(flag, "=", "_", -1) + filename, filepath := s.incrementFile(ctx, cleanedName, part) + rule := android.NewRuleBuilder() + rule.Command().Textf("rm -f %s", filepath.String()) + + if using { + rule.Command(). + Textf("echo '# Modules using %s'", flag). + FlagWithOutput(">> ", filepath) + } else { + rule.Command(). + Textf("echo '# Modules not using %s'", flag). + FlagWithOutput(">> ", filepath) + } + + length := len(modules) + + if length == 0 { + rule.Build(pctx, ctx, filename, "gen "+filename) + part++ + } + + // Following loop splits the module list for each tracked C Flag into + // chunks of length FileBP (file breakpoint) and generates a partial artifact + // (intermediary file) build rule for each split. + moduleShards := android.ShardStrings(modules, FileBP) + for index, shard := range moduleShards { + rule.Command(). + Textf("for m in %s; do echo $m", + strings.Join(proptools.ShellEscapeList(shard), " ")). + FlagWithOutput(">> ", filepath). + Text("; done") + rule.Build(pctx, ctx, filename, "gen "+filename) + + if index+1 != len(moduleShards) { + filename, filepath = s.incrementFile(ctx, cleanedName, part+index+1) + rule = android.NewRuleBuilder() + rule.Command().Textf("rm -f %s", filepath.String()) + } + } + + return part + len(moduleShards) +} + +// GenCFlagArtifacts is used to generate build rules which combine the +// intermediary files of a specific tracked flag into a single C Flag artifact +// for each tracked flag. +// e.g. module_cflags-FLAG.txt.0 + module_cflags-FLAG.txt.1 = module_cflags-FLAG.txt +func (s *cflagArtifactsText) GenCFlagArtifacts(ctx android.SingletonContext) { + // Scans through s.interOutputs and creates a build rule for each tracked C + // Flag that concatenates the associated intermediary file into a single + // artifact. + for _, flag := range TrackedCFlags { + // Generate build rule to combine related intermediary files into a + // C Flag artifact + rule := android.NewRuleBuilder() + filename := s.genFlagFilename(flag) + outputpath := android.PathForOutput(ctx, "cflags", filename) + rule.Command(). + Text("cat"). + Inputs(s.interOutputs[flag].Paths()). + FlagWithOutput("> ", outputpath) + rule.Build(pctx, ctx, filename, "gen "+filename) + s.outputs = append(s.outputs, outputpath) + } +} + +func (s *cflagArtifactsText) GenerateBuildActions(ctx android.SingletonContext) { + modulesWithCFlag := make(map[string][]string) + + // Scan through all modules, selecting the ones that are part of the filter, + // and then storing into a map which tracks whether or not tracked C flag is + // used or not. + ctx.VisitAllModules(func(module android.Module) { + if ccModule, ok := module.(*Module); ok { + if allowedDir(ctx.ModuleDir(ccModule)) { + cflags := ccModule.flags.CFlags + cppflags := ccModule.flags.CppFlags + module := fmt.Sprintf("%s:%s (%s)", + ctx.BlueprintFile(ccModule), + ctx.ModuleName(ccModule), + ctx.ModuleSubDir(ccModule)) + for _, flag := range TrackedCFlags { + if inList(flag, cflags) || inList(flag, cppflags) { + modulesWithCFlag[flag] = append(modulesWithCFlag[flag], module) + } else { + modulesWithCFlag["!"+flag] = append(modulesWithCFlag["!"+flag], module) + } + } + } + } + }) + + // Traversing map and setting up rules to produce intermediary files which + // contain parts of each expected C Flag artifact. + for _, flag := range TrackedCFlags { + sort.Strings(modulesWithCFlag[flag]) + part := s.GenCFlagArtifactParts(ctx, flag, true, modulesWithCFlag[flag], 0) + sort.Strings(modulesWithCFlag["!"+flag]) + s.GenCFlagArtifactParts(ctx, flag, false, modulesWithCFlag["!"+flag], part) + } + + // Combine intermediary files into a single C Flag artifact. + s.GenCFlagArtifacts(ctx) +} + +func cflagArtifactsTextFactory() android.Singleton { + return &cflagArtifactsText{ + interOutputs: make(map[string]android.WritablePaths), + } +} + +func (s *cflagArtifactsText) MakeVars(ctx android.MakeVarsContext) { + ctx.Strict("SOONG_MODULES_CFLAG_ARTIFACTS", strings.Join(s.outputs.Strings(), " ")) +} diff --git a/cc/config/clang.go b/cc/config/clang.go index 3636ae9fc..71bea4263 100644 --- a/cc/config/clang.go +++ b/cc/config/clang.go @@ -115,10 +115,6 @@ func init() { // TODO: can we remove this now? "-Wno-reserved-id-macro", - // Disable overly aggressive warning for format strings. - // Bug: 20148343 - "-Wno-format-pedantic", - // Workaround for ccache with clang. // See http://petereisentraut.blogspot.com/2011/05/ccache-and-clang.html. "-Wno-unused-command-line-argument", @@ -167,10 +163,6 @@ func init() { // new warnings are fixed. "-Wno-tautological-constant-compare", "-Wno-tautological-type-limit-compare", - - // Disable c++98-specific warning since Android is not concerned with C++98 - // compatibility. - "-Wno-c++98-compat-extra-semi", }, " ")) // Extra cflags for projects under external/ directory to disable warnings that are infeasible diff --git a/cc/config/global.go b/cc/config/global.go index 1bbc6f018..0943126f3 100644 --- a/cc/config/global.go +++ b/cc/config/global.go @@ -108,6 +108,7 @@ var ( noOverrideGlobalCflags = []string{ "-Werror=int-to-pointer-cast", "-Werror=pointer-to-int-cast", + "-Werror=fortify-source", } IllegalFlags = []string{ diff --git a/cc/fuzz.go b/cc/fuzz.go index b0fb262df..c19fdc5b0 100644 --- a/cc/fuzz.go +++ b/cc/fuzz.go @@ -16,6 +16,7 @@ package cc import ( "path/filepath" + "strings" "github.com/google/blueprint/proptools" @@ -23,8 +24,17 @@ import ( "android/soong/cc/config" ) +type FuzzProperties struct { + // Optional list of seed files to be installed to the fuzz target's output + // directory. + Corpus []string `android:"path"` + // Optional dictionary to be installed to the fuzz target's output directory. + Dictionary *string `android:"path"` +} + func init() { android.RegisterModuleType("cc_fuzz", FuzzFactory) + android.RegisterSingletonType("cc_fuzz_packaging", fuzzPackagingFactory) } // cc_fuzz creates a host/device fuzzer binary. Host binaries can be found at @@ -42,10 +52,15 @@ func NewFuzzInstaller() *baseInstaller { type fuzzBinary struct { *binaryDecorator *baseCompiler + + Properties FuzzProperties + corpus android.Paths + dictionary android.Path } func (fuzz *fuzzBinary) linkerProps() []interface{} { props := fuzz.binaryDecorator.linkerProps() + props = append(props, &fuzz.Properties) return props } @@ -81,9 +96,21 @@ func (fuzz *fuzzBinary) linkerFlags(ctx ModuleContext, flags Flags) Flags { } func (fuzz *fuzzBinary) install(ctx ModuleContext, file android.Path) { - fuzz.binaryDecorator.baseInstaller.dir = filepath.Join("fuzz", ctx.Target().Arch.ArchType.String()) - fuzz.binaryDecorator.baseInstaller.dir64 = filepath.Join("fuzz", ctx.Target().Arch.ArchType.String()) + fuzz.binaryDecorator.baseInstaller.dir = filepath.Join( + "fuzz", ctx.Target().Arch.ArchType.String(), ctx.ModuleName()) + fuzz.binaryDecorator.baseInstaller.dir64 = filepath.Join( + "fuzz", ctx.Target().Arch.ArchType.String(), ctx.ModuleName()) fuzz.binaryDecorator.baseInstaller.install(ctx, file) + + fuzz.corpus = android.PathsForModuleSrc(ctx, fuzz.Properties.Corpus) + if fuzz.Properties.Dictionary != nil { + fuzz.dictionary = android.PathForModuleSrc(ctx, *fuzz.Properties.Dictionary) + if fuzz.dictionary.Ext() != ".dict" { + ctx.PropertyErrorf("dictionary", + "Fuzzer dictionary %q does not have '.dict' extension", + fuzz.dictionary.String()) + } + } } func NewFuzz(hod android.HostOrDeviceSupported) *Module { @@ -130,3 +157,95 @@ func NewFuzz(hod android.HostOrDeviceSupported) *Module { return module } + +// Responsible for generating GNU Make rules that package fuzz targets into +// their architecture & target/host specific zip file. +type fuzzPackager struct { + packages android.Paths +} + +func fuzzPackagingFactory() android.Singleton { + return &fuzzPackager{} +} + +type fileToZip struct { + SourceFilePath android.Path + DestinationPathPrefix string +} + +func (s *fuzzPackager) GenerateBuildActions(ctx android.SingletonContext) { + // Map between each architecture + host/device combination, and the files that + // need to be packaged (in the tuple of {source file, destination folder in + // archive}). + archDirs := make(map[android.OutputPath][]fileToZip) + + ctx.VisitAllModules(func(module android.Module) { + // Discard non-fuzz targets. + ccModule, ok := module.(*Module) + if !ok { + return + } + fuzzModule, ok := ccModule.compiler.(*fuzzBinary) + if !ok { + return + } + + // Discard vendor-NDK-linked modules, they're duplicates of fuzz targets + // we're going to package anyway. + if ccModule.useVndk() || !ccModule.Enabled() { + return + } + + hostOrTargetString := "target" + if ccModule.Host() { + hostOrTargetString = "host" + } + + archString := ccModule.Arch().ArchType.String() + archDir := android.PathForIntermediates(ctx, "fuzz", hostOrTargetString, archString) + + // The executable. + archDirs[archDir] = append(archDirs[archDir], + fileToZip{ccModule.outputFile.Path(), ccModule.Name()}) + + // The corpora. + for _, corpusEntry := range fuzzModule.corpus { + archDirs[archDir] = append(archDirs[archDir], + fileToZip{corpusEntry, ccModule.Name() + "/corpus/" + corpusEntry.Base()}) + } + + // The dictionary. + if fuzzModule.dictionary != nil { + archDirs[archDir] = append(archDirs[archDir], + fileToZip{fuzzModule.dictionary, ccModule.Name()}) + } + }) + + for archDir, filesToZip := range archDirs { + arch := archDir.Base() + hostOrTarget := filepath.Base(filepath.Dir(archDir.String())) + builder := android.NewRuleBuilder() + outputFile := android.PathForOutput(ctx, "fuzz-"+hostOrTarget+"-"+arch+".zip") + s.packages = append(s.packages, outputFile) + + command := builder.Command().BuiltTool(ctx, "soong_zip"). + Flag("-j"). + FlagWithOutput("-o ", outputFile) + + for _, fileToZip := range filesToZip { + command.FlagWithArg("-P ", fileToZip.DestinationPathPrefix). + FlagWithInput("-f ", fileToZip.SourceFilePath) + } + + builder.Build(pctx, ctx, "create-fuzz-package-"+arch+"-"+hostOrTarget, + "Create fuzz target packages for "+arch+"-"+hostOrTarget) + } +} + +func (s *fuzzPackager) MakeVars(ctx android.MakeVarsContext) { + // TODO(mitchp): Migrate this to use MakeVarsContext::DistForGoal() when it's + // ready to handle phony targets created in Soong. In the meantime, this + // exports the phony 'fuzz' target and dependencies on packages to + // core/main.mk so that we can use dist-for-goals. + ctx.Strict("SOONG_FUZZ_PACKAGING_ARCH_MODULES", strings.Join(s.packages.Strings(), " ")) +} @@ -113,7 +113,14 @@ func genAidl(ctx android.ModuleContext, rule *android.RuleBuilder, aidlFile andr aidlPackage := strings.TrimSuffix(aidlFile.Rel(), aidlFile.Base()) baseName := strings.TrimSuffix(aidlFile.Base(), aidlFile.Ext()) - shortName := strings.TrimPrefix(baseName, "I") + shortName := baseName + // TODO(b/111362593): aidl_to_cpp_common.cpp uses heuristics to figure out if + // an interface name has a leading I. Those same heuristics have been + // moved here. + if len(baseName) >= 2 && baseName[0] == 'I' && + strings.ToUpper(baseName)[1] == baseName[1] { + shortName = strings.TrimPrefix(baseName, "I") + } outDir := android.PathForModuleGen(ctx, "aidl") headerI := outDir.Join(ctx, aidlPackage, baseName+".h") diff --git a/cc/installer.go b/cc/installer.go index 14b091ee0..9fdc88ab9 100644 --- a/cc/installer.go +++ b/cc/installer.go @@ -52,7 +52,7 @@ type baseInstaller struct { relative string location installLocation - path android.OutputPath + path android.InstallPath } var _ installer = (*baseInstaller)(nil) @@ -61,7 +61,7 @@ func (installer *baseInstaller) installerProps() []interface{} { return []interface{}{&installer.Properties} } -func (installer *baseInstaller) installDir(ctx ModuleContext) android.OutputPath { +func (installer *baseInstaller) installDir(ctx ModuleContext) android.InstallPath { dir := installer.dir if ctx.toolchain().Is64Bit() && installer.dir64 != "" { dir = installer.dir64 diff --git a/cc/library.go b/cc/library.go index 43bb1315d..0fb3c7824 100644 --- a/cc/library.go +++ b/cc/library.go @@ -31,24 +31,7 @@ import ( "android/soong/genrule" ) -type StaticSharedLibraryProperties struct { - Srcs []string `android:"path,arch_variant"` - Cflags []string `android:"arch_variant"` - - Enabled *bool `android:"arch_variant"` - Whole_static_libs []string `android:"arch_variant"` - Static_libs []string `android:"arch_variant"` - Shared_libs []string `android:"arch_variant"` - System_shared_libs []string `android:"arch_variant"` - - Export_shared_lib_headers []string `android:"arch_variant"` - Export_static_lib_headers []string `android:"arch_variant"` -} - type LibraryProperties struct { - Static StaticSharedLibraryProperties `android:"arch_variant"` - Shared StaticSharedLibraryProperties `android:"arch_variant"` - // local file name to pass to the linker as -unexported_symbols_list Unexported_symbols_list *string `android:"path,arch_variant"` // local file name to pass to the linker as -force_symbols_not_weak_list @@ -128,6 +111,28 @@ type LibraryProperties struct { Inject_bssl_hash *bool `android:"arch_variant"` } +type StaticProperties struct { + Static StaticOrSharedProperties `android:"arch_variant"` +} + +type SharedProperties struct { + Shared StaticOrSharedProperties `android:"arch_variant"` +} + +type StaticOrSharedProperties struct { + Srcs []string `android:"path,arch_variant"` + Cflags []string `android:"arch_variant"` + + Enabled *bool `android:"arch_variant"` + Whole_static_libs []string `android:"arch_variant"` + Static_libs []string `android:"arch_variant"` + Shared_libs []string `android:"arch_variant"` + System_shared_libs []string `android:"arch_variant"` + + Export_shared_lib_headers []string `android:"arch_variant"` + Export_static_lib_headers []string `android:"arch_variant"` +} + type LibraryMutatedProperties struct { // Build a static variant BuildStatic bool `blueprint:"mutated"` @@ -295,6 +300,8 @@ var _ exportedFlagsProducer = (*flagExporter)(nil) // functionality: static vs. shared linkage, reusing object files for shared libraries type libraryDecorator struct { Properties LibraryProperties + StaticProperties StaticProperties + SharedProperties SharedProperties MutatedProperties LibraryMutatedProperties // For reusing static library objects for shared library @@ -355,11 +362,20 @@ type libraryDecorator struct { func (library *libraryDecorator) linkerProps() []interface{} { var props []interface{} props = append(props, library.baseLinker.linkerProps()...) - return append(props, + props = append(props, &library.Properties, &library.MutatedProperties, &library.flagExporter.Properties, &library.stripper.StripProperties) + + if library.MutatedProperties.BuildShared { + props = append(props, &library.SharedProperties) + } + if library.MutatedProperties.BuildStatic { + props = append(props, &library.StaticProperties) + } + + return props } func (library *libraryDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags { @@ -373,9 +389,9 @@ func (library *libraryDecorator) linkerFlags(ctx ModuleContext, flags Flags) Fla } if library.static() { - flags.CFlags = append(flags.CFlags, library.Properties.Static.Cflags...) + flags.CFlags = append(flags.CFlags, library.StaticProperties.Static.Cflags...) } else if library.shared() { - flags.CFlags = append(flags.CFlags, library.Properties.Shared.Cflags...) + flags.CFlags = append(flags.CFlags, library.SharedProperties.Shared.Cflags...) } if library.shared() { @@ -498,10 +514,10 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa if len(library.baseCompiler.Properties.Srcs) > 0 { ctx.PropertyErrorf("srcs", "cc_library_headers must not have any srcs") } - if len(library.Properties.Static.Srcs) > 0 { + if len(library.StaticProperties.Static.Srcs) > 0 { ctx.PropertyErrorf("static.srcs", "cc_library_headers must not have any srcs") } - if len(library.Properties.Shared.Srcs) > 0 { + if len(library.SharedProperties.Shared.Srcs) > 0 { ctx.PropertyErrorf("shared.srcs", "cc_library_headers must not have any srcs") } return Objects{} @@ -516,8 +532,8 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa SourceAbiFlags = append(SourceAbiFlags, "-I"+reexportedInclude) } flags.SAbiFlags = SourceAbiFlags - total_length := len(library.baseCompiler.Properties.Srcs) + len(deps.GeneratedSources) + len(library.Properties.Shared.Srcs) + - len(library.Properties.Static.Srcs) + total_length := len(library.baseCompiler.Properties.Srcs) + len(deps.GeneratedSources) + + len(library.SharedProperties.Shared.Srcs) + len(library.StaticProperties.Static.Srcs) if total_length > 0 { flags.SAbiDump = true } @@ -527,11 +543,11 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa buildFlags := flagsToBuilderFlags(flags) if library.static() { - srcs := android.PathsForModuleSrc(ctx, library.Properties.Static.Srcs) + srcs := android.PathsForModuleSrc(ctx, library.StaticProperties.Static.Srcs) objs = objs.Append(compileObjs(ctx, buildFlags, android.DeviceStaticLibrary, srcs, library.baseCompiler.pathDeps, library.baseCompiler.cFlagsDeps)) } else if library.shared() { - srcs := android.PathsForModuleSrc(ctx, library.Properties.Shared.Srcs) + srcs := android.PathsForModuleSrc(ctx, library.SharedProperties.Shared.Srcs) objs = objs.Append(compileObjs(ctx, buildFlags, android.DeviceSharedLibrary, srcs, library.baseCompiler.pathDeps, library.baseCompiler.cFlagsDeps)) } @@ -625,12 +641,12 @@ func (library *libraryDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps { func (library *libraryDecorator) linkerDeps(ctx DepsContext, deps Deps) Deps { if library.static() { - if library.Properties.Static.System_shared_libs != nil { - library.baseLinker.Properties.System_shared_libs = library.Properties.Static.System_shared_libs + if library.StaticProperties.Static.System_shared_libs != nil { + library.baseLinker.Properties.System_shared_libs = library.StaticProperties.Static.System_shared_libs } } else if library.shared() { - if library.Properties.Shared.System_shared_libs != nil { - library.baseLinker.Properties.System_shared_libs = library.Properties.Shared.System_shared_libs + if library.SharedProperties.Shared.System_shared_libs != nil { + library.baseLinker.Properties.System_shared_libs = library.SharedProperties.Shared.System_shared_libs } } @@ -638,12 +654,12 @@ func (library *libraryDecorator) linkerDeps(ctx DepsContext, deps Deps) Deps { if library.static() { deps.WholeStaticLibs = append(deps.WholeStaticLibs, - library.Properties.Static.Whole_static_libs...) - deps.StaticLibs = append(deps.StaticLibs, library.Properties.Static.Static_libs...) - deps.SharedLibs = append(deps.SharedLibs, library.Properties.Static.Shared_libs...) + library.StaticProperties.Static.Whole_static_libs...) + deps.StaticLibs = append(deps.StaticLibs, library.StaticProperties.Static.Static_libs...) + deps.SharedLibs = append(deps.SharedLibs, library.StaticProperties.Static.Shared_libs...) - deps.ReexportSharedLibHeaders = append(deps.ReexportSharedLibHeaders, library.Properties.Static.Export_shared_lib_headers...) - deps.ReexportStaticLibHeaders = append(deps.ReexportStaticLibHeaders, library.Properties.Static.Export_static_lib_headers...) + deps.ReexportSharedLibHeaders = append(deps.ReexportSharedLibHeaders, library.StaticProperties.Static.Export_shared_lib_headers...) + deps.ReexportStaticLibHeaders = append(deps.ReexportStaticLibHeaders, library.StaticProperties.Static.Export_static_lib_headers...) } else if library.shared() { if ctx.toolchain().Bionic() && !Bool(library.baseLinker.Properties.Nocrt) { if !ctx.useSdk() { @@ -662,12 +678,12 @@ func (library *libraryDecorator) linkerDeps(ctx DepsContext, deps Deps) Deps { deps.CrtEnd = "ndk_crtend_so." + version } } - deps.WholeStaticLibs = append(deps.WholeStaticLibs, library.Properties.Shared.Whole_static_libs...) - deps.StaticLibs = append(deps.StaticLibs, library.Properties.Shared.Static_libs...) - deps.SharedLibs = append(deps.SharedLibs, library.Properties.Shared.Shared_libs...) + deps.WholeStaticLibs = append(deps.WholeStaticLibs, library.SharedProperties.Shared.Whole_static_libs...) + deps.StaticLibs = append(deps.StaticLibs, library.SharedProperties.Shared.Static_libs...) + deps.SharedLibs = append(deps.SharedLibs, library.SharedProperties.Shared.Shared_libs...) - deps.ReexportSharedLibHeaders = append(deps.ReexportSharedLibHeaders, library.Properties.Shared.Export_shared_lib_headers...) - deps.ReexportStaticLibHeaders = append(deps.ReexportStaticLibHeaders, library.Properties.Shared.Export_static_lib_headers...) + deps.ReexportSharedLibHeaders = append(deps.ReexportSharedLibHeaders, library.SharedProperties.Shared.Export_shared_lib_headers...) + deps.ReexportStaticLibHeaders = append(deps.ReexportStaticLibHeaders, library.SharedProperties.Shared.Export_static_lib_headers...) } if ctx.useVndk() { deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, library.baseLinker.Properties.Target.Vendor.Exclude_static_libs) @@ -775,9 +791,7 @@ func (library *libraryDecorator) linkShared(ctx ModuleContext, // Optimize out relinking against shared libraries whose interface hasn't changed by // depending on a table of contents file instead of the library itself. - tocPath := outputFile.RelPathString() - tocPath = pathtools.ReplaceExtension(tocPath, flags.Toolchain.ShlibSuffix()[1:]+".toc") - tocFile := android.PathForOutput(ctx, tocPath) + tocFile := outputFile.ReplaceExtension(ctx, flags.Toolchain.ShlibSuffix()[1:]+".toc") library.tocFile = android.OptionalPathForPath(tocFile) TransformSharedObjectToToc(ctx, outputFile, tocFile, builderFlags) @@ -978,11 +992,13 @@ func (library *libraryDecorator) link(ctx ModuleContext, } func (library *libraryDecorator) buildStatic() bool { - return library.MutatedProperties.BuildStatic && BoolDefault(library.Properties.Static.Enabled, true) + return library.MutatedProperties.BuildStatic && + BoolDefault(library.StaticProperties.Static.Enabled, true) } func (library *libraryDecorator) buildShared() bool { - return library.MutatedProperties.BuildShared && BoolDefault(library.Properties.Shared.Enabled, true) + return library.MutatedProperties.BuildShared && + BoolDefault(library.SharedProperties.Shared.Enabled, true) } func (library *libraryDecorator) getWholeStaticMissingDeps() []string { @@ -1166,16 +1182,16 @@ func reuseStaticLibrary(mctx android.BottomUpMutatorContext, static, shared *Mod // Check libraries in addition to cflags, since libraries may be exporting different // include directories. - if len(staticCompiler.Properties.Static.Cflags) == 0 && - len(sharedCompiler.Properties.Shared.Cflags) == 0 && - len(staticCompiler.Properties.Static.Whole_static_libs) == 0 && - len(sharedCompiler.Properties.Shared.Whole_static_libs) == 0 && - len(staticCompiler.Properties.Static.Static_libs) == 0 && - len(sharedCompiler.Properties.Shared.Static_libs) == 0 && - len(staticCompiler.Properties.Static.Shared_libs) == 0 && - len(sharedCompiler.Properties.Shared.Shared_libs) == 0 && - staticCompiler.Properties.Static.System_shared_libs == nil && - sharedCompiler.Properties.Shared.System_shared_libs == nil { + if len(staticCompiler.StaticProperties.Static.Cflags) == 0 && + len(sharedCompiler.SharedProperties.Shared.Cflags) == 0 && + len(staticCompiler.StaticProperties.Static.Whole_static_libs) == 0 && + len(sharedCompiler.SharedProperties.Shared.Whole_static_libs) == 0 && + len(staticCompiler.StaticProperties.Static.Static_libs) == 0 && + len(sharedCompiler.SharedProperties.Shared.Static_libs) == 0 && + len(staticCompiler.StaticProperties.Static.Shared_libs) == 0 && + len(sharedCompiler.SharedProperties.Shared.Shared_libs) == 0 && + staticCompiler.StaticProperties.Static.System_shared_libs == nil && + sharedCompiler.SharedProperties.Shared.System_shared_libs == nil { mctx.AddInterVariantDependency(reuseObjTag, shared, static) sharedCompiler.baseCompiler.Properties.OriginalSrcs = @@ -1333,6 +1349,7 @@ func maybeInjectBoringSSLHash(ctx android.ModuleContext, outputFile android.Modu rule := android.NewRuleBuilder() rule.Command(). BuiltTool(ctx, "bssl_inject_hash"). + Flag("-sha256"). FlagWithInput("-in-object ", outputFile). FlagWithOutput("-o ", hashedOutputfile) rule.Build(pctx, ctx, "injectCryptoHash", "inject crypto hash") diff --git a/cc/linker.go b/cc/linker.go index 563ad041d..e5e14861e 100644 --- a/cc/linker.go +++ b/cc/linker.go @@ -491,7 +491,7 @@ var ( gen_sorted_bss_symbols = pctx.AndroidStaticRule("gen_sorted_bss_symbols", blueprint.RuleParams{ Command: "CROSS_COMPILE=$crossCompile $genSortedBssSymbolsPath ${in} ${out}", - CommandDeps: []string{"$genSortedBssSymbolsPath"}, + CommandDeps: []string{"$genSortedBssSymbolsPath", "${crossCompile}nm"}, }, "crossCompile") ) diff --git a/cc/llndk_library.go b/cc/llndk_library.go index 4d59975f4..9cbe80080 100644 --- a/cc/llndk_library.go +++ b/cc/llndk_library.go @@ -76,7 +76,7 @@ func (stub *llndkStubDecorator) compilerFlags(ctx ModuleContext, flags Flags, de } func (stub *llndkStubDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects { - vndk_ver := ctx.DeviceConfig().VndkVersion() + vndk_ver := ctx.Module().(*Module).Properties.VndkVersion if vndk_ver == "current" { platform_vndk_ver := ctx.DeviceConfig().PlatformVndkVersion() if !inList(platform_vndk_ver, ctx.Config().PlatformVersionCombinedCodenames()) { @@ -177,7 +177,6 @@ func NewLLndkStubLibrary() *Module { libraryDecorator: library, } stub.Properties.Vendor_available = BoolPtr(true) - module.Properties.UseVndk = true module.compiler = stub module.linker = stub module.installer = nil diff --git a/cc/ndk_headers.go b/cc/ndk_headers.go index 40651280d..b8423be1f 100644 --- a/cc/ndk_headers.go +++ b/cc/ndk_headers.go @@ -48,7 +48,7 @@ func init() { } // Returns the NDK base include path for use with sdk_version current. Usable with -I. -func getCurrentIncludePath(ctx android.ModuleContext) android.OutputPath { +func getCurrentIncludePath(ctx android.ModuleContext) android.InstallPath { return getNdkSysrootBase(ctx).Join(ctx, "usr/include") } @@ -94,7 +94,7 @@ type headerModule struct { } func getHeaderInstallDir(ctx android.ModuleContext, header android.Path, from string, - to string) android.OutputPath { + to string) android.InstallPath { // Output path is the sysroot base + "usr/include" + to directory + directory component // of the file without the leading from directory stripped. // diff --git a/cc/ndk_sysroot.go b/cc/ndk_sysroot.go index e39bae559..f6de4ef6e 100644 --- a/cc/ndk_sysroot.go +++ b/cc/ndk_sysroot.go @@ -66,12 +66,12 @@ func init() { pctx.Import("android/soong/android") } -func getNdkInstallBase(ctx android.PathContext) android.OutputPath { - return android.PathForOutput(ctx, "ndk") +func getNdkInstallBase(ctx android.PathContext) android.InstallPath { + return android.PathForNdkInstall(ctx) } // Returns the main install directory for the NDK sysroot. Usable with --sysroot. -func getNdkSysrootBase(ctx android.PathContext) android.OutputPath { +func getNdkSysrootBase(ctx android.PathContext) android.InstallPath { return getNdkInstallBase(ctx).Join(ctx, "sysroot") } diff --git a/cc/object.go b/cc/object.go index 1a2711d2c..1f1ac8e1c 100644 --- a/cc/object.go +++ b/cc/object.go @@ -52,8 +52,9 @@ type ObjectLinkerProperties struct { // input to a cc_genrule module. func ObjectFactory() android.Module { module := newBaseModule(android.HostAndDeviceSupported, android.MultilibBoth) + module.sanitize = &sanitize{} module.linker = &objectLinker{ - baseLinker: NewBaseLinker(nil), + baseLinker: NewBaseLinker(module.sanitize), } module.compiler = NewBaseCompiler() @@ -123,7 +124,7 @@ func (object *objectLinker) link(ctx ModuleContext, output = input } - TransformObjsToObj(ctx, objs.objFiles, builderFlags, output) + TransformObjsToObj(ctx, objs.objFiles, builderFlags, output, flags.LdFlagsDeps) } ctx.CheckbuildFile(outputFile) diff --git a/cc/prebuilt.go b/cc/prebuilt.go index 8c72b6910..4e6cdd755 100644 --- a/cc/prebuilt.go +++ b/cc/prebuilt.go @@ -152,6 +152,7 @@ func NewPrebuiltSharedLibrary(hod android.HostOrDeviceSupported) (*Module, *libr // Prebuilt libraries can be included in APEXes android.InitApexModule(module) + android.InitSdkAwareModule(module) return module, library } @@ -176,6 +177,7 @@ func NewPrebuiltStaticLibrary(hod android.HostOrDeviceSupported) (*Module, *libr module.AddProperties(&prebuilt.properties) android.InitPrebuiltModule(module, &prebuilt.properties.Srcs) + android.InitSdkAwareModule(module) return module, library } diff --git a/cc/sanitize.go b/cc/sanitize.go index 415518c10..c0a7c63e0 100644 --- a/cc/sanitize.go +++ b/cc/sanitize.go @@ -674,7 +674,7 @@ func (sanitize *sanitize) isSanitizerEnabled(t sanitizerType) bool { func isSanitizableDependencyTag(tag blueprint.DependencyTag) bool { t, ok := tag.(dependencyTag) - return ok && t.library || t == reuseObjTag + return ok && t.library || t == reuseObjTag || t == objDepTag } // Propagate sanitizer requirements down from binaries @@ -221,13 +221,13 @@ func (stl *stl) flags(ctx ModuleContext, flags Flags) Flags { if !ctx.toolchain().Bionic() { flags.CppFlags = append(flags.CppFlags, "-nostdinc++") - flags.extraLibFlags = append(flags.extraLibFlags, "-nodefaultlibs") - if ctx.staticBinary() { - flags.extraLibFlags = append(flags.extraLibFlags, hostStaticGccLibs[ctx.Os()]...) - } else { - flags.extraLibFlags = append(flags.extraLibFlags, hostDynamicGccLibs[ctx.Os()]...) - } + flags.extraLibFlags = append(flags.extraLibFlags, "-nostdlib++") if ctx.Windows() { + if stl.Properties.SelectedStl == "libc++_static" { + // These are transitively needed by libc++_static. + flags.extraLibFlags = append(flags.extraLibFlags, + "-lmsvcrt", "-lucrt") + } // Use SjLj exceptions for 32-bit. libgcc_eh implements SjLj // exception model for 32-bit. if ctx.Arch().ArchType == android.X86 { @@ -260,12 +260,7 @@ func (stl *stl) flags(ctx ModuleContext, flags Flags) Flags { // None or error. if !ctx.toolchain().Bionic() { flags.CppFlags = append(flags.CppFlags, "-nostdinc++") - flags.extraLibFlags = append(flags.extraLibFlags, "-nodefaultlibs") - if ctx.staticBinary() { - flags.extraLibFlags = append(flags.extraLibFlags, hostStaticGccLibs[ctx.Os()]...) - } else { - flags.extraLibFlags = append(flags.extraLibFlags, hostDynamicGccLibs[ctx.Os()]...) - } + flags.extraLibFlags = append(flags.extraLibFlags, "-nostdlib++") } default: panic(fmt.Errorf("Unknown stl: %q", stl.Properties.SelectedStl)) @@ -273,22 +268,3 @@ func (stl *stl) flags(ctx ModuleContext, flags Flags) Flags { return flags } - -var hostDynamicGccLibs, hostStaticGccLibs map[android.OsType][]string - -func init() { - hostDynamicGccLibs = map[android.OsType][]string{ - android.Fuchsia: []string{"-lc", "-lunwind"}, - android.Linux: []string{"-lgcc_s", "-lgcc", "-lc", "-lgcc_s", "-lgcc"}, - android.Darwin: []string{"-lc", "-lSystem"}, - android.Windows: []string{"-Wl,--start-group", "-lmingw32", "-lgcc", "-lgcc_eh", - "-lmoldname", "-lmingwex", "-lmsvcrt", "-lucrt", "-lpthread", - "-ladvapi32", "-lshell32", "-luser32", "-lkernel32", "-lpsapi", - "-Wl,--end-group"}, - } - hostStaticGccLibs = map[android.OsType][]string{ - android.Linux: []string{"-Wl,--start-group", "-lgcc", "-lgcc_eh", "-lc", "-Wl,--end-group"}, - android.Darwin: []string{"NO_STATIC_HOST_BINARIES_ON_DARWIN"}, - android.Windows: []string{"NO_STATIC_HOST_BINARIES_ON_WINDOWS"}, - } -} diff --git a/cc/test.go b/cc/test.go index 1a0d44fd6..0e66e288e 100644 --- a/cc/test.go +++ b/cc/test.go @@ -16,6 +16,7 @@ package cc import ( "path/filepath" + "strconv" "strings" "android/soong/android" @@ -71,6 +72,19 @@ type TestBinaryProperties struct { // Add RunCommandTargetPreparer to stop framework before the test and start it after the test. Disable_framework *bool + + // Add MinApiLevelModuleController to auto generated test config. If the device property of + // "ro.product.first_api_level" < Test_min_api_level, then skip this module. + Test_min_api_level *int64 + + // Add MinApiLevelModuleController to auto generated test config. If the device property of + // "ro.build.version.sdk" < Test_min_sdk_version, then skip this module. + Test_min_sdk_version *int64 + + // Flag to indicate whether or not to create test config automatically. If AndroidTest.xml + // doesn't exist next to the Android.bp, this attribute doesn't need to be set to true + // explicitly. + Auto_gen_config *bool } func init() { @@ -314,15 +328,21 @@ func (test *testBinary) linkerFlags(ctx ModuleContext, flags Flags) Flags { func (test *testBinary) install(ctx ModuleContext, file android.Path) { test.data = android.PathsForModuleSrc(ctx, test.Properties.Data) + var api_level_prop string var configs []tradefed.Config + var min_level string if Bool(test.Properties.Require_root) { - configs = append(configs, tradefed.Preparer{"com.android.tradefed.targetprep.RootTargetPreparer", nil}) + configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RootTargetPreparer", nil}) + } else { + var options []tradefed.Option + options = append(options, tradefed.Option{"force-root", "false"}) + configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RootTargetPreparer", options}) } if Bool(test.Properties.Disable_framework) { var options []tradefed.Option options = append(options, tradefed.Option{"run-command", "stop"}) options = append(options, tradefed.Option{"teardown-command", "start"}) - configs = append(configs, tradefed.Preparer{"com.android.tradefed.targetprep.RunCommandTargetPreparer", options}) + configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RunCommandTargetPreparer", options}) } if Bool(test.testDecorator.Properties.Isolated) { configs = append(configs, tradefed.Option{"not-shardable", "true"}) @@ -330,9 +350,24 @@ func (test *testBinary) install(ctx ModuleContext, file android.Path) { if test.Properties.Test_options.Run_test_as != nil { configs = append(configs, tradefed.Option{"run-test-as", String(test.Properties.Test_options.Run_test_as)}) } + if test.Properties.Test_min_api_level != nil && test.Properties.Test_min_sdk_version != nil { + ctx.PropertyErrorf("test_min_api_level", "'test_min_api_level' and 'test_min_sdk_version' should not be set at the same time.") + } else if test.Properties.Test_min_api_level != nil { + api_level_prop = "ro.product.first_api_level" + min_level = strconv.FormatInt(int64(*test.Properties.Test_min_api_level), 10) + } else if test.Properties.Test_min_sdk_version != nil { + api_level_prop = "ro.build.version.sdk" + min_level = strconv.FormatInt(int64(*test.Properties.Test_min_sdk_version), 10) + } + if api_level_prop != "" { + var options []tradefed.Option + options = append(options, tradefed.Option{"min-api-level", min_level}) + options = append(options, tradefed.Option{"api-level-prop", api_level_prop}) + configs = append(configs, tradefed.Object{"module_controller", "com.android.tradefed.testtype.suite.module.MinApiLevelModuleController", options}) + } test.testConfig = tradefed.AutoGenNativeTestConfig(ctx, test.Properties.Test_config, - test.Properties.Test_config_template, test.Properties.Test_suites, configs) + test.Properties.Test_config_template, test.Properties.Test_suites, configs, test.Properties.Auto_gen_config) test.binaryDecorator.baseInstaller.dir = "nativetest" test.binaryDecorator.baseInstaller.dir64 = "nativetest64" @@ -423,6 +458,11 @@ type BenchmarkProperties struct { // Add RootTargetPreparer to auto generated test config. This guarantees the test to run // with root permission. Require_root *bool + + // Flag to indicate whether or not to create test config automatically. If AndroidTest.xml + // doesn't exist next to the Android.bp, this attribute doesn't need to be set to true + // explicitly. + Auto_gen_config *bool } type benchmarkDecorator struct { @@ -457,10 +497,10 @@ func (benchmark *benchmarkDecorator) install(ctx ModuleContext, file android.Pat benchmark.data = android.PathsForModuleSrc(ctx, benchmark.Properties.Data) var configs []tradefed.Config if Bool(benchmark.Properties.Require_root) { - configs = append(configs, tradefed.Preparer{"com.android.tradefed.targetprep.RootTargetPreparer", nil}) + configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RootTargetPreparer", nil}) } benchmark.testConfig = tradefed.AutoGenNativeBenchmarkTestConfig(ctx, benchmark.Properties.Test_config, - benchmark.Properties.Test_config_template, benchmark.Properties.Test_suites, configs) + benchmark.Properties.Test_config_template, benchmark.Properties.Test_suites, configs, benchmark.Properties.Auto_gen_config) benchmark.binaryDecorator.baseInstaller.dir = filepath.Join("benchmarktest", ctx.ModuleName()) benchmark.binaryDecorator.baseInstaller.dir64 = filepath.Join("benchmarktest64", ctx.ModuleName()) diff --git a/cc/testing.go b/cc/testing.go index a0b163498..11a5e3bd9 100644 --- a/cc/testing.go +++ b/cc/testing.go @@ -239,6 +239,7 @@ func CreateTestContext(bp string, fs map[string][]byte, os android.OsType) *android.TestContext { ctx := android.NewTestArchContext() + ctx.RegisterModuleType("cc_defaults", android.ModuleFactoryAdaptor(defaultsFactory)) ctx.RegisterModuleType("cc_binary", android.ModuleFactoryAdaptor(BinaryFactory)) ctx.RegisterModuleType("cc_binary_host", android.ModuleFactoryAdaptor(binaryHostFactory)) ctx.RegisterModuleType("cc_fuzz", android.ModuleFactoryAdaptor(FuzzFactory)) @@ -264,6 +265,7 @@ func CreateTestContext(bp string, fs map[string][]byte, ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) { ctx.TopDown("double_loadable", checkDoubleLoadableLibraries).Parallel() }) + ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators) ctx.RegisterSingletonType("vndk-snapshot", android.SingletonFactoryAdaptor(VndkSnapshotSingleton)) // add some modules that are required by the compiler and/or linker @@ -274,6 +276,7 @@ func CreateTestContext(bp string, fs map[string][]byte, "foo.c": nil, "foo.lds": nil, "bar.c": nil, + "baz.c": nil, "baz.o": nil, "a.proto": nil, "b.aidl": nil, diff --git a/cc/vndk.go b/cc/vndk.go index 698fab527..14bbf1156 100644 --- a/cc/vndk.go +++ b/cc/vndk.go @@ -49,10 +49,6 @@ type VndkProperties struct { // Extending another module Extends *string - - // for vndk_prebuilt_shared, this is set by "version" property. - // Otherwise, this is set as PLATFORM_VNDK_VERSION. - Version string `blueprint:"mutated"` } } @@ -129,7 +125,7 @@ func (vndk *vndkdep) vndkCheckLinkType(ctx android.ModuleContext, to *Module, ta // Other (static and LL-NDK) libraries are allowed to link. return } - if !to.Properties.UseVndk { + if !to.useVndk() { ctx.ModuleErrorf("(%s) should not link to %q which is not a vendor-available library", vndk.typeName(), to.Name()) return @@ -325,14 +321,6 @@ func VndkMutator(mctx android.BottomUpMutatorContext) { return } - if m.isVndk() { - if lib, ok := m.linker.(*vndkPrebuiltLibraryDecorator); ok { - m.vndkdep.Properties.Vndk.Version = lib.version() - } else { - m.vndkdep.Properties.Vndk.Version = mctx.DeviceConfig().PlatformVndkVersion() - } - } - if _, ok := m.linker.(*llndkStubDecorator); ok { processLlndkLibrary(mctx, m) return @@ -341,8 +329,8 @@ func VndkMutator(mctx android.BottomUpMutatorContext) { lib, is_lib := m.linker.(*libraryDecorator) prebuilt_lib, is_prebuilt_lib := m.linker.(*prebuiltLibraryLinker) - if (is_lib && lib.shared()) || (is_prebuilt_lib && prebuilt_lib.shared()) { - if m.vndkdep.isVndk() && !m.vndkdep.isVndkExt() { + if (is_lib && lib.buildShared()) || (is_prebuilt_lib && prebuilt_lib.buildShared()) { + if m.vndkdep != nil && m.vndkdep.isVndk() && !m.vndkdep.isVndkExt() { processVndkLibrary(mctx, m) return } diff --git a/cc/vndk_prebuilt.go b/cc/vndk_prebuilt.go index b32433473..2cebb6dcb 100644 --- a/cc/vndk_prebuilt.go +++ b/cc/vndk_prebuilt.go @@ -129,6 +129,18 @@ func (p *vndkPrebuiltLibraryDecorator) singleSourcePath(ctx ModuleContext) andro func (p *vndkPrebuiltLibraryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path { + + arches := ctx.DeviceConfig().Arches() + if len(arches) == 0 || arches[0].ArchType.String() != p.arch() { + ctx.Module().SkipInstall() + return nil + } + + if ctx.DeviceConfig().BinderBitness() != p.binderBit() { + ctx.Module().SkipInstall() + return nil + } + if len(p.properties.Srcs) > 0 && p.shared() { p.libraryDecorator.exportIncludes(ctx) p.libraryDecorator.reexportSystemDirs(p.properties.Export_system_include_dirs...) @@ -136,6 +148,8 @@ func (p *vndkPrebuiltLibraryDecorator) link(ctx ModuleContext, // current VNDK prebuilts are only shared libs. return p.singleSourcePath(ctx) } + + ctx.Module().SkipInstall() return nil } @@ -167,13 +181,19 @@ func vndkPrebuiltSharedLibrary() *Module { module.stl = nil module.sanitize = nil library.StripProperties.Strip.None = BoolPtr(true) - module.Properties.UseVndk = true prebuilt := &vndkPrebuiltLibraryDecorator{ libraryDecorator: library, } prebuilt.properties.Check_elf_files = BoolPtr(false) + prebuilt.baseLinker.Properties.No_libcrt = BoolPtr(true) + prebuilt.baseLinker.Properties.Nocrt = BoolPtr(true) + + // Prevent default system libs (libc, libm, and libdl) from being linked + if prebuilt.baseLinker.Properties.System_shared_libs == nil { + prebuilt.baseLinker.Properties.System_shared_libs = []string{} + } module.compiler = nil module.linker = prebuilt diff --git a/cmd/multiproduct_kati/main.go b/cmd/multiproduct_kati/main.go index 1171a6521..2800ade23 100644 --- a/cmd/multiproduct_kati/main.go +++ b/cmd/multiproduct_kati/main.go @@ -158,7 +158,7 @@ type mpContext struct { func main() { stdio := terminal.StdioImpl{} - output := terminal.NewStatusOutput(stdio.Stdout(), "", + output := terminal.NewStatusOutput(stdio.Stdout(), "", false, build.OsEnvironment().IsEnvTrue("ANDROID_QUIET_BUILD")) log := logger.New(output) @@ -391,7 +391,7 @@ func buildProduct(mpctx *mpContext, product string) { Thread: mpctx.Tracer.NewThread(product), Status: &status.Status{}, }} - ctx.Status.AddOutput(terminal.NewStatusOutput(ctx.Writer, "", + ctx.Status.AddOutput(terminal.NewStatusOutput(ctx.Writer, "", false, build.OsEnvironment().IsEnvTrue("ANDROID_QUIET_BUILD"))) config := build.NewConfig(ctx, flag.Args()...) diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go index ec4f90e06..974c644aa 100644 --- a/cmd/soong_ui/main.go +++ b/cmd/soong_ui/main.go @@ -41,6 +41,12 @@ type command struct { // description for the flag (to display when running help) description string + // Forces the status output into dumb terminal mode. + forceDumbOutput bool + + // Sets a prefix string to use for filenames of log files. + logsPrefix string + // Creates the build configuration based on the args and build context. config func(ctx build.Context, args ...string) build.Config @@ -64,17 +70,21 @@ var commands []command = []command{ stdio: stdio, run: make, }, { - flag: "--dumpvar-mode", - description: "print the value of the legacy make variable VAR to stdout", - config: dumpVarConfig, - stdio: customStdio, - run: dumpVar, + flag: "--dumpvar-mode", + description: "print the value of the legacy make variable VAR to stdout", + forceDumbOutput: true, + logsPrefix: "dumpvars-", + config: dumpVarConfig, + stdio: customStdio, + run: dumpVar, }, { - flag: "--dumpvars-mode", - description: "dump the values of one or more legacy make variables, in shell syntax", - config: dumpVarConfig, - stdio: customStdio, - run: dumpVars, + flag: "--dumpvars-mode", + description: "dump the values of one or more legacy make variables, in shell syntax", + forceDumbOutput: true, + logsPrefix: "dumpvars-", + config: dumpVarConfig, + stdio: customStdio, + run: dumpVars, }, { flag: "--build-mode", description: "build modules based on the specified build action", @@ -113,7 +123,7 @@ func main() { os.Exit(1) } - output := terminal.NewStatusOutput(c.stdio().Stdout(), os.Getenv("NINJA_STATUS"), + output := terminal.NewStatusOutput(c.stdio().Stdout(), os.Getenv("NINJA_STATUS"), c.forceDumbOutput, build.OsEnvironment().IsEnvTrue("ANDROID_QUIET_BUILD")) log := logger.New(output) @@ -157,14 +167,14 @@ func main() { } os.MkdirAll(logsDir, 0777) - log.SetOutput(filepath.Join(logsDir, "soong.log")) - trace.SetOutput(filepath.Join(logsDir, "build.trace")) - stat.AddOutput(status.NewVerboseLog(log, filepath.Join(logsDir, "verbose.log"))) - stat.AddOutput(status.NewErrorLog(log, filepath.Join(logsDir, "error.log"))) - stat.AddOutput(status.NewProtoErrorLog(log, filepath.Join(logsDir, "build_error"))) + log.SetOutput(filepath.Join(logsDir, c.logsPrefix+"soong.log")) + trace.SetOutput(filepath.Join(logsDir, c.logsPrefix+"build.trace")) + stat.AddOutput(status.NewVerboseLog(log, filepath.Join(logsDir, c.logsPrefix+"verbose.log"))) + stat.AddOutput(status.NewErrorLog(log, filepath.Join(logsDir, c.logsPrefix+"error.log"))) + stat.AddOutput(status.NewProtoErrorLog(log, filepath.Join(logsDir, c.logsPrefix+"build_error"))) stat.AddOutput(status.NewCriticalPath(log)) - defer met.Dump(filepath.Join(logsDir, "soong_metrics")) + defer met.Dump(filepath.Join(logsDir, c.logsPrefix+"soong_metrics")) if start, ok := os.LookupEnv("TRACE_BEGIN_SOONG"); ok { if !strings.HasSuffix(start, "N") { diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go index c378f096b..40644a35e 100644 --- a/dexpreopt/dexpreopt.go +++ b/dexpreopt/dexpreopt.go @@ -248,7 +248,7 @@ func dexpreoptCommand(ctx android.PathContext, global GlobalConfig, module Modul odexPath := module.BuildPath.InSameDir(ctx, "oat", arch.String(), pathtools.ReplaceExtension(base, "odex")) odexInstallPath := toOdexPath(module.DexLocation) if odexOnSystemOther(module, global) { - odexInstallPath = strings.Replace(odexInstallPath, SystemPartition, SystemOtherPartition, 1) + odexInstallPath = filepath.Join(SystemOtherPartition, odexInstallPath) } vdexPath := odexPath.ReplaceExtension(ctx, "vdex") diff --git a/dexpreopt/dexpreopt_test.go b/dexpreopt/dexpreopt_test.go index 7f1fe4276..aca5e63af 100644 --- a/dexpreopt/dexpreopt_test.go +++ b/dexpreopt/dexpreopt_test.go @@ -16,17 +16,30 @@ package dexpreopt import ( "android/soong/android" + "fmt" "reflect" "strings" "testing" ) -func testModuleConfig(ctx android.PathContext) ModuleConfig { +func testSystemModuleConfig(ctx android.PathContext, name string) ModuleConfig { + return testModuleConfig(ctx, name, "system") +} + +func testSystemProductModuleConfig(ctx android.PathContext, name string) ModuleConfig { + return testModuleConfig(ctx, name, "system/product") +} + +func testProductModuleConfig(ctx android.PathContext, name string) ModuleConfig { + return testModuleConfig(ctx, name, "product") +} + +func testModuleConfig(ctx android.PathContext, name, partition string) ModuleConfig { return ModuleConfig{ - Name: "test", - DexLocation: "/system/app/test/test.apk", - BuildPath: android.PathForOutput(ctx, "test/test.apk"), - DexPath: android.PathForOutput(ctx, "test/dex/test.jar"), + Name: name, + DexLocation: fmt.Sprintf("/%s/app/test/%s.apk", partition, name), + BuildPath: android.PathForOutput(ctx, fmt.Sprintf("%s/%s.apk", name, name)), + DexPath: android.PathForOutput(ctx, fmt.Sprintf("%s/dex/%s.jar", name, name)), UncompressedDex: false, HasApkLibraries: false, PreoptFlags: nil, @@ -46,14 +59,14 @@ func testModuleConfig(ctx android.PathContext) ModuleConfig { ForceCreateAppImage: false, PresignedPrebuilt: false, NoStripping: false, - StripInputPath: android.PathForOutput(ctx, "unstripped/test.apk"), - StripOutputPath: android.PathForOutput(ctx, "stripped/test.apk"), + StripInputPath: android.PathForOutput(ctx, fmt.Sprintf("unstripped/%s.apk", name)), + StripOutputPath: android.PathForOutput(ctx, fmt.Sprintf("stripped/%s.apk", name)), } } func TestDexPreopt(t *testing.T) { ctx := android.PathContextForTesting(android.TestConfig("out", nil), nil) - global, module := GlobalConfigForTests(ctx), testModuleConfig(ctx) + global, module := GlobalConfigForTests(ctx), testSystemModuleConfig(ctx, "test") rule, err := GenerateDexpreoptRule(ctx, global, module) if err != nil { @@ -73,7 +86,7 @@ func TestDexPreopt(t *testing.T) { func TestDexPreoptStrip(t *testing.T) { // Test that we panic if we strip in a configuration where stripping is not allowed. ctx := android.PathContextForTesting(android.TestConfig("out", nil), nil) - global, module := GlobalConfigForTests(ctx), testModuleConfig(ctx) + global, module := GlobalConfigForTests(ctx), testSystemModuleConfig(ctx, "test") global.NeverAllowStripping = true module.NoStripping = false @@ -86,29 +99,65 @@ func TestDexPreoptStrip(t *testing.T) { func TestDexPreoptSystemOther(t *testing.T) { ctx := android.PathContextForTesting(android.TestConfig("out", nil), nil) - global, module := GlobalConfigForTests(ctx), testModuleConfig(ctx) + global := GlobalConfigForTests(ctx) + systemModule := testSystemModuleConfig(ctx, "Stest") + systemProductModule := testSystemProductModuleConfig(ctx, "SPtest") + productModule := testProductModuleConfig(ctx, "Ptest") global.HasSystemOther = true - global.PatternsOnSystemOther = []string{"app/%"} - rule, err := GenerateDexpreoptRule(ctx, global, module) - if err != nil { - t.Fatal(err) + type moduleTest struct { + module ModuleConfig + expectedPartition string } - - wantInstalls := android.RuleBuilderInstalls{ - {android.PathForOutput(ctx, "test/oat/arm/package.odex"), "/system_other/app/test/oat/arm/test.odex"}, - {android.PathForOutput(ctx, "test/oat/arm/package.vdex"), "/system_other/app/test/oat/arm/test.vdex"}, + tests := []struct { + patterns []string + moduleTests []moduleTest + }{ + { + patterns: []string{"app/%"}, + moduleTests: []moduleTest{ + {module: systemModule, expectedPartition: "system_other/system"}, + {module: systemProductModule, expectedPartition: "system/product"}, + {module: productModule, expectedPartition: "product"}, + }, + }, + // product/app/% only applies to product apps inside the system partition + { + patterns: []string{"app/%", "product/app/%"}, + moduleTests: []moduleTest{ + {module: systemModule, expectedPartition: "system_other/system"}, + {module: systemProductModule, expectedPartition: "system_other/system/product"}, + {module: productModule, expectedPartition: "product"}, + }, + }, } - if rule.Installs().String() != wantInstalls.String() { - t.Errorf("\nwant installs:\n %v\ngot:\n %v", wantInstalls, rule.Installs()) + for _, test := range tests { + global.PatternsOnSystemOther = test.patterns + for _, mt := range test.moduleTests { + rule, err := GenerateDexpreoptRule(ctx, global, mt.module) + if err != nil { + t.Fatal(err) + } + + name := mt.module.Name + wantInstalls := android.RuleBuilderInstalls{ + {android.PathForOutput(ctx, name+"/oat/arm/package.odex"), fmt.Sprintf("/%s/app/test/oat/arm/%s.odex", mt.expectedPartition, name)}, + {android.PathForOutput(ctx, name+"/oat/arm/package.vdex"), fmt.Sprintf("/%s/app/test/oat/arm/%s.vdex", mt.expectedPartition, name)}, + } + + if rule.Installs().String() != wantInstalls.String() { + t.Errorf("\nwant installs:\n %v\ngot:\n %v", wantInstalls, rule.Installs()) + } + } } + } func TestDexPreoptProfile(t *testing.T) { ctx := android.PathContextForTesting(android.TestConfig("out", nil), nil) - global, module := GlobalConfigForTests(ctx), testModuleConfig(ctx) + global, module := GlobalConfigForTests(ctx), testSystemModuleConfig(ctx, "test") module.ProfileClassListing = android.OptionalPathForPath(android.PathForTesting("profile")) @@ -156,7 +205,7 @@ func TestStripDex(t *testing.T) { t.Run(test.name, func(t *testing.T) { ctx := android.PathContextForTesting(android.TestConfig("out", nil), nil) - global, module := GlobalConfigForTests(ctx), testModuleConfig(ctx) + global, module := GlobalConfigForTests(ctx), testSystemModuleConfig(ctx, "test") test.setup(&global, &module) diff --git a/genrule/genrule.go b/genrule/genrule.go index cf0b484e1..b8b0e0129 100644 --- a/genrule/genrule.go +++ b/genrule/genrule.go @@ -437,7 +437,7 @@ func (g *Module) generateSourceFile(ctx android.ModuleContext, task generateTask phonyFile := android.PathForModuleGen(ctx, "genrule-phony") ctx.Build(pctx, android.BuildParams{ - Rule: android.Phony, + Rule: blueprint.Phony, Output: phonyFile, Inputs: g.outputFiles, }) diff --git a/java/aapt2.go b/java/aapt2.go index f0eb99cee..cfe0deab1 100644 --- a/java/aapt2.go +++ b/java/aapt2.go @@ -63,7 +63,7 @@ var aapt2CompileRule = pctx.AndroidStaticRule("aapt2Compile", func aapt2Compile(ctx android.ModuleContext, dir android.Path, paths android.Paths, flags []string) android.WritablePaths { - shards := shardPaths(paths, AAPT2_SHARD_SIZE) + shards := android.ShardPaths(paths, AAPT2_SHARD_SIZE) ret := make(android.WritablePaths, 0, len(paths)) diff --git a/java/androidmk.go b/java/androidmk.go index 0e8e42248..bc61297d1 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -22,7 +22,9 @@ import ( "android/soong/android" ) -func (library *Library) AndroidMkHostDex(w io.Writer, name string, data android.AndroidMkData) { +// TODO(jungjw): We'll probably want AndroidMkEntriesProvider.AndroidMkEntries to return multiple +// entries so that this can be more error-proof. +func (library *Library) AndroidMkHostDex(w io.Writer, name string, entries *android.AndroidMkEntries) { if Bool(library.deviceProperties.Hostdex) && !library.Host() { fmt.Fprintln(w, "include $(CLEAR_VARS)") fmt.Fprintln(w, "LOCAL_MODULE := "+name+"-hostdex") @@ -38,14 +40,14 @@ func (library *Library) AndroidMkHostDex(w io.Writer, name string, data android. } fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", library.headerJarFile.String()) fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", library.implementationAndResourcesJar.String()) - if len(data.Required) > 0 { - fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", strings.Join(data.Required, " ")) + if len(entries.Required) > 0 { + fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", strings.Join(entries.Required, " ")) } - if len(data.Host_required) > 0 { - fmt.Fprintln(w, "LOCAL_HOST_REQUIRED_MODULES :=", strings.Join(data.Host_required, " ")) + if len(entries.Host_required) > 0 { + fmt.Fprintln(w, "LOCAL_HOST_REQUIRED_MODULES :=", strings.Join(entries.Host_required, " ")) } - if len(data.Target_required) > 0 { - fmt.Fprintln(w, "LOCAL_TARGET_REQUIRED_MODULES :=", strings.Join(data.Target_required, " ")) + if len(entries.Target_required) > 0 { + fmt.Fprintln(w, "LOCAL_TARGET_REQUIRED_MODULES :=", strings.Join(entries.Target_required, " ")) } if r := library.deviceProperties.Target.Hostdex.Required; len(r) > 0 { fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES +=", strings.Join(r, " ")) @@ -54,75 +56,64 @@ func (library *Library) AndroidMkHostDex(w io.Writer, name string, data android. } } -func (library *Library) AndroidMk() android.AndroidMkData { +func (library *Library) AndroidMkEntries() android.AndroidMkEntries { if !library.IsForPlatform() { - return android.AndroidMkData{ + return android.AndroidMkEntries{ Disabled: true, } } - return android.AndroidMkData{ + return android.AndroidMkEntries{ Class: "JAVA_LIBRARIES", OutputFile: android.OptionalPathForPath(library.outputFile), Include: "$(BUILD_SYSTEM)/soong_java_prebuilt.mk", - Extra: []android.AndroidMkExtraFunc{ - func(w io.Writer, outputFile android.Path) { + ExtraEntries: []android.AndroidMkExtraEntriesFunc{ + func(entries *android.AndroidMkEntries) { if len(library.logtagsSrcs) > 0 { var logtags []string for _, l := range library.logtagsSrcs { logtags = append(logtags, l.Rel()) } - fmt.Fprintln(w, "LOCAL_LOGTAGS_FILES :=", strings.Join(logtags, " ")) + entries.AddStrings("LOCAL_LOGTAGS_FILES", logtags...) } if library.installFile == nil { - fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true") + entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", true) } if library.dexJarFile != nil { - fmt.Fprintln(w, "LOCAL_SOONG_DEX_JAR :=", library.dexJarFile.String()) + entries.SetPath("LOCAL_SOONG_DEX_JAR", library.dexJarFile) } if len(library.dexpreopter.builtInstalled) > 0 { - fmt.Fprintln(w, "LOCAL_SOONG_BUILT_INSTALLED :=", library.dexpreopter.builtInstalled) + entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", library.dexpreopter.builtInstalled) } - fmt.Fprintln(w, "LOCAL_SDK_VERSION :=", library.sdkVersion()) - fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", library.implementationAndResourcesJar.String()) - fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", library.headerJarFile.String()) + entries.SetString("LOCAL_SDK_VERSION", library.sdkVersion()) + entries.SetPath("LOCAL_SOONG_CLASSES_JAR", library.implementationAndResourcesJar) + entries.SetPath("LOCAL_SOONG_HEADER_JAR", library.headerJarFile) if library.jacocoReportClassesFile != nil { - fmt.Fprintln(w, "LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR :=", library.jacocoReportClassesFile.String()) + entries.SetPath("LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR", library.jacocoReportClassesFile) } - if len(library.exportedSdkLibs) != 0 { - fmt.Fprintln(w, "LOCAL_EXPORT_SDK_LIBRARIES :=", strings.Join(library.exportedSdkLibs, " ")) - } + entries.AddStrings("LOCAL_EXPORT_SDK_LIBRARIES", library.exportedSdkLibs...) if len(library.additionalCheckedModules) != 0 { - fmt.Fprintln(w, "LOCAL_ADDITIONAL_CHECKED_MODULE +=", strings.Join(library.additionalCheckedModules.Strings(), " ")) + entries.AddStrings("LOCAL_ADDITIONAL_CHECKED_MODULE", library.additionalCheckedModules.Strings()...) } if library.proguardDictionary != nil { - fmt.Fprintln(w, "LOCAL_SOONG_PROGUARD_DICT :=", library.proguardDictionary.String()) + entries.SetPath("LOCAL_SOONG_PROGUARD_DICT", library.proguardDictionary) } }, }, - Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) { - android.WriteAndroidMkData(w, data) - library.AndroidMkHostDex(w, name, data) + ExtraFooters: []android.AndroidMkExtraFootersFunc{ + func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) { + library.AndroidMkHostDex(w, name, entries) + }, }, } } // Called for modules that are a component of a test suite. -func testSuiteComponent(w io.Writer, test_suites []string) { - fmt.Fprintln(w, "LOCAL_MODULE_TAGS := tests") - if len(test_suites) > 0 { - fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE :=", - strings.Join(test_suites, " ")) - } else { - fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE := null-suite") - } -} - -func testSuiteComponentEntries(entries *android.AndroidMkEntries, test_suites []string) { +func testSuiteComponent(entries *android.AndroidMkEntries, test_suites []string) { entries.SetString("LOCAL_MODULE_TAGS", "tests") if len(test_suites) > 0 { entries.AddStrings("LOCAL_COMPATIBILITY_SUITE", test_suites...) @@ -131,179 +122,175 @@ func testSuiteComponentEntries(entries *android.AndroidMkEntries, test_suites [] } } -func (j *Test) AndroidMk() android.AndroidMkData { - data := j.Library.AndroidMk() - data.Extra = append(data.Extra, func(w io.Writer, outputFile android.Path) { - testSuiteComponent(w, j.testProperties.Test_suites) +func (j *Test) AndroidMkEntries() android.AndroidMkEntries { + entries := j.Library.AndroidMkEntries() + entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) { + testSuiteComponent(entries, j.testProperties.Test_suites) if j.testConfig != nil { - fmt.Fprintln(w, "LOCAL_FULL_TEST_CONFIG :=", j.testConfig.String()) + entries.SetPath("LOCAL_FULL_TEST_CONFIG", j.testConfig) } + androidMkWriteTestData(j.data, entries) }) - androidMkWriteTestData(j.data, &data) - - return data + return entries } -func (j *TestHelperLibrary) AndroidMk() android.AndroidMkData { - data := j.Library.AndroidMk() - data.Extra = append(data.Extra, func(w io.Writer, outputFile android.Path) { - testSuiteComponent(w, j.testHelperLibraryProperties.Test_suites) +func (j *TestHelperLibrary) AndroidMkEntries() android.AndroidMkEntries { + entries := j.Library.AndroidMkEntries() + entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) { + testSuiteComponent(entries, j.testHelperLibraryProperties.Test_suites) }) - return data + return entries } -func (prebuilt *Import) AndroidMk() android.AndroidMkData { - if !prebuilt.IsForPlatform() { - return android.AndroidMkData{ +func (prebuilt *Import) AndroidMkEntries() android.AndroidMkEntries { + if !prebuilt.IsForPlatform() || !prebuilt.ContainingSdk().IsCurrentVersion() { + return android.AndroidMkEntries{ Disabled: true, } } - return android.AndroidMkData{ + return android.AndroidMkEntries{ Class: "JAVA_LIBRARIES", OutputFile: android.OptionalPathForPath(prebuilt.combinedClasspathFile), Include: "$(BUILD_SYSTEM)/soong_java_prebuilt.mk", - Extra: []android.AndroidMkExtraFunc{ - func(w io.Writer, outputFile android.Path) { - fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := ", !Bool(prebuilt.properties.Installable)) - fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", prebuilt.combinedClasspathFile.String()) - fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", prebuilt.combinedClasspathFile.String()) - fmt.Fprintln(w, "LOCAL_SDK_VERSION :=", prebuilt.sdkVersion()) + ExtraEntries: []android.AndroidMkExtraEntriesFunc{ + func(entries *android.AndroidMkEntries) { + entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", !Bool(prebuilt.properties.Installable)) + entries.SetPath("LOCAL_SOONG_HEADER_JAR", prebuilt.combinedClasspathFile) + entries.SetPath("LOCAL_SOONG_CLASSES_JAR", prebuilt.combinedClasspathFile) + entries.SetString("LOCAL_SDK_VERSION", prebuilt.sdkVersion()) }, }, } } -func (prebuilt *DexImport) AndroidMk() android.AndroidMkData { +func (prebuilt *DexImport) AndroidMkEntries() android.AndroidMkEntries { if !prebuilt.IsForPlatform() { - return android.AndroidMkData{ + return android.AndroidMkEntries{ Disabled: true, } } - return android.AndroidMkData{ + return android.AndroidMkEntries{ Class: "JAVA_LIBRARIES", OutputFile: android.OptionalPathForPath(prebuilt.maybeStrippedDexJarFile), Include: "$(BUILD_SYSTEM)/soong_java_prebuilt.mk", - Extra: []android.AndroidMkExtraFunc{ - func(w io.Writer, outputFile android.Path) { + ExtraEntries: []android.AndroidMkExtraEntriesFunc{ + func(entries *android.AndroidMkEntries) { if prebuilt.dexJarFile != nil { - fmt.Fprintln(w, "LOCAL_SOONG_DEX_JAR :=", prebuilt.dexJarFile.String()) + entries.SetPath("LOCAL_SOONG_DEX_JAR", prebuilt.dexJarFile) // TODO(b/125517186): export the dex jar as a classes jar to match some mis-uses in Make until // boot_jars_package_check.mk can check dex jars. - fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", prebuilt.dexJarFile.String()) - fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", prebuilt.dexJarFile.String()) + entries.SetPath("LOCAL_SOONG_HEADER_JAR", prebuilt.dexJarFile) + entries.SetPath("LOCAL_SOONG_CLASSES_JAR", prebuilt.dexJarFile) } if len(prebuilt.dexpreopter.builtInstalled) > 0 { - fmt.Fprintln(w, "LOCAL_SOONG_BUILT_INSTALLED :=", prebuilt.dexpreopter.builtInstalled) + entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", prebuilt.dexpreopter.builtInstalled) } }, }, } } -func (prebuilt *AARImport) AndroidMk() android.AndroidMkData { - return android.AndroidMkData{ +func (prebuilt *AARImport) AndroidMkEntries() android.AndroidMkEntries { + return android.AndroidMkEntries{ Class: "JAVA_LIBRARIES", OutputFile: android.OptionalPathForPath(prebuilt.classpathFile), Include: "$(BUILD_SYSTEM)/soong_java_prebuilt.mk", - Extra: []android.AndroidMkExtraFunc{ - func(w io.Writer, outputFile android.Path) { - fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true") - fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", prebuilt.classpathFile.String()) - fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", prebuilt.classpathFile.String()) - fmt.Fprintln(w, "LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE :=", prebuilt.exportPackage.String()) - fmt.Fprintln(w, "LOCAL_SOONG_EXPORT_PROGUARD_FLAGS :=", prebuilt.proguardFlags.String()) - fmt.Fprintln(w, "LOCAL_SOONG_STATIC_LIBRARY_EXTRA_PACKAGES :=", prebuilt.extraAaptPackagesFile.String()) - fmt.Fprintln(w, "LOCAL_FULL_MANIFEST_FILE :=", prebuilt.manifest.String()) - fmt.Fprintln(w, "LOCAL_SDK_VERSION :=", prebuilt.sdkVersion()) + ExtraEntries: []android.AndroidMkExtraEntriesFunc{ + func(entries *android.AndroidMkEntries) { + entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true) + entries.SetPath("LOCAL_SOONG_HEADER_JAR", prebuilt.classpathFile) + entries.SetPath("LOCAL_SOONG_CLASSES_JAR", prebuilt.classpathFile) + entries.SetPath("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE", prebuilt.exportPackage) + entries.SetPath("LOCAL_SOONG_EXPORT_PROGUARD_FLAGS", prebuilt.proguardFlags) + entries.SetPath("LOCAL_SOONG_STATIC_LIBRARY_EXTRA_PACKAGES", prebuilt.extraAaptPackagesFile) + entries.SetPath("LOCAL_FULL_MANIFEST_FILE", prebuilt.manifest) + entries.SetString("LOCAL_SDK_VERSION", prebuilt.sdkVersion()) }, }, } } -func (binary *Binary) AndroidMk() android.AndroidMkData { +func (binary *Binary) AndroidMkEntries() android.AndroidMkEntries { if !binary.isWrapperVariant { - return android.AndroidMkData{ + return android.AndroidMkEntries{ Class: "JAVA_LIBRARIES", OutputFile: android.OptionalPathForPath(binary.outputFile), Include: "$(BUILD_SYSTEM)/soong_java_prebuilt.mk", - Extra: []android.AndroidMkExtraFunc{ - func(w io.Writer, outputFile android.Path) { - fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", binary.headerJarFile.String()) - fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", binary.implementationAndResourcesJar.String()) + ExtraEntries: []android.AndroidMkExtraEntriesFunc{ + func(entries *android.AndroidMkEntries) { + entries.SetPath("LOCAL_SOONG_HEADER_JAR", binary.headerJarFile) + entries.SetPath("LOCAL_SOONG_CLASSES_JAR", binary.implementationAndResourcesJar) if binary.dexJarFile != nil { - fmt.Fprintln(w, "LOCAL_SOONG_DEX_JAR :=", binary.dexJarFile.String()) + entries.SetPath("LOCAL_SOONG_DEX_JAR", binary.dexJarFile) } if len(binary.dexpreopter.builtInstalled) > 0 { - fmt.Fprintln(w, "LOCAL_SOONG_BUILT_INSTALLED :=", binary.dexpreopter.builtInstalled) + entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", binary.dexpreopter.builtInstalled) } }, }, - Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) { - android.WriteAndroidMkData(w, data) - - fmt.Fprintln(w, "jar_installed_module := $(LOCAL_INSTALLED_MODULE)") + ExtraFooters: []android.AndroidMkExtraFootersFunc{ + func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) { + fmt.Fprintln(w, "jar_installed_module := $(LOCAL_INSTALLED_MODULE)") + }, }, } } else { - return android.AndroidMkData{ + return android.AndroidMkEntries{ Class: "EXECUTABLES", OutputFile: android.OptionalPathForPath(binary.wrapperFile), - Extra: []android.AndroidMkExtraFunc{ - func(w io.Writer, outputFile android.Path) { - fmt.Fprintln(w, "LOCAL_STRIP_MODULE := false") + ExtraEntries: []android.AndroidMkExtraEntriesFunc{ + func(entries *android.AndroidMkEntries) { + entries.SetBool("LOCAL_STRIP_MODULE", false) }, }, - Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) { - android.WriteAndroidMkData(w, data) - - // Ensure that the wrapper script timestamp is always updated when the jar is updated - fmt.Fprintln(w, "$(LOCAL_INSTALLED_MODULE): $(jar_installed_module)") - fmt.Fprintln(w, "jar_installed_module :=") + ExtraFooters: []android.AndroidMkExtraFootersFunc{ + func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) { + // Ensure that the wrapper script timestamp is always updated when the jar is updated + fmt.Fprintln(w, "$(LOCAL_INSTALLED_MODULE): $(jar_installed_module)") + fmt.Fprintln(w, "jar_installed_module :=") + }, }, } } } -func (app *AndroidApp) AndroidMk() android.AndroidMkData { - return android.AndroidMkData{ +func (app *AndroidApp) AndroidMkEntries() android.AndroidMkEntries { + return android.AndroidMkEntries{ Class: "APPS", OutputFile: android.OptionalPathForPath(app.outputFile), Include: "$(BUILD_SYSTEM)/soong_app_prebuilt.mk", - Extra: []android.AndroidMkExtraFunc{ - func(w io.Writer, outputFile android.Path) { - // TODO(jungjw): This, outputting two LOCAL_MODULE lines, works, but is not ideal. Find a better solution. - if app.Name() != app.installApkName { - fmt.Fprintln(w, "# Overridden by PRODUCT_PACKAGE_NAME_OVERRIDES") - fmt.Fprintln(w, "LOCAL_MODULE :=", app.installApkName) - } - fmt.Fprintln(w, "LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE :=", app.exportPackage.String()) + ExtraEntries: []android.AndroidMkExtraEntriesFunc{ + func(entries *android.AndroidMkEntries) { + // App module names can be overridden. + entries.SetString("LOCAL_MODULE", app.installApkName) + entries.SetPath("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE", app.exportPackage) if app.dexJarFile != nil { - fmt.Fprintln(w, "LOCAL_SOONG_DEX_JAR :=", app.dexJarFile.String()) + entries.SetPath("LOCAL_SOONG_DEX_JAR", app.dexJarFile) } if app.implementationAndResourcesJar != nil { - fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", app.implementationAndResourcesJar.String()) + entries.SetPath("LOCAL_SOONG_CLASSES_JAR", app.implementationAndResourcesJar) } if app.headerJarFile != nil { - fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", app.headerJarFile.String()) + entries.SetPath("LOCAL_SOONG_HEADER_JAR", app.headerJarFile) } if app.bundleFile != nil { - fmt.Fprintln(w, "LOCAL_SOONG_BUNDLE :=", app.bundleFile.String()) + entries.SetPath("LOCAL_SOONG_BUNDLE", app.bundleFile) } if app.jacocoReportClassesFile != nil { - fmt.Fprintln(w, "LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR :=", app.jacocoReportClassesFile.String()) + entries.SetPath("LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR", app.jacocoReportClassesFile) } if app.proguardDictionary != nil { - fmt.Fprintln(w, "LOCAL_SOONG_PROGUARD_DICT :=", app.proguardDictionary.String()) + entries.SetPath("LOCAL_SOONG_PROGUARD_DICT", app.proguardDictionary) } if app.Name() == "framework-res" { - fmt.Fprintln(w, "LOCAL_MODULE_PATH := $(TARGET_OUT_JAVA_LIBRARIES)") + entries.SetString("LOCAL_MODULE_PATH", "$(TARGET_OUT_JAVA_LIBRARIES)") // Make base_rules.mk not put framework-res in a subdirectory called // framework_res. - fmt.Fprintln(w, "LOCAL_NO_STANDARD_LIBRARIES := true") + entries.SetBoolIfTrue("LOCAL_NO_STANDARD_LIBRARIES", true) } filterRRO := func(filter overlayType) android.Paths { @@ -319,38 +306,37 @@ func (app *AndroidApp) AndroidMk() android.AndroidMkData { } deviceRRODirs := filterRRO(device) if len(deviceRRODirs) > 0 { - fmt.Fprintln(w, "LOCAL_SOONG_DEVICE_RRO_DIRS :=", strings.Join(deviceRRODirs.Strings(), " ")) + entries.AddStrings("LOCAL_SOONG_DEVICE_RRO_DIRS", deviceRRODirs.Strings()...) } productRRODirs := filterRRO(product) if len(productRRODirs) > 0 { - fmt.Fprintln(w, "LOCAL_SOONG_PRODUCT_RRO_DIRS :=", strings.Join(productRRODirs.Strings(), " ")) + entries.AddStrings("LOCAL_SOONG_PRODUCT_RRO_DIRS", productRRODirs.Strings()...) } - if Bool(app.appProperties.Export_package_resources) { - fmt.Fprintln(w, "LOCAL_EXPORT_PACKAGE_RESOURCES := true") - } + entries.SetBoolIfTrue("LOCAL_EXPORT_PACKAGE_RESOURCES", Bool(app.appProperties.Export_package_resources)) - fmt.Fprintln(w, "LOCAL_FULL_MANIFEST_FILE :=", app.manifestPath.String()) + entries.SetPath("LOCAL_FULL_MANIFEST_FILE", app.manifestPath) - if Bool(app.appProperties.Privileged) { - fmt.Fprintln(w, "LOCAL_PRIVILEGED_MODULE := true") - } + entries.SetBoolIfTrue("LOCAL_PRIVILEGED_MODULE", Bool(app.appProperties.Privileged)) - fmt.Fprintln(w, "LOCAL_CERTIFICATE :=", app.certificate.Pem.String()) - if overriddenPkgs := app.getOverriddenPackages(); len(overriddenPkgs) > 0 { - fmt.Fprintln(w, "LOCAL_OVERRIDES_PACKAGES :=", strings.Join(overriddenPkgs, " ")) - } + entries.SetPath("LOCAL_CERTIFICATE", app.certificate.Pem) + entries.AddStrings("LOCAL_OVERRIDES_PACKAGES", app.getOverriddenPackages()...) for _, jniLib := range app.installJniLibs { - fmt.Fprintln(w, "LOCAL_SOONG_JNI_LIBS_"+jniLib.target.Arch.ArchType.String(), "+=", jniLib.name) + entries.AddStrings("LOCAL_SOONG_JNI_LIBS_"+jniLib.target.Arch.ArchType.String(), jniLib.name) } if len(app.dexpreopter.builtInstalled) > 0 { - fmt.Fprintln(w, "LOCAL_SOONG_BUILT_INSTALLED :=", app.dexpreopter.builtInstalled) + entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", app.dexpreopter.builtInstalled) } for _, split := range app.aapt.splits { - install := "$(LOCAL_MODULE_PATH)/" + strings.TrimSuffix(app.installApkName, ".apk") + split.suffix + ".apk" - fmt.Fprintln(w, "LOCAL_SOONG_BUILT_INSTALLED +=", split.path.String()+":"+install) + install := app.onDeviceDir + "/" + + strings.TrimSuffix(app.installApkName, ".apk") + "_" + split.suffix + ".apk" + entries.AddStrings("LOCAL_SOONG_BUILT_INSTALLED", split.path.String()+":"+install) } + }, + }, + ExtraFooters: []android.AndroidMkExtraFootersFunc{ + func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) { if app.noticeOutputs.Merged.Valid() { fmt.Fprintf(w, "$(call dist-for-goals,%s,%s:%s)\n", app.installApkName, app.noticeOutputs.Merged.String(), app.installApkName+"_NOTICE") @@ -379,85 +365,116 @@ func (a *AndroidApp) getOverriddenPackages() []string { return overridden } -func (a *AndroidTest) AndroidMk() android.AndroidMkData { - data := a.AndroidApp.AndroidMk() - data.Extra = append(data.Extra, func(w io.Writer, outputFile android.Path) { - testSuiteComponent(w, a.testProperties.Test_suites) +func (a *AndroidTest) AndroidMkEntries() android.AndroidMkEntries { + entries := a.AndroidApp.AndroidMkEntries() + entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) { + testSuiteComponent(entries, a.testProperties.Test_suites) if a.testConfig != nil { - fmt.Fprintln(w, "LOCAL_FULL_TEST_CONFIG :=", a.testConfig.String()) + entries.SetPath("LOCAL_FULL_TEST_CONFIG", a.testConfig) } + androidMkWriteTestData(a.data, entries) }) - androidMkWriteTestData(a.data, &data) - return data + return entries } -func (a *AndroidTestHelperApp) AndroidMk() android.AndroidMkData { - data := a.AndroidApp.AndroidMk() - data.Extra = append(data.Extra, func(w io.Writer, outputFile android.Path) { - testSuiteComponent(w, a.appTestHelperAppProperties.Test_suites) +func (a *AndroidTestHelperApp) AndroidMkEntries() android.AndroidMkEntries { + entries := a.AndroidApp.AndroidMkEntries() + entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) { + testSuiteComponent(entries, a.appTestHelperAppProperties.Test_suites) }) - return data + return entries } -func (a *AndroidLibrary) AndroidMk() android.AndroidMkData { - data := a.Library.AndroidMk() +func (a *AndroidLibrary) AndroidMkEntries() android.AndroidMkEntries { + entries := a.Library.AndroidMkEntries() - data.Extra = append(data.Extra, func(w io.Writer, outputFile android.Path) { + entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) { if a.aarFile != nil { - fmt.Fprintln(w, "LOCAL_SOONG_AAR :=", a.aarFile.String()) + entries.SetPath("LOCAL_SOONG_AAR", a.aarFile) } if a.Name() == "framework-res" { - fmt.Fprintln(w, "LOCAL_MODULE_PATH := $(TARGET_OUT_JAVA_LIBRARIES)") + entries.SetString("LOCAL_MODULE_PATH", "$(TARGET_OUT_JAVA_LIBRARIES)") // Make base_rules.mk not put framework-res in a subdirectory called // framework_res. - fmt.Fprintln(w, "LOCAL_NO_STANDARD_LIBRARIES := true") + entries.SetBoolIfTrue("LOCAL_NO_STANDARD_LIBRARIES", true) } - fmt.Fprintln(w, "LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE :=", a.exportPackage.String()) - fmt.Fprintln(w, "LOCAL_SOONG_STATIC_LIBRARY_EXTRA_PACKAGES :=", a.extraAaptPackagesFile.String()) - fmt.Fprintln(w, "LOCAL_FULL_MANIFEST_FILE :=", a.mergedManifestFile.String()) - fmt.Fprintln(w, "LOCAL_SOONG_EXPORT_PROGUARD_FLAGS :=", - strings.Join(a.exportedProguardFlagFiles.Strings(), " ")) - fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true") + entries.SetPath("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE", a.exportPackage) + entries.SetPath("LOCAL_SOONG_STATIC_LIBRARY_EXTRA_PACKAGES", a.extraAaptPackagesFile) + entries.SetPath("LOCAL_FULL_MANIFEST_FILE", a.mergedManifestFile) + entries.AddStrings("LOCAL_SOONG_EXPORT_PROGUARD_FLAGS", a.exportedProguardFlagFiles.Strings()...) + entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", true) }) - return data + return entries } -func (jd *Javadoc) AndroidMk() android.AndroidMkData { - return android.AndroidMkData{ +func (jd *Javadoc) AndroidMkEntries() android.AndroidMkEntries { + return android.AndroidMkEntries{ Class: "JAVA_LIBRARIES", OutputFile: android.OptionalPathForPath(jd.stubsSrcJar), Include: "$(BUILD_SYSTEM)/soong_droiddoc_prebuilt.mk", - Extra: []android.AndroidMkExtraFunc{ - func(w io.Writer, outputFile android.Path) { + ExtraEntries: []android.AndroidMkExtraEntriesFunc{ + func(entries *android.AndroidMkEntries) { if BoolDefault(jd.properties.Installable, true) { - fmt.Fprintln(w, "LOCAL_DROIDDOC_DOC_ZIP := ", jd.docZip.String()) + entries.SetPath("LOCAL_DROIDDOC_DOC_ZIP", jd.docZip) } if jd.stubsSrcJar != nil { - fmt.Fprintln(w, "LOCAL_DROIDDOC_STUBS_SRCJAR := ", jd.stubsSrcJar.String()) + entries.SetPath("LOCAL_DROIDDOC_STUBS_SRCJAR", jd.stubsSrcJar) } }, }, } } -func (ddoc *Droiddoc) AndroidMk() android.AndroidMkData { - return android.AndroidMkData{ +func (ddoc *Droiddoc) AndroidMkEntries() android.AndroidMkEntries { + return android.AndroidMkEntries{ Class: "JAVA_LIBRARIES", OutputFile: android.OptionalPathForPath(ddoc.stubsSrcJar), Include: "$(BUILD_SYSTEM)/soong_droiddoc_prebuilt.mk", - Extra: []android.AndroidMkExtraFunc{ - func(w io.Writer, outputFile android.Path) { + ExtraEntries: []android.AndroidMkExtraEntriesFunc{ + func(entries *android.AndroidMkEntries) { if BoolDefault(ddoc.Javadoc.properties.Installable, true) && ddoc.Javadoc.docZip != nil { - fmt.Fprintln(w, "LOCAL_DROIDDOC_DOC_ZIP := ", ddoc.Javadoc.docZip.String()) + entries.SetPath("LOCAL_DROIDDOC_DOC_ZIP", ddoc.Javadoc.docZip) } if ddoc.Javadoc.stubsSrcJar != nil { - fmt.Fprintln(w, "LOCAL_DROIDDOC_STUBS_SRCJAR := ", ddoc.Javadoc.stubsSrcJar.String()) + entries.SetPath("LOCAL_DROIDDOC_STUBS_SRCJAR", ddoc.Javadoc.stubsSrcJar) + } + apiFilePrefix := "INTERNAL_PLATFORM_" + if String(ddoc.properties.Api_tag_name) != "" { + apiFilePrefix += String(ddoc.properties.Api_tag_name) + "_" } + if ddoc.apiFile != nil { + entries.SetPath(apiFilePrefix+"API_FILE", ddoc.apiFile) + } + if ddoc.dexApiFile != nil { + entries.SetPath(apiFilePrefix+"DEX_API_FILE", ddoc.dexApiFile) + } + if ddoc.privateApiFile != nil { + entries.SetPath(apiFilePrefix+"PRIVATE_API_FILE", ddoc.privateApiFile) + } + if ddoc.privateDexApiFile != nil { + entries.SetPath(apiFilePrefix+"PRIVATE_DEX_API_FILE", ddoc.privateDexApiFile) + } + if ddoc.removedApiFile != nil { + entries.SetPath(apiFilePrefix+"REMOVED_API_FILE", ddoc.removedApiFile) + } + if ddoc.removedDexApiFile != nil { + entries.SetPath(apiFilePrefix+"REMOVED_DEX_API_FILE", ddoc.removedDexApiFile) + } + if ddoc.exactApiFile != nil { + entries.SetPath(apiFilePrefix+"EXACT_API_FILE", ddoc.exactApiFile) + } + if ddoc.proguardFile != nil { + entries.SetPath(apiFilePrefix+"PROGUARD_FILE", ddoc.proguardFile) + } + }, + }, + ExtraFooters: []android.AndroidMkExtraFootersFunc{ + func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) { if ddoc.checkCurrentApiTimestamp != nil { fmt.Fprintln(w, ".PHONY:", ddoc.Name()+"-check-current-api") fmt.Fprintln(w, ddoc.Name()+"-check-current-api:", @@ -493,58 +510,59 @@ func (ddoc *Droiddoc) AndroidMk() android.AndroidMkData { fmt.Fprintln(w, "droidcore: checkapi") } } - apiFilePrefix := "INTERNAL_PLATFORM_" - if String(ddoc.properties.Api_tag_name) != "" { - apiFilePrefix += String(ddoc.properties.Api_tag_name) + "_" - } - if ddoc.apiFile != nil { - fmt.Fprintln(w, apiFilePrefix+"API_FILE := ", ddoc.apiFile.String()) - } - if ddoc.dexApiFile != nil { - fmt.Fprintln(w, apiFilePrefix+"DEX_API_FILE := ", ddoc.dexApiFile.String()) - } - if ddoc.privateApiFile != nil { - fmt.Fprintln(w, apiFilePrefix+"PRIVATE_API_FILE := ", ddoc.privateApiFile.String()) - } - if ddoc.privateDexApiFile != nil { - fmt.Fprintln(w, apiFilePrefix+"PRIVATE_DEX_API_FILE := ", ddoc.privateDexApiFile.String()) - } - if ddoc.removedApiFile != nil { - fmt.Fprintln(w, apiFilePrefix+"REMOVED_API_FILE := ", ddoc.removedApiFile.String()) - } - if ddoc.removedDexApiFile != nil { - fmt.Fprintln(w, apiFilePrefix+"REMOVED_DEX_API_FILE := ", ddoc.removedDexApiFile.String()) - } - if ddoc.exactApiFile != nil { - fmt.Fprintln(w, apiFilePrefix+"EXACT_API_FILE := ", ddoc.exactApiFile.String()) - } - if ddoc.proguardFile != nil { - fmt.Fprintln(w, apiFilePrefix+"PROGUARD_FILE := ", ddoc.proguardFile.String()) - } }, }, } } -func (dstubs *Droidstubs) AndroidMk() android.AndroidMkData { - return android.AndroidMkData{ +func (dstubs *Droidstubs) AndroidMkEntries() android.AndroidMkEntries { + return android.AndroidMkEntries{ Class: "JAVA_LIBRARIES", OutputFile: android.OptionalPathForPath(dstubs.stubsSrcJar), Include: "$(BUILD_SYSTEM)/soong_droiddoc_prebuilt.mk", - Extra: []android.AndroidMkExtraFunc{ - func(w io.Writer, outputFile android.Path) { + ExtraEntries: []android.AndroidMkExtraEntriesFunc{ + func(entries *android.AndroidMkEntries) { if dstubs.Javadoc.stubsSrcJar != nil { - fmt.Fprintln(w, "LOCAL_DROIDDOC_STUBS_SRCJAR := ", dstubs.Javadoc.stubsSrcJar.String()) + entries.SetPath("LOCAL_DROIDDOC_STUBS_SRCJAR", dstubs.Javadoc.stubsSrcJar) } if dstubs.apiVersionsXml != nil { - fmt.Fprintln(w, "LOCAL_DROIDDOC_API_VERSIONS_XML := ", dstubs.apiVersionsXml.String()) + entries.SetPath("LOCAL_DROIDDOC_API_VERSIONS_XML", dstubs.apiVersionsXml) } if dstubs.annotationsZip != nil { - fmt.Fprintln(w, "LOCAL_DROIDDOC_ANNOTATIONS_ZIP := ", dstubs.annotationsZip.String()) + entries.SetPath("LOCAL_DROIDDOC_ANNOTATIONS_ZIP", dstubs.annotationsZip) } if dstubs.jdiffDocZip != nil { - fmt.Fprintln(w, "LOCAL_DROIDDOC_JDIFF_DOC_ZIP := ", dstubs.jdiffDocZip.String()) + entries.SetPath("LOCAL_DROIDDOC_JDIFF_DOC_ZIP", dstubs.jdiffDocZip) } + apiFilePrefix := "INTERNAL_PLATFORM_" + if String(dstubs.properties.Api_tag_name) != "" { + apiFilePrefix += String(dstubs.properties.Api_tag_name) + "_" + } + if dstubs.apiFile != nil { + entries.SetPath(apiFilePrefix+"API_FILE", dstubs.apiFile) + } + if dstubs.dexApiFile != nil { + entries.SetPath(apiFilePrefix+"DEX_API_FILE", dstubs.dexApiFile) + } + if dstubs.privateApiFile != nil { + entries.SetPath(apiFilePrefix+"PRIVATE_API_FILE", dstubs.privateApiFile) + } + if dstubs.privateDexApiFile != nil { + entries.SetPath(apiFilePrefix+"PRIVATE_DEX_API_FILE", dstubs.privateDexApiFile) + } + if dstubs.removedApiFile != nil { + entries.SetPath(apiFilePrefix+"REMOVED_API_FILE", dstubs.removedApiFile) + } + if dstubs.removedDexApiFile != nil { + entries.SetPath(apiFilePrefix+"REMOVED_DEX_API_FILE", dstubs.removedDexApiFile) + } + if dstubs.exactApiFile != nil { + entries.SetPath(apiFilePrefix+"EXACT_API_FILE", dstubs.exactApiFile) + } + }, + }, + ExtraFooters: []android.AndroidMkExtraFootersFunc{ + func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) { if dstubs.checkCurrentApiTimestamp != nil { fmt.Fprintln(w, ".PHONY:", dstubs.Name()+"-check-current-api") fmt.Fprintln(w, dstubs.Name()+"-check-current-api:", @@ -588,31 +606,6 @@ func (dstubs *Droidstubs) AndroidMk() android.AndroidMkData { fmt.Fprintln(w, ".PHONY:", "droidcore") fmt.Fprintln(w, "droidcore: ", dstubs.Name()+"-check-nullability-warnings") } - apiFilePrefix := "INTERNAL_PLATFORM_" - if String(dstubs.properties.Api_tag_name) != "" { - apiFilePrefix += String(dstubs.properties.Api_tag_name) + "_" - } - if dstubs.apiFile != nil { - fmt.Fprintln(w, apiFilePrefix+"API_FILE := ", dstubs.apiFile.String()) - } - if dstubs.dexApiFile != nil { - fmt.Fprintln(w, apiFilePrefix+"DEX_API_FILE := ", dstubs.dexApiFile.String()) - } - if dstubs.privateApiFile != nil { - fmt.Fprintln(w, apiFilePrefix+"PRIVATE_API_FILE := ", dstubs.privateApiFile.String()) - } - if dstubs.privateDexApiFile != nil { - fmt.Fprintln(w, apiFilePrefix+"PRIVATE_DEX_API_FILE := ", dstubs.privateDexApiFile.String()) - } - if dstubs.removedApiFile != nil { - fmt.Fprintln(w, apiFilePrefix+"REMOVED_API_FILE := ", dstubs.removedApiFile.String()) - } - if dstubs.removedDexApiFile != nil { - fmt.Fprintln(w, apiFilePrefix+"REMOVED_DEX_API_FILE := ", dstubs.removedDexApiFile.String()) - } - if dstubs.exactApiFile != nil { - fmt.Fprintln(w, apiFilePrefix+"EXACT_API_FILE := ", dstubs.exactApiFile.String()) - } }, }, } @@ -627,7 +620,7 @@ func (a *AndroidAppImport) AndroidMkEntries() android.AndroidMkEntries { func(entries *android.AndroidMkEntries) { entries.SetBoolIfTrue("LOCAL_PRIVILEGED_MODULE", Bool(a.properties.Privileged)) if a.certificate != nil { - entries.SetString("LOCAL_CERTIFICATE", a.certificate.Pem.String()) + entries.SetPath("LOCAL_CERTIFICATE", a.certificate.Pem) } else { entries.SetString("LOCAL_CERTIFICATE", "PRESIGNED") } @@ -644,25 +637,13 @@ func (a *AndroidAppImport) AndroidMkEntries() android.AndroidMkEntries { func (a *AndroidTestImport) AndroidMkEntries() android.AndroidMkEntries { entries := a.AndroidAppImport.AndroidMkEntries() entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) { - testSuiteComponentEntries(entries, a.testProperties.Test_suites) - androidMkEntriesWriteTestData(a.data, entries) + testSuiteComponent(entries, a.testProperties.Test_suites) + androidMkWriteTestData(a.data, entries) }) return entries } -func androidMkWriteTestData(data android.Paths, ret *android.AndroidMkData) { - var testFiles []string - for _, d := range data { - testFiles = append(testFiles, d.String()+":"+d.Rel()) - } - if len(testFiles) > 0 { - ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) { - fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUPPORT_FILES := "+strings.Join(testFiles, " ")) - }) - } -} - -func androidMkEntriesWriteTestData(data android.Paths, entries *android.AndroidMkEntries) { +func androidMkWriteTestData(data android.Paths, entries *android.AndroidMkEntries) { var testFiles []string for _, d := range data { testFiles = append(testFiles, d.String()+":"+d.Rel()) diff --git a/java/androidmk_test.go b/java/androidmk_test.go index fbf2baa97..438b66a8a 100644 --- a/java/androidmk_test.go +++ b/java/androidmk_test.go @@ -15,107 +15,12 @@ package java import ( - "bytes" - "io" - "io/ioutil" - "strings" + "reflect" "testing" "android/soong/android" ) -type testAndroidMk struct { - *testing.T - body []byte -} - -type testAndroidMkModule struct { - *testing.T - props map[string]string -} - -func newTestAndroidMk(t *testing.T, r io.Reader) *testAndroidMk { - t.Helper() - buf, err := ioutil.ReadAll(r) - if err != nil { - t.Fatal("failed to open read Android.mk.", err) - } - return &testAndroidMk{ - T: t, - body: buf, - } -} - -func parseAndroidMkProps(lines []string) map[string]string { - props := make(map[string]string) - for _, line := range lines { - line = strings.TrimLeft(line, " ") - if line == "" || strings.HasPrefix(line, "#") { - continue - } - tokens := strings.Split(line, " ") - if tokens[1] == "+=" { - props[tokens[0]] += " " + strings.Join(tokens[2:], " ") - } else { - props[tokens[0]] = strings.Join(tokens[2:], " ") - } - } - return props -} - -func (t *testAndroidMk) moduleFor(moduleName string) *testAndroidMkModule { - t.Helper() - lines := strings.Split(string(t.body), "\n") - index := android.IndexList("LOCAL_MODULE := "+moduleName, lines) - if index == -1 { - t.Fatalf("%q is not found.", moduleName) - } - lines = lines[index:] - includeIndex := android.IndexListPred(func(line string) bool { - return strings.HasPrefix(line, "include") - }, lines) - if includeIndex == -1 { - t.Fatalf("%q is not properly defined. (\"include\" not found).", moduleName) - } - props := parseAndroidMkProps(lines[:includeIndex]) - return &testAndroidMkModule{ - T: t.T, - props: props, - } -} - -func (t *testAndroidMkModule) hasRequired(dep string) { - t.Helper() - required, ok := t.props["LOCAL_REQUIRED_MODULES"] - if !ok { - t.Error("LOCAL_REQUIRED_MODULES is not found.") - return - } - if !android.InList(dep, strings.Split(required, " ")) { - t.Errorf("%q is expected in LOCAL_REQUIRED_MODULES, but not found in %q.", dep, required) - } -} - -func (t *testAndroidMkModule) hasNoRequired(dep string) { - t.Helper() - required, ok := t.props["LOCAL_REQUIRED_MODULES"] - if !ok { - return - } - if android.InList(dep, strings.Split(required, " ")) { - t.Errorf("%q is not expected in LOCAL_REQUIRED_MODULES, but found.", dep) - } -} - -func getAndroidMk(t *testing.T, ctx *android.TestContext, config android.Config, name string) *testAndroidMk { - t.Helper() - lib, _ := ctx.ModuleForTests(name, "android_common").Module().(*Library) - data := android.AndroidMkDataForTest(t, config, "", lib) - w := &bytes.Buffer{} - data.Custom(w, name, "", "", data) - return newTestAndroidMk(t, w) -} - func TestRequired(t *testing.T) { ctx, config := testJava(t, ` java_library { @@ -125,8 +30,14 @@ func TestRequired(t *testing.T) { } `) - mk := getAndroidMk(t, ctx, config, "foo") - mk.moduleFor("foo").hasRequired("libfoo") + mod := ctx.ModuleForTests("foo", "android_common").Module() + entries := android.AndroidMkEntriesForTest(t, config, "", mod) + + expected := []string{"libfoo"} + actual := entries.EntryMap["LOCAL_REQUIRED_MODULES"] + if !reflect.DeepEqual(expected, actual) { + t.Errorf("Unexpected required modules - expected: %q, actual: %q", expected, actual) + } } func TestHostdex(t *testing.T) { @@ -138,9 +49,19 @@ func TestHostdex(t *testing.T) { } `) - mk := getAndroidMk(t, ctx, config, "foo") - mk.moduleFor("foo") - mk.moduleFor("foo-hostdex") + mod := ctx.ModuleForTests("foo", "android_common").Module() + entries := android.AndroidMkEntriesForTest(t, config, "", mod) + + expected := []string{"foo"} + actual := entries.EntryMap["LOCAL_MODULE"] + if !reflect.DeepEqual(expected, actual) { + t.Errorf("Unexpected module name - expected: %q, actual: %q", expected, actual) + } + + footerLines := entries.FooterLinesForTests() + if !android.InList("LOCAL_MODULE := foo-hostdex", footerLines) { + t.Errorf("foo-hostdex is not found in the footers: %q", footerLines) + } } func TestHostdexRequired(t *testing.T) { @@ -153,9 +74,19 @@ func TestHostdexRequired(t *testing.T) { } `) - mk := getAndroidMk(t, ctx, config, "foo") - mk.moduleFor("foo").hasRequired("libfoo") - mk.moduleFor("foo-hostdex").hasRequired("libfoo") + mod := ctx.ModuleForTests("foo", "android_common").Module() + entries := android.AndroidMkEntriesForTest(t, config, "", mod) + + expected := []string{"libfoo"} + actual := entries.EntryMap["LOCAL_REQUIRED_MODULES"] + if !reflect.DeepEqual(expected, actual) { + t.Errorf("Unexpected required modules - expected: %q, actual: %q", expected, actual) + } + + footerLines := entries.FooterLinesForTests() + if !android.InList("LOCAL_REQUIRED_MODULES := libfoo", footerLines) { + t.Errorf("Wrong or missing required line for foo-hostdex in the footers: %q", footerLines) + } } func TestHostdexSpecificRequired(t *testing.T) { @@ -172,7 +103,15 @@ func TestHostdexSpecificRequired(t *testing.T) { } `) - mk := getAndroidMk(t, ctx, config, "foo") - mk.moduleFor("foo").hasNoRequired("libfoo") - mk.moduleFor("foo-hostdex").hasRequired("libfoo") + mod := ctx.ModuleForTests("foo", "android_common").Module() + entries := android.AndroidMkEntriesForTest(t, config, "", mod) + + if r, ok := entries.EntryMap["LOCAL_REQUIRED_MODULES"]; ok { + t.Errorf("Unexpected required modules: %q", r) + } + + footerLines := entries.FooterLinesForTests() + if !android.InList("LOCAL_REQUIRED_MODULES += libfoo", footerLines) { + t.Errorf("Wrong or missing required line for foo-hostdex in the footers: %q", footerLines) + } } diff --git a/java/app.go b/java/app.go index d00c4c031..e03366174 100644 --- a/java/app.go +++ b/java/app.go @@ -126,6 +126,10 @@ type AndroidApp struct { // the install APK name is normally the same as the module name, but can be overridden with PRODUCT_PACKAGE_NAME_OVERRIDES. installApkName string + installDir android.InstallPath + + onDeviceDir string + additionalAaptFlags []string noticeOutputs android.NoticeOutputs @@ -319,7 +323,6 @@ func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) android.Path { } else { installDir = filepath.Join("app", a.installApkName) } - a.dexpreopter.installPath = android.PathForModuleInstall(ctx, installDir, a.installApkName+".apk") a.dexpreopter.isInstallable = Bool(a.properties.Installable) a.dexpreopter.uncompressedDex = a.shouldUncompressDex(ctx) @@ -352,7 +355,7 @@ func (a *AndroidApp) jniBuildActions(jniLibs []jniLib, ctx android.ModuleContext return jniJarFile } -func (a *AndroidApp) noticeBuildActions(ctx android.ModuleContext, installDir android.OutputPath) { +func (a *AndroidApp) noticeBuildActions(ctx android.ModuleContext) { // Collect NOTICE files from all dependencies. seenModules := make(map[android.Module]bool) noticePathSet := make(map[android.Path]bool) @@ -392,7 +395,7 @@ func (a *AndroidApp) noticeBuildActions(ctx android.ModuleContext, installDir an return noticePaths[i].String() < noticePaths[j].String() }) - a.noticeOutputs = android.BuildNoticeOutput(ctx, installDir, a.installApkName+".apk", noticePaths) + a.noticeOutputs = android.BuildNoticeOutput(ctx, a.installDir, a.installApkName+".apk", noticePaths) } // Reads and prepends a main cert from the default cert dir if it hasn't been set already, i.e. it @@ -438,17 +441,19 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { // Check if the install APK name needs to be overridden. a.installApkName = ctx.DeviceConfig().OverridePackageNameFor(a.Name()) - var installDir android.OutputPath if ctx.ModuleName() == "framework-res" { // framework-res.apk is installed as system/framework/framework-res.apk - installDir = android.PathForModuleInstall(ctx, "framework") + a.installDir = android.PathForModuleInstall(ctx, "framework") } else if Bool(a.appProperties.Privileged) { - installDir = android.PathForModuleInstall(ctx, "priv-app", a.installApkName) + a.installDir = android.PathForModuleInstall(ctx, "priv-app", a.installApkName) + } else if ctx.InstallInTestcases() { + a.installDir = android.PathForModuleInstall(ctx, a.installApkName) } else { - installDir = android.PathForModuleInstall(ctx, "app", a.installApkName) + a.installDir = android.PathForModuleInstall(ctx, "app", a.installApkName) } + a.onDeviceDir = android.InstallPathToOnDevicePath(ctx, a.installDir) - a.noticeBuildActions(ctx, installDir) + a.noticeBuildActions(ctx) if Bool(a.appProperties.Embed_notices) || ctx.Config().IsEnvTrue("ALWAYS_EMBED_NOTICES") { a.aapt.noticeFile = a.noticeOutputs.HtmlGzOutput } @@ -494,9 +499,9 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { a.bundleFile = bundleFile // Install the app package. - ctx.InstallFile(installDir, a.installApkName+".apk", a.outputFile) + ctx.InstallFile(a.installDir, a.installApkName+".apk", a.outputFile) for _, split := range a.aapt.splits { - ctx.InstallFile(installDir, a.installApkName+"_"+split.suffix+".apk", split.path) + ctx.InstallFile(a.installDir, a.installApkName+"_"+split.suffix+".apk", split.path) } } @@ -598,6 +603,10 @@ type AndroidTest struct { data android.Paths } +func (a *AndroidTest) InstallInTestcases() bool { + return true +} + func (a *AndroidTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { // Check if the instrumentation target package is overridden before generating build actions. if a.appTestProperties.Instrumentation_for != nil { @@ -608,7 +617,8 @@ func (a *AndroidTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { } a.generateAndroidBuildActions(ctx) - a.testConfig = tradefed.AutoGenInstrumentationTestConfig(ctx, a.testProperties.Test_config, a.testProperties.Test_config_template, a.manifestPath, a.testProperties.Test_suites) + a.testConfig = tradefed.AutoGenInstrumentationTestConfig(ctx, a.testProperties.Test_config, + a.testProperties.Test_config_template, a.manifestPath, a.testProperties.Test_suites, a.testProperties.Auto_gen_config) a.data = android.PathsForModuleSrc(ctx, a.testProperties.Data) } @@ -656,6 +666,11 @@ type appTestHelperAppProperties struct { // list of compatibility suites (for example "cts", "vts") that the module should be // installed into. Test_suites []string `android:"arch_variant"` + + // Flag to indicate whether or not to create test config automatically. If AndroidTest.xml + // doesn't exist next to the Android.bp, this attribute doesn't need to be set to true + // explicitly. + Auto_gen_config *bool } type AndroidTestHelperApp struct { @@ -758,7 +773,7 @@ type AndroidAppImport struct { usesLibrary usesLibrary - installPath android.OutputPath + installPath android.InstallPath } type AndroidAppImportProperties struct { diff --git a/java/builder.go b/java/builder.go index 9e068fa64..0a5c79bfa 100644 --- a/java/builder.go +++ b/java/builder.go @@ -64,6 +64,7 @@ var ( _ = pctx.VariableFunc("kytheCorpus", func(ctx android.PackageVarContext) string { return ctx.Config().XrefCorpusName() }) + _ = pctx.SourcePathVariable("kytheVnames", "build/soong/vnames.json") // Run it with -add-opens=java.base/java.nio=ALL-UNNAMED to avoid JDK9's warning about // "Illegal reflective access by com.google.protobuf.Utf8$UnsafeProcessor ... // to field java.nio.Buffer.address" @@ -74,6 +75,7 @@ var ( `( [ ! -s $srcJarDir/list -a ! -s $out.rsp ] || ` + `KYTHE_ROOT_DIRECTORY=. KYTHE_OUTPUT_FILE=$out ` + `KYTHE_CORPUS=${kytheCorpus} ` + + `KYTHE_VNAMES=${kytheVnames} ` + `${config.SoongJavacWrapper} ${config.JavaCmd} ` + `--add-opens=java.base/java.nio=ALL-UNNAMED ` + `-jar ${config.JavaKytheExtractorJar} ` + @@ -84,6 +86,7 @@ var ( CommandDeps: []string{ "${config.JavaCmd}", "${config.JavaKytheExtractorJar}", + "${kytheVnames}", "${config.ZipSyncCmd}", }, CommandOrderOnly: []string{"${config.SoongJavacWrapper}"}, diff --git a/java/dexpreopt.go b/java/dexpreopt.go index 8bc9b19ad..b48871e43 100644 --- a/java/dexpreopt.go +++ b/java/dexpreopt.go @@ -22,7 +22,7 @@ import ( type dexpreopter struct { dexpreoptProperties DexpreoptProperties - installPath android.OutputPath + installPath android.InstallPath uncompressedDex bool isSDKLibrary bool isTest bool @@ -94,7 +94,7 @@ func (d *dexpreopter) dexpreoptDisabled(ctx android.ModuleContext) bool { return false } -func odexOnSystemOther(ctx android.ModuleContext, installPath android.OutputPath) bool { +func odexOnSystemOther(ctx android.ModuleContext, installPath android.InstallPath) bool { return dexpreopt.OdexOnSystemOtherByName(ctx.ModuleName(), android.InstallPathToOnDevicePath(ctx, installPath), dexpreoptGlobalConfig(ctx)) } diff --git a/java/droiddoc.go b/java/droiddoc.go index 5deac5ea9..aab61c5a7 100644 --- a/java/droiddoc.go +++ b/java/droiddoc.go @@ -57,6 +57,10 @@ type JavadocProperties struct { // filegroup or genrule can be included within this property. Exclude_srcs []string `android:"path,arch_variant"` + // list of package names that should actually be used. If this property is left unspecified, + // all the sources from the srcs property is used. + Filter_packages []string + // list of java libraries that will be in the classpath. Libs []string `android:"arch_variant"` @@ -457,14 +461,14 @@ func (j *Javadoc) genSources(ctx android.ModuleContext, srcFiles android.Paths, flags droiddocBuilderFlags) android.Paths { outSrcFiles := make(android.Paths, 0, len(srcFiles)) + var aidlSrcs android.Paths aidlIncludeFlags := genAidlIncludeFlags(srcFiles) for _, srcFile := range srcFiles { switch srcFile.Ext() { case ".aidl": - javaFile := genAidl(ctx, srcFile, flags.aidlFlags+aidlIncludeFlags, flags.aidlDeps) - outSrcFiles = append(outSrcFiles, javaFile) + aidlSrcs = append(aidlSrcs, srcFile) case ".logtags": javaFile := genLogtags(ctx, srcFile) outSrcFiles = append(outSrcFiles, javaFile) @@ -473,6 +477,12 @@ func (j *Javadoc) genSources(ctx android.ModuleContext, srcFiles android.Paths, } } + // Process all aidl files together to support sharding them into one or more rules that produce srcjars. + if len(aidlSrcs) > 0 { + srcJarFiles := genAidl(ctx, aidlSrcs, flags.aidlFlags+aidlIncludeFlags, flags.aidlDeps) + outSrcFiles = append(outSrcFiles, srcJarFiles...) + } + return outSrcFiles } @@ -524,6 +534,34 @@ func (j *Javadoc) collectDeps(ctx android.ModuleContext) deps { // do not pass exclude_srcs directly when expanding srcFiles since exclude_srcs // may contain filegroup or genrule. srcFiles := android.PathsForModuleSrcExcludes(ctx, j.properties.Srcs, j.properties.Exclude_srcs) + + filterByPackage := func(srcs []android.Path, filterPackages []string) []android.Path { + if filterPackages == nil { + return srcs + } + filtered := []android.Path{} + for _, src := range srcs { + if src.Ext() != ".java" { + // Don't filter-out non-Java (=generated sources) by package names. This is not ideal, + // but otherwise metalava emits stub sources having references to the generated AIDL classes + // in filtered-out pacages (e.g. com.android.internal.*). + // TODO(b/141149570) We need to fix this by introducing default private constructors or + // fixing metalava to not emit constructors having references to unknown classes. + filtered = append(filtered, src) + continue + } + packageName := strings.ReplaceAll(filepath.Dir(src.Rel()), "/", ".") + for _, pkg := range filterPackages { + if strings.HasPrefix(packageName, pkg) { + filtered = append(filtered, src) + break + } + } + } + return filtered + } + srcFiles = filterByPackage(srcFiles, j.properties.Filter_packages) + flags := j.collectAidlFlags(ctx, deps) srcFiles = j.genSources(ctx, srcFiles, flags) diff --git a/java/gen.go b/java/gen.go index a69e9a2b9..d50a6653e 100644 --- a/java/gen.go +++ b/java/gen.go @@ -15,28 +15,22 @@ package java import ( + "strconv" "strings" "github.com/google/blueprint" + "github.com/google/blueprint/pathtools" "android/soong/android" ) func init() { - pctx.HostBinToolVariable("syspropCmd", "sysprop_java") pctx.SourcePathVariable("logtagsCmd", "build/make/tools/java-event-log-tags.py") pctx.SourcePathVariable("mergeLogtagsCmd", "build/make/tools/merge-event-log-tags.py") pctx.SourcePathVariable("logtagsLib", "build/make/tools/event_log_tags.py") } var ( - aidl = pctx.AndroidStaticRule("aidl", - blueprint.RuleParams{ - Command: "${config.AidlCmd} -d$depFile $aidlFlags $in $out", - CommandDeps: []string{"${config.AidlCmd}"}, - }, - "depFile", "aidlFlags") - logtags = pctx.AndroidStaticRule("logtags", blueprint.RuleParams{ Command: "$logtagsCmd -o $out $in", @@ -48,36 +42,66 @@ var ( Command: "$mergeLogtagsCmd -o $out $in", CommandDeps: []string{"$mergeLogtagsCmd", "$logtagsLib"}, }) - - sysprop = pctx.AndroidStaticRule("sysprop", - blueprint.RuleParams{ - Command: `rm -rf $out.tmp && mkdir -p $out.tmp && ` + - `$syspropCmd --scope $scope --java-output-dir $out.tmp $in && ` + - `${config.SoongZipCmd} -jar -o $out -C $out.tmp -D $out.tmp && rm -rf $out.tmp`, - CommandDeps: []string{ - "$syspropCmd", - "${config.SoongZipCmd}", - }, - }, "scope") ) -func genAidl(ctx android.ModuleContext, aidlFile android.Path, aidlFlags string, deps android.Paths) android.Path { - javaFile := android.GenPathWithExt(ctx, "aidl", aidlFile, "java") - depFile := javaFile.String() + ".d" +func genAidl(ctx android.ModuleContext, aidlFiles android.Paths, aidlFlags string, deps android.Paths) android.Paths { + // Shard aidl files into groups of 50 to avoid having to recompile all of them if one changes and to avoid + // hitting command line length limits. + shards := android.ShardPaths(aidlFiles, 50) - ctx.Build(pctx, android.BuildParams{ - Rule: aidl, - Description: "aidl " + aidlFile.Rel(), - Output: javaFile, - Input: aidlFile, - Implicits: deps, - Args: map[string]string{ - "depFile": depFile, - "aidlFlags": aidlFlags, - }, - }) + srcJarFiles := make(android.Paths, 0, len(shards)) - return javaFile + for i, shard := range shards { + srcJarFile := android.PathForModuleGen(ctx, "aidl", "aidl"+strconv.Itoa(i)+".srcjar") + srcJarFiles = append(srcJarFiles, srcJarFile) + + outDir := srcJarFile.ReplaceExtension(ctx, "tmp") + + rule := android.NewRuleBuilder() + + rule.Command().Text("rm -rf").Flag(outDir.String()) + rule.Command().Text("mkdir -p").Flag(outDir.String()) + rule.Command().Text("FLAGS=' " + aidlFlags + "'") + + for _, aidlFile := range shard { + depFile := srcJarFile.InSameDir(ctx, aidlFile.String()+".d") + javaFile := outDir.Join(ctx, pathtools.ReplaceExtension(aidlFile.String(), "java")) + rule.Command(). + Tool(ctx.Config().HostToolPath(ctx, "aidl")). + FlagWithDepFile("-d", depFile). + Flag("$FLAGS"). + Input(aidlFile). + Output(javaFile). + Implicits(deps) + rule.Temporary(javaFile) + } + + rule.Command(). + Tool(ctx.Config().HostToolPath(ctx, "soong_zip")). + // TODO(b/124333557): this can't use -srcjar for now, aidl on parcelables generates java files + // without a package statement, which causes -srcjar to put them in the top level of the zip file. + // Once aidl skips parcelables we can use -srcjar. + //Flag("-srcjar"). + Flag("-write_if_changed"). + FlagWithOutput("-o ", srcJarFile). + FlagWithArg("-C ", outDir.String()). + FlagWithArg("-D ", outDir.String()) + + rule.Command().Text("rm -rf").Flag(outDir.String()) + + rule.Restat() + + ruleName := "aidl" + ruleDesc := "aidl" + if len(shards) > 1 { + ruleName += "_" + strconv.Itoa(i) + ruleDesc += " " + strconv.Itoa(i) + } + + rule.Build(pctx, ctx, ruleName, ruleDesc) + } + + return srcJarFiles } func genLogtags(ctx android.ModuleContext, logtagsFile android.Path) android.Path { @@ -93,22 +117,6 @@ func genLogtags(ctx android.ModuleContext, logtagsFile android.Path) android.Pat return javaFile } -func genSysprop(ctx android.ModuleContext, syspropFile android.Path, scope string) android.Path { - srcJarFile := android.GenPathWithExt(ctx, "sysprop", syspropFile, "srcjar") - - ctx.Build(pctx, android.BuildParams{ - Rule: sysprop, - Description: "sysprop_java " + syspropFile.Rel(), - Output: srcJarFile, - Input: syspropFile, - Args: map[string]string{ - "scope": scope, - }, - }) - - return srcJarFile -} - func genAidlIncludeFlags(srcFiles android.Paths) string { var baseDirs []string for _, srcFile := range srcFiles { @@ -126,49 +134,38 @@ func (j *Module) genSources(ctx android.ModuleContext, srcFiles android.Paths, flags javaBuilderFlags) android.Paths { outSrcFiles := make(android.Paths, 0, len(srcFiles)) + var protoSrcs android.Paths + var aidlSrcs android.Paths aidlIncludeFlags := genAidlIncludeFlags(srcFiles) for _, srcFile := range srcFiles { switch srcFile.Ext() { case ".aidl": - javaFile := genAidl(ctx, srcFile, flags.aidlFlags+aidlIncludeFlags, flags.aidlDeps) - outSrcFiles = append(outSrcFiles, javaFile) + aidlSrcs = append(aidlSrcs, srcFile) case ".logtags": j.logtagsSrcs = append(j.logtagsSrcs, srcFile) javaFile := genLogtags(ctx, srcFile) outSrcFiles = append(outSrcFiles, javaFile) case ".proto": - srcJarFile := genProto(ctx, srcFile, flags.proto) - outSrcFiles = append(outSrcFiles, srcJarFile) - case ".sysprop": - // internal scope contains all properties - // public scope only contains public properties - // use public if the owner is different from client - scope := "internal" - if j.properties.Sysprop.Platform != nil { - isProduct := ctx.ProductSpecific() - isVendor := ctx.SocSpecific() - isOwnerPlatform := Bool(j.properties.Sysprop.Platform) - - if isProduct { - // product can't own any sysprop_library now, so product must use public scope - scope = "public" - } else if isVendor && !isOwnerPlatform { - // vendor and odm can't use system's internal property. - scope = "public" - } - - // We don't care about clients under system. - // They can't use sysprop_library owned by other partitions. - } - srcJarFile := genSysprop(ctx, srcFile, scope) - outSrcFiles = append(outSrcFiles, srcJarFile) + protoSrcs = append(protoSrcs, srcFile) default: outSrcFiles = append(outSrcFiles, srcFile) } } + // Process all proto files together to support sharding them into one or more rules that produce srcjars. + if len(protoSrcs) > 0 { + srcJarFiles := genProto(ctx, protoSrcs, flags.proto) + outSrcFiles = append(outSrcFiles, srcJarFiles...) + } + + // Process all aidl files together to support sharding them into one or more rules that produce srcjars. + if len(aidlSrcs) > 0 { + srcJarFiles := genAidl(ctx, aidlSrcs, flags.aidlFlags+aidlIncludeFlags, flags.aidlDeps) + outSrcFiles = append(outSrcFiles, srcJarFiles...) + } + return outSrcFiles } diff --git a/java/java.go b/java/java.go index b05d7bbd5..4264ba908 100644 --- a/java/java.go +++ b/java/java.go @@ -184,10 +184,6 @@ type CompilerProperties struct { Output_params []string } - Sysprop struct { - Platform *bool - } `blueprint:"mutated"` - Instrument bool `blueprint:"mutated"` // List of files to include in the META-INF/services folder of the resulting jar. @@ -290,6 +286,7 @@ type Module struct { android.ModuleBase android.DefaultableModuleBase android.ApexModuleBase + android.SdkBase properties CompilerProperties protoProperties android.ProtoProperties @@ -398,6 +395,7 @@ type Dependency interface { AidlIncludeDirs() android.Paths ExportedSdkLibs() []string SrcJarArgs() ([]string, android.Paths) + BaseModuleName() string } type SdkLibraryDependency interface { @@ -534,7 +532,9 @@ func (j *Module) deps(ctx android.BottomUpMutatorContext) { ctx.PropertyErrorf("sdk_version", `system_modules is required to be set when sdk_version is "none", did you mean "core_platform"`) } else if *j.deviceProperties.System_modules != "none" { + // Add the system modules to both the system modules and bootclasspath. ctx.AddVariationDependencies(nil, systemModulesTag, *j.deviceProperties.System_modules) + ctx.AddVariationDependencies(nil, bootClasspathTag, *j.deviceProperties.System_modules) } if ctx.ModuleName() == "android_stubs_current" || ctx.ModuleName() == "android_system_stubs_current" || @@ -580,18 +580,6 @@ func hasSrcExt(srcs []string, ext string) bool { return false } -func shardPaths(paths android.Paths, shardSize int) []android.Paths { - ret := make([]android.Paths, 0, (len(paths)+shardSize-1)/shardSize) - for len(paths) > shardSize { - ret = append(ret, paths[0:shardSize]) - paths = paths[shardSize:] - } - if len(paths) > 0 { - ret = append(ret, paths) - } - return ret -} - func (j *Module) hasSrcExt(ext string) bool { return hasSrcExt(j.properties.Srcs, ext) } @@ -847,6 +835,12 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { } default: switch tag { + case bootClasspathTag: + // If a system modules dependency has been added to the bootclasspath + // then add its libs to the bootclasspath. + sm := module.(*SystemModules) + deps.bootClasspath = append(deps.bootClasspath, sm.headerJars...) + case systemModulesTag: if deps.systemModules != nil { panic("Found two system module dependencies") @@ -1150,7 +1144,7 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { shardSize := int(*(j.properties.Javac_shard_size)) var shardSrcs []android.Paths if len(uniqueSrcFiles) > 0 { - shardSrcs = shardPaths(uniqueSrcFiles, shardSize) + shardSrcs = android.ShardPaths(uniqueSrcFiles, shardSize) for idx, shardSrc := range shardSrcs { classes := j.compileJavaClasses(ctx, jarName, idx, shardSrc, nil, flags, extraJarDeps) @@ -1632,6 +1626,7 @@ func LibraryFactory() android.Module { InitJavaModule(module, android.HostAndDeviceSupported) android.InitApexModule(module) + android.InitSdkAwareModule(module) return module } @@ -1678,6 +1673,11 @@ type testProperties struct { // list of files or filegroup modules that provide data that should be installed alongside // the test Data []string `android:"path"` + + // Flag to indicate whether or not to create test config automatically. If AndroidTest.xml + // doesn't exist next to the Android.bp, this attribute doesn't need to be set to true + // explicitly. + Auto_gen_config *bool } type testHelperLibraryProperties struct { @@ -1702,7 +1702,8 @@ type TestHelperLibrary struct { } func (j *Test) GenerateAndroidBuildActions(ctx android.ModuleContext) { - j.testConfig = tradefed.AutoGenJavaTestConfig(ctx, j.testProperties.Test_config, j.testProperties.Test_config_template, j.testProperties.Test_suites) + j.testConfig = tradefed.AutoGenJavaTestConfig(ctx, j.testProperties.Test_config, j.testProperties.Test_config_template, + j.testProperties.Test_suites, j.testProperties.Auto_gen_config) j.data = android.PathsForModuleSrc(ctx, j.testProperties.Data) j.Library.GenerateAndroidBuildActions(ctx) @@ -1794,7 +1795,7 @@ type Binary struct { isWrapperVariant bool wrapperFile android.Path - binaryFile android.OutputPath + binaryFile android.InstallPath } func (j *Binary) HostToolPath() android.OptionalPath { @@ -1912,6 +1913,7 @@ type Import struct { android.DefaultableModuleBase android.ApexModuleBase prebuilt android.Prebuilt + android.SdkBase properties ImportProperties @@ -2068,6 +2070,7 @@ func ImportFactory() android.Module { android.InitPrebuiltModule(module, &module.properties.Jars) InitJavaModule(module, android.HostAndDeviceSupported) android.InitApexModule(module) + android.InitSdkAwareModule(module) return module } diff --git a/java/java_test.go b/java/java_test.go index a9323199d..f0cb6f8bd 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -18,6 +18,7 @@ import ( "io/ioutil" "os" "path/filepath" + "reflect" "strconv" "strings" "testing" @@ -811,19 +812,22 @@ func TestDroiddoc(t *testing.T) { } `) - inputs := ctx.ModuleForTests("bar-doc", "android_common").Rule("javadoc").Inputs + barDoc := ctx.ModuleForTests("bar-doc", "android_common").Rule("javadoc") var javaSrcs []string - for _, i := range inputs { + for _, i := range barDoc.Inputs { javaSrcs = append(javaSrcs, i.Base()) } - if len(javaSrcs) != 3 || javaSrcs[0] != "a.java" || javaSrcs[1] != "IFoo.java" || javaSrcs[2] != "IBar.java" { - t.Errorf("inputs of bar-doc must be []string{\"a.java\", \"IFoo.java\", \"IBar.java\", but was %#v.", javaSrcs) + if len(javaSrcs) != 1 || javaSrcs[0] != "a.java" { + t.Errorf("inputs of bar-doc must be []string{\"a.java\"}, but was %#v.", javaSrcs) } - aidlRule := ctx.ModuleForTests("bar-doc", "android_common").Output(inputs[2].String()) - aidlFlags := aidlRule.Args["aidlFlags"] - if !strings.Contains(aidlFlags, "-Ibar-doc") { - t.Errorf("aidl flags for IBar.aidl should contain \"-Ibar-doc\", but was %q", aidlFlags) + aidl := ctx.ModuleForTests("bar-doc", "android_common").Rule("aidl") + if g, w := barDoc.Implicits.Strings(), aidl.Output.String(); !inList(w, g) { + t.Errorf("implicits of bar-doc must contain %q, but was %q.", w, g) + } + + if g, w := aidl.Implicits.Strings(), []string{"bar-doc/IBar.aidl", "bar-doc/IFoo.aidl"}; !reflect.DeepEqual(w, g) { + t.Errorf("aidl inputs must be %q, but was %q", w, g) } } diff --git a/java/platform_compat_config.go b/java/platform_compat_config.go index 3d46077b5..23ba2b01e 100644 --- a/java/platform_compat_config.go +++ b/java/platform_compat_config.go @@ -30,7 +30,7 @@ type platformCompatConfig struct { android.ModuleBase properties platformCompatConfigProperties - installDirPath android.OutputPath + installDirPath android.InstallPath configFile android.OutputPath } @@ -78,7 +78,7 @@ func (p *platformCompatConfig) AndroidMkEntries() android.AndroidMkEntries { Include: "$(BUILD_PREBUILT)", ExtraEntries: []android.AndroidMkExtraEntriesFunc{ func(entries *android.AndroidMkEntries) { - entries.SetString("LOCAL_MODULE_PATH", "$(OUT_DIR)/"+p.installDirPath.RelPathString()) + entries.SetString("LOCAL_MODULE_PATH", p.installDirPath.ToMakePath().String()) entries.SetString("LOCAL_INSTALLED_MODULE_STEM", p.configFile.Base()) }, }, diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go index c37081130..0d5e31f69 100644 --- a/java/prebuilt_apis.go +++ b/java/prebuilt_apis.go @@ -82,7 +82,7 @@ func createImport(mctx android.TopDownMutatorContext, module string, scope strin props.Sdk_version = proptools.StringPtr("current") props.Installable = proptools.BoolPtr(false) - mctx.CreateModule(android.ModuleFactoryAdaptor(ImportFactory), &props) + mctx.CreateModule(ImportFactory, &props) } func createFilegroup(mctx android.TopDownMutatorContext, module string, scope string, apiver string, path string) { @@ -93,7 +93,7 @@ func createFilegroup(mctx android.TopDownMutatorContext, module string, scope st }{} filegroupProps.Name = proptools.StringPtr(fgName) filegroupProps.Srcs = []string{path} - mctx.CreateModule(android.ModuleFactoryAdaptor(android.FileGroupFactory), &filegroupProps) + mctx.CreateModule(android.FileGroupFactory, &filegroupProps) } func getPrebuiltFiles(mctx android.TopDownMutatorContext, name string) []string { diff --git a/java/proto.go b/java/proto.go index f5c233c69..e013bb4ee 100644 --- a/java/proto.go +++ b/java/proto.go @@ -15,36 +15,61 @@ package java import ( + "path/filepath" + "strconv" + "android/soong/android" ) -func genProto(ctx android.ModuleContext, protoFile android.Path, flags android.ProtoFlags) android.Path { - srcJarFile := android.GenPathWithExt(ctx, "proto", protoFile, "srcjar") +func genProto(ctx android.ModuleContext, protoFiles android.Paths, flags android.ProtoFlags) android.Paths { + // Shard proto files into groups of 100 to avoid having to recompile all of them if one changes and to avoid + // hitting command line length limits. + shards := android.ShardPaths(protoFiles, 100) - outDir := srcJarFile.ReplaceExtension(ctx, "tmp") - depFile := srcJarFile.ReplaceExtension(ctx, "srcjar.d") + srcJarFiles := make(android.Paths, 0, len(shards)) - rule := android.NewRuleBuilder() + for i, shard := range shards { + srcJarFile := android.PathForModuleGen(ctx, "proto", "proto"+strconv.Itoa(i)+".srcjar") + srcJarFiles = append(srcJarFiles, srcJarFile) - rule.Command().Text("rm -rf").Flag(outDir.String()) - rule.Command().Text("mkdir -p").Flag(outDir.String()) + outDir := srcJarFile.ReplaceExtension(ctx, "tmp") - android.ProtoRule(ctx, rule, protoFile, flags, flags.Deps, outDir, depFile, nil) + rule := android.NewRuleBuilder() - // Proto generated java files have an unknown package name in the path, so package the entire output directory - // into a srcjar. - rule.Command(). - BuiltTool(ctx, "soong_zip"). - Flag("-jar"). - FlagWithOutput("-o ", srcJarFile). - FlagWithArg("-C ", outDir.String()). - FlagWithArg("-D ", outDir.String()) + rule.Command().Text("rm -rf").Flag(outDir.String()) + rule.Command().Text("mkdir -p").Flag(outDir.String()) - rule.Command().Text("rm -rf").Flag(outDir.String()) + for _, protoFile := range shard { + depFile := srcJarFile.InSameDir(ctx, protoFile.String()+".d") + rule.Command().Text("mkdir -p").Flag(filepath.Dir(depFile.String())) + android.ProtoRule(ctx, rule, protoFile, flags, flags.Deps, outDir, depFile, nil) + } - rule.Build(pctx, ctx, "protoc_"+protoFile.Rel(), "protoc "+protoFile.Rel()) + // Proto generated java files have an unknown package name in the path, so package the entire output directory + // into a srcjar. + rule.Command(). + BuiltTool(ctx, "soong_zip"). + Flag("-jar"). + Flag("-write_if_changed"). + FlagWithOutput("-o ", srcJarFile). + FlagWithArg("-C ", outDir.String()). + FlagWithArg("-D ", outDir.String()) + + rule.Command().Text("rm -rf").Flag(outDir.String()) + + rule.Restat() + + ruleName := "protoc" + ruleDesc := "protoc" + if len(shards) > 1 { + ruleName += "_" + strconv.Itoa(i) + ruleDesc += " " + strconv.Itoa(i) + } + + rule.Build(pctx, ctx, ruleName, ruleDesc) + } - return srcJarFile + return srcJarFiles } func protoDeps(ctx android.BottomUpMutatorContext, p *android.ProtoProperties) { diff --git a/java/robolectric.go b/java/robolectric.go index cbe3557bc..b7646eb45 100644 --- a/java/robolectric.go +++ b/java/robolectric.go @@ -105,7 +105,7 @@ func (r *robolectricTest) GenerateAndroidBuildActions(ctx android.ModuleContext) r.roboSrcJar = roboSrcJar for _, dep := range ctx.GetDirectDepsWithTag(libTag) { - r.libs = append(r.libs, ctx.OtherModuleName(dep)) + r.libs = append(r.libs, dep.(Dependency).BaseModuleName()) } // TODO: this could all be removed if tradefed was used as the test runner, it will find everything @@ -123,25 +123,6 @@ func (r *robolectricTest) GenerateAndroidBuildActions(ctx android.ModuleContext) } } -func shardTests(paths []string, shards int) [][]string { - if shards > len(paths) { - shards = len(paths) - } - if shards == 0 { - return nil - } - ret := make([][]string, 0, shards) - shardSize := (len(paths) + shards - 1) / shards - for len(paths) > shardSize { - ret = append(ret, paths[0:shardSize]) - paths = paths[shardSize:] - } - if len(paths) > 0 { - ret = append(ret, paths) - } - return ret -} - func generateRoboTestConfig(ctx android.ModuleContext, outputFile android.WritablePath, instrumentedApp *AndroidApp) { manifest := instrumentedApp.mergedManifestFile resourceApk := instrumentedApp.outputFile @@ -177,32 +158,34 @@ func (r *robolectricTest) generateRoboSrcJar(ctx android.ModuleContext, outputFi TransformResourcesToJar(ctx, outputFile, srcJarArgs, srcJarDeps) } -func (r *robolectricTest) AndroidMk() android.AndroidMkData { - data := r.Library.AndroidMk() - - data.Custom = func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) { - android.WriteAndroidMkData(w, data) - - if s := r.robolectricProperties.Test_options.Shards; s != nil && *s > 1 { - shards := shardTests(r.tests, int(*s)) - for i, shard := range shards { - r.writeTestRunner(w, name, "Run"+name+strconv.Itoa(i), shard) +func (r *robolectricTest) AndroidMkEntries() android.AndroidMkEntries { + entries := r.Library.AndroidMkEntries() + + entries.ExtraFooters = []android.AndroidMkExtraFootersFunc{ + func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) { + if s := r.robolectricProperties.Test_options.Shards; s != nil && *s > 1 { + numShards := int(*s) + shardSize := (len(r.tests) + numShards - 1) / numShards + shards := android.ShardStrings(r.tests, shardSize) + for i, shard := range shards { + r.writeTestRunner(w, name, "Run"+name+strconv.Itoa(i), shard) + } + + // TODO: add rules to dist the outputs of the individual tests, or combine them together? + fmt.Fprintln(w, "") + fmt.Fprintln(w, ".PHONY:", "Run"+name) + fmt.Fprintln(w, "Run"+name, ": \\") + for i := range shards { + fmt.Fprintln(w, " ", "Run"+name+strconv.Itoa(i), "\\") + } + fmt.Fprintln(w, "") + } else { + r.writeTestRunner(w, name, "Run"+name, r.tests) } - - // TODO: add rules to dist the outputs of the individual tests, or combine them together? - fmt.Fprintln(w, "") - fmt.Fprintln(w, ".PHONY:", "Run"+name) - fmt.Fprintln(w, "Run"+name, ": \\") - for i := range shards { - fmt.Fprintln(w, " ", "Run"+name+strconv.Itoa(i), "\\") - } - fmt.Fprintln(w, "") - } else { - r.writeTestRunner(w, name, "Run"+name, r.tests) - } + }, } - return data + return entries } func (r *robolectricTest) writeTestRunner(w io.Writer, module, name string, tests []string) { @@ -233,6 +216,7 @@ func RobolectricTestFactory() android.Module { module.AddProperties( &module.Module.properties, + &module.Module.deviceProperties, &module.Module.protoProperties, &module.robolectricProperties) diff --git a/java/robolectric_test.go b/java/robolectric_test.go deleted file mode 100644 index e89c6e74c..000000000 --- a/java/robolectric_test.go +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2019 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 java - -import ( - "reflect" - "testing" -) - -func Test_shardTests(t *testing.T) { - type args struct { - paths []string - shards int - } - tests := []struct { - name string - args args - want [][]string - }{ - { - name: "empty", - args: args{ - paths: nil, - shards: 1, - }, - want: [][]string(nil), - }, - { - name: "too many shards", - args: args{ - paths: []string{"a", "b"}, - shards: 3, - }, - want: [][]string{{"a"}, {"b"}}, - }, - { - name: "single shard", - args: args{ - paths: []string{"a", "b"}, - shards: 1, - }, - want: [][]string{{"a", "b"}}, - }, - { - name: "shard per input", - args: args{ - paths: []string{"a", "b", "c"}, - shards: 3, - }, - want: [][]string{{"a"}, {"b"}, {"c"}}, - }, - { - name: "balanced shards", - args: args{ - paths: []string{"a", "b", "c", "d"}, - shards: 2, - }, - want: [][]string{{"a", "b"}, {"c", "d"}}, - }, - { - name: "unbalanced shards", - args: args{ - paths: []string{"a", "b", "c"}, - shards: 2, - }, - want: [][]string{{"a", "b"}, {"c"}}, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := shardTests(tt.args.paths, tt.args.shards); !reflect.DeepEqual(got, tt.want) { - t.Errorf("shardTests() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/java/sdk_library.go b/java/sdk_library.go index 30fd1c4e2..476e5491b 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -197,65 +197,65 @@ func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) }) } -func (module *SdkLibrary) AndroidMk() android.AndroidMkData { - data := module.Library.AndroidMk() - data.Required = append(data.Required, module.xmlFileName()) - - data.Custom = func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) { - android.WriteAndroidMkData(w, data) - - module.Library.AndroidMkHostDex(w, name, data) - if !Bool(module.sdkLibraryProperties.No_dist) { - // Create a phony module that installs the impl library, for the case when this lib is - // in PRODUCT_PACKAGES. - owner := module.ModuleBase.Owner() - if owner == "" { - if Bool(module.sdkLibraryProperties.Core_lib) { - owner = "core" - } else { - owner = "android" +func (module *SdkLibrary) AndroidMkEntries() android.AndroidMkEntries { + entries := module.Library.AndroidMkEntries() + entries.Required = append(entries.Required, module.xmlFileName()) + + entries.ExtraFooters = []android.AndroidMkExtraFootersFunc{ + func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) { + module.Library.AndroidMkHostDex(w, name, entries) + if !Bool(module.sdkLibraryProperties.No_dist) { + // Create a phony module that installs the impl library, for the case when this lib is + // in PRODUCT_PACKAGES. + owner := module.ModuleBase.Owner() + if owner == "" { + if Bool(module.sdkLibraryProperties.Core_lib) { + owner = "core" + } else { + owner = "android" + } + } + // Create dist rules to install the stubs libs to the dist dir + if len(module.publicApiStubsPath) == 1 { + fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+ + module.publicApiStubsImplPath.Strings()[0]+ + ":"+path.Join("apistubs", owner, "public", + module.BaseModuleName()+".jar")+")") + } + if len(module.systemApiStubsPath) == 1 { + fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+ + module.systemApiStubsImplPath.Strings()[0]+ + ":"+path.Join("apistubs", owner, "system", + module.BaseModuleName()+".jar")+")") + } + if len(module.testApiStubsPath) == 1 { + fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+ + module.testApiStubsImplPath.Strings()[0]+ + ":"+path.Join("apistubs", owner, "test", + module.BaseModuleName()+".jar")+")") + } + if module.publicApiFilePath != nil { + fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+ + module.publicApiFilePath.String()+ + ":"+path.Join("apistubs", owner, "public", "api", + module.BaseModuleName()+".txt")+")") + } + if module.systemApiFilePath != nil { + fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+ + module.systemApiFilePath.String()+ + ":"+path.Join("apistubs", owner, "system", "api", + module.BaseModuleName()+".txt")+")") + } + if module.testApiFilePath != nil { + fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+ + module.testApiFilePath.String()+ + ":"+path.Join("apistubs", owner, "test", "api", + module.BaseModuleName()+".txt")+")") } } - // Create dist rules to install the stubs libs to the dist dir - if len(module.publicApiStubsPath) == 1 { - fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+ - module.publicApiStubsImplPath.Strings()[0]+ - ":"+path.Join("apistubs", owner, "public", - module.BaseModuleName()+".jar")+")") - } - if len(module.systemApiStubsPath) == 1 { - fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+ - module.systemApiStubsImplPath.Strings()[0]+ - ":"+path.Join("apistubs", owner, "system", - module.BaseModuleName()+".jar")+")") - } - if len(module.testApiStubsPath) == 1 { - fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+ - module.testApiStubsImplPath.Strings()[0]+ - ":"+path.Join("apistubs", owner, "test", - module.BaseModuleName()+".jar")+")") - } - if module.publicApiFilePath != nil { - fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+ - module.publicApiFilePath.String()+ - ":"+path.Join("apistubs", owner, "public", "api", - module.BaseModuleName()+".txt")+")") - } - if module.systemApiFilePath != nil { - fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+ - module.systemApiFilePath.String()+ - ":"+path.Join("apistubs", owner, "system", "api", - module.BaseModuleName()+".txt")+")") - } - if module.testApiFilePath != nil { - fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+ - module.testApiFilePath.String()+ - ":"+path.Join("apistubs", owner, "test", "api", - module.BaseModuleName()+".txt")+")") - } - } + }, } - return data + return entries } // Module name of the stubs library @@ -422,7 +422,7 @@ func (module *SdkLibrary) createStubsLibrary(mctx android.LoadHookContext, apiSc props.Product_specific = proptools.BoolPtr(true) } - mctx.CreateModule(android.ModuleFactoryAdaptor(LibraryFactory), &props) + mctx.CreateModule(LibraryFactory, &props) } // Creates a droiddoc module that creates stubs source files from the given full source @@ -522,7 +522,7 @@ func (module *SdkLibrary) createDocs(mctx android.LoadHookContext, apiScope apiS module.latestRemovedApiFilegroupName(apiScope)) props.Check_api.Ignore_missing_latest_api = proptools.BoolPtr(true) - mctx.CreateModule(android.ModuleFactoryAdaptor(DroidstubsFactory), &props) + mctx.CreateModule(DroidstubsFactory, &props) } // Creates the xml file that publicizes the runtime library @@ -560,7 +560,7 @@ func (module *SdkLibrary) createXmlFile(mctx android.LoadHookContext) { genruleProps.Name = proptools.StringPtr(module.xmlFileName() + "-gen") genruleProps.Cmd = proptools.StringPtr("echo '" + xmlContent + "' > $(out)") genruleProps.Out = []string{module.xmlFileName()} - mctx.CreateModule(android.ModuleFactoryAdaptor(genrule.GenRuleFactory), &genruleProps) + mctx.CreateModule(genrule.GenRuleFactory, &genruleProps) // creates a prebuilt_etc module to actually place the xml file under // <partition>/etc/permissions @@ -582,7 +582,7 @@ func (module *SdkLibrary) createXmlFile(mctx android.LoadHookContext) { } else if module.ProductSpecific() { etcProps.Product_specific = proptools.BoolPtr(true) } - mctx.CreateModule(android.ModuleFactoryAdaptor(android.PrebuiltEtcFactory), &etcProps) + mctx.CreateModule(android.PrebuiltEtcFactory, &etcProps) } func (module *SdkLibrary) PrebuiltJars(ctx android.BaseModuleContext, sdkVersion string) android.Paths { @@ -815,7 +815,7 @@ func (module *sdkLibraryImport) createInternalModules(mctx android.LoadHookConte props.Product_specific = proptools.BoolPtr(true) } - mctx.CreateModule(android.ModuleFactoryAdaptor(ImportFactory), &props, &module.properties) + mctx.CreateModule(ImportFactory, &props, &module.properties) javaSdkLibraries := javaSdkLibraries(mctx.Config()) javaSdkLibrariesLock.Lock() diff --git a/java/sdk_test.go b/java/sdk_test.go index 6be17eb88..5001b477b 100644 --- a/java/sdk_test.go +++ b/java/sdk_test.go @@ -124,7 +124,7 @@ func TestClasspath(t *testing.T) { name: "nostdlib system_modules", properties: `sdk_version: "none", system_modules: "core-platform-api-stubs-system-modules"`, system: "core-platform-api-stubs-system-modules", - bootclasspath: []string{`""`}, + bootclasspath: []string{"core-platform-api-stubs-system-modules-lib"}, classpath: []string{}, }, { @@ -250,7 +250,10 @@ func TestClasspath(t *testing.T) { } checkClasspath := func(t *testing.T, ctx *android.TestContext) { - javac := ctx.ModuleForTests("foo", variant).Rule("javac") + foo := ctx.ModuleForTests("foo", variant) + javac := foo.Rule("javac") + + aidl := foo.MaybeRule("aidl") got := javac.Args["bootClasspath"] if got != bc { @@ -263,6 +266,9 @@ func TestClasspath(t *testing.T) { } var deps []string + if aidl.Rule != nil { + deps = append(deps, aidl.Output.String()) + } if len(bootclasspath) > 0 && bootclasspath[0] != `""` { deps = append(deps, bootclasspath...) } @@ -290,12 +296,8 @@ func TestClasspath(t *testing.T) { if testcase.host != android.Host { aidl := ctx.ModuleForTests("foo", variant).Rule("aidl") - aidlFlags := aidl.Args["aidlFlags"] - // Trim trailing "-I." to avoid having to specify it in every test - aidlFlags = strings.TrimSpace(strings.TrimSuffix(aidlFlags, "-I.")) - - if g, w := aidlFlags, testcase.aidl; g != w { - t.Errorf("want aidl flags %q, got %q", w, g) + if g, w := aidl.RuleParams.Command, testcase.aidl+" -I."; !strings.Contains(g, w) { + t.Errorf("want aidl command to contain %q, got %q", w, g) } } }) diff --git a/java/system_modules.go b/java/system_modules.go index c616249d5..43e4e118b 100644 --- a/java/system_modules.go +++ b/java/system_modules.go @@ -101,6 +101,9 @@ type SystemModules struct { properties SystemModulesProperties + // The aggregated header jars from all jars specified in the libs property. + // Used when system module is added as a dependency to bootclasspath. + headerJars android.Paths outputDir android.Path outputDeps android.Paths } @@ -118,6 +121,8 @@ func (system *SystemModules) GenerateAndroidBuildActions(ctx android.ModuleConte jars = append(jars, dep.HeaderJars()...) }) + system.headerJars = jars + system.outputDir, system.outputDeps = TransformJarsToSystemModules(ctx, "java.base", jars) } diff --git a/java/testing.go b/java/testing.go index a37c0a9dc..acbefb92c 100644 --- a/java/testing.go +++ b/java/testing.go @@ -103,7 +103,6 @@ func GatherRequiredDepsForTest() string { ` systemModules := []string{ - "core-system-modules", "core-current-stubs-system-modules", "core-platform-api-stubs-system-modules", "android_stubs_current_system_modules", @@ -114,7 +113,13 @@ func GatherRequiredDepsForTest() string { for _, extra := range systemModules { bp += fmt.Sprintf(` java_system_modules { - name: "%s", + name: "%[1]s", + libs: ["%[1]s-lib"], + } + java_library { + name: "%[1]s-lib", + sdk_version: "none", + system_modules: "none", } `, extra) } diff --git a/makedeps/deps.go b/makedeps/deps.go index e64e6f788..db4953259 100644 --- a/makedeps/deps.go +++ b/makedeps/deps.go @@ -57,10 +57,12 @@ func Parse(filename string, r io.Reader) (*Deps, error) { return nil, fmt.Errorf("%sunsupported variable expansion: %v", pos(node), x.Target.Dump()) } outputs := x.Target.Words() - if len(outputs) == 0 { - return nil, fmt.Errorf("%smissing output: %v", pos(node), x) + if len(outputs) > 0 { + ret.Output = outputs[0].Value(nil) + } else { + // TODO(b/141372861): put this back + //return nil, fmt.Errorf("%smissing output: %v", pos(node), x) } - ret.Output = outputs[0].Value(nil) if !x.Prerequisites.Const() { return nil, fmt.Errorf("%sunsupported variable expansion: %v", pos(node), x.Prerequisites.Dump()) diff --git a/makedeps/deps_test.go b/makedeps/deps_test.go index a32df650e..ac2f6996a 100644 --- a/makedeps/deps_test.go +++ b/makedeps/deps_test.go @@ -147,6 +147,20 @@ b: e`, }, }, }, + { + // TODO(b/141372861): remove this + // AIDL produces a dep file with no output file for a parcelable (b/ + name: "AIDL parcelable", + input: ` : \ + frameworks/base/tests/net/integration/src/com/android/server/net/integrationtests/HttpResponse.aidl +`, + output: Deps{ + Output: "", + Inputs: []string{ + "frameworks/base/tests/net/integration/src/com/android/server/net/integrationtests/HttpResponse.aidl", + }, + }, + }, } for _, tc := range testCases { diff --git a/python/androidmk.go b/python/androidmk.go index 1e51e7b8a..aae7cedc9 100644 --- a/python/androidmk.go +++ b/python/androidmk.go @@ -89,12 +89,11 @@ func (installer *pythonInstaller) AndroidMk(base *Module, ret *android.AndroidMk ret.Required = append(ret.Required, "libc++") ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) { - path := installer.path.RelPathString() - dir, file := filepath.Split(path) + path, file := filepath.Split(installer.path.ToMakePath().String()) stem := strings.TrimSuffix(file, filepath.Ext(file)) fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+filepath.Ext(file)) - fmt.Fprintln(w, "LOCAL_MODULE_PATH := $(OUT_DIR)/"+filepath.Clean(dir)) + fmt.Fprintln(w, "LOCAL_MODULE_PATH := "+path) fmt.Fprintln(w, "LOCAL_MODULE_STEM := "+stem) fmt.Fprintln(w, "LOCAL_SHARED_LIBRARIES := "+strings.Join(installer.androidMkSharedLibs, " ")) }) diff --git a/python/binary.go b/python/binary.go index 140f07af9..695fa123b 100644 --- a/python/binary.go +++ b/python/binary.go @@ -47,6 +47,11 @@ type BinaryProperties struct { // false it will act much like the normal `python` executable, but with the sources and // libraries automatically included in the PYTHONPATH. Autorun *bool `android:"arch_variant"` + + // Flag to indicate whether or not to create test config automatically. If AndroidTest.xml + // doesn't exist next to the Android.bp, this attribute doesn't need to be set to true + // explicitly. + Auto_gen_config *bool } type binaryDecorator struct { diff --git a/python/installer.go b/python/installer.go index ed16e143e..396f03667 100644 --- a/python/installer.go +++ b/python/installer.go @@ -33,7 +33,7 @@ type pythonInstaller struct { dir64 string relative string - path android.OutputPath + path android.InstallPath androidMkSharedLibs []string } @@ -47,7 +47,7 @@ func NewPythonInstaller(dir, dir64 string) *pythonInstaller { var _ installer = (*pythonInstaller)(nil) -func (installer *pythonInstaller) installDir(ctx android.ModuleContext) android.OutputPath { +func (installer *pythonInstaller) installDir(ctx android.ModuleContext) android.InstallPath { dir := installer.dir if ctx.Arch().ArchType.Multilib == "lib64" && installer.dir64 != "" { dir = installer.dir64 diff --git a/python/test.go b/python/test.go index 55b0ab53a..f684fd51d 100644 --- a/python/test.go +++ b/python/test.go @@ -50,7 +50,8 @@ func (test *testDecorator) bootstrapperProps() []interface{} { func (test *testDecorator) install(ctx android.ModuleContext, file android.Path) { test.testConfig = tradefed.AutoGenPythonBinaryHostTestConfig(ctx, test.testProperties.Test_config, - test.testProperties.Test_config_template, test.binaryDecorator.binaryProperties.Test_suites) + test.testProperties.Test_config_template, test.binaryDecorator.binaryProperties.Test_suites, + test.binaryDecorator.binaryProperties.Auto_gen_config) test.binaryDecorator.pythonInstaller.dir = "nativetest" test.binaryDecorator.pythonInstaller.dir64 = "nativetest64" diff --git a/rust/androidmk.go b/rust/androidmk.go index 107959f84..a6208dbcd 100644 --- a/rust/androidmk.go +++ b/rust/androidmk.go @@ -116,11 +116,10 @@ func (compiler *baseCompiler) AndroidMk(ctx AndroidMkContext, ret *android.Andro ret.OutputFile = android.OptionalPathForPath(compiler.path) } ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) { - path := compiler.path.RelPathString() - dir, file := filepath.Split(path) + path, file := filepath.Split(compiler.path.ToMakePath().String()) stem, suffix, _ := android.SplitFileExt(file) fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+suffix) - fmt.Fprintln(w, "LOCAL_MODULE_PATH := $(OUT_DIR)/"+filepath.Clean(dir)) + fmt.Fprintln(w, "LOCAL_MODULE_PATH := "+path) fmt.Fprintln(w, "LOCAL_MODULE_STEM := "+stem) }) } diff --git a/rust/binary.go b/rust/binary.go index 279c6f50f..52f840e7a 100644 --- a/rust/binary.go +++ b/rust/binary.go @@ -71,6 +71,15 @@ func (binary *binaryDecorator) preferDynamic() bool { func (binary *binaryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags { flags = binary.baseCompiler.compilerFlags(ctx, flags) + + if ctx.toolchain().Bionic() { + // no-undefined-version breaks dylib compilation since __rust_*alloc* functions aren't defined, but we can apply this to binaries. + flags.LinkFlags = append(flags.LinkFlags, + "-Wl,--gc-sections", + "-Wl,-z,nocopyreloc", + "-Wl,--no-undefined-version") + } + if binary.preferDynamic() { flags.RustFlags = append(flags.RustFlags, "-C prefer-dynamic") } @@ -86,6 +95,12 @@ func (binary *binaryDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps { } } + if ctx.toolchain().Bionic() { + deps = binary.baseCompiler.bionicDeps(ctx, deps) + deps.CrtBegin = "crtbegin_dynamic" + deps.CrtEnd = "crtend_android" + } + return deps } diff --git a/rust/builder.go b/rust/builder.go index 64e387b9f..104313f8a 100644 --- a/rust/builder.go +++ b/rust/builder.go @@ -28,14 +28,13 @@ var ( blueprint.RuleParams{ Command: "$rustcCmd " + "-C linker=${config.RustLinker} " + - "-C link-args=\"${config.RustLinkerArgs} ${linkFlags}\" " + - "-o $out $in ${libFlags} $rustcFlags " + - "&& $rustcCmd --emit=dep-info -o $out.d $in ${libFlags} $rustcFlags", + "-C link-args=\"${crtBegin} ${config.RustLinkerArgs} ${linkFlags} ${crtEnd}\" " + + "--emit link -o $out --emit dep-info=$out.d $in ${libFlags} $rustcFlags", CommandDeps: []string{"$rustcCmd"}, Depfile: "$out.d", Deps: blueprint.DepsGCC, // Rustc deps-info writes out make compatible dep files: https://github.com/rust-lang/rust/issues/7633 }, - "rustcFlags", "linkFlags", "libFlags") + "rustcFlags", "linkFlags", "libFlags", "crtBegin", "crtEnd") ) func init() { @@ -43,28 +42,19 @@ func init() { } func TransformSrcToBinary(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags, outputFile android.WritablePath, includeDirs []string) { - targetTriple := ctx.(ModuleContext).toolchain().RustTriple() - - transformSrctoCrate(ctx, mainSrc, deps.RLibs, deps.DyLibs, deps.ProcMacros, deps.StaticLibs, deps.SharedLibs, flags, outputFile, "bin", includeDirs, targetTriple) + transformSrctoCrate(ctx, mainSrc, deps.RLibs, deps.DyLibs, deps.ProcMacros, deps.StaticLibs, deps.SharedLibs, deps.CrtBegin, deps.CrtEnd, flags, outputFile, "bin", includeDirs) } func TransformSrctoRlib(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags, outputFile android.WritablePath, includeDirs []string) { - targetTriple := ctx.(ModuleContext).toolchain().RustTriple() - - transformSrctoCrate(ctx, mainSrc, deps.RLibs, deps.DyLibs, deps.ProcMacros, deps.StaticLibs, deps.SharedLibs, flags, outputFile, "rlib", includeDirs, targetTriple) + transformSrctoCrate(ctx, mainSrc, deps.RLibs, deps.DyLibs, deps.ProcMacros, deps.StaticLibs, deps.SharedLibs, deps.CrtBegin, deps.CrtEnd, flags, outputFile, "rlib", includeDirs) } func TransformSrctoDylib(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags, outputFile android.WritablePath, includeDirs []string) { - targetTriple := ctx.(ModuleContext).toolchain().RustTriple() - - transformSrctoCrate(ctx, mainSrc, deps.RLibs, deps.DyLibs, deps.ProcMacros, deps.StaticLibs, deps.SharedLibs, flags, outputFile, "dylib", includeDirs, targetTriple) + transformSrctoCrate(ctx, mainSrc, deps.RLibs, deps.DyLibs, deps.ProcMacros, deps.StaticLibs, deps.SharedLibs, deps.CrtBegin, deps.CrtEnd, flags, outputFile, "dylib", includeDirs) } func TransformSrctoProcMacro(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags, outputFile android.WritablePath, includeDirs []string) { - // Proc macros are compiler plugins, and thus should target the host compiler - targetTriple := "" - - transformSrctoCrate(ctx, mainSrc, deps.RLibs, deps.DyLibs, deps.ProcMacros, deps.StaticLibs, deps.SharedLibs, flags, outputFile, "proc-macro", includeDirs, targetTriple) + transformSrctoCrate(ctx, mainSrc, deps.RLibs, deps.DyLibs, deps.ProcMacros, deps.StaticLibs, deps.SharedLibs, deps.CrtBegin, deps.CrtEnd, flags, outputFile, "proc-macro", includeDirs) } func rustLibsToPaths(libs RustLibraries) android.Paths { @@ -76,23 +66,28 @@ func rustLibsToPaths(libs RustLibraries) android.Paths { } func transformSrctoCrate(ctx android.ModuleContext, main android.Path, - rlibs, dylibs, proc_macros RustLibraries, static_libs, shared_libs android.Paths, flags Flags, outputFile android.WritablePath, crate_type string, includeDirs []string, targetTriple string) { + rlibs, dylibs, proc_macros RustLibraries, static_libs, shared_libs android.Paths, crtBegin, crtEnd android.OptionalPath, flags Flags, outputFile android.WritablePath, crate_type string, includeDirs []string) { var inputs android.Paths var deps android.Paths - var libFlags, rustcFlags []string + var libFlags, rustcFlags, linkFlags []string crate_name := ctx.(ModuleContext).CrateName() + targetTriple := ctx.(ModuleContext).toolchain().RustTriple() inputs = append(inputs, main) // Collect rustc flags - rustcFlags = append(rustcFlags, flags.GlobalFlags...) + rustcFlags = append(rustcFlags, flags.GlobalRustFlags...) rustcFlags = append(rustcFlags, flags.RustFlags...) rustcFlags = append(rustcFlags, "--crate-type="+crate_type) rustcFlags = append(rustcFlags, "--crate-name="+crate_name) if targetTriple != "" { rustcFlags = append(rustcFlags, "--target="+targetTriple) + linkFlags = append(linkFlags, "-target "+targetTriple) } + // Collect linker flags + linkFlags = append(linkFlags, flags.GlobalLinkFlags...) + linkFlags = append(linkFlags, flags.LinkFlags...) // Collect library/crate flags for _, lib := range rlibs { @@ -115,6 +110,9 @@ func transformSrctoCrate(ctx android.ModuleContext, main android.Path, deps = append(deps, rustLibsToPaths(proc_macros)...) deps = append(deps, static_libs...) deps = append(deps, shared_libs...) + if crtBegin.Valid() { + deps = append(deps, crtBegin.Path(), crtEnd.Path()) + } ctx.Build(pctx, android.BuildParams{ Rule: rustc, @@ -124,8 +122,10 @@ func transformSrctoCrate(ctx android.ModuleContext, main android.Path, Implicits: deps, Args: map[string]string{ "rustcFlags": strings.Join(rustcFlags, " "), - "linkFlags": strings.Join(flags.LinkFlags, " "), + "linkFlags": strings.Join(linkFlags, " "), "libFlags": strings.Join(libFlags, " "), + "crtBegin": crtBegin.String(), + "crtEnd": crtEnd.String(), }, }) diff --git a/rust/compiler.go b/rust/compiler.go index 4e0118325..3f028350a 100644 --- a/rust/compiler.go +++ b/rust/compiler.go @@ -20,19 +20,29 @@ import ( "android/soong/android" "android/soong/rust/config" + "github.com/google/blueprint/proptools" ) +func getEdition(compiler *baseCompiler) string { + return proptools.StringDefault(compiler.Properties.Edition, config.DefaultEdition) +} + +func getDenyWarnings(compiler *baseCompiler) bool { + return BoolDefault(compiler.Properties.Deny_warnings, config.DefaultDenyWarnings) +} + func NewBaseCompiler(dir, dir64 string) *baseCompiler { return &baseCompiler{ - Properties: BaseCompilerProperties{ - Edition: &config.DefaultEdition, - }, - dir: dir, - dir64: dir64, + Properties: BaseCompilerProperties{}, + dir: dir, + dir64: dir64, } } type BaseCompilerProperties struct { + // whether to pass "-D warnings" to rustc. Defaults to true. + Deny_warnings *bool + // flags to pass to rustc Flags []string `android:"path,arch_variant"` @@ -90,7 +100,7 @@ type baseCompiler struct { dir64 string subDir string relative string - path android.OutputPath + path android.InstallPath } var _ compiler = (*baseCompiler)(nil) @@ -109,11 +119,16 @@ func (compiler *baseCompiler) featuresToFlags(features []string) []string { func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags) Flags { + if getDenyWarnings(compiler) { + flags.RustFlags = append(flags.RustFlags, "-D warnings") + } flags.RustFlags = append(flags.RustFlags, compiler.Properties.Flags...) flags.RustFlags = append(flags.RustFlags, compiler.featuresToFlags(compiler.Properties.Features)...) - flags.RustFlags = append(flags.RustFlags, "--edition="+*compiler.Properties.Edition) + flags.RustFlags = append(flags.RustFlags, "--edition="+getEdition(compiler)) flags.LinkFlags = append(flags.LinkFlags, compiler.Properties.Ld_flags...) - flags.GlobalFlags = append(flags.GlobalFlags, ctx.toolchain().ToolchainRustFlags()) + flags.GlobalRustFlags = append(flags.GlobalRustFlags, config.GlobalRustFlags...) + flags.GlobalRustFlags = append(flags.GlobalRustFlags, ctx.toolchain().ToolchainRustFlags()) + flags.GlobalLinkFlags = append(flags.GlobalLinkFlags, ctx.toolchain().ToolchainLinkFlags()) if ctx.Host() && !ctx.Windows() { rpath_prefix := `\$$ORIGIN/` @@ -148,11 +163,23 @@ func (compiler *baseCompiler) compilerDeps(ctx DepsContext, deps Deps) Deps { return deps } +func (compiler *baseCompiler) bionicDeps(ctx DepsContext, deps Deps) Deps { + deps.SharedLibs = append(deps.SharedLibs, "liblog") + deps.SharedLibs = append(deps.SharedLibs, "libc") + deps.SharedLibs = append(deps.SharedLibs, "libm") + deps.SharedLibs = append(deps.SharedLibs, "libdl") + + //TODO(b/141331117) libstd requires libgcc on Android + deps.StaticLibs = append(deps.StaticLibs, "libgcc") + + return deps +} + func (compiler *baseCompiler) crateName() string { return compiler.Properties.Crate_name } -func (compiler *baseCompiler) installDir(ctx ModuleContext) android.OutputPath { +func (compiler *baseCompiler) installDir(ctx ModuleContext) android.InstallPath { dir := compiler.dir if ctx.toolchain().Is64Bit() && compiler.dir64 != "" { dir = compiler.dir64 diff --git a/rust/compiler_test.go b/rust/compiler_test.go index 536909641..bbf9f8d11 100644 --- a/rust/compiler_test.go +++ b/rust/compiler_test.go @@ -64,7 +64,6 @@ func TestEnforceSingleSourceFile(t *testing.T) { rust_proc_macro { name: "foo-bar-proc-macro", srcs: ["foo.rs", "src/bar.rs"], - host_supported: true, }`) // Test prebuilts diff --git a/rust/config/arm64_device.go b/rust/config/arm64_device.go new file mode 100644 index 000000000..0264052db --- /dev/null +++ b/rust/config/arm64_device.go @@ -0,0 +1,92 @@ +// Copyright 2019 The Android Open Source Project +// +// 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 config + +import ( + "strings" + + "android/soong/android" +) + +var ( + Arm64RustFlags = []string{} + Arm64ArchFeatureRustFlags = map[string][]string{} + Arm64LinkFlags = []string{ + "-Wl,--icf=safe", + "-Wl,-z,max-page-size=4096", + + "-Wl,-execute-only", + } + + Arm64ArchVariantRustFlags = map[string][]string{ + "armv8-a": []string{}, + "armv8-2a": []string{}, + } +) + +func init() { + registerToolchainFactory(android.Android, android.Arm64, Arm64ToolchainFactory) + + pctx.StaticVariable("Arm64ToolchainRustFlags", strings.Join(Arm64RustFlags, " ")) + pctx.StaticVariable("Arm64ToolchainLinkFlags", strings.Join(Arm64LinkFlags, " ")) + + for variant, rustFlags := range Arm64ArchVariantRustFlags { + pctx.StaticVariable("Arm64"+variant+"VariantRustFlags", + strings.Join(rustFlags, " ")) + } + +} + +type toolchainArm64 struct { + toolchain64Bit + toolchainRustFlags string +} + +func (t *toolchainArm64) RustTriple() string { + return "aarch64-linux-android" +} + +func (t *toolchainArm64) ToolchainLinkFlags() string { + return "${config.DeviceGlobalLinkFlags} ${config.Arm64ToolchainLinkFlags}" +} + +func (t *toolchainArm64) ToolchainRustFlags() string { + return t.toolchainRustFlags +} + +func (t *toolchainArm64) RustFlags() string { + return "${config.Arm64ToolchainRustFlags}" +} + +func (t *toolchainArm64) Supported() bool { + return true +} + +func Arm64ToolchainFactory(arch android.Arch) Toolchain { + toolchainRustFlags := []string{ + "${config.Arm64ToolchainRustFlags}", + "${config.Arm64" + arch.ArchVariant + "VariantRustFlags}", + } + + toolchainRustFlags = append(toolchainRustFlags, deviceGlobalRustFlags...) + + for _, feature := range arch.ArchFeatures { + toolchainRustFlags = append(toolchainRustFlags, Arm64ArchFeatureRustFlags[feature]...) + } + + return &toolchainArm64{ + toolchainRustFlags: strings.Join(toolchainRustFlags, " "), + } +} diff --git a/rust/config/arm_device.go b/rust/config/arm_device.go new file mode 100644 index 000000000..aedb42b31 --- /dev/null +++ b/rust/config/arm_device.go @@ -0,0 +1,92 @@ +// Copyright 2019 The Android Open Source Project +// +// 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 config + +import ( + "strings" + + "android/soong/android" +) + +var ( + ArmRustFlags = []string{} + ArmArchFeatureRustFlags = map[string][]string{} + ArmLinkFlags = []string{ + "-Wl,--icf=safe", + "-Wl,-m,armelf", + } + + ArmArchVariantRustFlags = map[string][]string{ + "armv7-a": []string{}, + "armv7-a-neon": []string{}, + "armv8-a": []string{}, + "armv8-2a": []string{}, + } +) + +func init() { + registerToolchainFactory(android.Android, android.Arm, ArmToolchainFactory) + + pctx.StaticVariable("ArmToolchainRustFlags", strings.Join(ArmRustFlags, " ")) + pctx.StaticVariable("ArmToolchainLinkFlags", strings.Join(ArmLinkFlags, " ")) + + for variant, rustFlags := range ArmArchVariantRustFlags { + pctx.StaticVariable("Arm"+variant+"VariantRustFlags", + strings.Join(rustFlags, " ")) + } + +} + +type toolchainArm struct { + toolchain64Bit + toolchainRustFlags string +} + +func (t *toolchainArm) RustTriple() string { + return "arm-linux-androideabi" +} + +func (t *toolchainArm) ToolchainLinkFlags() string { + return "${config.DeviceGlobalLinkFlags} ${config.ArmToolchainLinkFlags}" +} + +func (t *toolchainArm) ToolchainRustFlags() string { + return t.toolchainRustFlags +} + +func (t *toolchainArm) RustFlags() string { + return "${config.ArmToolchainRustFlags}" +} + +func (t *toolchainArm) Supported() bool { + return true +} + +func ArmToolchainFactory(arch android.Arch) Toolchain { + toolchainRustFlags := []string{ + "${config.ArmToolchainRustFlags}", + "${config.Arm" + arch.ArchVariant + "VariantRustFlags}", + } + + toolchainRustFlags = append(toolchainRustFlags, deviceGlobalRustFlags...) + + for _, feature := range arch.ArchFeatures { + toolchainRustFlags = append(toolchainRustFlags, ArmArchFeatureRustFlags[feature]...) + } + + return &toolchainArm{ + toolchainRustFlags: strings.Join(toolchainRustFlags, " "), + } +} diff --git a/rust/config/global.go b/rust/config/global.go index 7f9f9930c..7846d212e 100644 --- a/rust/config/global.go +++ b/rust/config/global.go @@ -15,6 +15,8 @@ package config import ( + "strings" + "android/soong/android" _ "android/soong/cc/config" ) @@ -26,15 +28,33 @@ var ( RustDefaultBase = "prebuilts/rust/" DefaultEdition = "2018" Stdlibs = []string{ - "libarena", - "libfmt_macros", - "libgraphviz", - "libserialize", "libstd", - "libsyntax", - "libsyntax_ext", - "libsyntax_pos", "libterm", + "libtest", + } + + DefaultDenyWarnings = true + + GlobalRustFlags = []string{ + "--remap-path-prefix $$(pwd)=", + } + + deviceGlobalRustFlags = []string{} + + deviceGlobalLinkFlags = []string{ + "-Bdynamic", + "-nostdlib", + "-Wl,-z,noexecstack", + "-Wl,-z,relro", + "-Wl,-z,now", + "-Wl,--build-id=md5", + "-Wl,--warn-shared-textrel", + "-Wl,--fatal-warnings", + + "-Wl,--pack-dyn-relocs=android+relr", + "-Wl,--use-android-relr-tags", + "-Wl,--no-undefined", + "-Wl,--hash-style=gnu", } ) @@ -62,4 +82,7 @@ func init() { pctx.ImportAs("ccConfig", "android/soong/cc/config") pctx.StaticVariable("RustLinker", "${ccConfig.ClangBin}/clang++") pctx.StaticVariable("RustLinkerArgs", "-B ${ccConfig.ClangBin} -fuse-ld=lld") + + pctx.StaticVariable("DeviceGlobalLinkFlags", strings.Join(deviceGlobalLinkFlags, " ")) + } diff --git a/rust/config/toolchain.go b/rust/config/toolchain.go index a36d61bfd..328bca3b9 100644 --- a/rust/config/toolchain.go +++ b/rust/config/toolchain.go @@ -32,6 +32,8 @@ type Toolchain interface { Is64Bit() bool Supported() bool + + Bionic() bool } type toolchainBase struct { @@ -53,6 +55,10 @@ func (toolchainBase) Is64Bit() bool { panic("toolchainBase cannot determine datapath width.") } +func (toolchainBase) Bionic() bool { + return true +} + type toolchain64Bit struct { toolchainBase } diff --git a/rust/config/whitelist.go b/rust/config/whitelist.go new file mode 100644 index 000000000..464626424 --- /dev/null +++ b/rust/config/whitelist.go @@ -0,0 +1,21 @@ +package config + +var ( + RustAllowedPaths = []string{ + "external/rust/crates", + "external/crosvm", + "external/adhd", + } + + RustModuleTypes = []string{ + "rust_binary", + "rust_binary_host", + "rust_library", + "rust_library_dylib", + "rust_library_rlib", + "rust_library_host", + "rust_library_host_dylib", + "rust_library_host_rlib", + "rust_proc_macro", + } +) diff --git a/rust/config/x86_linux_host.go b/rust/config/x86_linux_host.go index cb6bf1a22..5376e5ba5 100644 --- a/rust/config/x86_linux_host.go +++ b/rust/config/x86_linux_host.go @@ -61,6 +61,10 @@ func (toolchainLinuxX8664) Supported() bool { return true } +func (toolchainLinuxX8664) Bionic() bool { + return false +} + func (t *toolchainLinuxX8664) Name() string { return "x86_64" } @@ -85,6 +89,10 @@ func (toolchainLinuxX86) Supported() bool { return true } +func (toolchainLinuxX86) Bionic() bool { + return false +} + func (t *toolchainLinuxX86) Name() string { return "x86" } diff --git a/rust/library.go b/rust/library.go index 5cf8ac700..c831727c5 100644 --- a/rust/library.go +++ b/rust/library.go @@ -191,6 +191,16 @@ func (library *libraryDecorator) compilerProps() []interface{} { &library.MutatedProperties) } +func (library *libraryDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps { + deps = library.baseCompiler.compilerDeps(ctx, deps) + + if ctx.toolchain().Bionic() && library.dylib() { + deps = library.baseCompiler.bionicDeps(ctx, deps) + } + + return deps +} + func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path { var outputFile android.WritablePath diff --git a/rust/prebuilt.go b/rust/prebuilt.go index d4e631ba6..fa69fbb86 100644 --- a/rust/prebuilt.go +++ b/rust/prebuilt.go @@ -63,3 +63,8 @@ func (prebuilt *prebuiltLibraryDecorator) compile(ctx ModuleContext, flags Flags return srcPath } + +func (prebuilt *prebuiltLibraryDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps { + deps = prebuilt.baseCompiler.compilerDeps(ctx, deps) + return deps +} diff --git a/rust/proc_macro.go b/rust/proc_macro.go index 4acb06fcd..1a247d9b3 100644 --- a/rust/proc_macro.go +++ b/rust/proc_macro.go @@ -45,7 +45,7 @@ type procMacroInterface interface { var _ compiler = (*procMacroDecorator)(nil) func ProcMacroFactory() android.Module { - module, _ := NewProcMacro(android.HostAndDeviceSupported) + module, _ := NewProcMacro(android.HostSupportedNoCross) return module.Init() } diff --git a/rust/rust.go b/rust/rust.go index 7cc0b2c3b..61b51e547 100644 --- a/rust/rust.go +++ b/rust/rust.go @@ -29,28 +29,11 @@ var pctx = android.NewPackageContext("android/soong/rust") func init() { // Only allow rust modules to be defined for certain projects - rustModuleTypes := []string{ - "rust_binary", - "rust_binary_host", - "rust_library", - "rust_library_dylib", - "rust_library_rlib", - "rust_library_host", - "rust_library_host_dylib", - "rust_library_host_rlib", - "rust_proc_macro", - } - - rustAllowedPaths := []string{ - "external/rust/crates", - "external/crosvm", - "external/adhd", - } android.AddNeverAllowRules( android.NeverAllow(). - NotIn(rustAllowedPaths...). - ModuleType(rustModuleTypes...)) + NotIn(config.RustAllowedPaths...). + ModuleType(config.RustModuleTypes...)) android.RegisterModuleType("rust_defaults", defaultsFactory) android.PreDepsMutators(func(ctx android.RegisterMutatorsContext) { @@ -60,11 +43,12 @@ func init() { } type Flags struct { - GlobalFlags []string // Flags that apply globally - RustFlags []string // Flags that apply to rust - LinkFlags []string // Flags that apply to linker - RustFlagsDeps android.Paths // Files depended on by compiler flags - Toolchain config.Toolchain + GlobalRustFlags []string // Flags that apply globally to rust + GlobalLinkFlags []string // Flags that apply globally to linker + RustFlags []string // Flags that apply to rust + LinkFlags []string // Flags that apply to linker + RustFlagsDeps android.Paths // Files depended on by compiler flags + Toolchain config.Toolchain } type BaseProperties struct { @@ -109,6 +93,9 @@ type PathDeps struct { linkDirs []string depFlags []string //ReexportedDeps android.Paths + + CrtBegin android.OptionalPath + CrtEnd android.OptionalPath } type RustLibraries []RustLibrary @@ -338,15 +325,6 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { if rustDep, ok := dep.(*Module); ok { //Handle Rust Modules - if rustDep.Target().Os != ctx.Os() { - ctx.ModuleErrorf("OS mismatch between %q and %q", ctx.ModuleName(), depName) - return - } - if rustDep.Target().Arch.ArchType != ctx.Arch().ArchType { - ctx.ModuleErrorf("Arch mismatch between %q and %q", ctx.ModuleName(), depName) - return - } - linkFile := rustDep.outputFile if !linkFile.Valid() { ctx.ModuleErrorf("Invalid output file when adding dep %q to %q", depName, ctx.ModuleName()) @@ -378,9 +356,6 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { if lib, ok := rustDep.compiler.(*libraryDecorator); ok { depPaths.linkDirs = append(depPaths.linkDirs, lib.exportedDirs()...) depPaths.depFlags = append(depPaths.depFlags, lib.exportedDepFlags()...) - } else if procMacro, ok := rustDep.compiler.(*libraryDecorator); ok { - depPaths.linkDirs = append(depPaths.linkDirs, procMacro.exportedDirs()...) - depPaths.depFlags = append(depPaths.depFlags, procMacro.exportedDepFlags()...) } // Append this dependencies output to this mod's linkDirs so they can be exported to dependencies @@ -427,6 +402,10 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { directSharedLibDeps = append(directSharedLibDeps, ccDep) mod.Properties.AndroidMkSharedLibs = append(mod.Properties.AndroidMkSharedLibs, depName) exportDep = true + case cc.CrtBeginDepTag(): + depPaths.CrtBegin = linkFile + case cc.CrtEndDepTag(): + depPaths.CrtEnd = linkFile } // Make sure these dependencies are propagated @@ -508,7 +487,16 @@ func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) { } actx.AddVariationDependencies(append(ccDepVariations, blueprint.Variation{Mutator: "link", Variation: "shared"}), cc.SharedDepTag(), deps.SharedLibs...) actx.AddVariationDependencies(append(ccDepVariations, blueprint.Variation{Mutator: "link", Variation: "static"}), cc.StaticDepTag(), deps.StaticLibs...) - actx.AddDependency(mod, procMacroDepTag, deps.ProcMacros...) + + if deps.CrtBegin != "" { + actx.AddVariationDependencies(ccDepVariations, cc.CrtBeginDepTag(), deps.CrtBegin) + } + if deps.CrtEnd != "" { + actx.AddVariationDependencies(ccDepVariations, cc.CrtEndDepTag(), deps.CrtEnd) + } + + // proc_macros are compiler plugins, and so we need the host arch variant as a dependendcy. + actx.AddFarVariationDependencies([]blueprint.Variation{{Mutator: "arch", Variation: ctx.Config().BuildOsVariant}}, procMacroDepTag, deps.ProcMacros...) } func (mod *Module) Name() string { diff --git a/rust/rust_test.go b/rust/rust_test.go index f7c96dd6a..0c8d35586 100644 --- a/rust/rust_test.go +++ b/rust/rust_test.go @@ -18,6 +18,7 @@ import ( "io/ioutil" "os" "runtime" + "strings" "testing" "android/soong/android" @@ -150,7 +151,6 @@ func TestDepsTracking(t *testing.T) { rust_proc_macro { name: "libpm", srcs: ["foo.rs"], - host_supported: true, } rust_binary_host { name: "fizz-buzz", @@ -176,3 +176,28 @@ func TestDepsTracking(t *testing.T) { } } + +// Test to make sure proc_macros use host variants when building device modules. +func TestProcMacroDeviceDeps(t *testing.T) { + ctx := testRust(t, ` + rust_library_host_rlib { + name: "libbar", + srcs: ["foo.rs"], + } + rust_proc_macro { + name: "libpm", + rlibs: ["libbar"], + srcs: ["foo.rs"], + } + rust_binary { + name: "fizz-buzz", + proc_macros: ["libpm"], + srcs: ["foo.rs"], + } + `) + rustc := ctx.ModuleForTests("libpm", "linux_glibc_x86_64").Rule("rustc") + + if !strings.Contains(rustc.Args["libFlags"], "libbar/linux_glibc_x86_64") { + t.Errorf("Proc_macro is not using host variant of dependent modules.") + } +} diff --git a/rust/testing.go b/rust/testing.go index a38697f88..92347f1f3 100644 --- a/rust/testing.go +++ b/rust/testing.go @@ -16,6 +16,7 @@ package rust import ( "android/soong/android" + "android/soong/cc" ) func GatherRequiredDepsForTest() string { @@ -70,12 +71,101 @@ func GatherRequiredDepsForTest() string { srcs: [""], host_supported: true, } + + ////////////////////////////// + // Device module requirements + + toolchain_library { + name: "libgcc", + no_libcrt: true, + nocrt: true, + src: "", + system_shared_libs: [], + } + cc_library { + name: "libc", + no_libcrt: true, + nocrt: true, + system_shared_libs: [], + } + cc_library { + name: "libm", + no_libcrt: true, + nocrt: true, + system_shared_libs: [], + } + cc_library { + name: "libdl", + no_libcrt: true, + nocrt: true, + system_shared_libs: [], + } + cc_object { + name: "crtbegin_dynamic", + } + + cc_object { + name: "crtend_android", + } + cc_library { + name: "liblog", + no_libcrt: true, + nocrt: true, + system_shared_libs: [], + } + + ////////////////////////////// + // cc module requirements + + toolchain_library { + name: "libatomic", + src: "", + } + toolchain_library { + name: "libclang_rt.builtins-aarch64-android", + src: "", + } + toolchain_library { + name: "libgcc_stripped", + src: "", + } + cc_library { + name: "libc++_static", + no_libcrt: true, + nocrt: true, + system_shared_libs: [], + stl: "none", + } + cc_library { + name: "libc++demangle", + no_libcrt: true, + nocrt: true, + system_shared_libs: [], + stl: "none", + host_supported: false, + } + cc_library { + name: "libc++", + no_libcrt: true, + nocrt: true, + system_shared_libs: [], + stl: "none", + } + cc_library { + name: "libunwind_llvm", + no_libcrt: true, + nocrt: true, + system_shared_libs: [], + stl: "none", + } ` return bp } func CreateTestContext(bp string) *android.TestContext { ctx := android.NewTestArchContext() + ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(cc.LibraryFactory)) + ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(cc.ObjectFactory)) ctx.RegisterModuleType("rust_binary", android.ModuleFactoryAdaptor(RustBinaryFactory)) ctx.RegisterModuleType("rust_binary_host", android.ModuleFactoryAdaptor(RustBinaryHostFactory)) ctx.RegisterModuleType("rust_library", android.ModuleFactoryAdaptor(RustLibraryFactory)) @@ -86,9 +176,16 @@ func CreateTestContext(bp string) *android.TestContext { ctx.RegisterModuleType("rust_library_dylib", android.ModuleFactoryAdaptor(RustLibraryDylibFactory)) ctx.RegisterModuleType("rust_proc_macro", android.ModuleFactoryAdaptor(ProcMacroFactory)) ctx.RegisterModuleType("rust_prebuilt_dylib", android.ModuleFactoryAdaptor(PrebuiltDylibFactory)) + ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(cc.ToolchainLibraryFactory)) ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) { ctx.BottomUp("rust_libraries", LibraryMutator).Parallel() + + ctx.BottomUp("image", cc.ImageMutator).Parallel() + ctx.BottomUp("link", cc.LinkageMutator).Parallel() + ctx.BottomUp("version", cc.VersionMutator).Parallel() + ctx.BottomUp("begin", cc.BeginMutator).Parallel() }) + bp = bp + GatherRequiredDepsForTest() mockFS := map[string][]byte{ diff --git a/sdk/sdk.go b/sdk/sdk.go new file mode 100644 index 000000000..fcb3fb7fe --- /dev/null +++ b/sdk/sdk.go @@ -0,0 +1,172 @@ +// Copyright (C) 2019 The Android Open Source Project +// +// 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 sdk + +import ( + "github.com/google/blueprint" + + "android/soong/android" + // This package doesn't depend on the apex package, but import it to make its mutators to be + // registered before mutators in this package. See RegisterPostDepsMutators for more details. + _ "android/soong/apex" +) + +func init() { + android.RegisterModuleType("sdk", ModuleFactory) + android.PreDepsMutators(RegisterPreDepsMutators) + android.PostDepsMutators(RegisterPostDepsMutators) +} + +type sdk struct { + android.ModuleBase + android.DefaultableModuleBase + + properties sdkProperties +} + +type sdkProperties struct { + // The list of java_import modules that provide Java stubs for this SDK + Java_libs []string + Native_shared_libs []string +} + +// sdk defines an SDK which is a logical group of modules (e.g. native libs, headers, java libs, etc.) +// which Mainline modules like APEX can choose to build with. +func ModuleFactory() android.Module { + s := &sdk{} + s.AddProperties(&s.properties) + android.InitAndroidMultiTargetsArchModule(s, android.HostAndDeviceSupported, android.MultilibCommon) + android.InitDefaultableModule(s) + return s +} + +func (s *sdk) GenerateAndroidBuildActions(ctx android.ModuleContext) { + // TODO(jiyong): add build rules for creating stubs from members of this SDK +} + +// RegisterPreDepsMutators registers pre-deps mutators to support modules implementing SdkAware +// interface and the sdk module type. This function has been made public to be called by tests +// outside of the sdk package +func RegisterPreDepsMutators(ctx android.RegisterMutatorsContext) { + ctx.BottomUp("SdkMember", memberMutator).Parallel() + ctx.TopDown("SdkMember_deps", memberDepsMutator).Parallel() + ctx.BottomUp("SdkMemberInterVersion", memberInterVersionMutator).Parallel() +} + +// RegisterPostDepshMutators registers post-deps mutators to support modules implementing SdkAware +// interface and the sdk module type. This function has been made public to be called by tests +// outside of the sdk package +func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) { + // These must run AFTER apexMutator. Note that the apex package is imported even though there is + // no direct dependency to the package here. sdkDepsMutator sets the SDK requirements from an + // APEX to its dependents. Since different versions of the same SDK can be used by different + // APEXes, the apex and its dependents (which includes the dependencies to the sdk members) + // should have been mutated for the apex before the SDK requirements are set. + ctx.TopDown("SdkDepsMutator", sdkDepsMutator).Parallel() + ctx.BottomUp("SdkDepsReplaceMutator", sdkDepsReplaceMutator).Parallel() +} + +type dependencyTag struct { + blueprint.BaseDependencyTag +} + +// For dependencies from an SDK module to its members +// e.g. mysdk -> libfoo and libbar +var sdkMemberDepTag dependencyTag + +// For dependencies from an in-development version of an SDK member to frozen versions of the same member +// e.g. libfoo -> libfoo.mysdk.11 and libfoo.mysdk.12 +type sdkMemberVesionedDepTag struct { + dependencyTag + member string + version string +} + +// Step 1: create dependencies from an SDK module to its members. +func memberMutator(mctx android.BottomUpMutatorContext) { + if m, ok := mctx.Module().(*sdk); ok { + mctx.AddVariationDependencies(nil, sdkMemberDepTag, m.properties.Java_libs...) + + targets := mctx.MultiTargets() + for _, target := range targets { + mctx.AddFarVariationDependencies([]blueprint.Variation{ + {Mutator: "arch", Variation: target.String()}, + {Mutator: "image", Variation: "core"}, + {Mutator: "link", Variation: "shared"}, + }, sdkMemberDepTag, m.properties.Native_shared_libs...) + } + } +} + +// Step 2: record that dependencies of SDK modules are members of the SDK modules +func memberDepsMutator(mctx android.TopDownMutatorContext) { + if _, ok := mctx.Module().(*sdk); ok { + mySdkRef := android.ParseSdkRef(mctx, mctx.ModuleName(), "name") + mctx.VisitDirectDeps(func(child android.Module) { + if member, ok := child.(android.SdkAware); ok { + member.MakeMemberOf(mySdkRef) + } + }) + } +} + +// Step 3: create dependencies from the in-development version of an SDK member to frozen versions +// of the same member. By having these dependencies, they are mutated for multiple Mainline modules +// (apex and apk), each of which might want different sdks to be built with. For example, if both +// apex A and B are referencing libfoo which is a member of sdk 'mysdk', the two APEXes can be +// built with libfoo.mysdk.11 and libfoo.mysdk.12, respectively depending on which sdk they are +// using. +func memberInterVersionMutator(mctx android.BottomUpMutatorContext) { + if m, ok := mctx.Module().(android.SdkAware); ok && m.IsInAnySdk() { + if !m.ContainingSdk().IsCurrentVersion() { + memberName := m.MemberName() + tag := sdkMemberVesionedDepTag{member: memberName, version: m.ContainingSdk().Version} + mctx.AddReverseDependency(mctx.Module(), tag, memberName) + } + } +} + +// Step 4: transitively ripple down the SDK requirements from the root modules like APEX to its +// descendants +func sdkDepsMutator(mctx android.TopDownMutatorContext) { + if m, ok := mctx.Module().(android.SdkAware); ok { + // Module types for Mainline modules (e.g. APEX) are expected to implement RequiredSdks() + // by reading its own properties like `uses_sdks`. + requiredSdks := m.RequiredSdks() + if len(requiredSdks) > 0 { + mctx.VisitDirectDeps(func(m android.Module) { + if dep, ok := m.(android.SdkAware); ok { + dep.BuildWithSdks(requiredSdks) + } + }) + } + } +} + +// Step 5: if libfoo.mysdk.11 is in the context where version 11 of mysdk is requested, the +// versioned module is used instead of the un-versioned (in-development) module libfoo +func sdkDepsReplaceMutator(mctx android.BottomUpMutatorContext) { + if m, ok := mctx.Module().(android.SdkAware); ok && m.IsInAnySdk() { + if sdk := m.ContainingSdk(); !sdk.IsCurrentVersion() { + if m.RequiredSdks().Contains(sdk) { + // Note that this replacement is done only for the modules that have the same + // variations as the current module. Since current module is already mutated for + // apex references in other APEXes are not affected by this replacement. + memberName := m.MemberName() + mctx.ReplaceDependencies(memberName) + } + } + } +} diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go new file mode 100644 index 000000000..9eca72fdc --- /dev/null +++ b/sdk/sdk_test.go @@ -0,0 +1,318 @@ +// Copyright 2019 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 sdk + +import ( + "io/ioutil" + "os" + "strings" + "testing" + + "android/soong/android" + "android/soong/apex" + "android/soong/cc" + "android/soong/java" +) + +func testSdkContext(t *testing.T, bp string) (*android.TestContext, android.Config) { + config := android.TestArchConfig(buildDir, nil) + ctx := android.NewTestArchContext() + + // from android package + ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators) + ctx.PreArchMutators(func(ctx android.RegisterMutatorsContext) { + ctx.BottomUp("prebuilts", android.PrebuiltMutator).Parallel() + }) + ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) { + ctx.TopDown("prebuilt_select", android.PrebuiltSelectModuleMutator).Parallel() + ctx.BottomUp("prebuilt_postdeps", android.PrebuiltPostDepsMutator).Parallel() + }) + + // from java package + ctx.RegisterModuleType("android_app_certificate", android.ModuleFactoryAdaptor(java.AndroidAppCertificateFactory)) + ctx.RegisterModuleType("java_library", android.ModuleFactoryAdaptor(java.LibraryFactory)) + ctx.RegisterModuleType("java_import", android.ModuleFactoryAdaptor(java.ImportFactory)) + + // from cc package + ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(cc.LibraryFactory)) + ctx.RegisterModuleType("cc_library_shared", android.ModuleFactoryAdaptor(cc.LibrarySharedFactory)) + ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(cc.ObjectFactory)) + ctx.RegisterModuleType("cc_prebuilt_library_shared", android.ModuleFactoryAdaptor(cc.PrebuiltSharedLibraryFactory)) + ctx.RegisterModuleType("cc_prebuilt_library_static", android.ModuleFactoryAdaptor(cc.PrebuiltStaticLibraryFactory)) + ctx.RegisterModuleType("llndk_library", android.ModuleFactoryAdaptor(cc.LlndkLibraryFactory)) + ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(cc.ToolchainLibraryFactory)) + ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) { + ctx.BottomUp("image", cc.ImageMutator).Parallel() + ctx.BottomUp("link", cc.LinkageMutator).Parallel() + ctx.BottomUp("vndk", cc.VndkMutator).Parallel() + ctx.BottomUp("test_per_src", cc.TestPerSrcMutator).Parallel() + ctx.BottomUp("version", cc.VersionMutator).Parallel() + ctx.BottomUp("begin", cc.BeginMutator).Parallel() + }) + + // from apex package + ctx.RegisterModuleType("apex", android.ModuleFactoryAdaptor(apex.BundleFactory)) + ctx.RegisterModuleType("apex_key", android.ModuleFactoryAdaptor(apex.ApexKeyFactory)) + ctx.PostDepsMutators(apex.RegisterPostDepsMutators) + + // from this package + ctx.RegisterModuleType("sdk", android.ModuleFactoryAdaptor(ModuleFactory)) + ctx.PreDepsMutators(RegisterPreDepsMutators) + ctx.PostDepsMutators(RegisterPostDepsMutators) + + ctx.Register() + + bp = bp + ` + apex_key { + name: "myapex.key", + public_key: "myapex.avbpubkey", + private_key: "myapex.pem", + } + + android_app_certificate { + name: "myapex.cert", + certificate: "myapex", + } + ` + cc.GatherRequiredDepsForTest(android.Android) + + ctx.MockFileSystem(map[string][]byte{ + "Android.bp": []byte(bp), + "build/make/target/product/security": nil, + "apex_manifest.json": nil, + "system/sepolicy/apex/myapex-file_contexts": nil, + "system/sepolicy/apex/myapex2-file_contexts": nil, + "myapex.avbpubkey": nil, + "myapex.pem": nil, + "myapex.x509.pem": nil, + "myapex.pk8": nil, + "Test.java": nil, + "Test.cpp": nil, + "libfoo.so": nil, + }) + + return ctx, config +} + +func testSdk(t *testing.T, bp string) (*android.TestContext, android.Config) { + ctx, config := testSdkContext(t, bp) + _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) + android.FailIfErrored(t, errs) + _, errs = ctx.PrepareBuildActions(config) + android.FailIfErrored(t, errs) + return ctx, config +} + +// ensure that 'result' contains 'expected' +func ensureContains(t *testing.T, result string, expected string) { + t.Helper() + if !strings.Contains(result, expected) { + t.Errorf("%q is not found in %q", expected, result) + } +} + +// ensures that 'result' does not contain 'notExpected' +func ensureNotContains(t *testing.T, result string, notExpected string) { + t.Helper() + if strings.Contains(result, notExpected) { + t.Errorf("%q is found in %q", notExpected, result) + } +} + +func ensureListContains(t *testing.T, result []string, expected string) { + t.Helper() + if !android.InList(expected, result) { + t.Errorf("%q is not found in %v", expected, result) + } +} + +func ensureListNotContains(t *testing.T, result []string, notExpected string) { + t.Helper() + if android.InList(notExpected, result) { + t.Errorf("%q is found in %v", notExpected, result) + } +} + +func pathsToStrings(paths android.Paths) []string { + ret := []string{} + for _, p := range paths { + ret = append(ret, p.String()) + } + return ret +} + +func TestBasicSdkWithJava(t *testing.T) { + ctx, _ := testSdk(t, ` + sdk { + name: "mysdk#1", + java_libs: ["sdkmember_mysdk_1"], + } + + sdk { + name: "mysdk#2", + java_libs: ["sdkmember_mysdk_2"], + } + + java_import { + name: "sdkmember", + prefer: false, + host_supported: true, + } + + java_import { + name: "sdkmember_mysdk_1", + sdk_member_name: "sdkmember", + host_supported: true, + } + + java_import { + name: "sdkmember_mysdk_2", + sdk_member_name: "sdkmember", + host_supported: true, + } + + java_library { + name: "myjavalib", + srcs: ["Test.java"], + libs: ["sdkmember"], + system_modules: "none", + sdk_version: "none", + compile_dex: true, + host_supported: true, + } + + apex { + name: "myapex", + java_libs: ["myjavalib"], + uses_sdks: ["mysdk#1"], + key: "myapex.key", + certificate: ":myapex.cert", + } + + apex { + name: "myapex2", + java_libs: ["myjavalib"], + uses_sdks: ["mysdk#2"], + key: "myapex.key", + certificate: ":myapex.cert", + } + `) + + sdkMemberV1 := ctx.ModuleForTests("sdkmember_mysdk_1", "android_common_myapex").Rule("combineJar").Output + sdkMemberV2 := ctx.ModuleForTests("sdkmember_mysdk_2", "android_common_myapex2").Rule("combineJar").Output + + javalibForMyApex := ctx.ModuleForTests("myjavalib", "android_common_myapex") + javalibForMyApex2 := ctx.ModuleForTests("myjavalib", "android_common_myapex2") + + // Depending on the uses_sdks value, different libs are linked + ensureListContains(t, pathsToStrings(javalibForMyApex.Rule("javac").Implicits), sdkMemberV1.String()) + ensureListContains(t, pathsToStrings(javalibForMyApex2.Rule("javac").Implicits), sdkMemberV2.String()) +} + +func TestBasicSdkWithCc(t *testing.T) { + ctx, _ := testSdk(t, ` + sdk { + name: "mysdk#1", + native_shared_libs: ["sdkmember_mysdk_1"], + } + + sdk { + name: "mysdk#2", + native_shared_libs: ["sdkmember_mysdk_2"], + } + + cc_prebuilt_library_shared { + name: "sdkmember", + srcs: ["libfoo.so"], + prefer: false, + system_shared_libs: [], + stl: "none", + } + + cc_prebuilt_library_shared { + name: "sdkmember_mysdk_1", + sdk_member_name: "sdkmember", + srcs: ["libfoo.so"], + system_shared_libs: [], + stl: "none", + } + + cc_prebuilt_library_shared { + name: "sdkmember_mysdk_2", + sdk_member_name: "sdkmember", + srcs: ["libfoo.so"], + system_shared_libs: [], + stl: "none", + } + + cc_library_shared { + name: "mycpplib", + srcs: ["Test.cpp"], + shared_libs: ["sdkmember"], + system_shared_libs: [], + stl: "none", + } + + apex { + name: "myapex", + native_shared_libs: ["mycpplib"], + uses_sdks: ["mysdk#1"], + key: "myapex.key", + certificate: ":myapex.cert", + } + + apex { + name: "myapex2", + native_shared_libs: ["mycpplib"], + uses_sdks: ["mysdk#2"], + key: "myapex.key", + certificate: ":myapex.cert", + } + `) + + sdkMemberV1 := ctx.ModuleForTests("sdkmember_mysdk_1", "android_arm64_armv8-a_core_shared_myapex").Rule("toc").Output + sdkMemberV2 := ctx.ModuleForTests("sdkmember_mysdk_2", "android_arm64_armv8-a_core_shared_myapex2").Rule("toc").Output + + cpplibForMyApex := ctx.ModuleForTests("mycpplib", "android_arm64_armv8-a_core_shared_myapex") + cpplibForMyApex2 := ctx.ModuleForTests("mycpplib", "android_arm64_armv8-a_core_shared_myapex2") + + // Depending on the uses_sdks value, different libs are linked + ensureListContains(t, pathsToStrings(cpplibForMyApex.Rule("ld").Implicits), sdkMemberV1.String()) + ensureListContains(t, pathsToStrings(cpplibForMyApex2.Rule("ld").Implicits), sdkMemberV2.String()) +} + +var buildDir string + +func setUp() { + var err error + buildDir, err = ioutil.TempDir("", "soong_sdk_test") + if err != nil { + panic(err) + } +} + +func tearDown() { + os.RemoveAll(buildDir) +} + +func TestMain(m *testing.M) { + run := func() int { + setUp() + defer tearDown() + + return m.Run() + } + + os.Exit(run()) +} diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go index c7669bd9d..a87634182 100644 --- a/sysprop/sysprop_library.go +++ b/sysprop/sysprop_library.go @@ -32,6 +32,86 @@ type dependencyTag struct { name string } +type syspropGenProperties struct { + Srcs []string `android:"path"` + Scope string +} + +type syspropJavaGenRule struct { + android.ModuleBase + + properties syspropGenProperties + + genSrcjars android.Paths +} + +var _ android.OutputFileProducer = (*syspropJavaGenRule)(nil) + +var ( + syspropJava = pctx.AndroidStaticRule("syspropJava", + blueprint.RuleParams{ + Command: `rm -rf $out.tmp && mkdir -p $out.tmp && ` + + `$syspropJavaCmd --scope $scope --java-output-dir $out.tmp $in && ` + + `$soongZipCmd -jar -o $out -C $out.tmp -D $out.tmp && rm -rf $out.tmp`, + CommandDeps: []string{ + "$syspropJavaCmd", + "$soongZipCmd", + }, + }, "scope") +) + +func init() { + pctx.HostBinToolVariable("soongZipCmd", "soong_zip") + pctx.HostBinToolVariable("syspropJavaCmd", "sysprop_java") + + android.PreArchMutators(func(ctx android.RegisterMutatorsContext) { + ctx.BottomUp("sysprop_deps", syspropDepsMutator).Parallel() + }) +} + +func (g *syspropJavaGenRule) GenerateAndroidBuildActions(ctx android.ModuleContext) { + var checkApiFileTimeStamp android.WritablePath + + ctx.VisitDirectDeps(func(dep android.Module) { + if m, ok := dep.(*syspropLibrary); ok { + checkApiFileTimeStamp = m.checkApiFileTimeStamp + } + }) + + for _, syspropFile := range android.PathsForModuleSrc(ctx, g.properties.Srcs) { + srcJarFile := android.GenPathWithExt(ctx, "sysprop", syspropFile, "srcjar") + + ctx.Build(pctx, android.BuildParams{ + Rule: syspropJava, + Description: "sysprop_java " + syspropFile.Rel(), + Output: srcJarFile, + Input: syspropFile, + Implicit: checkApiFileTimeStamp, + Args: map[string]string{ + "scope": g.properties.Scope, + }, + }) + + g.genSrcjars = append(g.genSrcjars, srcJarFile) + } +} + +func (g *syspropJavaGenRule) OutputFiles(tag string) (android.Paths, error) { + switch tag { + case "": + return g.genSrcjars, nil + default: + return nil, fmt.Errorf("unsupported module reference tag %q", tag) + } +} + +func syspropJavaGenFactory() android.Module { + g := &syspropJavaGenRule{} + g.AddProperties(&g.properties) + android.InitAndroidModule(g) + return g +} + type syspropLibrary struct { android.ModuleBase @@ -81,13 +161,29 @@ func (m *syspropLibrary) CcModuleName() string { return "lib" + m.BaseModuleName() } +func (m *syspropLibrary) javaGenModuleName() string { + return m.BaseModuleName() + "_java_gen" +} + func (m *syspropLibrary) BaseModuleName() string { return m.ModuleBase.Name() } func (m *syspropLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { - m.currentApiFile = android.PathForSource(ctx, ctx.ModuleDir(), "api", m.BaseModuleName()+"-current.txt") - m.latestApiFile = android.PathForSource(ctx, ctx.ModuleDir(), "api", m.BaseModuleName()+"-latest.txt") + baseModuleName := m.BaseModuleName() + + for _, syspropFile := range android.PathsForModuleSrc(ctx, m.properties.Srcs) { + if syspropFile.Ext() != ".sysprop" { + ctx.PropertyErrorf("srcs", "srcs contains non-sysprop file %q", syspropFile.String()) + } + } + + if ctx.Failed() { + return + } + + m.currentApiFile = android.PathForSource(ctx, ctx.ModuleDir(), "api", baseModuleName+"-current.txt") + m.latestApiFile = android.PathForSource(ctx, ctx.ModuleDir(), "api", baseModuleName+"-latest.txt") // dump API rule rule := android.NewRuleBuilder() @@ -96,7 +192,7 @@ func (m *syspropLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) BuiltTool(ctx, "sysprop_api_dump"). Output(m.dumpedApiFile). Inputs(android.PathsForModuleSrc(ctx, m.properties.Srcs)) - rule.Build(pctx, ctx, m.BaseModuleName()+"_api_dump", m.BaseModuleName()+" api dump") + rule.Build(pctx, ctx, baseModuleName+"_api_dump", baseModuleName+" api dump") // check API rule rule = android.NewRuleBuilder() @@ -105,8 +201,8 @@ func (m *syspropLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) msg := fmt.Sprintf(`\n******************************\n`+ `API of sysprop_library %s doesn't match with current.txt\n`+ `Please update current.txt by:\n`+ - `rm -rf %q && cp -f %q %q\n`+ - `******************************\n`, m.BaseModuleName(), + `m %s-dump-api && rm -rf %q && cp -f %q %q\n`+ + `******************************\n`, baseModuleName, baseModuleName, m.currentApiFile.String(), m.dumpedApiFile.String(), m.currentApiFile.String()) rule.Command(). @@ -121,7 +217,7 @@ func (m *syspropLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) msg = fmt.Sprintf(`\n******************************\n`+ `API of sysprop_library %s doesn't match with latest version\n`+ `Please fix the breakage and rebuild.\n`+ - `******************************\n`, m.BaseModuleName()) + `******************************\n`, baseModuleName) rule.Command(). Text("( "). @@ -138,7 +234,7 @@ func (m *syspropLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) Text("touch"). Output(m.checkApiFileTimeStamp) - rule.Build(pctx, ctx, m.BaseModuleName()+"_check_api", m.BaseModuleName()+" check api") + rule.Build(pctx, ctx, baseModuleName+"_check_api", baseModuleName+" check api") } func (m *syspropLibrary) AndroidMk() android.AndroidMkData { @@ -153,13 +249,13 @@ func (m *syspropLibrary) AndroidMk() android.AndroidMkData { fmt.Fprintf(w, "include $(BUILD_SYSTEM)/base_rules.mk\n\n") fmt.Fprintf(w, "$(LOCAL_BUILT_MODULE): %s\n", m.checkApiFileTimeStamp.String()) fmt.Fprintf(w, "\ttouch $@\n\n") - fmt.Fprintf(w, ".PHONY: %s-check-api\n\n", name) + fmt.Fprintf(w, ".PHONY: %s-check-api %s-dump-api\n\n", name, name) + + // dump API rule + fmt.Fprintf(w, "%s-dump-api: %s\n\n", name, m.dumpedApiFile.String()) // check API rule fmt.Fprintf(w, "%s-check-api: %s\n\n", name, m.checkApiFileTimeStamp.String()) - - // "make {sysprop_library}" should also build the C++ library - fmt.Fprintf(w, "%s: %s\n\n", name, m.CcModuleName()) }} } @@ -263,14 +359,38 @@ func syspropLibraryHook(ctx android.LoadHookContext, m *syspropLibrary) { ccProps.Sysprop.Platform = proptools.BoolPtr(owner == "Platform") ccProps.Header_libs = []string{"libbase_headers"} ccProps.Shared_libs = []string{"liblog"} - - // add sysprop_library module to perform check API - ccProps.Required = []string{m.Name()} - ccProps.Sysprop.Platform = proptools.BoolPtr(owner == "Platform") ccProps.Recovery_available = m.properties.Recovery_available ccProps.Vendor_available = m.properties.Vendor_available - ctx.CreateModule(android.ModuleFactoryAdaptor(cc.LibraryFactory), &ccProps) + ctx.CreateModule(cc.LibraryFactory, &ccProps) + + // internal scope contains all properties + // public scope only contains public properties + // use public if the owner is different from client + scope := "internal" + isProduct := ctx.ProductSpecific() + isVendor := ctx.SocSpecific() + isOwnerPlatform := owner == "Platform" + + if isProduct { + // product can't own any sysprop_library now, so product must use public scope + scope = "public" + } else if isVendor && !isOwnerPlatform { + // vendor and odm can't use system's internal property. + scope = "public" + } + + javaGenProps := struct { + Srcs []string + Scope string + Name *string + }{ + Srcs: m.properties.Srcs, + Scope: scope, + Name: proptools.StringPtr(m.javaGenModuleName()), + } + + ctx.CreateModule(syspropJavaGenFactory, &javaGenProps) javaProps := struct { Name *string @@ -278,27 +398,26 @@ func syspropLibraryHook(ctx android.LoadHookContext, m *syspropLibrary) { Soc_specific *bool Device_specific *bool Product_specific *bool - Sysprop struct { - Platform *bool - } - Required []string - Sdk_version *string - Installable *bool - Libs []string + Required []string + Sdk_version *string + Installable *bool + Libs []string }{} javaProps.Name = proptools.StringPtr(m.BaseModuleName()) - javaProps.Srcs = m.properties.Srcs + javaProps.Srcs = []string{":" + *javaGenProps.Name} javaProps.Soc_specific = proptools.BoolPtr(socSpecific) javaProps.Device_specific = proptools.BoolPtr(deviceSpecific) javaProps.Product_specific = proptools.BoolPtr(productSpecific) javaProps.Installable = m.properties.Installable - - // add sysprop_library module to perform check API - javaProps.Required = []string{m.Name()} javaProps.Sdk_version = proptools.StringPtr("core_current") - javaProps.Sysprop.Platform = proptools.BoolPtr(owner == "Platform") javaProps.Libs = []string{stub} - ctx.CreateModule(android.ModuleFactoryAdaptor(java.LibraryFactory), &javaProps) + ctx.CreateModule(java.LibraryFactory, &javaProps) +} + +func syspropDepsMutator(ctx android.BottomUpMutatorContext) { + if m, ok := ctx.Module().(*syspropLibrary); ok { + ctx.AddReverseDependency(m, nil, m.javaGenModuleName()) + } } diff --git a/sysprop/sysprop_test.go b/sysprop/sysprop_test.go index 5345770a8..6b4337a04 100644 --- a/sysprop/sysprop_test.go +++ b/sysprop/sysprop_test.go @@ -62,6 +62,9 @@ func testContext(config android.Config, bp string, ctx.PreArchMutators(android.RegisterPrebuiltsPreArchMutators) ctx.PreArchMutators(android.RegisterPrebuiltsPostDepsMutators) ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators) + ctx.PreArchMutators(func(ctx android.RegisterMutatorsContext) { + ctx.BottomUp("sysprop_deps", syspropDepsMutator).Parallel() + }) ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(cc.LibraryFactory)) ctx.RegisterModuleType("cc_library_headers", android.ModuleFactoryAdaptor(cc.LibraryHeaderFactory)) @@ -282,10 +285,10 @@ func TestSyspropLibrary(t *testing.T) { // Check for generated cc_library for _, variant := range []string{ - "android_arm_armv7-a-neon_vendor_shared", - "android_arm_armv7-a-neon_vendor_static", - "android_arm64_armv8-a_vendor_shared", - "android_arm64_armv8-a_vendor_static", + "android_arm_armv7-a-neon_vendor.VER_shared", + "android_arm_armv7-a-neon_vendor.VER_static", + "android_arm64_armv8-a_vendor.VER_shared", + "android_arm64_armv8-a_vendor.VER_static", } { ctx.ModuleForTests("libsysprop-platform", variant) ctx.ModuleForTests("libsysprop-vendor", variant) @@ -309,15 +312,15 @@ func TestSyspropLibrary(t *testing.T) { // Check for exported includes coreVariant := "android_arm64_armv8-a_core_static" - vendorVariant := "android_arm64_armv8-a_vendor_static" + vendorVariant := "android_arm64_armv8-a_vendor.VER_static" platformInternalPath := "libsysprop-platform/android_arm64_armv8-a_core_static/gen/sysprop/include" platformPublicCorePath := "libsysprop-platform/android_arm64_armv8-a_core_static/gen/sysprop/public/include" - platformPublicVendorPath := "libsysprop-platform/android_arm64_armv8-a_vendor_static/gen/sysprop/public/include" + platformPublicVendorPath := "libsysprop-platform/android_arm64_armv8-a_vendor.VER_static/gen/sysprop/public/include" platformOnProductPath := "libsysprop-platform-on-product/android_arm64_armv8-a_core_static/gen/sysprop/public/include" - vendorInternalPath := "libsysprop-vendor/android_arm64_armv8-a_vendor_static/gen/sysprop/include" + vendorInternalPath := "libsysprop-vendor/android_arm64_armv8-a_vendor.VER_static/gen/sysprop/include" vendorPublicPath := "libsysprop-vendor/android_arm64_armv8-a_core_static/gen/sysprop/public/include" platformClient := ctx.ModuleForTests("cc-client-platform", coreVariant) diff --git a/tradefed/autogen.go b/tradefed/autogen.go index 7cd7c5a37..3d30cfa13 100644 --- a/tradefed/autogen.go +++ b/tradefed/autogen.go @@ -44,10 +44,11 @@ var autogenTestConfig = pctx.StaticRule("autogenTestConfig", blueprint.RuleParam CommandDeps: []string{"$template"}, }, "name", "template", "extraConfigs") -func testConfigPath(ctx android.ModuleContext, prop *string, testSuites []string) (path android.Path, autogenPath android.WritablePath) { - if p := getTestConfig(ctx, prop); p != nil { +func testConfigPath(ctx android.ModuleContext, prop *string, testSuites []string, autoGenConfig *bool) (path android.Path, autogenPath android.WritablePath) { + p := getTestConfig(ctx, prop) + if !Bool(autoGenConfig) && p != nil { return p, nil - } else if !android.InList("cts", testSuites) { + } else if !android.InList("cts", testSuites) && BoolDefault(autoGenConfig, true) { outputFile := android.PathForModuleOut(ctx, ctx.ModuleName()+".config") return nil, outputFile } else { @@ -73,26 +74,34 @@ func (o Option) Config() string { return fmt.Sprintf(`<option name="%s" value="%s" />`, o.Name, o.Value) } -type Preparer struct { +// It can be a template of object or target_preparer. +type Object struct { + // Set it as a target_preparer if object type == "target_preparer". + Type string Class string Options []Option } -var _ Config = Preparer{} +var _ Config = Object{} -func (p Preparer) Config() string { +func (ob Object) Config() string { var optionStrings []string - for _, option := range p.Options { + for _, option := range ob.Options { optionStrings = append(optionStrings, option.Config()) } var options string - if len(p.Options) == 0 { + if len(ob.Options) == 0 { options = "" } else { optionDelimiter := fmt.Sprintf("\\n%s%s", test_xml_indent, test_xml_indent) options = optionDelimiter + strings.Join(optionStrings, optionDelimiter) } - return fmt.Sprintf(`<target_preparer class="%s">%s\n%s</target_preparer>`, p.Class, options, test_xml_indent) + if ob.Type == "target_preparer" { + return fmt.Sprintf(`<target_preparer class="%s">%s\n%s</target_preparer>`, ob.Class, options, test_xml_indent) + } else { + return fmt.Sprintf(`<object type="%s" class="%s">%s\n%s</object>`, ob.Type, ob.Class, options, test_xml_indent) + } + } func autogenTemplate(ctx android.ModuleContext, output android.WritablePath, template string, configs []Config) { @@ -116,8 +125,8 @@ func autogenTemplate(ctx android.ModuleContext, output android.WritablePath, tem } func AutoGenNativeTestConfig(ctx android.ModuleContext, testConfigProp *string, - testConfigTemplateProp *string, testSuites []string, config []Config) android.Path { - path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites) + testConfigTemplateProp *string, testSuites []string, config []Config, autoGenConfig *bool) android.Path { + path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig) if autogenPath != nil { templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp) if templatePath.Valid() { @@ -135,8 +144,8 @@ func AutoGenNativeTestConfig(ctx android.ModuleContext, testConfigProp *string, } func AutoGenNativeBenchmarkTestConfig(ctx android.ModuleContext, testConfigProp *string, - testConfigTemplateProp *string, testSuites []string, configs []Config) android.Path { - path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites) + testConfigTemplateProp *string, testSuites []string, configs []Config, autoGenConfig *bool) android.Path { + path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig) if autogenPath != nil { templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp) if templatePath.Valid() { @@ -149,8 +158,9 @@ func AutoGenNativeBenchmarkTestConfig(ctx android.ModuleContext, testConfigProp return path } -func AutoGenJavaTestConfig(ctx android.ModuleContext, testConfigProp *string, testConfigTemplateProp *string, testSuites []string) android.Path { - path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites) +func AutoGenJavaTestConfig(ctx android.ModuleContext, testConfigProp *string, testConfigTemplateProp *string, + testSuites []string, autoGenConfig *bool) android.Path { + path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig) if autogenPath != nil { templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp) if templatePath.Valid() { @@ -168,9 +178,9 @@ func AutoGenJavaTestConfig(ctx android.ModuleContext, testConfigProp *string, te } func AutoGenPythonBinaryHostTestConfig(ctx android.ModuleContext, testConfigProp *string, - testConfigTemplateProp *string, testSuites []string) android.Path { + testConfigTemplateProp *string, testSuites []string, autoGenConfig *bool) android.Path { - path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites) + path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig) if autogenPath != nil { templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp) if templatePath.Valid() { @@ -192,8 +202,9 @@ var autogenInstrumentationTest = pctx.StaticRule("autogenInstrumentationTest", b }, }, "name", "template") -func AutoGenInstrumentationTestConfig(ctx android.ModuleContext, testConfigProp *string, testConfigTemplateProp *string, manifest android.Path, testSuites []string) android.Path { - path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites) +func AutoGenInstrumentationTestConfig(ctx android.ModuleContext, testConfigProp *string, + testConfigTemplateProp *string, manifest android.Path, testSuites []string, autoGenConfig *bool) android.Path { + path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig) if autogenPath != nil { template := "${InstrumentationTestConfigTemplate}" moduleTemplate := getTestConfigTemplate(ctx, testConfigTemplateProp) @@ -214,3 +225,6 @@ func AutoGenInstrumentationTestConfig(ctx android.ModuleContext, testConfigProp } return path } + +var Bool = proptools.Bool +var BoolDefault = proptools.BoolDefault diff --git a/ui/build/cleanbuild.go b/ui/build/cleanbuild.go index bfe2c36e4..0a2b51065 100644 --- a/ui/build/cleanbuild.go +++ b/ui/build/cleanbuild.go @@ -87,6 +87,7 @@ func installClean(ctx Context, config Config, what int) { // otherwise we'd have to rebuild any generated files created with // those tools. removeGlobs(ctx, + hostOut("apex"), hostOut("obj/NOTICE_FILES"), hostOut("obj/PACKAGING"), hostOut("coverage"), diff --git a/ui/build/config.go b/ui/build/config.go index 665d2f0fa..def3345e9 100644 --- a/ui/build/config.go +++ b/ui/build/config.go @@ -16,7 +16,6 @@ package build import ( "io/ioutil" - "log" "os" "path/filepath" "runtime" @@ -189,27 +188,27 @@ func NewConfig(ctx Context, args ...string) Config { checkTopDir(ctx) if srcDir := absPath(ctx, "."); strings.ContainsRune(srcDir, ' ') { - log.Println("You are building in a directory whose absolute path contains a space character:") - log.Println() - log.Printf("%q\n", srcDir) - log.Println() - log.Fatalln("Directory names containing spaces are not supported") + ctx.Println("You are building in a directory whose absolute path contains a space character:") + ctx.Println() + ctx.Printf("%q\n", srcDir) + ctx.Println() + ctx.Fatalln("Directory names containing spaces are not supported") } if outDir := ret.OutDir(); strings.ContainsRune(outDir, ' ') { - log.Println("The absolute path of your output directory ($OUT_DIR) contains a space character:") - log.Println() - log.Printf("%q\n", outDir) - log.Println() - log.Fatalln("Directory names containing spaces are not supported") + ctx.Println("The absolute path of your output directory ($OUT_DIR) contains a space character:") + ctx.Println() + ctx.Printf("%q\n", outDir) + ctx.Println() + ctx.Fatalln("Directory names containing spaces are not supported") } if distDir := ret.DistDir(); strings.ContainsRune(distDir, ' ') { - log.Println("The absolute path of your dist directory ($DIST_DIR) contains a space character:") - log.Println() - log.Printf("%q\n", distDir) - log.Println() - log.Fatalln("Directory names containing spaces are not supported") + ctx.Println("The absolute path of your dist directory ($DIST_DIR) contains a space character:") + ctx.Println() + ctx.Printf("%q\n", distDir) + ctx.Println() + ctx.Fatalln("Directory names containing spaces are not supported") } // Configure Java-related variables, including adding it to $PATH diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go index 6b9eac1c4..1925e87b9 100644 --- a/ui/build/dumpvars.go +++ b/ui/build/dumpvars.go @@ -17,6 +17,8 @@ package build import ( "bytes" "fmt" + "io/ioutil" + "os" "strings" "android/soong/ui/metrics" @@ -51,7 +53,17 @@ func DumpMakeVars(ctx Context, config Config, goals, vars []string) (map[string] var ret map[string]string if len(makeVars) > 0 { - var err error + tmpDir, err := ioutil.TempDir("", "dumpvars") + if err != nil { + return nil, err + } + defer os.RemoveAll(tmpDir) + + // It's not safe to use the same TMPDIR as the build, as that can be removed. + config.Environment().Set("TMPDIR", tmpDir) + + SetupLitePath(ctx, config) + ret, err = dumpMakeVars(ctx, config, goals, makeVars, false) if err != nil { return ret, err @@ -208,6 +220,7 @@ func runMakeProductConfig(ctx Context, config Config) { "DEFAULT_WARNING_BUILD_MODULE_TYPES", "DEFAULT_ERROR_BUILD_MODULE_TYPES", + "BUILD_BROKEN_PREBUILT_ELF_FILES", "BUILD_BROKEN_USES_BUILD_AUX_EXECUTABLE", "BUILD_BROKEN_USES_BUILD_AUX_STATIC_LIBRARY", "BUILD_BROKEN_USES_BUILD_COPY_HEADERS", diff --git a/ui/build/path.go b/ui/build/path.go index 0e1c02cac..c34ba1b52 100644 --- a/ui/build/path.go +++ b/ui/build/path.go @@ -18,6 +18,7 @@ import ( "fmt" "io/ioutil" "os" + "os/exec" "path/filepath" "runtime" "strings" @@ -53,6 +54,51 @@ func parsePathDir(dir string) []string { return ret } +// A "lite" version of SetupPath used for dumpvars, or other places that need +// minimal overhead (but at the expense of logging). +func SetupLitePath(ctx Context, config Config) { + if config.pathReplaced { + return + } + + ctx.BeginTrace(metrics.RunSetupTool, "litepath") + defer ctx.EndTrace() + + origPath, _ := config.Environment().Get("PATH") + myPath, _ := config.Environment().Get("TMPDIR") + myPath = filepath.Join(myPath, "path") + ensureEmptyDirectoriesExist(ctx, myPath) + + os.Setenv("PATH", origPath) + for name, pathConfig := range paths.Configuration { + if !pathConfig.Symlink { + continue + } + + origExec, err := exec.LookPath(name) + if err != nil { + continue + } + origExec, err = filepath.Abs(origExec) + if err != nil { + continue + } + + err = os.Symlink(origExec, filepath.Join(myPath, name)) + if err != nil { + ctx.Fatalln("Failed to create symlink:", err) + } + } + + myPath, _ = filepath.Abs(myPath) + + prebuiltsPath, _ := filepath.Abs("prebuilts/build-tools/path/" + runtime.GOOS + "-x86") + myPath = prebuiltsPath + string(os.PathListSeparator) + myPath + + config.Environment().Set("PATH", myPath) + config.pathReplaced = true +} + func SetupPath(ctx Context, config Config) { if config.pathReplaced { return diff --git a/ui/terminal/smart_status.go b/ui/terminal/smart_status.go index 57f71ab86..efcfd4359 100644 --- a/ui/terminal/smart_status.go +++ b/ui/terminal/smart_status.go @@ -189,7 +189,7 @@ func (s *smartStatusOutput) Flush() { fmt.Fprintf(s.writer, ansi.resetScrollingMargins()) _, height, _ := termSize(s.writer) // Move the cursor to the top of the now-blank, previously non-scrolling region - fmt.Fprintf(s.writer, ansi.setCursor(height-s.tableHeight, 0)) + fmt.Fprintf(s.writer, ansi.setCursor(height-s.tableHeight, 1)) // Turn the cursor back on fmt.Fprintf(s.writer, ansi.showCursor()) } @@ -334,52 +334,44 @@ func (s *smartStatusOutput) actionTable() { scrollingHeight := s.termHeight - s.tableHeight // Update the scrolling region in case the height of the terminal changed - fmt.Fprint(s.writer, ansi.setScrollingMargins(0, scrollingHeight)) - // Move the cursor to the first line of the non-scrolling region - fmt.Fprint(s.writer, ansi.setCursor(scrollingHeight+1, 0)) + + fmt.Fprint(s.writer, ansi.setScrollingMargins(1, scrollingHeight)) // Write as many status lines as fit in the table - var tableLine int - var runningAction actionTableEntry - for tableLine, runningAction = range s.runningActions { + for tableLine := 0; tableLine < s.tableHeight; tableLine++ { if tableLine >= s.tableHeight { break } + // Move the cursor to the correct line of the non-scrolling region + fmt.Fprint(s.writer, ansi.setCursor(scrollingHeight+1+tableLine, 1)) - seconds := int(time.Since(runningAction.startTime).Round(time.Second).Seconds()) + if tableLine < len(s.runningActions) { + runningAction := s.runningActions[tableLine] - desc := runningAction.action.Description - if desc == "" { - desc = runningAction.action.Command - } + seconds := int(time.Since(runningAction.startTime).Round(time.Second).Seconds()) - color := "" - if seconds >= 60 { - color = ansi.red() + ansi.bold() - } else if seconds >= 30 { - color = ansi.yellow() + ansi.bold() - } + desc := runningAction.action.Description + if desc == "" { + desc = runningAction.action.Command + } - durationStr := fmt.Sprintf(" %2d:%02d ", seconds/60, seconds%60) - desc = elide(desc, s.termWidth-len(durationStr)) - durationStr = color + durationStr + ansi.regular() + color := "" + if seconds >= 60 { + color = ansi.red() + ansi.bold() + } else if seconds >= 30 { + color = ansi.yellow() + ansi.bold() + } - fmt.Fprint(s.writer, durationStr, desc, ansi.clearToEndOfLine()) - if tableLine < s.tableHeight-1 { - fmt.Fprint(s.writer, "\n") + durationStr := fmt.Sprintf(" %2d:%02d ", seconds/60, seconds%60) + desc = elide(desc, s.termWidth-len(durationStr)) + durationStr = color + durationStr + ansi.regular() + fmt.Fprint(s.writer, durationStr, desc) } - } - - // Clear any remaining lines in the table - for ; tableLine < s.tableHeight; tableLine++ { fmt.Fprint(s.writer, ansi.clearToEndOfLine()) - if tableLine < s.tableHeight-1 { - fmt.Fprint(s.writer, "\n") - } } // Move the cursor back to the last line of the scrolling region - fmt.Fprint(s.writer, ansi.setCursor(scrollingHeight, 0)) + fmt.Fprint(s.writer, ansi.setCursor(scrollingHeight, 1)) } var ansi = ansiImpl{} diff --git a/ui/terminal/status.go b/ui/terminal/status.go index 69a2a0929..60dfc7025 100644 --- a/ui/terminal/status.go +++ b/ui/terminal/status.go @@ -26,10 +26,10 @@ import ( // // statusFormat takes nearly all the same options as NINJA_STATUS. // %c is currently unsupported. -func NewStatusOutput(w io.Writer, statusFormat string, quietBuild bool) status.StatusOutput { +func NewStatusOutput(w io.Writer, statusFormat string, forceDumbOutput, quietBuild bool) status.StatusOutput { formatter := newFormatter(statusFormat, quietBuild) - if isSmartTerminal(w) { + if !forceDumbOutput && isSmartTerminal(w) { return NewSmartStatusOutput(w, formatter) } else { return NewDumbStatusOutput(w, formatter) diff --git a/ui/terminal/status_test.go b/ui/terminal/status_test.go index 81aa238b8..9f6082988 100644 --- a/ui/terminal/status_test.go +++ b/ui/terminal/status_test.go @@ -94,7 +94,7 @@ func TestStatusOutput(t *testing.T) { t.Run("smart", func(t *testing.T) { smart := &fakeSmartTerminal{termWidth: 40} - stat := NewStatusOutput(smart, "", false) + stat := NewStatusOutput(smart, "", false, false) tt.calls(stat) stat.Flush() @@ -105,7 +105,7 @@ func TestStatusOutput(t *testing.T) { t.Run("dumb", func(t *testing.T) { dumb := &bytes.Buffer{} - stat := NewStatusOutput(dumb, "", false) + stat := NewStatusOutput(dumb, "", false, false) tt.calls(stat) stat.Flush() @@ -113,6 +113,17 @@ func TestStatusOutput(t *testing.T) { t.Errorf("want:\n%q\ngot:\n%q", w, g) } }) + + t.Run("force dumb", func(t *testing.T) { + smart := &fakeSmartTerminal{termWidth: 40} + stat := NewStatusOutput(smart, "", true, false) + tt.calls(stat) + stat.Flush() + + if g, w := smart.String(), tt.dumb; g != w { + t.Errorf("want:\n%q\ngot:\n%q", w, g) + } + }) }) } } @@ -258,7 +269,7 @@ func TestSmartStatusOutputWidthChange(t *testing.T) { os.Setenv(tableHeightEnVar, "") smart := &fakeSmartTerminal{termWidth: 40} - stat := NewStatusOutput(smart, "", false) + stat := NewStatusOutput(smart, "", false, false) smartStat := stat.(*smartStatusOutput) smartStat.sigwinchHandled = make(chan bool) diff --git a/vnames.json b/vnames.json new file mode 100644 index 000000000..f9d3adc8b --- /dev/null +++ b/vnames.json @@ -0,0 +1,18 @@ +[ + { + "pattern": "out/(.*)", + "vname": { + "corpus": "android.googlesource.com/platform/superproject", + "root": "out", + "path": "@1@" + } + }, + { + "pattern": "(.*)", + "vname": { + "corpus": "android.googlesource.com/platform/superproject", + "path": "@1@" + } + } +] + diff --git a/xml/xml_test.go b/xml/xml_test.go index ae3e9fe3c..f2a440f9a 100644 --- a/xml/xml_test.go +++ b/xml/xml_test.go @@ -15,15 +15,40 @@ package xml import ( - "android/soong/android" "io/ioutil" "os" "testing" + + "android/soong/android" ) +var buildDir string + +func setUp() { + var err error + buildDir, err = ioutil.TempDir("", "soong_xml_test") + if err != nil { + panic(err) + } +} + +func tearDown() { + os.RemoveAll(buildDir) +} + +func TestMain(m *testing.M) { + run := func() int { + setUp() + defer tearDown() + + return m.Run() + } + + os.Exit(run()) +} + func testXml(t *testing.T, bp string) *android.TestContext { - config, buildDir := setup(t) - defer teardown(buildDir) + config := android.TestArchConfig(buildDir, nil) ctx := android.NewTestArchContext() ctx.RegisterModuleType("prebuilt_etc", android.ModuleFactoryAdaptor(android.PrebuiltEtcFactory)) ctx.RegisterModuleType("prebuilt_etc_xml", android.ModuleFactoryAdaptor(PrebuiltEtcXmlFactory)) @@ -45,21 +70,6 @@ func testXml(t *testing.T, bp string) *android.TestContext { return ctx } -func setup(t *testing.T) (config android.Config, buildDir string) { - buildDir, err := ioutil.TempDir("", "soong_xml_test") - if err != nil { - t.Fatal(err) - } - - config = android.TestArchConfig(buildDir, nil) - - return -} - -func teardown(buildDir string) { - os.RemoveAll(buildDir) -} - func assertEqual(t *testing.T, name, expected, actual string) { t.Helper() if expected != actual { @@ -103,5 +113,5 @@ func TestPrebuiltEtcXml(t *testing.T) { } m := ctx.ModuleForTests("foo.xml", "android_arm64_armv8-a").Module().(*prebuiltEtcXml) - assertEqual(t, "installDir", "target/product/test_device/system/etc", m.InstallDirPath().RelPathString()) + assertEqual(t, "installDir", buildDir+"/target/product/test_device/system/etc", m.InstallDirPath().String()) } |