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
This commit is contained in:
Colin Cross
2022-10-03 21:02:27 -07:00
parent a2aaa2fdef
commit 14ec66c2fb
3 changed files with 130 additions and 9 deletions

View File

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

View File

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

View File

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