From 14ec66c2fba30e951b175d2a70c7cf62438eb5d3 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Mon, 3 Oct 2022 21:02:27 -0700 Subject: [PATCH] Make OutputFileForModule work for AllowMissingDependencies Report missing output files as missing dependencies when AllowMissingDependencies is enabled. This will fix AllowMissingDependencies builds where a dependency module is present but missing support for a specific architecture. Bug: 250918230 Test: lunch aosp_riscv64-userdebug && m ALLOW_MISSING_DEPENDENCIES=true nothing Test: TestOutputFileForModule Change-Id: I95e96e3e7cb3df7bf678ed628b45baf659addbad --- android/android_test.go | 26 ++++++++++++- android/module.go | 27 +++++++++---- android/module_test.go | 86 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 130 insertions(+), 9 deletions(-) diff --git a/android/android_test.go b/android/android_test.go index fb82e3765..64ceedc4d 100644 --- a/android/android_test.go +++ b/android/android_test.go @@ -15,10 +15,32 @@ package android import ( + "io/ioutil" "os" "testing" ) -func TestMain(m *testing.M) { - os.Exit(m.Run()) +var buildDir string + +func setUp() { + var err error + buildDir, err = ioutil.TempDir("", "android_test") + if err != nil { + panic(err) + } +} + +func tearDown() { + os.RemoveAll(buildDir) +} + +func TestMain(m *testing.M) { + run := func() int { + setUp() + defer tearDown() + + return m.Run() + } + + os.Exit(run()) } diff --git a/android/module.go b/android/module.go index a150e6191..68d9f8e75 100644 --- a/android/module.go +++ b/android/module.go @@ -3546,10 +3546,29 @@ func OutputFileForModule(ctx PathContext, module blueprint.Module, tag string) P reportPathError(ctx, err) return nil } + if len(paths) == 0 { + type addMissingDependenciesIntf interface { + AddMissingDependencies([]string) + OtherModuleName(blueprint.Module) string + } + if mctx, ok := ctx.(addMissingDependenciesIntf); ok && ctx.Config().AllowMissingDependencies() { + mctx.AddMissingDependencies([]string{mctx.OtherModuleName(module)}) + } else { + ReportPathErrorf(ctx, "failed to get output files from module %q", pathContextName(ctx, module)) + } + // Return a fake output file to avoid nil dereferences of Path objects later. + // This should never get used for an actual build as the error or missing + // dependency has already been reported. + p, err := pathForSource(ctx, filepath.Join("missing_output_file", pathContextName(ctx, module))) + if err != nil { + reportPathError(ctx, err) + return nil + } + return p + } if len(paths) > 1 { ReportPathErrorf(ctx, "got multiple output files from module %q, expected exactly one", pathContextName(ctx, module)) - return nil } return paths[0] } @@ -3561,18 +3580,12 @@ func outputFilesForModule(ctx PathContext, module blueprint.Module, tag string) return nil, fmt.Errorf("failed to get output file from module %q: %s", pathContextName(ctx, module), err.Error()) } - if len(paths) == 0 { - return nil, fmt.Errorf("failed to get output files from module %q", pathContextName(ctx, module)) - } return paths, nil } else if sourceFileProducer, ok := module.(SourceFileProducer); ok { if tag != "" { return nil, fmt.Errorf("module %q is a SourceFileProducer, not an OutputFileProducer, and so does not support tag %q", pathContextName(ctx, module), tag) } paths := sourceFileProducer.Srcs() - if len(paths) == 0 { - return nil, fmt.Errorf("failed to get output files from module %q", pathContextName(ctx, module)) - } return paths, nil } else { return nil, fmt.Errorf("module %q is not an OutputFileProducer", pathContextName(ctx, module)) diff --git a/android/module_test.go b/android/module_test.go index 0580bef24..1ca742213 100644 --- a/android/module_test.go +++ b/android/module_test.go @@ -15,6 +15,7 @@ package android import ( + "github.com/google/blueprint" "path/filepath" "runtime" "testing" @@ -978,3 +979,88 @@ func TestSetAndroidMkEntriesWithTestOptions(t *testing.T) { }) } } + +type fakeBlueprintModule struct{} + +func (fakeBlueprintModule) Name() string { return "foo" } + +func (fakeBlueprintModule) GenerateBuildActions(blueprint.ModuleContext) {} + +type sourceProducerTestModule struct { + fakeBlueprintModule + source Path +} + +func (s sourceProducerTestModule) Srcs() Paths { return Paths{s.source} } + +type outputFileProducerTestModule struct { + fakeBlueprintModule + output map[string]Path + error map[string]error +} + +func (o outputFileProducerTestModule) OutputFiles(tag string) (Paths, error) { + return PathsIfNonNil(o.output[tag]), o.error[tag] +} + +type pathContextAddMissingDependenciesWrapper struct { + PathContext + missingDeps []string +} + +func (p *pathContextAddMissingDependenciesWrapper) AddMissingDependencies(deps []string) { + p.missingDeps = append(p.missingDeps, deps...) +} +func (p *pathContextAddMissingDependenciesWrapper) OtherModuleName(module blueprint.Module) string { + return module.Name() +} + +func TestOutputFileForModule(t *testing.T) { + testcases := []struct { + name string + module blueprint.Module + tag string + env map[string]string + config func(*config) + expected string + missingDeps []string + }{ + { + name: "SourceFileProducer", + module: &sourceProducerTestModule{source: PathForTesting("foo.txt")}, + expected: "foo.txt", + }, + { + name: "OutputFileProducer", + module: &outputFileProducerTestModule{output: map[string]Path{"": PathForTesting("foo.txt")}}, + expected: "foo.txt", + }, + { + name: "OutputFileProducer_tag", + module: &outputFileProducerTestModule{output: map[string]Path{"foo": PathForTesting("foo.txt")}}, + tag: "foo", + expected: "foo.txt", + }, + { + name: "OutputFileProducer_AllowMissingDependencies", + config: func(config *config) { + config.TestProductVariables.Allow_missing_dependencies = boolPtr(true) + }, + module: &outputFileProducerTestModule{}, + missingDeps: []string{"foo"}, + expected: "missing_output_file/foo", + }, + } + for _, tt := range testcases { + config := TestConfig(buildDir, tt.env, "", nil) + if tt.config != nil { + tt.config(config.config) + } + ctx := &pathContextAddMissingDependenciesWrapper{ + PathContext: PathContextForTesting(config), + } + got := OutputFileForModule(ctx, tt.module, tt.tag) + AssertPathRelativeToTopEquals(t, "expected source path", tt.expected, got) + AssertArrayString(t, "expected missing deps", tt.missingDeps, ctx.missingDeps) + } +}