diff --git a/android/androidmk.go b/android/androidmk.go index d579e30c3..3487b287d 100644 --- a/android/androidmk.go +++ b/android/androidmk.go @@ -46,7 +46,7 @@ type AndroidMkDataProvider interface { type AndroidMkData struct { Class string SubName string - DistFile OptionalPath + DistFiles TaggedDistFiles OutputFile OptionalPath Disabled bool Include string @@ -72,7 +72,7 @@ type AndroidMkEntriesProvider interface { type AndroidMkEntries struct { Class string SubName string - DistFile OptionalPath + DistFiles TaggedDistFiles OutputFile OptionalPath Disabled bool Include string @@ -137,6 +137,96 @@ func (a *AndroidMkEntries) AddStrings(name string, value ...string) { a.EntryMap[name] = append(a.EntryMap[name], value...) } +// Compute the list of Make strings to declare phone goals and dist-for-goals +// calls from the module's dist and dists properties. +func (a *AndroidMkEntries) GetDistForGoals(mod blueprint.Module) []string { + amod := mod.(Module).base() + name := amod.BaseModuleName() + + var ret []string + + availableTaggedDists := TaggedDistFiles{} + if a.DistFiles != nil && len(a.DistFiles[""]) > 0 { + availableTaggedDists = a.DistFiles + } else if a.OutputFile.Valid() { + availableTaggedDists = MakeDefaultDistFiles(a.OutputFile.Path()) + } + + // Iterate over this module's dist structs, merged from the dist and dists properties. + for _, dist := range amod.Dists() { + // Get the list of goals this dist should be enabled for. e.g. sdk, droidcore + goals := strings.Join(dist.Targets, " ") + + // Get the tag representing the output files to be dist'd. e.g. ".jar", ".proguard_map" + var tag string + if dist.Tag == nil { + // If the dist struct does not specify a tag, use the default output files tag. + tag = "" + } else { + tag = *dist.Tag + } + + // Get the paths of the output files to be dist'd, represented by the tag. + // Can be an empty list. + tagPaths := availableTaggedDists[tag] + if len(tagPaths) == 0 { + // Nothing to dist for this tag, continue to the next dist. + continue + } + + if len(tagPaths) > 1 && (dist.Dest != nil || dist.Suffix != nil) { + errorMessage := "Cannot apply dest/suffix for more than one dist " + + "file for %s goals in module %s. The list of dist files, " + + "which should have a single element, is:\n%s" + panic(fmt.Errorf(errorMessage, goals, name, tagPaths)) + } + + ret = append(ret, fmt.Sprintf(".PHONY: %s\n", goals)) + + // Create dist-for-goals calls for each path in the dist'd files. + for _, path := range tagPaths { + // It's possible that the Path is nil from errant modules. Be defensive here. + if path == nil { + tagName := "default" // for error message readability + if dist.Tag != nil { + tagName = *dist.Tag + } + panic(fmt.Errorf("Dist file should not be nil for the %s tag in %s", tagName, name)) + } + + dest := filepath.Base(path.String()) + + if dist.Dest != nil { + var err error + if dest, err = validateSafePath(*dist.Dest); err != nil { + // This was checked in ModuleBase.GenerateBuildActions + panic(err) + } + } + + if dist.Suffix != nil { + ext := filepath.Ext(dest) + suffix := *dist.Suffix + dest = strings.TrimSuffix(dest, ext) + suffix + ext + } + + if dist.Dir != nil { + var err error + if dest, err = validateSafePath(*dist.Dir, dest); err != nil { + // This was checked in ModuleBase.GenerateBuildActions + panic(err) + } + } + + ret = append( + ret, + fmt.Sprintf("$(call dist-for-goals,%s,%s:%s)\n", goals, path.String(), dest)) + } + } + + return ret +} + func (a *AndroidMkEntries) fillInEntries(config Config, bpPath string, mod blueprint.Module) { a.EntryMap = make(map[string][]string) amod := mod.(Module).base() @@ -149,42 +239,8 @@ func (a *AndroidMkEntries) fillInEntries(config Config, bpPath string, mod bluep a.Host_required = append(a.Host_required, amod.commonProperties.Host_required...) a.Target_required = append(a.Target_required, amod.commonProperties.Target_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) - } + for _, distString := range a.GetDistForGoals(mod) { + fmt.Fprintf(&a.header, distString) } fmt.Fprintln(&a.header, "\ninclude $(CLEAR_VARS)") @@ -430,7 +486,7 @@ func (data *AndroidMkData) fillInData(config Config, bpPath string, mod blueprin entries := AndroidMkEntries{ Class: data.Class, SubName: data.SubName, - DistFile: data.DistFile, + DistFiles: data.DistFiles, OutputFile: data.OutputFile, Disabled: data.Disabled, Include: data.Include, diff --git a/android/androidmk_test.go b/android/androidmk_test.go index 71f802043..250f086e5 100644 --- a/android/androidmk_test.go +++ b/android/androidmk_test.go @@ -15,6 +15,7 @@ package android import ( + "fmt" "io" "reflect" "testing" @@ -22,10 +23,12 @@ import ( type customModule struct { ModuleBase - data AndroidMkData + data AndroidMkData + distFiles TaggedDistFiles } func (m *customModule) GenerateAndroidBuildActions(ctx ModuleContext) { + m.distFiles = m.GenerateTaggedDistFiles(ctx) } func (m *customModule) AndroidMk() AndroidMkData { @@ -36,6 +39,26 @@ func (m *customModule) AndroidMk() AndroidMkData { } } +func (m *customModule) OutputFiles(tag string) (Paths, error) { + switch tag { + case "": + return PathsForTesting("one.out"), nil + case ".multiple": + return PathsForTesting("two.out", "three/four.out"), nil + default: + return nil, fmt.Errorf("unsupported module reference tag %q", tag) + } +} + +func (m *customModule) AndroidMkEntries() []AndroidMkEntries { + return []AndroidMkEntries{ + { + Class: "CUSTOM_MODULE", + DistFiles: m.distFiles, + }, + } +} + func customModuleFactory() Module { module := &customModule{} InitAndroidModule(module) @@ -76,3 +99,159 @@ func TestAndroidMkSingleton_PassesUpdatedAndroidMkDataToCustomCallback(t *testin assertEqual([]string{"baz"}, m.data.Host_required) assertEqual([]string{"qux"}, m.data.Target_required) } + +func TestGetDistForGoals(t *testing.T) { + testCases := []struct { + bp string + expectedAndroidMkLines []string + }{ + { + bp: ` + custom { + name: "foo", + dist: { + targets: ["my_goal"] + } + } + `, + expectedAndroidMkLines: []string{ + ".PHONY: my_goal\n", + "$(call dist-for-goals,my_goal,one.out:one.out)\n", + }, + }, + { + bp: ` + custom { + name: "foo", + dists: [ + { + targets: ["my_goal"], + }, + { + targets: ["my_second_goal", "my_third_goal"], + }, + ], + } + `, + expectedAndroidMkLines: []string{ + ".PHONY: my_goal\n", + "$(call dist-for-goals,my_goal,one.out:one.out)\n", + ".PHONY: my_second_goal my_third_goal\n", + "$(call dist-for-goals,my_second_goal my_third_goal,one.out:one.out)\n", + }, + }, + { + bp: ` + custom { + name: "foo", + dist: { + targets: ["my_goal"], + }, + dists: [ + { + targets: ["my_second_goal", "my_third_goal"], + }, + ], + } + `, + expectedAndroidMkLines: []string{ + ".PHONY: my_second_goal my_third_goal\n", + "$(call dist-for-goals,my_second_goal my_third_goal,one.out:one.out)\n", + ".PHONY: my_goal\n", + "$(call dist-for-goals,my_goal,one.out:one.out)\n", + }, + }, + { + bp: ` + custom { + name: "foo", + dist: { + targets: ["my_goal", "my_other_goal"], + tag: ".multiple", + }, + dists: [ + { + targets: ["my_second_goal"], + tag: ".multiple", + }, + { + targets: ["my_third_goal"], + dir: "test/dir", + }, + { + targets: ["my_fourth_goal"], + suffix: ".suffix", + }, + { + targets: ["my_fifth_goal"], + dest: "new-name", + }, + { + targets: ["my_sixth_goal"], + dest: "new-name", + dir: "some/dir", + suffix: ".suffix", + }, + ], + } + `, + expectedAndroidMkLines: []string{ + ".PHONY: my_second_goal\n", + "$(call dist-for-goals,my_second_goal,two.out:two.out)\n", + "$(call dist-for-goals,my_second_goal,three/four.out:four.out)\n", + ".PHONY: my_third_goal\n", + "$(call dist-for-goals,my_third_goal,one.out:test/dir/one.out)\n", + ".PHONY: my_fourth_goal\n", + "$(call dist-for-goals,my_fourth_goal,one.out:one.suffix.out)\n", + ".PHONY: my_fifth_goal\n", + "$(call dist-for-goals,my_fifth_goal,one.out:new-name)\n", + ".PHONY: my_sixth_goal\n", + "$(call dist-for-goals,my_sixth_goal,one.out:some/dir/new-name.suffix)\n", + ".PHONY: my_goal my_other_goal\n", + "$(call dist-for-goals,my_goal my_other_goal,two.out:two.out)\n", + "$(call dist-for-goals,my_goal my_other_goal,three/four.out:four.out)\n", + }, + }, + } + + for _, testCase := range testCases { + config := TestConfig(buildDir, nil, testCase.bp, nil) + config.inMake = true // Enable androidmk Singleton + + ctx := NewTestContext() + ctx.RegisterSingletonType("androidmk", AndroidMkSingleton) + ctx.RegisterModuleType("custom", customModuleFactory) + ctx.Register(config) + + _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) + FailIfErrored(t, errs) + _, errs = ctx.PrepareBuildActions(config) + FailIfErrored(t, errs) + + module := ctx.ModuleForTests("foo", "").Module().(*customModule) + entries := AndroidMkEntriesForTest(t, config, "", module) + if len(entries) != 1 { + t.Errorf("Expected a single AndroidMk entry, got %d", len(entries)) + } + androidMkLines := entries[0].GetDistForGoals(module) + + if len(androidMkLines) != len(testCase.expectedAndroidMkLines) { + t.Errorf( + "Expected %d AndroidMk lines, got %d:\n%v", + len(testCase.expectedAndroidMkLines), + len(androidMkLines), + androidMkLines, + ) + } + for idx, line := range androidMkLines { + expectedLine := testCase.expectedAndroidMkLines[idx] + if line != expectedLine { + t.Errorf( + "Expected AndroidMk line to be '%s', got '%s'", + line, + expectedLine, + ) + } + } + } +} diff --git a/android/module.go b/android/module.go index ac3394ddd..06079cae9 100644 --- a/android/module.go +++ b/android/module.go @@ -315,6 +315,28 @@ func newPackageId(pkg string) qualifiedModuleName { return qualifiedModuleName{pkg: pkg, name: ""} } +type Dist struct { + // Copy the output of this module to the $DIST_DIR when `dist` is specified on the + // command line and any of these targets are also on the command line, or otherwise + // built + Targets []string `android:"arch_variant"` + + // The name of the output artifact. This defaults to the basename of the output of + // the module. + Dest *string `android:"arch_variant"` + + // The directory within the dist directory to store the artifact. Defaults to the + // top level directory (""). + Dir *string `android:"arch_variant"` + + // A suffix to add to the artifact file name (before any extension). + Suffix *string `android:"arch_variant"` + + // A string tag to select the OutputFiles associated with the tag. Defaults to the + // the empty "" string. + Tag *string `android:"arch_variant"` +} + type nameProperties struct { // The name of the module. Must be unique across all modules. Name *string @@ -454,23 +476,13 @@ type commonProperties struct { // relative path to a file to include in the list of notices for the device Notice *string `android:"path"` - Dist struct { - // copy the output of this module to the $DIST_DIR when `dist` is specified on the - // command line and any of these targets are also on the command line, or otherwise - // built - Targets []string `android:"arch_variant"` + // configuration to distribute output files from this module to the distribution + // directory (default: $OUT/dist, configurable with $DIST_DIR) + Dist Dist `android:"arch_variant"` - // The name of the output artifact. This defaults to the basename of the output of - // the module. - Dest *string `android:"arch_variant"` - - // The directory within the dist directory to store the artifact. Defaults to the - // top level directory (""). - Dir *string `android:"arch_variant"` - - // A suffix to add to the artifact file name (before any extension). - Suffix *string `android:"arch_variant"` - } `android:"arch_variant"` + // a list of configurations to distribute output files from this module to the + // distribution directory (default: $OUT/dist, configurable with $DIST_DIR) + Dists []Dist `android:"arch_variant"` // The OsType of artifacts that this module variant is responsible for creating. // @@ -537,6 +549,14 @@ type commonProperties struct { ImageVariation string `blueprint:"mutated"` } +// A map of OutputFile tag keys to Paths, for disting purposes. +type TaggedDistFiles map[string]Paths + +func MakeDefaultDistFiles(paths ...Path) TaggedDistFiles { + // The default OutputFile tag is the empty "" string. + return TaggedDistFiles{"": paths} +} + type hostAndDeviceProperties struct { // If set to true, build a variant of the module for the host. Defaults to false. Host_supported *bool @@ -815,6 +835,41 @@ func (m *ModuleBase) visibilityProperties() []visibilityProperty { return m.visibilityPropertyInfo } +func (m *ModuleBase) Dists() []Dist { + if len(m.commonProperties.Dist.Targets) > 0 { + // Make a copy of the underlying Dists slice to protect against + // backing array modifications with repeated calls to this method. + distsCopy := append([]Dist(nil), m.commonProperties.Dists...) + return append(distsCopy, m.commonProperties.Dist) + } else { + return m.commonProperties.Dists + } +} + +func (m *ModuleBase) GenerateTaggedDistFiles(ctx BaseModuleContext) TaggedDistFiles { + distFiles := make(TaggedDistFiles) + for _, dist := range m.Dists() { + var tag string + var distFilesForTag Paths + if dist.Tag == nil { + tag = "" + } else { + tag = *dist.Tag + } + distFilesForTag, err := m.base().module.(OutputFileProducer).OutputFiles(tag) + if err != nil { + ctx.PropertyErrorf("dist.tag", "%s", err.Error()) + } + for _, distFile := range distFilesForTag { + if distFile != nil && !distFiles[tag].containsPath(distFile) { + distFiles[tag] = append(distFiles[tag], distFile) + } + } + } + + return distFiles +} + func (m *ModuleBase) Target() Target { return m.commonProperties.CompileTarget } diff --git a/android/paths.go b/android/paths.go index bed6f3f58..d8d51a777 100644 --- a/android/paths.go +++ b/android/paths.go @@ -220,6 +220,15 @@ func (p OptionalPath) String() string { // Paths is a slice of Path objects, with helpers to operate on the collection. type Paths []Path +func (paths Paths) containsPath(path Path) bool { + for _, p := range paths { + if p == path { + return true + } + } + return false +} + // PathsForSource returns Paths rooted from SrcDir func PathsForSource(ctx PathContext, paths []string) Paths { ret := make(Paths, len(paths)) diff --git a/cc/androidmk.go b/cc/androidmk.go index b3ad610d6..3f812c2c0 100644 --- a/cc/androidmk.go +++ b/cc/androidmk.go @@ -249,7 +249,10 @@ func (library *libraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries entries.Class = "HEADER_LIBRARIES" } - entries.DistFile = library.distFile + if library.distFile != nil { + entries.DistFiles = android.MakeDefaultDistFiles(library.distFile) + } + entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) { library.androidMkWriteExportedFlags(entries) library.androidMkEntriesWriteAdditionalDependenciesForSourceAbiDiff(entries) @@ -318,7 +321,7 @@ func (binary *binaryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *a ctx.subAndroidMk(entries, binary.baseInstaller) entries.Class = "EXECUTABLES" - entries.DistFile = binary.distFile + entries.DistFiles = binary.distFiles entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) { entries.SetString("LOCAL_SOONG_UNSTRIPPED_BINARY", binary.unstrippedOutputFile.String()) if len(binary.symlinks) > 0 { diff --git a/cc/binary.go b/cc/binary.go index 251b7f0c4..565cb8ae7 100644 --- a/cc/binary.go +++ b/cc/binary.go @@ -98,8 +98,8 @@ type binaryDecorator struct { // Output archive of gcno coverage information coverageOutputFile android.OptionalPath - // Location of the file that should be copied to dist dir when requested - distFile android.OptionalPath + // Location of the files that should be copied to dist dir when requested + distFiles android.TaggedDistFiles post_install_cmds []string } @@ -367,11 +367,11 @@ func (binary *binaryDecorator) link(ctx ModuleContext, binary.injectVersionSymbol(ctx, outputFile, versionedOutputFile) } else { versionedOutputFile := android.PathForModuleOut(ctx, "versioned", fileName) - binary.distFile = android.OptionalPathForPath(versionedOutputFile) + binary.distFiles = android.MakeDefaultDistFiles(versionedOutputFile) if binary.stripper.needsStrip(ctx) { out := android.PathForModuleOut(ctx, "versioned-stripped", fileName) - binary.distFile = android.OptionalPathForPath(out) + binary.distFiles = android.MakeDefaultDistFiles(out) binary.stripper.stripExecutableOrSharedLib(ctx, versionedOutputFile, out, builderFlags) } diff --git a/cc/library.go b/cc/library.go index 968702e59..98f4d48d6 100644 --- a/cc/library.go +++ b/cc/library.go @@ -369,7 +369,7 @@ type libraryDecorator struct { unstrippedOutputFile android.Path // Location of the file that should be copied to dist dir when requested - distFile android.OptionalPath + distFile android.Path versionScriptPath android.ModuleGenPath @@ -894,7 +894,7 @@ func (library *libraryDecorator) linkStatic(ctx ModuleContext, library.injectVersionSymbol(ctx, outputFile, versionedOutputFile) } else { versionedOutputFile := android.PathForModuleOut(ctx, "versioned", fileName) - library.distFile = android.OptionalPathForPath(versionedOutputFile) + library.distFile = versionedOutputFile library.injectVersionSymbol(ctx, outputFile, versionedOutputFile) } } @@ -988,11 +988,11 @@ func (library *libraryDecorator) linkShared(ctx ModuleContext, library.injectVersionSymbol(ctx, outputFile, versionedOutputFile) } else { versionedOutputFile := android.PathForModuleOut(ctx, "versioned", fileName) - library.distFile = android.OptionalPathForPath(versionedOutputFile) + library.distFile = versionedOutputFile if library.stripper.needsStrip(ctx) { out := android.PathForModuleOut(ctx, "versioned-stripped", fileName) - library.distFile = android.OptionalPathForPath(out) + library.distFile = out library.stripper.stripExecutableOrSharedLib(ctx, versionedOutputFile, out, builderFlags) } diff --git a/java/androidmk.go b/java/androidmk.go index 62cf169fa..e73b03058 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -91,7 +91,7 @@ func (library *Library) AndroidMkEntries() []android.AndroidMkEntries { } else { mainEntries = android.AndroidMkEntries{ Class: "JAVA_LIBRARIES", - DistFile: android.OptionalPathForPath(library.distFile), + DistFiles: library.distFiles, OutputFile: android.OptionalPathForPath(library.outputFile), Include: "$(BUILD_SYSTEM)/soong_java_prebuilt.mk", ExtraEntries: []android.AndroidMkExtraEntriesFunc{ @@ -550,14 +550,14 @@ func (dstubs *Droidstubs) AndroidMkEntries() []android.AndroidMkEntries { // needed because an invalid output file would prevent the make entries from // being written. // TODO(b/146727827): Revert when we do not need to generate stubs and API separately. - distFile := android.OptionalPathForPath(dstubs.apiFile) + distFile := dstubs.apiFile outputFile := android.OptionalPathForPath(dstubs.stubsSrcJar) if !outputFile.Valid() { - outputFile = distFile + outputFile = android.OptionalPathForPath(distFile) } return []android.AndroidMkEntries{android.AndroidMkEntries{ Class: "JAVA_LIBRARIES", - DistFile: distFile, + DistFiles: android.MakeDefaultDistFiles(distFile), OutputFile: outputFile, Include: "$(BUILD_SYSTEM)/soong_droiddoc_prebuilt.mk", ExtraEntries: []android.AndroidMkExtraEntriesFunc{ diff --git a/java/androidmk_test.go b/java/androidmk_test.go index d471fb7d5..075b7aa6f 100644 --- a/java/androidmk_test.go +++ b/java/androidmk_test.go @@ -156,17 +156,158 @@ func TestDistWithTag(t *testing.T) { } `) - without_tag_entries := android.AndroidMkEntriesForTest(t, config, "", ctx.ModuleForTests("foo_without_tag", "android_common").Module()) - with_tag_entries := android.AndroidMkEntriesForTest(t, config, "", ctx.ModuleForTests("foo_with_tag", "android_common").Module()) + withoutTagEntries := android.AndroidMkEntriesForTest(t, config, "", ctx.ModuleForTests("foo_without_tag", "android_common").Module()) + withTagEntries := android.AndroidMkEntriesForTest(t, config, "", ctx.ModuleForTests("foo_with_tag", "android_common").Module()) - if len(without_tag_entries) != 2 || len(with_tag_entries) != 2 { - t.Errorf("two mk entries per module expected, got %d and %d", len(without_tag_entries), len(with_tag_entries)) + if len(withoutTagEntries) != 2 || len(withTagEntries) != 2 { + t.Errorf("two mk entries per module expected, got %d and %d", len(withoutTagEntries), len(withTagEntries)) } - if !with_tag_entries[0].DistFile.Valid() || !strings.Contains(with_tag_entries[0].DistFile.String(), "/javac/foo_with_tag.jar") { - t.Errorf("expected classes.jar DistFile, got %v", with_tag_entries[0].DistFile) + if len(withTagEntries[0].DistFiles[".jar"]) != 1 || + !strings.Contains(withTagEntries[0].DistFiles[".jar"][0].String(), "/javac/foo_with_tag.jar") { + t.Errorf("expected DistFiles to contain classes.jar, got %v", withTagEntries[0].DistFiles) } - if without_tag_entries[0].DistFile.Valid() { - t.Errorf("did not expect explicit DistFile, got %v", without_tag_entries[0].DistFile) + if len(withoutTagEntries[0].DistFiles[".jar"]) > 0 { + t.Errorf("did not expect explicit DistFile for .jar tag, got %v", withoutTagEntries[0].DistFiles[".jar"]) + } +} + +func TestDistWithDest(t *testing.T) { + ctx, config := testJava(t, ` + java_library { + name: "foo", + srcs: ["a.java"], + compile_dex: true, + dist: { + targets: ["my_goal"], + dest: "my/custom/dest/dir", + }, + } + `) + + module := ctx.ModuleForTests("foo", "android_common").Module() + entries := android.AndroidMkEntriesForTest(t, config, "", module) + if len(entries) != 2 { + t.Errorf("Expected 2 AndroidMk entries, got %d", len(entries)) + } + + distStrings := entries[0].GetDistForGoals(module) + + if len(distStrings) != 2 { + t.Errorf("Expected 2 entries for dist: PHONY and dist-for-goals, but got %q", distStrings) + } + + if distStrings[0] != ".PHONY: my_goal\n" { + t.Errorf("Expected .PHONY entry to declare my_goal, but got: %s", distStrings[0]) + } + + if !strings.Contains(distStrings[1], "$(call dist-for-goals,my_goal") || + !strings.Contains(distStrings[1], ".intermediates/foo/android_common/dex/foo.jar:my/custom/dest/dir") { + t.Errorf( + "Expected dist-for-goals entry to contain my_goal and new dest dir, but got: %s", distStrings[1]) + } +} + +func TestDistsWithAllProperties(t *testing.T) { + ctx, config := testJava(t, ` + java_library { + name: "foo", + srcs: ["a.java"], + compile_dex: true, + dist: { + targets: ["baz"], + }, + dists: [ + { + targets: ["bar"], + tag: ".jar", + dest: "bar.jar", + dir: "bar/dir", + suffix: ".qux", + }, + ] + } + `) + + module := ctx.ModuleForTests("foo", "android_common").Module() + entries := android.AndroidMkEntriesForTest(t, config, "", module) + if len(entries) != 2 { + t.Errorf("Expected 2 AndroidMk entries, got %d", len(entries)) + } + + distStrings := entries[0].GetDistForGoals(module) + + if len(distStrings) != 4 { + t.Errorf("Expected 4 entries for dist: PHONY and dist-for-goals, but got %d", len(distStrings)) + } + + if distStrings[0] != ".PHONY: bar\n" { + t.Errorf("Expected .PHONY entry to declare bar, but got: %s", distStrings[0]) + } + + if !strings.Contains(distStrings[1], "$(call dist-for-goals,bar") || + !strings.Contains( + distStrings[1], + ".intermediates/foo/android_common/javac/foo.jar:bar/dir/bar.qux.jar") { + t.Errorf( + "Expected dist-for-goals entry to contain bar and new dest dir, but got: %s", distStrings[1]) + } + + if distStrings[2] != ".PHONY: baz\n" { + t.Errorf("Expected .PHONY entry to declare baz, but got: %s", distStrings[2]) + } + + if !strings.Contains(distStrings[3], "$(call dist-for-goals,baz") || + !strings.Contains(distStrings[3], ".intermediates/foo/android_common/dex/foo.jar:foo.jar") { + t.Errorf( + "Expected dist-for-goals entry to contain my_other_goal and new dest dir, but got: %s", + distStrings[3]) + } +} + +func TestDistsWithTag(t *testing.T) { + ctx, config := testJava(t, ` + java_library { + name: "foo_without_tag", + srcs: ["a.java"], + compile_dex: true, + dists: [ + { + targets: ["hi"], + }, + ], + } + java_library { + name: "foo_with_tag", + srcs: ["a.java"], + compile_dex: true, + dists: [ + { + targets: ["hi"], + tag: ".jar", + }, + ], + } + `) + + moduleWithoutTag := ctx.ModuleForTests("foo_without_tag", "android_common").Module() + moduleWithTag := ctx.ModuleForTests("foo_with_tag", "android_common").Module() + + withoutTagEntries := android.AndroidMkEntriesForTest(t, config, "", moduleWithoutTag) + withTagEntries := android.AndroidMkEntriesForTest(t, config, "", moduleWithTag) + + if len(withoutTagEntries) != 2 || len(withTagEntries) != 2 { + t.Errorf("two mk entries per module expected, got %d and %d", len(withoutTagEntries), len(withTagEntries)) + } + + distFilesWithoutTag := withoutTagEntries[0].DistFiles + distFilesWithTag := withTagEntries[0].DistFiles + + if len(distFilesWithTag[".jar"]) != 1 || + !strings.Contains(distFilesWithTag[".jar"][0].String(), "/javac/foo_with_tag.jar") { + t.Errorf("expected foo_with_tag's .jar-tagged DistFiles to contain classes.jar, got %v", distFilesWithTag[".jar"]) + } + if len(distFilesWithoutTag[".jar"]) > 0 { + t.Errorf("did not expect foo_without_tag's .jar-tagged DistFiles to contain files, but got %v", distFilesWithoutTag[".jar"]) } } diff --git a/java/java.go b/java/java.go index fee5b36cc..42e40b9a3 100644 --- a/java/java.go +++ b/java/java.go @@ -483,7 +483,7 @@ type Module struct { // list of the xref extraction files kytheFiles android.Paths - distFile android.Path + distFiles android.TaggedDistFiles // Collect the module directory for IDE info in java/jdeps.go. modulePaths []string @@ -1925,18 +1925,9 @@ func (j *Module) IsInstallable() bool { // Java libraries (.jar file) // -type LibraryProperties struct { - Dist struct { - // The tag of the output of this module that should be output. - Tag *string `android:"arch_variant"` - } `android:"arch_variant"` -} - type Library struct { Module - libraryProperties LibraryProperties - InstallMixin func(ctx android.ModuleContext, installPath android.Path) (extraInstallDeps android.Paths) } @@ -1998,14 +1989,7 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { j.Stem()+".jar", j.outputFile, extraInstallDeps...) } - // Verify Dist.Tag is set to a supported output - if j.libraryProperties.Dist.Tag != nil { - distFiles, err := j.OutputFiles(*j.libraryProperties.Dist.Tag) - if err != nil { - ctx.PropertyErrorf("dist.tag", "%s", err.Error()) - } - j.distFile = distFiles[0] - } + j.distFiles = j.GenerateTaggedDistFiles(ctx) } func (j *Library) DepsMutator(ctx android.BottomUpMutatorContext) { @@ -2123,7 +2107,6 @@ func LibraryFactory() android.Module { module := &Library{} module.addHostAndDeviceProperties() - module.AddProperties(&module.libraryProperties) module.initModuleAndImport(&module.ModuleBase) diff --git a/rust/androidmk.go b/rust/androidmk.go index 69d0df562..aea899baa 100644 --- a/rust/androidmk.go +++ b/rust/androidmk.go @@ -86,8 +86,11 @@ func (mod *Module) AndroidMk() android.AndroidMkData { func (binary *binaryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) { ctx.subAndroidMk(ret, binary.baseCompiler) + if binary.distFile.Valid() { + ret.DistFiles = android.MakeDefaultDistFiles(binary.distFile.Path()) + } + ret.Class = "EXECUTABLES" - ret.DistFile = binary.distFile ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) { fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", binary.unstrippedOutputFile.String()) if binary.coverageOutputZipFile.Valid() { @@ -127,7 +130,10 @@ func (library *libraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.An ret.Class = "SHARED_LIBRARIES" } - ret.DistFile = library.distFile + if library.distFile.Valid() { + ret.DistFiles = android.MakeDefaultDistFiles(library.distFile.Path()) + } + ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) { if !library.rlib() { fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", library.unstrippedOutputFile.String()) @@ -143,7 +149,9 @@ func (procMacro *procMacroDecorator) AndroidMk(ctx AndroidMkContext, ret *androi ctx.subAndroidMk(ret, procMacro.baseCompiler) ret.Class = "PROC_MACRO_LIBRARIES" - ret.DistFile = procMacro.distFile + if procMacro.distFile.Valid() { + ret.DistFiles = android.MakeDefaultDistFiles(procMacro.distFile.Path()) + } } diff --git a/sdk/sdk.go b/sdk/sdk.go index cb5a6053d..b9b8199d3 100644 --- a/sdk/sdk.go +++ b/sdk/sdk.go @@ -291,7 +291,7 @@ func (s *sdk) AndroidMkEntries() []android.AndroidMkEntries { return []android.AndroidMkEntries{android.AndroidMkEntries{ Class: "FAKE", OutputFile: s.snapshotFile, - DistFile: s.snapshotFile, + DistFiles: android.MakeDefaultDistFiles(s.snapshotFile.Path()), Include: "$(BUILD_PHONY_PACKAGE)", ExtraFooters: []android.AndroidMkExtraFootersFunc{ func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) {