Merge "Fix genrule tool dependencies when a prebuilt tool is preferred." am: 3a1a4b070e am: 6656d4671a

Original change: https://android-review.googlesource.com/c/platform/build/soong/+/1946708

Change-Id: Ibdde2fed1b43a945c5f5001e69f2b908cff0e48b
This commit is contained in:
Martin Stjernholm 2022-01-13 08:14:57 +00:00 committed by Automerger Merge Worker
commit e163811966
3 changed files with 155 additions and 0 deletions

View file

@ -309,6 +309,54 @@ func GetEmbeddedPrebuilt(module Module) *Prebuilt {
return nil
}
// PrebuiltGetPreferred returns the module that is preferred for the given
// module. That is either the module itself or the prebuilt counterpart that has
// taken its place. The given module must be a direct dependency of the current
// context module, and it must be the source module if both source and prebuilt
// exist.
//
// This function is for use on dependencies after PrebuiltPostDepsMutator has
// run - any dependency that is registered before that will already reference
// the right module. This function is only safe to call after all mutators that
// may call CreateVariations, e.g. in GenerateAndroidBuildActions.
func PrebuiltGetPreferred(ctx BaseModuleContext, module Module) Module {
if !module.IsReplacedByPrebuilt() {
return module
}
if IsModulePrebuilt(module) {
// If we're given a prebuilt then assume there's no source module around.
return module
}
sourceModDepFound := false
var prebuiltMod Module
ctx.WalkDeps(func(child, parent Module) bool {
if prebuiltMod != nil {
return false
}
if parent == ctx.Module() {
// First level: Only recurse if the module is found as a direct dependency.
sourceModDepFound = child == module
return sourceModDepFound
}
// Second level: Follow PrebuiltDepTag to the prebuilt.
if t := ctx.OtherModuleDependencyTag(child); t == PrebuiltDepTag {
prebuiltMod = child
}
return false
})
if prebuiltMod == nil {
if !sourceModDepFound {
panic(fmt.Errorf("Failed to find source module as a direct dependency: %s", module))
} else {
panic(fmt.Errorf("Failed to find prebuilt for source module: %s", module))
}
}
return prebuiltMod
}
func RegisterPrebuiltsPreArchMutators(ctx RegisterMutatorsContext) {
ctx.BottomUp("prebuilt_rename", PrebuiltRenameMutator).Parallel()
}

View file

@ -106,6 +106,16 @@ type hostToolDependencyTag struct {
android.LicenseAnnotationToolchainDependencyTag
label string
}
func (t hostToolDependencyTag) AllowDisabledModuleDependency(target android.Module) bool {
// Allow depending on a disabled module if it's replaced by a prebuilt
// counterpart. We get the prebuilt through android.PrebuiltGetPreferred in
// GenerateAndroidBuildActions.
return target.IsReplacedByPrebuilt()
}
var _ android.AllowDisabledModuleDependency = (*hostToolDependencyTag)(nil)
type generatorProperties struct {
// The command to run on one or more input files. Cmd supports substitution of a few variables.
//
@ -298,6 +308,12 @@ func (g *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) {
switch tag := ctx.OtherModuleDependencyTag(module).(type) {
case hostToolDependencyTag:
tool := ctx.OtherModuleName(module)
if m, ok := module.(android.Module); ok {
// Necessary to retrieve any prebuilt replacement for the tool, since
// toolDepsMutator runs too late for the prebuilt mutators to have
// replaced the dependency.
module = android.PrebuiltGetPreferred(ctx, m)
}
switch t := module.(type) {
case android.HostToolProvider:

View file

@ -34,7 +34,9 @@ var prepareForGenRuleTest = android.GroupFixturePreparers(
android.PrepareForTestWithFilegroup,
PrepareForTestWithGenRuleBuildComponents,
android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
android.RegisterPrebuiltMutators(ctx)
ctx.RegisterModuleType("tool", toolFactory)
ctx.RegisterModuleType("prebuilt_tool", prebuiltToolFactory)
ctx.RegisterModuleType("output", outputProducerFactory)
ctx.RegisterModuleType("use_source", useSourceFactory)
}),
@ -720,6 +722,69 @@ func TestGenruleOutputFiles(t *testing.T) {
result.ModuleForTests("gen_all", "").Module().(*useSource).srcs)
}
func TestPrebuiltTool(t *testing.T) {
testcases := []struct {
name string
bp string
expectedToolName string
}{
{
name: "source only",
bp: `
tool { name: "tool" }
`,
expectedToolName: "bin/tool",
},
{
name: "prebuilt only",
bp: `
prebuilt_tool { name: "tool" }
`,
expectedToolName: "prebuilt_bin/tool",
},
{
name: "source preferred",
bp: `
tool { name: "tool" }
prebuilt_tool { name: "tool" }
`,
expectedToolName: "bin/tool",
},
{
name: "prebuilt preferred",
bp: `
tool { name: "tool" }
prebuilt_tool { name: "tool", prefer: true }
`,
expectedToolName: "prebuilt_bin/prebuilt_tool",
},
{
name: "source disabled",
bp: `
tool { name: "tool", enabled: false }
prebuilt_tool { name: "tool" }
`,
expectedToolName: "prebuilt_bin/prebuilt_tool",
},
}
for _, test := range testcases {
t.Run(test.name, func(t *testing.T) {
result := prepareForGenRuleTest.RunTestWithBp(t, test.bp+`
genrule {
name: "gen",
tools: ["tool"],
out: ["foo"],
cmd: "$(location tool)",
}
`)
gen := result.Module("gen", "").(*Module)
expectedCmd := "__SBOX_SANDBOX_DIR__/tools/out/" + test.expectedToolName
android.AssertStringEquals(t, "command", expectedCmd, gen.rawCommands[0])
})
}
}
func TestGenruleWithBazel(t *testing.T) {
bp := `
genrule {
@ -764,7 +829,33 @@ func (t *testTool) HostToolPath() android.OptionalPath {
return android.OptionalPathForPath(t.outputFile)
}
type prebuiltTestTool struct {
android.ModuleBase
prebuilt android.Prebuilt
testTool
}
func (p *prebuiltTestTool) Name() string {
return p.prebuilt.Name(p.ModuleBase.Name())
}
func (p *prebuiltTestTool) Prebuilt() *android.Prebuilt {
return &p.prebuilt
}
func (t *prebuiltTestTool) GenerateAndroidBuildActions(ctx android.ModuleContext) {
t.outputFile = ctx.InstallFile(android.PathForModuleInstall(ctx, "prebuilt_bin"), ctx.ModuleName(), android.PathForOutput(ctx, ctx.ModuleName()))
}
func prebuiltToolFactory() android.Module {
module := &prebuiltTestTool{}
android.InitPrebuiltModuleWithoutSrcs(module)
android.InitAndroidArchModule(module, android.HostSupported, android.MultilibFirst)
return module
}
var _ android.HostToolProvider = (*testTool)(nil)
var _ android.HostToolProvider = (*prebuiltTestTool)(nil)
type testOutputProducer struct {
android.ModuleBase