From 756d3400d67b4cff3ba0f403c1f54356e4911e46 Mon Sep 17 00:00:00 2001 From: Spandan Das Date: Mon, 5 Jun 2023 22:49:50 +0000 Subject: [PATCH] Mixed builds support for prebuilt_* targets These targets do not have any build actions per se, but return a PrebuiltFileInfo provider. Parse this info from cquery and generate the appropriate installation rules and androidmk entries Details - Support the bp2build available properties. Not all properties have been converted by bp2build yet, and those are being tracked in b/207489266 - Create a addInstallRules helper function to reduce duplication between GenerateAndroidBuildActions and ProcessBazelQueryResponse Test: unit test Bug: 280094612 Change-Id: Ia67986af1dd2ff4712586dbec86ee9fda380f726 --- etc/prebuilt_etc.go | 80 ++++++++++++++++++++++++++++++++++------ etc/prebuilt_etc_test.go | 39 ++++++++++++++++++++ 2 files changed, 107 insertions(+), 12 deletions(-) diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go index 3e1bbded6..370a4235b 100644 --- a/etc/prebuilt_etc.go +++ b/etc/prebuilt_etc.go @@ -38,6 +38,7 @@ import ( "android/soong/android" "android/soong/bazel" + "android/soong/bazel/cquery" "android/soong/snapshot" ) @@ -329,7 +330,6 @@ func (p *PrebuiltEtc) GenerateAndroidBuildActions(ctx android.ModuleContext) { ctx.PropertyErrorf("src", "missing prebuilt source file") return } - p.outputFilePath = android.PathForModuleOut(ctx, filename).OutputPath if strings.Contains(filename, "/") { ctx.PropertyErrorf("filename", "filename cannot contain separator '/'") @@ -349,21 +349,42 @@ func (p *PrebuiltEtc) GenerateAndroidBuildActions(ctx android.ModuleContext) { } p.installDirPath = android.PathForModuleInstall(ctx, installBaseDir, p.SubDir()) - // This ensures that outputFilePath has the correct name for others to - // use, as the source file may have a different name. - ctx.Build(pctx, android.BuildParams{ - Rule: android.Cp, - Output: p.outputFilePath, - Input: p.sourceFilePath, - }) + // 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, + } + p.addInstallRules(ctx, ip) +} - if !p.Installable() { +type installProperties struct { + installable bool + filename string + sourceFilePath android.Path + 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() } - // Call InstallFile even when uninstallable to make the module included in the package - installPath := ctx.InstallFile(p.installDirPath, p.outputFilePath.Base(), p.outputFilePath) - for _, sl := range p.properties.Symlinks { + // 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, + Input: ip.sourceFilePath, + }) + + installPath := ctx.InstallFile(p.installDirPath, ip.filename, p.outputFilePath) + for _, sl := range ip.symlinks { ctx.InstallSymlink(p.installDirPath, sl, installPath) } } @@ -781,3 +802,38 @@ func (module *PrebuiltEtc) ConvertWithBp2build(ctx android.TopDownMutatorContext ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name()}, attrs) } + +var _ android.MixedBuildBuildable = (*PrebuiltEtc)(nil) + +func (pe *PrebuiltEtc) IsMixedBuildSupported(ctx android.BaseModuleContext) bool { + return true +} + +func (pe *PrebuiltEtc) QueueBazelCall(ctx android.BaseModuleContext) { + ctx.Config().BazelContext.QueueBazelRequest( + pe.GetBazelLabel(ctx, pe), + cquery.GetPrebuiltFileInfo, + android.GetConfigKey(ctx), + ) +} + +func (pe *PrebuiltEtc) ProcessBazelQueryResponse(ctx android.ModuleContext) { + bazelCtx := ctx.Config().BazelContext + pfi, err := bazelCtx.GetPrebuiltFileInfo(pe.GetBazelLabel(ctx, pe), android.GetConfigKey(ctx)) + if err != nil { + ctx.ModuleErrorf(err.Error()) + return + } + + // Set properties for androidmk + pe.installDirPath = android.PathForModuleInstall(ctx, pfi.Dir) + + // Installation rules + ip := installProperties{ + installable: pfi.Installable, + filename: pfi.Filename, + sourceFilePath: android.PathForSource(ctx, pfi.Src), + // symlinks: pe.properties.Symlinks, // TODO: b/207489266 - Fully support all properties in prebuilt_file + } + pe.addInstallRules(ctx, ip) +} diff --git a/etc/prebuilt_etc_test.go b/etc/prebuilt_etc_test.go index 0d44c31ef..df7664d7d 100644 --- a/etc/prebuilt_etc_test.go +++ b/etc/prebuilt_etc_test.go @@ -23,6 +23,7 @@ import ( "github.com/google/blueprint/proptools" "android/soong/android" + "android/soong/bazel/cquery" "android/soong/snapshot" ) @@ -494,3 +495,41 @@ func TestPrebuiltTakeSnapshot(t *testing.T) { checkIfSnapshotNotTaken(t, result, "recovery", "prebuilt_recovery_indirect") }) } + +func TestPrebuiltEtcAndroidMkEntriesWithBazel(t *testing.T) { + t.Parallel() + bp := ` +prebuilt_etc { + name: "myetc", + src: "prebuilt_etc.rc", // filename in src tree + filename: "init.rc", // target filename on device + sub_dir: "subdir", // relative subdir for installation + bazel_module: { label: "//foo/bar:myetc" }, +} +` + res := android.GroupFixturePreparers( + prepareForPrebuiltEtcTest, + android.FixtureModifyConfig(func(cfg android.Config) { + cfg.BazelContext = android.MockBazelContext{ + LabelToPrebuiltFileInfo: map[string]cquery.PrebuiltFileInfo{ + "//foo/bar:myetc": cquery.PrebuiltFileInfo{ + Src: "foo/bar/prebuilt_etc.rc", + Dir: "etc/subdir", + Filename: "init.rc", + Installable: true, + }, + }, + } + }), + ).RunTestWithBp(t, bp) + ctx := res.ModuleForTests("myetc", "android_arm64_armv8-a") + mod := ctx.Module() + entries := android.AndroidMkEntriesForTest(t, res.TestContext, mod)[0] + // verify androidmk entries + android.AssertStringDoesContain(t, "LOCAL_MODULE_PATH should contain", entries.EntryMap["LOCAL_MODULE_PATH"][0], "etc/subdir") + android.AssertStringEquals(t, "LOCAL_INSTALLED_MODULE_STEM is incorrect", "init.rc", entries.EntryMap["LOCAL_INSTALLED_MODULE_STEM"][0]) + // verify installation rules + install := ctx.Description("install") + android.AssertStringEquals(t, "Source location of prebuilt_etc installation", "out/soong/.intermediates/myetc/android_arm64_armv8-a/init.rc", install.Input.String()) + android.AssertStringEquals(t, "Target location of prebuilt_etc installation", "out/soong/target/product/test_device/system/etc/subdir/init.rc", install.Output.String()) +}