diff options
| -rw-r--r-- | android/androidmk.go | 362 | ||||
| -rw-r--r-- | android/prebuilt_etc.go | 49 | ||||
| -rw-r--r-- | android/prebuilt_etc_test.go | 46 | ||||
| -rw-r--r-- | android/testing.go | 11 | ||||
| -rw-r--r-- | java/androidmk.go | 4 |
5 files changed, 279 insertions, 193 deletions
diff --git a/android/androidmk.go b/android/androidmk.go index bd49e4c6..89dfd0ea 100644 --- a/android/androidmk.go +++ b/android/androidmk.go @@ -32,6 +32,8 @@ func init() { RegisterSingletonType("androidmk", AndroidMkSingleton) } +// Deprecated: consider using AndroidMkEntriesProvider instead, especially if you're not going to +// use the Custom function. type AndroidMkDataProvider interface { AndroidMk() AndroidMkData BaseModuleName() string @@ -55,6 +57,194 @@ type AndroidMkData struct { type AndroidMkExtraFunc func(w io.Writer, outputFile Path) +// Allows modules to customize their Android*.mk output. +type AndroidMkEntriesProvider interface { + AndroidMkEntries() AndroidMkEntries + BaseModuleName() string +} + +type AndroidMkEntries struct { + Class string + SubName string + DistFile OptionalPath + OutputFile OptionalPath + Disabled bool + Include string + Required []string + + header bytes.Buffer + footer bytes.Buffer + + AddCustomEntries func(name, prefix, moduleDir string, entries *AndroidMkEntries) + + EntryMap map[string][]string + entryOrder []string +} + +func (a *AndroidMkEntries) SetString(name, value string) { + if _, ok := a.EntryMap[name]; !ok { + a.entryOrder = append(a.entryOrder, name) + } + a.EntryMap[name] = []string{value} +} + +func (a *AndroidMkEntries) SetBoolIfTrue(name string, flag bool) { + if flag { + if _, ok := a.EntryMap[name]; !ok { + a.entryOrder = append(a.entryOrder, name) + } + a.EntryMap[name] = []string{"true"} + } +} + +func (a *AndroidMkEntries) AddStrings(name string, value ...string) { + if len(value) == 0 { + return + } + if _, ok := a.EntryMap[name]; !ok { + a.entryOrder = append(a.entryOrder, name) + } + a.EntryMap[name] = append(a.EntryMap[name], value...) +} + +func (a *AndroidMkEntries) fillInEntries(config Config, bpPath string, mod blueprint.Module) { + a.EntryMap = make(map[string][]string) + amod := mod.(Module).base() + name := amod.BaseModuleName() + + if a.Include == "" { + a.Include = "$(BUILD_PREBUILT)" + } + a.Required = append(a.Required, amod.commonProperties.Required...) + + // Fill in the header part. + if len(amod.commonProperties.Dist.Targets) > 0 { + distFile := a.DistFile + if !distFile.Valid() { + distFile = a.OutputFile + } + if distFile.Valid() { + dest := filepath.Base(distFile.String()) + + if amod.commonProperties.Dist.Dest != nil { + var err error + if dest, err = validateSafePath(*amod.commonProperties.Dist.Dest); err != nil { + // This was checked in ModuleBase.GenerateBuildActions + panic(err) + } + } + + if amod.commonProperties.Dist.Suffix != nil { + ext := filepath.Ext(dest) + suffix := *amod.commonProperties.Dist.Suffix + dest = strings.TrimSuffix(dest, ext) + suffix + ext + } + + if amod.commonProperties.Dist.Dir != nil { + var err error + if dest, err = validateSafePath(*amod.commonProperties.Dist.Dir, dest); err != nil { + // This was checked in ModuleBase.GenerateBuildActions + panic(err) + } + } + + goals := strings.Join(amod.commonProperties.Dist.Targets, " ") + fmt.Fprintln(&a.header, ".PHONY:", goals) + fmt.Fprintf(&a.header, "$(call dist-for-goals,%s,%s:%s)\n", + goals, distFile.String(), dest) + } + } + + fmt.Fprintln(&a.header, "\ninclude $(CLEAR_VARS)") + + // Collect make variable assignment entries. + a.SetString("LOCAL_PATH", filepath.Dir(bpPath)) + a.SetString("LOCAL_MODULE", name+a.SubName) + a.SetString("LOCAL_MODULE_CLASS", a.Class) + a.SetString("LOCAL_PREBUILT_MODULE_FILE", a.OutputFile.String()) + a.AddStrings("LOCAL_REQUIRED_MODULES", a.Required...) + + archStr := amod.Arch().ArchType.String() + host := false + switch amod.Os().Class { + case Host: + // Make cannot identify LOCAL_MODULE_HOST_ARCH:= common. + if archStr != "common" { + a.SetString("LOCAL_MODULE_HOST_ARCH", archStr) + } + host = true + case HostCross: + // Make cannot identify LOCAL_MODULE_HOST_CROSS_ARCH:= common. + if archStr != "common" { + a.SetString("LOCAL_MODULE_HOST_CROSS_ARCH", archStr) + } + host = true + case Device: + // Make cannot identify LOCAL_MODULE_TARGET_ARCH:= common. + if archStr != "common" { + a.SetString("LOCAL_MODULE_TARGET_ARCH", archStr) + } + + a.AddStrings("LOCAL_INIT_RC", amod.commonProperties.Init_rc...) + a.AddStrings("LOCAL_VINTF_FRAGMENTS", amod.commonProperties.Vintf_fragments...) + a.SetBoolIfTrue("LOCAL_PROPRIETARY_MODULE", Bool(amod.commonProperties.Proprietary)) + if Bool(amod.commonProperties.Vendor) || Bool(amod.commonProperties.Soc_specific) { + a.SetString("LOCAL_VENDOR_MODULE", "true") + } + a.SetBoolIfTrue("LOCAL_ODM_MODULE", Bool(amod.commonProperties.Device_specific)) + a.SetBoolIfTrue("LOCAL_PRODUCT_MODULE", Bool(amod.commonProperties.Product_specific)) + a.SetBoolIfTrue("LOCAL_PRODUCT_SERVICES_MODULE", Bool(amod.commonProperties.Product_services_specific)) + if amod.commonProperties.Owner != nil { + a.SetString("LOCAL_MODULE_OWNER", *amod.commonProperties.Owner) + } + } + + if amod.noticeFile.Valid() { + a.SetString("LOCAL_NOTICE_FILE", amod.noticeFile.String()) + } + + if host { + makeOs := amod.Os().String() + if amod.Os() == Linux || amod.Os() == LinuxBionic { + makeOs = "linux" + } + a.SetString("LOCAL_MODULE_HOST_OS", makeOs) + a.SetString("LOCAL_IS_HOST_MODULE", "true") + } + + prefix := "" + if amod.ArchSpecific() { + switch amod.Os().Class { + case Host: + prefix = "HOST_" + case HostCross: + prefix = "HOST_CROSS_" + case Device: + prefix = "TARGET_" + + } + + if amod.Arch().ArchType != config.Targets[amod.Os()][0].Arch.ArchType { + prefix = "2ND_" + prefix + } + } + blueprintDir := filepath.Dir(bpPath) + if a.AddCustomEntries != nil { + a.AddCustomEntries(name, prefix, blueprintDir, a) + } + + // Write to footer. + fmt.Fprintln(&a.footer, "include "+a.Include) +} + +func (a *AndroidMkEntries) write(w io.Writer) { + w.Write(a.header.Bytes()) + for _, name := range a.entryOrder { + fmt.Fprintln(w, name+" := "+strings.Join(a.EntryMap[name], " ")) + } + w.Write(a.footer.Bytes()) +} + func AndroidMkSingleton() Singleton { return &androidMkSingleton{} } @@ -157,6 +347,8 @@ func translateAndroidMkModule(ctx SingletonContext, w io.Writer, mod blueprint.M return translateAndroidModule(ctx, w, mod, x) case bootstrap.GoBinaryTool: return translateGoBinaryModule(ctx, w, mod, x) + case AndroidMkEntriesProvider: + return translateAndroidMkEntriesModule(ctx, w, mod, x) default: return nil } @@ -176,35 +368,30 @@ func translateGoBinaryModule(ctx SingletonContext, w io.Writer, mod blueprint.Mo func translateAndroidModule(ctx SingletonContext, w io.Writer, mod blueprint.Module, provider AndroidMkDataProvider) error { - name := provider.BaseModuleName() amod := mod.(Module).base() - - if !amod.Enabled() { - return nil - } - - if amod.commonProperties.SkipInstall { - return nil - } - - if !amod.commonProperties.NamespaceExportedToMake { - // TODO(jeffrygaston) do we want to validate that there are no modules being - // exported to Kati that depend on this module? + if shouldSkipAndroidMkProcessing(amod) { return nil } data := provider.AndroidMk() - if data.Include == "" { data.Include = "$(BUILD_PREBUILT)" } - data.Required = append(data.Required, amod.commonProperties.Required...) - - // Make does not understand LinuxBionic - if amod.Os() == LinuxBionic { - return nil + // Get the preamble content through AndroidMkEntries logic. + entries := AndroidMkEntries{ + Class: data.Class, + SubName: data.SubName, + DistFile: data.DistFile, + OutputFile: data.OutputFile, + Disabled: data.Disabled, + Include: data.Include, + Required: data.Required, } + entries.fillInEntries(ctx.Config(), ctx.BlueprintFile(mod), mod) + // preamble doesn't need the footer content. + entries.footer = bytes.Buffer{} + entries.write(&data.preamble) prefix := "" if amod.ArchSpecific() { @@ -223,115 +410,7 @@ func translateAndroidModule(ctx SingletonContext, w io.Writer, mod blueprint.Mod } } - if len(amod.commonProperties.Dist.Targets) > 0 { - distFile := data.DistFile - if !distFile.Valid() { - distFile = data.OutputFile - } - if distFile.Valid() { - dest := filepath.Base(distFile.String()) - - if amod.commonProperties.Dist.Dest != nil { - var err error - dest, err = validateSafePath(*amod.commonProperties.Dist.Dest) - if err != nil { - // This was checked in ModuleBase.GenerateBuildActions - panic(err) - } - } - - if amod.commonProperties.Dist.Suffix != nil { - ext := filepath.Ext(dest) - suffix := *amod.commonProperties.Dist.Suffix - dest = strings.TrimSuffix(dest, ext) + suffix + ext - } - - if amod.commonProperties.Dist.Dir != nil { - var err error - dest, err = validateSafePath(*amod.commonProperties.Dist.Dir, dest) - if err != nil { - // This was checked in ModuleBase.GenerateBuildActions - panic(err) - } - } - - goals := strings.Join(amod.commonProperties.Dist.Targets, " ") - fmt.Fprintln(&data.preamble, ".PHONY:", goals) - fmt.Fprintf(&data.preamble, "$(call dist-for-goals,%s,%s:%s)\n", - goals, distFile.String(), dest) - } - } - - fmt.Fprintln(&data.preamble, "\ninclude $(CLEAR_VARS)") - fmt.Fprintln(&data.preamble, "LOCAL_PATH :=", filepath.Dir(ctx.BlueprintFile(mod))) - fmt.Fprintln(&data.preamble, "LOCAL_MODULE :=", name+data.SubName) - fmt.Fprintln(&data.preamble, "LOCAL_MODULE_CLASS :=", data.Class) - fmt.Fprintln(&data.preamble, "LOCAL_PREBUILT_MODULE_FILE :=", data.OutputFile.String()) - - if len(data.Required) > 0 { - fmt.Fprintln(&data.preamble, "LOCAL_REQUIRED_MODULES := "+strings.Join(data.Required, " ")) - } - - archStr := amod.Arch().ArchType.String() - host := false - switch amod.Os().Class { - case Host: - // Make cannot identify LOCAL_MODULE_HOST_ARCH:= common. - if archStr != "common" { - fmt.Fprintln(&data.preamble, "LOCAL_MODULE_HOST_ARCH :=", archStr) - } - host = true - case HostCross: - // Make cannot identify LOCAL_MODULE_HOST_CROSS_ARCH:= common. - if archStr != "common" { - fmt.Fprintln(&data.preamble, "LOCAL_MODULE_HOST_CROSS_ARCH :=", archStr) - } - host = true - case Device: - // Make cannot identify LOCAL_MODULE_TARGET_ARCH:= common. - if archStr != "common" { - fmt.Fprintln(&data.preamble, "LOCAL_MODULE_TARGET_ARCH :=", archStr) - } - - if len(amod.commonProperties.Init_rc) > 0 { - fmt.Fprintln(&data.preamble, "LOCAL_INIT_RC := ", strings.Join(amod.commonProperties.Init_rc, " ")) - } - if len(amod.commonProperties.Vintf_fragments) > 0 { - fmt.Fprintln(&data.preamble, "LOCAL_VINTF_FRAGMENTS := ", strings.Join(amod.commonProperties.Vintf_fragments, " ")) - } - if Bool(amod.commonProperties.Proprietary) { - fmt.Fprintln(&data.preamble, "LOCAL_PROPRIETARY_MODULE := true") - } - if Bool(amod.commonProperties.Vendor) || Bool(amod.commonProperties.Soc_specific) { - fmt.Fprintln(&data.preamble, "LOCAL_VENDOR_MODULE := true") - } - if Bool(amod.commonProperties.Device_specific) { - fmt.Fprintln(&data.preamble, "LOCAL_ODM_MODULE := true") - } - if Bool(amod.commonProperties.Product_specific) { - fmt.Fprintln(&data.preamble, "LOCAL_PRODUCT_MODULE := true") - } - if Bool(amod.commonProperties.Product_services_specific) { - fmt.Fprintln(&data.preamble, "LOCAL_PRODUCT_SERVICES_MODULE := true") - } - if amod.commonProperties.Owner != nil { - fmt.Fprintln(&data.preamble, "LOCAL_MODULE_OWNER :=", *amod.commonProperties.Owner) - } - } - - if amod.noticeFile.Valid() { - fmt.Fprintln(&data.preamble, "LOCAL_NOTICE_FILE :=", amod.noticeFile.String()) - } - - if host { - makeOs := amod.Os().String() - if amod.Os() == Linux || amod.Os() == LinuxBionic { - makeOs = "linux" - } - fmt.Fprintln(&data.preamble, "LOCAL_MODULE_HOST_OS :=", makeOs) - fmt.Fprintln(&data.preamble, "LOCAL_IS_HOST_MODULE := true") - } - + name := provider.BaseModuleName() blueprintDir := filepath.Dir(ctx.BlueprintFile(mod)) if data.Custom != nil { @@ -360,3 +439,30 @@ func WriteAndroidMkData(w io.Writer, data AndroidMkData) { fmt.Fprintln(w, "include "+data.Include) } + +func translateAndroidMkEntriesModule(ctx SingletonContext, w io.Writer, mod blueprint.Module, + provider AndroidMkEntriesProvider) error { + if shouldSkipAndroidMkProcessing(mod.(Module).base()) { + return nil + } + + entries := provider.AndroidMkEntries() + entries.fillInEntries(ctx.Config(), ctx.BlueprintFile(mod), mod) + + entries.write(w) + + return nil +} + +func shouldSkipAndroidMkProcessing(module *ModuleBase) bool { + if !module.commonProperties.NamespaceExportedToMake { + // TODO(jeffrygaston) do we want to validate that there are no modules being + // exported to Kati that depend on this module? + return true + } + + return !module.Enabled() || + module.commonProperties.SkipInstall || + // Make does not understand LinuxBionic + module.Os() == LinuxBionic +} diff --git a/android/prebuilt_etc.go b/android/prebuilt_etc.go index 8f23d78e..bec24c77 100644 --- a/android/prebuilt_etc.go +++ b/android/prebuilt_etc.go @@ -14,11 +14,7 @@ package android -import ( - "fmt" - "io" - "strings" -) +import "strconv" // TODO(jungw): Now that it handles more than the ones in etc/, consider renaming this file. @@ -135,38 +131,25 @@ func (p *PrebuiltEtc) GenerateAndroidBuildActions(ctx ModuleContext) { }) } -func (p *PrebuiltEtc) AndroidMk() AndroidMkData { - return AndroidMkData{ - Custom: func(w io.Writer, name, prefix, moduleDir string, data AndroidMkData) { - nameSuffix := "" - if p.inRecovery() && !p.onlyInRecovery() { - nameSuffix = ".recovery" - } - fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)") - fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir) - fmt.Fprintln(w, "LOCAL_MODULE :=", name+nameSuffix) - fmt.Fprintln(w, "LOCAL_MODULE_CLASS := ETC") - if p.commonProperties.Owner != nil { - fmt.Fprintln(w, "LOCAL_MODULE_OWNER :=", *p.commonProperties.Owner) - } - fmt.Fprintln(w, "LOCAL_MODULE_TAGS := optional") - if p.Host() { - fmt.Fprintln(w, "LOCAL_IS_HOST_MODULE := true") - } - fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", p.outputFilePath.String()) - fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", "$(OUT_DIR)/"+p.installDirPath.RelPathString()) - fmt.Fprintln(w, "LOCAL_INSTALLED_MODULE_STEM :=", p.outputFilePath.Base()) - fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE :=", !p.Installable()) - fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", strings.Join(data.Required, " ")) - fmt.Fprintln(w, "LOCAL_MODULE_TARGET_ARCH :=", p.Arch().ArchType.String()) +func (p *PrebuiltEtc) AndroidMkEntries() AndroidMkEntries { + nameSuffix := "" + if p.inRecovery() && !p.onlyInRecovery() { + nameSuffix = ".recovery" + } + return AndroidMkEntries{ + Class: "ETC", + SubName: nameSuffix, + OutputFile: OptionalPathForPath(p.outputFilePath), + AddCustomEntries: func(name, prefix, moduleDir string, entries *AndroidMkEntries) { + entries.SetString("LOCAL_MODULE_TAGS", "optional") + entries.SetString("LOCAL_MODULE_PATH", "$(OUT_DIR)/"+p.installDirPath.RelPathString()) + entries.SetString("LOCAL_INSTALLED_MODULE_STEM", p.outputFilePath.Base()) + entries.SetString("LOCAL_UNINSTALLABLE_MODULE", strconv.FormatBool(!p.Installable())) if p.additionalDependencies != nil { - fmt.Fprint(w, "LOCAL_ADDITIONAL_DEPENDENCIES :=") for _, path := range *p.additionalDependencies { - fmt.Fprint(w, " "+path.String()) + entries.SetString("LOCAL_ADDITIONAL_DEPENDENCIES", path.String()) } - fmt.Fprintln(w, "") } - fmt.Fprintln(w, "include $(BUILD_PREBUILT)") }, } } diff --git a/android/prebuilt_etc_test.go b/android/prebuilt_etc_test.go index e0ade7e5..ee6e990e 100644 --- a/android/prebuilt_etc_test.go +++ b/android/prebuilt_etc_test.go @@ -15,12 +15,10 @@ package android import ( - "bufio" - "bytes" "io/ioutil" "os" "path/filepath" - "strings" + "reflect" "testing" ) @@ -139,45 +137,33 @@ func TestPrebuiltEtcGlob(t *testing.T) { } func TestPrebuiltEtcAndroidMk(t *testing.T) { - ctx, _ := testPrebuiltEtc(t, ` + ctx, config := testPrebuiltEtc(t, ` prebuilt_etc { name: "foo", src: "foo.conf", owner: "abc", filename_from_src: true, + required: ["modA", "moduleB"], } `) - data := AndroidMkData{} - data.Required = append(data.Required, "modA", "moduleB") - - expected := map[string]string{ - "LOCAL_MODULE": "foo", - "LOCAL_MODULE_CLASS": "ETC", - "LOCAL_MODULE_OWNER": "abc", - "LOCAL_INSTALLED_MODULE_STEM": "foo.conf", - "LOCAL_REQUIRED_MODULES": "modA moduleB", + expected := map[string][]string{ + "LOCAL_MODULE": {"foo"}, + "LOCAL_MODULE_CLASS": {"ETC"}, + "LOCAL_MODULE_OWNER": {"abc"}, + "LOCAL_INSTALLED_MODULE_STEM": {"foo.conf"}, + "LOCAL_REQUIRED_MODULES": {"modA", "moduleB"}, } mod := ctx.ModuleForTests("foo", "android_arm64_armv8-a_core").Module().(*PrebuiltEtc) - buf := &bytes.Buffer{} - mod.AndroidMk().Custom(buf, "foo", "", "", data) - for k, expected := range expected { - found := false - scanner := bufio.NewScanner(bytes.NewReader(buf.Bytes())) - for scanner.Scan() { - line := scanner.Text() - tok := strings.Split(line, " := ") - if tok[0] == k { - found = true - if tok[1] != expected { - t.Errorf("Incorrect %s '%s', expected '%s'", k, tok[1], expected) - } + entries := AndroidMkEntriesForTest(t, config, "", mod) + for k, expectedValue := range expected { + if value, ok := entries.EntryMap[k]; ok { + if !reflect.DeepEqual(value, expectedValue) { + t.Errorf("Incorrect %s '%s', expected '%s'", k, value, expectedValue) } - } - - if !found { - t.Errorf("No %s defined, saw %s", k, buf.String()) + } else { + t.Errorf("No %s defined, saw %q", k, entries.EntryMap) } } } diff --git a/android/testing.go b/android/testing.go index 0ec5af58..ab3c69cf 100644 --- a/android/testing.go +++ b/android/testing.go @@ -369,3 +369,14 @@ func FailIfNoMatchingErrors(t *testing.T, pattern string, errs []error) { } } } + +func AndroidMkEntriesForTest(t *testing.T, config Config, bpPath string, mod blueprint.Module) AndroidMkEntries { + var p AndroidMkEntriesProvider + var ok bool + if p, ok = mod.(AndroidMkEntriesProvider); !ok { + t.Errorf("module does not implmement AndroidMkEntriesProvider: " + mod.Name()) + } + entries := p.AndroidMkEntries() + entries.fillInEntries(config, bpPath, mod) + return entries +} diff --git a/java/androidmk.go b/java/androidmk.go index 8d9cbdd5..7e7ea36b 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -39,8 +39,8 @@ 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()) fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES := "+strings.Join(data.Required, " ")) - if r := library.deviceProperties.Target.Hostdex.Required; len(r) > 0 { - fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES +=", strings.Join(r, " ")) + if len(data.Required) > 0 { + fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", strings.Join(data.Required, " ")) } fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_java_prebuilt.mk") } |
