Skip to content

Commit

Permalink
Support multiple sources for prebuilt_etc
Browse files Browse the repository at this point in the history
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
  • Loading branch information
tweksteen authored and ReveRTX committed Mar 29, 2024
1 parent ba7a8a7 commit 76c205d
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 65 deletions.
15 changes: 10 additions & 5 deletions apex/apex.go
Original file line number Diff line number Diff line change
Expand Up @@ -1609,10 +1609,9 @@ func apexFileForShBinary(ctx android.BaseModuleContext, sh *sh.ShBinary) apexFil
return af
}

func apexFileForPrebuiltEtc(ctx android.BaseModuleContext, prebuilt prebuilt_etc.PrebuiltEtcModule, depName string) apexFile {
func apexFileForPrebuiltEtc(ctx android.BaseModuleContext, prebuilt prebuilt_etc.PrebuiltEtcModule, outputFile android.Path) apexFile {
dirInApex := filepath.Join(prebuilt.BaseDir(), prebuilt.SubDir())
fileToCopy := prebuilt.OutputFile()
return newApexFile(ctx, fileToCopy, depName, dirInApex, etc, prebuilt)
return newApexFile(ctx, outputFile, outputFile.Base(), dirInApex, etc, prebuilt)
}

func apexFileForCompatConfig(ctx android.BaseModuleContext, config java.PlatformCompatConfigIntf, depName string) apexFile {
Expand Down Expand Up @@ -2078,7 +2077,10 @@ func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext,
}
case prebuiltTag:
if prebuilt, ok := child.(prebuilt_etc.PrebuiltEtcModule); ok {
vctx.filesInfo = append(vctx.filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName))
filesToCopy, _ := prebuilt.OutputFiles("")
for _, etcFile := range filesToCopy {
vctx.filesInfo = append(vctx.filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, etcFile))
}
} else {
ctx.PropertyErrorf("prebuilts", "%q is not a prebuilt_etc module", depName)
}
Expand Down Expand Up @@ -2217,7 +2219,10 @@ func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext,
// Because APK-in-APEX embeds jni_libs transitively, we don't need to track transitive deps
} else if java.IsXmlPermissionsFileDepTag(depTag) {
if prebuilt, ok := child.(prebuilt_etc.PrebuiltEtcModule); ok {
vctx.filesInfo = append(vctx.filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName))
filesToCopy, _ := prebuilt.OutputFiles("")
for _, etcFile := range filesToCopy {
vctx.filesInfo = append(vctx.filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, etcFile))
}
}
} else if rust.IsDylibDepTag(depTag) {
if rustm, ok := child.(*rust.Module); ok && rustm.IsInstallableToApex() {
Expand Down
173 changes: 118 additions & 55 deletions etc/prebuilt_etc.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,15 @@ var PrepareForTestWithPrebuiltEtc = android.FixtureRegisterWithContext(RegisterP

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
Expand Down Expand Up @@ -127,9 +132,9 @@ type PrebuiltEtcModule interface {
// 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 {
Expand All @@ -142,8 +147,8 @@ type PrebuiltEtc struct {
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
Expand Down Expand Up @@ -243,6 +248,9 @@ func (p *PrebuiltEtc) SetImageVariation(ctx android.BaseModuleContext, variation
}

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))
}

Expand All @@ -257,15 +265,18 @@ func (p *PrebuiltEtc) SetAdditionalDependencies(paths android.Paths) {
}

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)

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)
}
Expand Down Expand Up @@ -298,11 +309,44 @@ func (p *PrebuiltEtc) ExcludeFromRecoverySnapshot() bool {
return false
}

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
if p.Target().Arch.ArchType.Multilib == "lib64" && p.installDirBase64 != "" {
installBaseDir = p.installDirBase64
}
if p.SocSpecific() && p.socInstallDirBase != "" {
installBaseDir = p.socInstallDirBase
}
if p.installAvoidMultilibConflict && !ctx.Host() && ctx.Config().HasMultilibConflict(ctx.Arch().ArchType) {
installBaseDir = filepath.Join(installBaseDir, ctx.Arch().ArchType.String())
}
return installBaseDir
}

func (p *PrebuiltEtc) GenerateAndroidBuildActions(ctx android.ModuleContext) {
var installs []installProperties

if p.properties.Src != nil && len(p.properties.Srcs) > 0 {
ctx.PropertyErrorf("src", "src is set. Cannot set srcs")
}

// 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.sourceFilePath = android.PathForModuleSrc(ctx, proptools.String(p.properties.Src))
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.
Expand All @@ -314,86 +358,101 @@ func (p *PrebuiltEtc) GenerateAndroidBuildActions(ctx android.ModuleContext) {
return
}
} else if filenameFromSrc {
filename = p.sourceFilePath.Base()
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.sourceFilePath = android.PathForModuleSrc(ctx)
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
}

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")
}

// If soc install dir was specified and SOC specific is set, set the installDirPath to the
// specified socInstallDirBase.
installBaseDir := p.installDirBase
if p.Target().Arch.ArchType.Multilib == "lib64" && p.installDirBase64 != "" {
installBaseDir = p.installDirBase64
}
if p.SocSpecific() && p.socInstallDirBase != "" {
installBaseDir = p.socInstallDirBase
}
if p.installAvoidMultilibConflict && !ctx.Host() && ctx.Config().HasMultilibConflict(ctx.Arch().ArchType) {
installBaseDir = filepath.Join(installBaseDir, ctx.Arch().ArchType.String())
// Call InstallFile even when uninstallable to make the module included in the package.
if !p.Installable() {
p.SkipInstall()
}

p.installDirPath = android.PathForModuleInstall(ctx, installBaseDir, p.SubDir())

// 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,
for _, ip := range installs {
ip.addInstallRules(ctx)
}
p.addInstallRules(ctx, ip)
}

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)
}
}

Expand All @@ -417,15 +476,15 @@ func (p *PrebuiltEtc) AndroidMkEntries() []android.AndroidMkEntries {
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...)
}
Expand Down Expand Up @@ -691,7 +750,11 @@ func generatePrebuiltSnapshot(s snapshot.SnapshotSingleton, ctx android.Singleto
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"
Expand Down
20 changes: 17 additions & 3 deletions etc/prebuilt_etc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ func TestPrebuiltEtcOutputPath(t *testing.T) {
`)

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) {
Expand All @@ -113,10 +113,24 @@ func TestPrebuiltEtcGlob(t *testing.T) {
`)

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) {
Expand Down
7 changes: 5 additions & 2 deletions java/sdk_library.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (

"android/soong/android"
"android/soong/dexpreopt"
"android/soong/etc"
)

const (
Expand Down Expand Up @@ -2935,10 +2936,12 @@ func (module *sdkLibraryXml) SubDir() string {
}

// from android.PrebuiltEtcModule
func (module *sdkLibraryXml) OutputFile() android.OutputPath {
return module.outputFilePath
func (module *sdkLibraryXml) OutputFiles(tag string) (android.Paths, error) {
return android.OutputPaths{module.outputFilePath}.Paths(), nil
}

var _ etc.PrebuiltEtcModule = (*sdkLibraryXml)(nil)

// from android.ApexModule
func (module *sdkLibraryXml) AvailableFor(what string) bool {
return true
Expand Down

0 comments on commit 76c205d

Please sign in to comment.