Support multiple sources for prebuilt_etc
Keep the Src attribute for compatibility. The new attribute (Srcs) is
mutually exclusive with Src.
Keep SourceFilePath and OutputFile for compatibility with other modules.
These can be removed in a follow up change.
Bug: 328313691
Test: presubmit
Test: m blueprint_tests
Test: prebuilts/build-tools/build-prebuilts.sh (on build-tools branch)
Change-Id: I5d5b2657715a7180a829c7ed0f501872d561b662
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index 7642378..a42c576 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -71,10 +71,15 @@
type prebuiltEtcProperties struct {
// Source file of this prebuilt. Can reference a genrule type module with the ":module" syntax.
+ // Mutually exclusive with srcs.
Src *string `android:"path,arch_variant"`
+ // Source files of this prebuilt. Can reference a genrule type module with the ":module" syntax.
+ // Mutually exclusive with src. When used, filename_from_src is set to true.
+ Srcs []string `android:"path,arch_variant"`
+
// Optional name for the installed file. If unspecified, name of the module is used as the file
- // name.
+ // name. Only available when using a single source (src).
Filename *string `android:"arch_variant"`
// When set to true, and filename property is not set, the name for the installed file
@@ -127,9 +132,9 @@
// Returns the sub install directory relative to BaseDir().
SubDir() string
- // Returns an android.OutputPath to the intermeidate file, which is the renamed prebuilt source
+ // Returns an android.OutputPath to the intermediate file, which is the renamed prebuilt source
// file.
- OutputFile() android.OutputPath
+ OutputFiles(tag string) (android.Paths, error)
}
type PrebuiltEtc struct {
@@ -142,8 +147,8 @@
properties prebuiltEtcProperties
subdirProperties prebuiltSubdirProperties
- sourceFilePath android.Path
- outputFilePath android.OutputPath
+ sourceFilePaths android.Paths
+ outputFilePaths android.OutputPaths
// The base install location, e.g. "etc" for prebuilt_etc, "usr/share" for prebuilt_usr_share.
installDirBase string
installDirBase64 string
@@ -246,6 +251,9 @@
}
func (p *PrebuiltEtc) SourceFilePath(ctx android.ModuleContext) android.Path {
+ if len(p.properties.Srcs) > 0 {
+ panic(fmt.Errorf("SourceFilePath not available on multi-source prebuilt %q", p.Name()))
+ }
return android.PathForModuleSrc(ctx, proptools.String(p.properties.Src))
}
@@ -260,7 +268,10 @@
}
func (p *PrebuiltEtc) OutputFile() android.OutputPath {
- return p.outputFilePath
+ if len(p.properties.Srcs) > 0 {
+ panic(fmt.Errorf("OutputFile not available on multi-source prebuilt %q", p.Name()))
+ }
+ return p.outputFilePaths[0]
}
var _ android.OutputFileProducer = (*PrebuiltEtc)(nil)
@@ -268,7 +279,7 @@
func (p *PrebuiltEtc) OutputFiles(tag string) (android.Paths, error) {
switch tag {
case "":
- return android.Paths{p.outputFilePath}, nil
+ return p.outputFilePaths.Paths(), nil
default:
return nil, fmt.Errorf("unsupported module reference tag %q", tag)
}
@@ -301,50 +312,7 @@
return false
}
-func (p *PrebuiltEtc) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- filename := proptools.String(p.properties.Filename)
- filenameFromSrc := proptools.Bool(p.properties.Filename_from_src)
- if p.properties.Src != nil {
- p.sourceFilePath = android.PathForModuleSrc(ctx, proptools.String(p.properties.Src))
-
- // Determine the output file basename.
- // If Filename is set, use the name specified by the property.
- // If Filename_from_src is set, use the source file name.
- // Otherwise use the module name.
- if filename != "" {
- if filenameFromSrc {
- ctx.PropertyErrorf("filename_from_src", "filename is set. filename_from_src can't be true")
- return
- }
- } else if filenameFromSrc {
- filename = p.sourceFilePath.Base()
- } else {
- filename = ctx.ModuleName()
- }
- } else if ctx.Config().AllowMissingDependencies() {
- // If no srcs was set and AllowMissingDependencies is enabled then
- // mark the module as missing dependencies and set a fake source path
- // and file name.
- ctx.AddMissingDependencies([]string{"MISSING_PREBUILT_SRC_FILE"})
- p.sourceFilePath = android.PathForModuleSrc(ctx)
- if filename == "" {
- filename = ctx.ModuleName()
- }
- } else {
- ctx.PropertyErrorf("src", "missing prebuilt source file")
- return
- }
-
- if strings.Contains(filename, "/") {
- ctx.PropertyErrorf("filename", "filename cannot contain separator '/'")
- return
- }
-
- // Check that `sub_dir` and `relative_install_path` are not set at the same time.
- if p.subdirProperties.Sub_dir != nil && p.subdirProperties.Relative_install_path != nil {
- ctx.PropertyErrorf("sub_dir", "relative_install_path is set. Cannot set sub_dir")
- }
-
+func (p *PrebuiltEtc) installBaseDir(ctx android.ModuleContext) string {
// If soc install dir was specified and SOC specific is set, set the installDirPath to the
// specified socInstallDirBase.
installBaseDir := p.installDirBase
@@ -357,47 +325,138 @@
if p.installAvoidMultilibConflict && !ctx.Host() && ctx.Config().HasMultilibConflict(ctx.Arch().ArchType) {
installBaseDir = filepath.Join(installBaseDir, ctx.Arch().ArchType.String())
}
+ return installBaseDir
+}
- p.installDirPath = android.PathForModuleInstall(ctx, installBaseDir, p.SubDir())
+func (p *PrebuiltEtc) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ var installs []installProperties
- // Call InstallFile even when uninstallable to make the module included in the package
- ip := installProperties{
- installable: p.Installable(),
- filename: filename,
- sourceFilePath: p.sourceFilePath,
- symlinks: p.properties.Symlinks,
+ if p.properties.Src != nil && len(p.properties.Srcs) > 0 {
+ ctx.PropertyErrorf("src", "src is set. Cannot set srcs")
}
- p.addInstallRules(ctx, ip)
+
+ // Check that `sub_dir` and `relative_install_path` are not set at the same time.
+ if p.subdirProperties.Sub_dir != nil && p.subdirProperties.Relative_install_path != nil {
+ ctx.PropertyErrorf("sub_dir", "relative_install_path is set. Cannot set sub_dir")
+ }
+ p.installDirPath = android.PathForModuleInstall(ctx, p.installBaseDir(ctx), p.SubDir())
+
+ filename := proptools.String(p.properties.Filename)
+ filenameFromSrc := proptools.Bool(p.properties.Filename_from_src)
+ if p.properties.Src != nil {
+ p.sourceFilePaths = android.PathsForModuleSrc(ctx, []string{proptools.String(p.properties.Src)})
+ // If the source was not found, set a fake source path to
+ // support AllowMissingDependencies executions.
+ if len(p.sourceFilePaths) == 0 {
+ p.sourceFilePaths = android.Paths{android.PathForModuleSrc(ctx)}
+ }
+
+ // Determine the output file basename.
+ // If Filename is set, use the name specified by the property.
+ // If Filename_from_src is set, use the source file name.
+ // Otherwise use the module name.
+ if filename != "" {
+ if filenameFromSrc {
+ ctx.PropertyErrorf("filename_from_src", "filename is set. filename_from_src can't be true")
+ return
+ }
+ } else if filenameFromSrc {
+ filename = p.sourceFilePaths[0].Base()
+ } else {
+ filename = ctx.ModuleName()
+ }
+ if strings.Contains(filename, "/") {
+ ctx.PropertyErrorf("filename", "filename cannot contain separator '/'")
+ return
+ }
+ p.outputFilePaths = android.OutputPaths{android.PathForModuleOut(ctx, filename).OutputPath}
+
+ ip := installProperties{
+ filename: filename,
+ sourceFilePath: p.sourceFilePaths[0],
+ outputFilePath: p.outputFilePaths[0],
+ installDirPath: p.installDirPath,
+ symlinks: p.properties.Symlinks,
+ }
+ installs = append(installs, ip)
+ } else if len(p.properties.Srcs) > 0 {
+ if filename != "" {
+ ctx.PropertyErrorf("filename", "filename cannot be set when using srcs")
+ }
+ if len(p.properties.Symlinks) > 0 {
+ ctx.PropertyErrorf("symlinks", "symlinks cannot be set when using srcs")
+ }
+ if p.properties.Filename_from_src != nil {
+ ctx.PropertyErrorf("filename_from_src", "filename_from_src is implicitly set to true when using srcs")
+ }
+ p.sourceFilePaths = android.PathsForModuleSrc(ctx, p.properties.Srcs)
+ for _, src := range p.sourceFilePaths {
+ filename := src.Base()
+ output := android.PathForModuleOut(ctx, filename).OutputPath
+ ip := installProperties{
+ filename: filename,
+ sourceFilePath: src,
+ outputFilePath: output,
+ installDirPath: p.installDirPath,
+ }
+ p.outputFilePaths = append(p.outputFilePaths, output)
+ installs = append(installs, ip)
+ }
+ } else if ctx.Config().AllowMissingDependencies() {
+ // If no srcs was set and AllowMissingDependencies is enabled then
+ // mark the module as missing dependencies and set a fake source path
+ // and file name.
+ ctx.AddMissingDependencies([]string{"MISSING_PREBUILT_SRC_FILE"})
+ p.sourceFilePaths = android.Paths{android.PathForModuleSrc(ctx)}
+ if filename == "" {
+ filename = ctx.ModuleName()
+ }
+ p.outputFilePaths = android.OutputPaths{android.PathForModuleOut(ctx, filename).OutputPath}
+ ip := installProperties{
+ filename: filename,
+ sourceFilePath: p.sourceFilePaths[0],
+ outputFilePath: p.outputFilePaths[0],
+ installDirPath: p.installDirPath,
+ }
+ installs = append(installs, ip)
+ } else {
+ ctx.PropertyErrorf("src", "missing prebuilt source file")
+ return
+ }
+
+ // Call InstallFile even when uninstallable to make the module included in the package.
+ if !p.Installable() {
+ p.SkipInstall()
+ }
+ for _, ip := range installs {
+ ip.addInstallRules(ctx)
+ }
android.CollectDependencyAconfigFiles(ctx, &p.mergedAconfigFiles)
}
type installProperties struct {
- installable bool
filename string
sourceFilePath android.Path
+ outputFilePath android.OutputPath
+ installDirPath android.InstallPath
symlinks []string
}
// utility function to add install rules to the build graph.
// Reduces code duplication between Soong and Mixed build analysis
-func (p *PrebuiltEtc) addInstallRules(ctx android.ModuleContext, ip installProperties) {
- if !ip.installable {
- p.SkipInstall()
- }
-
+func (ip *installProperties) addInstallRules(ctx android.ModuleContext) {
// Copy the file from src to a location in out/ with the correct `filename`
// This ensures that outputFilePath has the correct name for others to
// use, as the source file may have a different name.
- p.outputFilePath = android.PathForModuleOut(ctx, ip.filename).OutputPath
ctx.Build(pctx, android.BuildParams{
Rule: android.Cp,
- Output: p.outputFilePath,
+ Output: ip.outputFilePath,
Input: ip.sourceFilePath,
})
- installPath := ctx.InstallFile(p.installDirPath, ip.filename, p.outputFilePath)
+ installPath := ctx.InstallFile(ip.installDirPath, ip.filename, ip.outputFilePath)
for _, sl := range ip.symlinks {
- ctx.InstallSymlink(p.installDirPath, sl, installPath)
+ ctx.InstallSymlink(ip.installDirPath, sl, installPath)
}
}
@@ -421,15 +480,15 @@
class = "ETC"
}
- return []android.AndroidMkEntries{android.AndroidMkEntries{
+ return []android.AndroidMkEntries{{
Class: class,
SubName: nameSuffix,
- OutputFile: android.OptionalPathForPath(p.outputFilePath),
+ OutputFile: android.OptionalPathForPath(p.outputFilePaths[0]),
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
entries.SetString("LOCAL_MODULE_TAGS", "optional")
entries.SetString("LOCAL_MODULE_PATH", p.installDirPath.String())
- entries.SetString("LOCAL_INSTALLED_MODULE_STEM", p.outputFilePath.Base())
+ entries.SetString("LOCAL_INSTALLED_MODULE_STEM", p.outputFilePaths[0].Base())
if len(p.properties.Symlinks) > 0 {
entries.AddStrings("LOCAL_MODULE_SYMLINKS", p.properties.Symlinks...)
}
@@ -700,7 +759,11 @@
targetArch := "arch-" + m.Target().Arch.ArchType.String()
snapshotLibOut := filepath.Join(snapshotArchDir, targetArch, "etc", m.BaseModuleName())
- snapshotOutputs = append(snapshotOutputs, copyFile(ctx, m.OutputFile(), snapshotLibOut, s.Fake))
+ outputs, _ := m.OutputFiles("")
+ for _, output := range outputs {
+ cp := copyFile(ctx, output, snapshotLibOut, s.Fake)
+ snapshotOutputs = append(snapshotOutputs, cp)
+ }
prop := snapshot.SnapshotJsonFlags{}
propOut := snapshotLibOut + ".json"
diff --git a/etc/prebuilt_etc_test.go b/etc/prebuilt_etc_test.go
index df11709..1d9aa8e 100644
--- a/etc/prebuilt_etc_test.go
+++ b/etc/prebuilt_etc_test.go
@@ -96,7 +96,7 @@
`)
p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc)
- android.AssertStringEquals(t, "output file path", "foo.installed.conf", p.outputFilePath.Base())
+ android.AssertStringEquals(t, "output file path", "foo.installed.conf", p.outputFilePaths[0].Base())
}
func TestPrebuiltEtcGlob(t *testing.T) {
@@ -113,10 +113,24 @@
`)
p := result.Module("my_foo", "android_arm64_armv8-a").(*PrebuiltEtc)
- android.AssertStringEquals(t, "my_foo output file path", "my_foo", p.outputFilePath.Base())
+ android.AssertStringEquals(t, "my_foo output file path", "my_foo", p.outputFilePaths[0].Base())
p = result.Module("my_bar", "android_arm64_armv8-a").(*PrebuiltEtc)
- android.AssertStringEquals(t, "my_bar output file path", "bar.conf", p.outputFilePath.Base())
+ android.AssertStringEquals(t, "my_bar output file path", "bar.conf", p.outputFilePaths[0].Base())
+}
+
+func TestPrebuiltEtcMultipleSrcs(t *testing.T) {
+ result := prepareForPrebuiltEtcTest.RunTestWithBp(t, `
+ prebuilt_etc {
+ name: "foo",
+ srcs: ["*.conf"],
+ }
+ `)
+
+ p := result.Module("foo", "android_arm64_armv8-a").(*PrebuiltEtc)
+ android.AssertStringEquals(t, "output file path", "bar.conf", p.outputFilePaths[0].Base())
+ android.AssertStringEquals(t, "output file path", "baz.conf", p.outputFilePaths[1].Base())
+ android.AssertStringEquals(t, "output file path", "foo.conf", p.outputFilePaths[2].Base())
}
func TestPrebuiltEtcAndroidMk(t *testing.T) {