From 59037628f4232b98887738d3598a5567798d1809 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Mon, 10 Jun 2019 13:12:56 -0700 Subject: [PATCH 1/6] Add GenerateAndroidBuildActions to DefaultsModuleBase Add an empty GenerateAndroidBuildActiosn to DefaultsModuleBase so that every defaults module doesn't need to provide one. This will also allow adding an implementation in the next patch. Test: m checkbuild Change-Id: I13554bdb3a287c2f18e1efab74d4f08a1ba8620c --- android/defaults.go | 3 +++ android/visibility_test.go | 3 --- apex/apex.go | 3 --- cc/cc.go | 3 --- genrule/genrule.go | 3 --- java/droiddoc.go | 3 --- java/java.go | 3 --- 7 files changed, 3 insertions(+), 18 deletions(-) diff --git a/android/defaults.go b/android/defaults.go index d4fbf487d..844b4d408 100644 --- a/android/defaults.go +++ b/android/defaults.go @@ -80,6 +80,9 @@ func (d *DefaultsModuleBase) properties() []interface{} { return d.defaultableProperties } +func (d *DefaultsModuleBase) GenerateAndroidBuildActions(ctx ModuleContext) { +} + func InitDefaultsModule(module DefaultableModule) { module.AddProperties( &hostAndDeviceProperties{}, diff --git a/android/visibility_test.go b/android/visibility_test.go index 09c5b1b34..5ea32a2ef 100644 --- a/android/visibility_test.go +++ b/android/visibility_test.go @@ -759,6 +759,3 @@ func defaultsFactory() Module { InitDefaultsModule(m) return m } - -func (*mockDefaults) GenerateAndroidBuildActions(ctx ModuleContext) { -} diff --git a/apex/apex.go b/apex/apex.go index 41a21c92c..11b433c95 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -1295,9 +1295,6 @@ type Defaults struct { android.DefaultsModuleBase } -func (*Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) { -} - func defaultsFactory() android.Module { return DefaultsFactory() } diff --git a/cc/cc.go b/cc/cc.go index 559fe4b8f..62f3995dd 100644 --- a/cc/cc.go +++ b/cc/cc.go @@ -2036,9 +2036,6 @@ type Defaults struct { android.ApexModuleBase } -func (*Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) { -} - // cc_defaults provides a set of properties that can be inherited by other cc // modules. A module can use the properties from a cc_defaults using // `defaults: ["<:default_module_name>"]`. Properties of both modules are diff --git a/genrule/genrule.go b/genrule/genrule.go index 87e6747e9..b08d3492f 100644 --- a/genrule/genrule.go +++ b/genrule/genrule.go @@ -582,9 +582,6 @@ type Defaults struct { android.DefaultsModuleBase } -func (*Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) { -} - func defaultsFactory() android.Module { return DefaultsFactory() } diff --git a/java/droiddoc.go b/java/droiddoc.go index 0ec7799a8..c6e85b755 100644 --- a/java/droiddoc.go +++ b/java/droiddoc.go @@ -1808,9 +1808,6 @@ type DocDefaults struct { android.DefaultsModuleBase } -func (*DocDefaults) GenerateAndroidBuildActions(ctx android.ModuleContext) { -} - func DocDefaultsFactory() android.Module { module := &DocDefaults{} diff --git a/java/java.go b/java/java.go index fee262d83..a1addb38c 100644 --- a/java/java.go +++ b/java/java.go @@ -2131,9 +2131,6 @@ type Defaults struct { android.DefaultsModuleBase } -func (*Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) { -} - // java_defaults provides a set of properties that can be inherited by other java or android modules. // // A module can use the properties from a java_defaults module using `defaults: ["defaults_module_name"]`. Each From 6c4f21f3a14dbd05d5fb36067c8175f54887b689 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Thu, 6 Jun 2019 15:41:36 -0700 Subject: [PATCH 2/6] Reimplement AddMissingDependencies AddMissingDependencies is needed in BaseModuleContext in order to allow PathsForModuleSrc and friends to be called in mutators, It's not a simple move, as it currently writes to a module field that would be lost if any mutators cloned new variants by calling CreateVariations. Reimplement it using a mutated property instead. Test: m checkbuild Change-Id: I851125065e4c5302b552773dae4640426c62965e --- android/module.go | 28 +++++++++++++++++++++------- android/paths_test.go | 5 +++++ 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/android/module.go b/android/module.go index 88eba87db..2481000fe 100644 --- a/android/module.go +++ b/android/module.go @@ -338,6 +338,8 @@ type commonProperties struct { SkipInstall bool `blueprint:"mutated"` NamespaceExportedToMake bool `blueprint:"mutated"` + + MissingDeps []string `blueprint:"mutated"` } type hostAndDeviceProperties struct { @@ -841,10 +843,14 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) baseModuleContext: m.baseModuleContextFactory(blueprintCtx), installDeps: m.computeInstallDeps(blueprintCtx), installFiles: m.installFiles, - missingDeps: blueprintCtx.GetMissingDependencies(), variables: make(map[string]string), } + // Temporarily continue to call blueprintCtx.GetMissingDependencies() to maintain the previous behavior of never + // reporting missing dependency errors in Blueprint when AllowMissingDependencies == true. + // TODO: This will be removed once defaults modules handle missing dependency errors + blueprintCtx.GetMissingDependencies() + if ctx.config.captureBuild { ctx.ruleParams = make(map[blueprint.Rule]blueprint.RuleParams) } @@ -931,7 +937,6 @@ type moduleContext struct { installDeps Paths installFiles Paths checkbuildFiles Paths - missingDeps []string module Module // For tests @@ -1032,24 +1037,33 @@ func (m *moduleContext) Build(pctx PackageContext, params BuildParams) { bparams.Description = "${moduleDesc}" + params.Description + "${moduleDescSuffix}" } - if m.missingDeps != nil { + if missingDeps := m.GetMissingDependencies(); len(missingDeps) > 0 { m.ninjaError(bparams.Description, bparams.Outputs, fmt.Errorf("module %s missing dependencies: %s\n", - m.ModuleName(), strings.Join(m.missingDeps, ", "))) + m.ModuleName(), strings.Join(missingDeps, ", "))) return } m.ModuleContext.Build(pctx.PackageContext, bparams) } +func (m *moduleContext) Module() Module { + return m.ModuleContext.Module().(Module) +} + func (m *moduleContext) GetMissingDependencies() []string { - return m.missingDeps + var missingDeps []string + missingDeps = append(missingDeps, m.Module().base().commonProperties.MissingDeps...) + missingDeps = append(missingDeps, m.ModuleContext.GetMissingDependencies()...) + missingDeps = FirstUniqueStrings(missingDeps) + return missingDeps } func (m *moduleContext) AddMissingDependencies(deps []string) { if deps != nil { - m.missingDeps = append(m.missingDeps, deps...) - m.missingDeps = FirstUniqueStrings(m.missingDeps) + missingDeps := &m.Module().base().commonProperties.MissingDeps + *missingDeps = append(*missingDeps, deps...) + *missingDeps = FirstUniqueStrings(*missingDeps) } } diff --git a/android/paths_test.go b/android/paths_test.go index 78cfbbe78..e0c2f6c96 100644 --- a/android/paths_test.go +++ b/android/paths_test.go @@ -758,6 +758,11 @@ func (p *pathForModuleSrcTestModule) GenerateAndroidBuildActions(ctx ModuleConte if !p.props.Module_handles_missing_deps { p.missingDeps = ctx.GetMissingDependencies() } + + ctx.Build(pctx, BuildParams{ + Rule: Touch, + Output: PathForModuleOut(ctx, "output"), + }) } type pathForModuleSrcOutputFileProviderModule struct { From 2ffb9a8d7d334a17b779d1b96f1db1d001298aa0 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Mon, 10 Jun 2019 14:32:38 -0700 Subject: [PATCH 3/6] Share buildDir for android/soong/android tests There is no need to create a separate buildDir for each test file, use TestMain to create a global one for the package. Test: all soong tests Change-Id: I435ee7aa88b7e0bb8ccc1ba79f82833a7accf3e9 --- Android.bp | 1 + android/android_test.go | 46 ++++++++++++++++++++++++++++++++++++ android/namespace_test.go | 8 ------- android/neverallow_test.go | 8 ------- android/paths_test.go | 20 ---------------- android/prebuilt_etc_test.go | 19 +-------------- android/prebuilt_test.go | 8 ------- android/rule_builder_test.go | 8 ------- android/sh_binary_test.go | 8 ------- android/visibility_test.go | 8 ------- android/vts_config_test.go | 8 ------- 11 files changed, 48 insertions(+), 94 deletions(-) create mode 100644 android/android_test.go diff --git a/Android.bp b/Android.bp index 4db98f851..ec4eb61e9 100644 --- a/Android.bp +++ b/Android.bp @@ -78,6 +78,7 @@ bootstrap_go_package { "android/env.go", ], testSrcs: [ + "android/android_test.go", "android/arch_test.go", "android/config_test.go", "android/expand_test.go", diff --git a/android/android_test.go b/android/android_test.go new file mode 100644 index 000000000..46b705468 --- /dev/null +++ b/android/android_test.go @@ -0,0 +1,46 @@ +// Copyright 2019 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package android + +import ( + "io/ioutil" + "os" + "testing" +) + +var buildDir string + +func setUp() { + var err error + buildDir, err = ioutil.TempDir("", "soong_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/namespace_test.go b/android/namespace_test.go index 9a791a534..51a0af225 100644 --- a/android/namespace_test.go +++ b/android/namespace_test.go @@ -16,8 +16,6 @@ package android import ( "errors" - "io/ioutil" - "os" "path/filepath" "reflect" "testing" @@ -613,12 +611,6 @@ func mockFiles(bps map[string]string) (files map[string][]byte) { } func setupTestFromFiles(bps map[string][]byte) (ctx *TestContext, errs []error) { - buildDir, err := ioutil.TempDir("", "soong_namespace_test") - if err != nil { - return nil, []error{err} - } - defer os.RemoveAll(buildDir) - config := TestConfig(buildDir, nil) ctx = NewTestContext() diff --git a/android/neverallow_test.go b/android/neverallow_test.go index 00c51eaab..d0d22d890 100644 --- a/android/neverallow_test.go +++ b/android/neverallow_test.go @@ -15,8 +15,6 @@ package android import ( - "io/ioutil" - "os" "testing" ) @@ -151,12 +149,6 @@ var neverallowTests = []struct { } func TestNeverallow(t *testing.T) { - buildDir, err := ioutil.TempDir("", "soong_neverallow_test") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(buildDir) - config := TestConfig(buildDir, nil) for _, test := range neverallowTests { diff --git a/android/paths_test.go b/android/paths_test.go index e0c2f6c96..7bcfe41d1 100644 --- a/android/paths_test.go +++ b/android/paths_test.go @@ -17,8 +17,6 @@ package android import ( "errors" "fmt" - "io/ioutil" - "os" "reflect" "strings" "testing" @@ -880,12 +878,6 @@ func testPathForModuleSrc(t *testing.T, buildDir string, tests []pathForModuleSr } func TestPathsForModuleSrc(t *testing.T) { - buildDir, err := ioutil.TempDir("", "soong_paths_for_module_src_test") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(buildDir) - tests := []pathForModuleSrcTestCase{ { name: "path", @@ -966,12 +958,6 @@ func TestPathsForModuleSrc(t *testing.T) { } func TestPathForModuleSrc(t *testing.T) { - buildDir, err := ioutil.TempDir("", "soong_path_for_module_src_test") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(buildDir) - tests := []pathForModuleSrcTestCase{ { name: "path", @@ -1039,12 +1025,6 @@ func TestPathForModuleSrc(t *testing.T) { } func TestPathsForModuleSrc_AllowMissingDependencies(t *testing.T) { - buildDir, err := ioutil.TempDir("", "soong_paths_for_module_src_allow_missing_dependencies_test") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(buildDir) - config := TestConfig(buildDir, nil) config.TestProductVariables.Allow_missing_dependencies = proptools.BoolPtr(true) diff --git a/android/prebuilt_etc_test.go b/android/prebuilt_etc_test.go index d977c307e..0a2c7a4f5 100644 --- a/android/prebuilt_etc_test.go +++ b/android/prebuilt_etc_test.go @@ -15,16 +15,13 @@ package android import ( - "io/ioutil" - "os" "path/filepath" "reflect" "testing" ) func testPrebuiltEtc(t *testing.T, bp string) (*TestContext, Config) { - config, buildDir := setUp(t) - defer tearDown(buildDir) + config := TestArchConfig(buildDir, nil) ctx := NewTestArchContext() ctx.RegisterModuleType("prebuilt_etc", ModuleFactoryAdaptor(PrebuiltEtcFactory)) ctx.RegisterModuleType("prebuilt_etc_host", ModuleFactoryAdaptor(PrebuiltEtcHostFactory)) @@ -51,20 +48,6 @@ func testPrebuiltEtc(t *testing.T, bp string) (*TestContext, Config) { return ctx, config } -func setUp(t *testing.T) (config Config, buildDir string) { - buildDir, err := ioutil.TempDir("", "soong_prebuilt_etc_test") - if err != nil { - t.Fatal(err) - } - - config = TestArchConfig(buildDir, nil) - return -} - -func tearDown(buildDir string) { - os.RemoveAll(buildDir) -} - func TestPrebuiltEtcVariants(t *testing.T) { ctx, _ := testPrebuiltEtc(t, ` prebuilt_etc { diff --git a/android/prebuilt_test.go b/android/prebuilt_test.go index a5b85c8c2..0a18e2c90 100644 --- a/android/prebuilt_test.go +++ b/android/prebuilt_test.go @@ -16,8 +16,6 @@ package android import ( "fmt" - "io/ioutil" - "os" "testing" "github.com/google/blueprint" @@ -127,12 +125,6 @@ var prebuiltsTests = []struct { } func TestPrebuilts(t *testing.T) { - buildDir, err := ioutil.TempDir("", "soong_prebuilt_test") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(buildDir) - config := TestConfig(buildDir, nil) for _, test := range prebuiltsTests { diff --git a/android/rule_builder_test.go b/android/rule_builder_test.go index df0f25640..cfbc2abee 100644 --- a/android/rule_builder_test.go +++ b/android/rule_builder_test.go @@ -16,8 +16,6 @@ package android import ( "fmt" - "io/ioutil" - "os" "path/filepath" "reflect" "strings" @@ -418,12 +416,6 @@ func testRuleBuilder_Build(ctx BuilderContext, in Path, out, outDep, outDir Writ } func TestRuleBuilder_Build(t *testing.T) { - buildDir, err := ioutil.TempDir("", "soong_test_rule_builder") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(buildDir) - bp := ` rule_builder_test { name: "foo", diff --git a/android/sh_binary_test.go b/android/sh_binary_test.go index becb35a21..c99e18c3e 100644 --- a/android/sh_binary_test.go +++ b/android/sh_binary_test.go @@ -1,19 +1,11 @@ package android import ( - "io/ioutil" - "os" "reflect" "testing" ) func testShBinary(t *testing.T, bp string) (*TestContext, Config) { - buildDir, err := ioutil.TempDir("", "soong_sh_binary_test") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(buildDir) - config := TestArchConfig(buildDir, nil) ctx := NewTestArchContext() diff --git a/android/visibility_test.go b/android/visibility_test.go index 5ea32a2ef..1a514955d 100644 --- a/android/visibility_test.go +++ b/android/visibility_test.go @@ -1,8 +1,6 @@ package android import ( - "io/ioutil" - "os" "testing" "github.com/google/blueprint" @@ -663,12 +661,6 @@ var visibilityTests = []struct { } func TestVisibility(t *testing.T) { - buildDir, err := ioutil.TempDir("", "soong_neverallow_test") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(buildDir) - for _, test := range visibilityTests { t.Run(test.name, func(t *testing.T) { _, errs := testVisibility(buildDir, test.fs) diff --git a/android/vts_config_test.go b/android/vts_config_test.go index 7d4c9b1cf..142b2f591 100644 --- a/android/vts_config_test.go +++ b/android/vts_config_test.go @@ -15,19 +15,11 @@ package android import ( - "io/ioutil" - "os" "testing" ) func testVtsConfig(test *testing.T, bpFileContents string) *TestContext { - buildDir, err := ioutil.TempDir("", "soong_vts_config_test") - if err != nil { - test.Fatal(err) - } - config := TestArchConfig(buildDir, nil) - defer func() { os.RemoveAll(buildDir) }() ctx := NewTestArchContext() ctx.RegisterModuleType("vts_config", ModuleFactoryAdaptor(VtsConfigFactory)) From b88b3c5e77a80ba3a9816bf16da67ce017cd6d56 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Mon, 10 Jun 2019 15:15:17 -0700 Subject: [PATCH 4/6] Capture missing dependency error rules Allow missing dependency errors to be tested by capturing the missing dependency error rule instead of the originally requested rule. Test: all soong tests Change-Id: Id2b23b9ee354cdafc44fb9adfaf8fe7bab973478 --- android/module.go | 37 ++++++++++++++++--------------------- android/testing.go | 2 +- 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/android/module.go b/android/module.go index 2481000fe..3a9ef9636 100644 --- a/android/module.go +++ b/android/module.go @@ -945,17 +945,16 @@ type moduleContext struct { variables map[string]string } -func (m *moduleContext) ninjaError(desc string, outputs []string, err error) { - m.ModuleContext.Build(pctx.PackageContext, blueprint.BuildParams{ +func (m *moduleContext) ninjaError(params BuildParams, err error) (PackageContext, BuildParams) { + return pctx, BuildParams{ Rule: ErrorRule, - Description: desc, - Outputs: outputs, - Optional: true, + Description: params.Description, + Output: params.Output, + Outputs: params.Outputs, Args: map[string]string{ "error": err.Error(), }, - }) - return + } } func (m *moduleContext) Config() Config { @@ -1027,24 +1026,20 @@ func (m *moduleContext) Rule(pctx PackageContext, name string, params blueprint. } func (m *moduleContext) Build(pctx PackageContext, params BuildParams) { + if params.Description != "" { + params.Description = "${moduleDesc}" + params.Description + "${moduleDescSuffix}" + } + + if missingDeps := m.GetMissingDependencies(); len(missingDeps) > 0 { + pctx, params = m.ninjaError(params, fmt.Errorf("module %s missing dependencies: %s\n", + m.ModuleName(), strings.Join(missingDeps, ", "))) + } + if m.config.captureBuild { m.buildParams = append(m.buildParams, params) } - bparams := convertBuildParams(params) - - if bparams.Description != "" { - bparams.Description = "${moduleDesc}" + params.Description + "${moduleDescSuffix}" - } - - if missingDeps := m.GetMissingDependencies(); len(missingDeps) > 0 { - m.ninjaError(bparams.Description, bparams.Outputs, - fmt.Errorf("module %s missing dependencies: %s\n", - m.ModuleName(), strings.Join(missingDeps, ", "))) - return - } - - m.ModuleContext.Build(pctx.PackageContext, bparams) + m.ModuleContext.Build(pctx.PackageContext, convertBuildParams(params)) } func (m *moduleContext) Module() Module { diff --git a/android/testing.go b/android/testing.go index c0db75ecc..44bee4b7d 100644 --- a/android/testing.go +++ b/android/testing.go @@ -179,7 +179,7 @@ func buildParamsFromRule(provider testBuildProvider, rule string) TestingBuildPa func maybeBuildParamsFromDescription(provider testBuildProvider, desc string) TestingBuildParams { for _, p := range provider.BuildParamsForTests() { - if p.Description == desc { + if strings.Contains(p.Description, desc) { return newTestingBuildParams(provider, p) } } From 0e99175bb67e542374b353f8d7ee3a2ee27b3396 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Mon, 10 Jun 2019 15:41:28 -0700 Subject: [PATCH 5/6] Add test for missing defaults modules with AllowMissingDependencies Test: defaults_test.go Change-Id: Ic71892c379f8850996ea4dd94f606f4e937591df --- android/defaults_test.go | 116 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 android/defaults_test.go diff --git a/android/defaults_test.go b/android/defaults_test.go new file mode 100644 index 000000000..fa2659563 --- /dev/null +++ b/android/defaults_test.go @@ -0,0 +1,116 @@ +// Copyright 2019 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package android + +import ( + "testing" + + "github.com/google/blueprint/proptools" +) + +type defaultsTestProperties struct { + Foo []string +} + +type defaultsTestModule struct { + ModuleBase + DefaultableModuleBase + properties defaultsTestProperties +} + +func (d *defaultsTestModule) GenerateAndroidBuildActions(ctx ModuleContext) { + ctx.Build(pctx, BuildParams{ + Rule: Touch, + Output: PathForModuleOut(ctx, "out"), + }) +} + +func defaultsTestModuleFactory() Module { + module := &defaultsTestModule{} + module.AddProperties(&module.properties) + InitDefaultableModule(module) + InitAndroidModule(module) + return module +} + +type defaultsTestDefaults struct { + ModuleBase + DefaultsModuleBase +} + +func defaultsTestDefaultsFactory() Module { + defaults := &defaultsTestDefaults{} + defaults.AddProperties(&defaultsTestProperties{}) + InitDefaultsModule(defaults) + return defaults +} + +func TestDefaultsAllowMissingDependencies(t *testing.T) { + config := TestConfig(buildDir, nil) + config.TestProductVariables.Allow_missing_dependencies = proptools.BoolPtr(true) + + ctx := NewTestContext() + ctx.SetAllowMissingDependencies(true) + + ctx.RegisterModuleType("test", ModuleFactoryAdaptor(defaultsTestModuleFactory)) + ctx.RegisterModuleType("defaults", ModuleFactoryAdaptor(defaultsTestDefaultsFactory)) + + ctx.PreArchMutators(RegisterDefaultsPreArchMutators) + + ctx.Register() + + bp := ` + defaults { + name: "defaults", + defaults: ["missing"], + foo: ["defaults"], + } + + test { + name: "missing_defaults", + defaults: ["missing"], + foo: ["module"], + } + + test { + name: "missing_transitive_defaults", + defaults: ["defaults"], + foo: ["module"], + } + ` + + ctx.MockFileSystem(map[string][]byte{ + "Android.bp": []byte(bp), + }) + + _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) + FailIfErrored(t, errs) + _, errs = ctx.PrepareBuildActions(config) + FailIfErrored(t, errs) + + missingDefaults := ctx.ModuleForTests("missing_defaults", "").Output("out") + missingTransitiveDefaults := ctx.ModuleForTests("missing_transitive_defaults", "").Output("out") + + if missingDefaults.Rule != ErrorRule { + t.Errorf("expected missing_defaults rule to be ErrorRule, got %#v", missingDefaults.Rule) + } + + if g, w := missingDefaults.Args["error"], "module missing_defaults missing dependencies: missing\n"; g != w { + t.Errorf("want error %q, got %q", w, g) + } + + // TODO: missing transitive defaults is currently not handled + _ = missingTransitiveDefaults +} From dc35e21124b684087aeb66fb74e9ca43f0e7c741 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Thu, 6 Jun 2019 16:13:11 -0700 Subject: [PATCH 6/6] Consolidate *MutatorContext and ModuleContext into BaseModuleContext Following 99bdb2ab4fd5168a71a20aecf10611425be47ec4 in build/blueprint, move more methods into BaseModuleContext. This reapplies I9f8df94f1ae2b55d3cccf7b9468247f3e7cb2ebd after fixing missing errors thrown for missing defaults modules when AllowMissingDependencies == true. Test: m checkbuild Test: defaults_test.go Change-Id: Ia17b2bcbf2bac6889c419b2e73953946f6aa40ad --- Android.bp | 1 + android/module.go | 220 +++++++++++++++++++++++----------------- android/mutator.go | 186 ++++++++++++--------------------- android/mutator_test.go | 99 ++++++++++++++++++ android/paths.go | 2 +- 5 files changed, 294 insertions(+), 214 deletions(-) create mode 100644 android/mutator_test.go diff --git a/Android.bp b/Android.bp index ec4eb61e9..614e71fdb 100644 --- a/Android.bp +++ b/Android.bp @@ -83,6 +83,7 @@ bootstrap_go_package { "android/config_test.go", "android/expand_test.go", "android/module_test.go", + "android/mutator_test.go", "android/namespace_test.go", "android/neverallow_test.go", "android/onceper_test.go", diff --git a/android/module.go b/android/module.go index 3a9ef9636..03993e519 100644 --- a/android/module.go +++ b/android/module.go @@ -56,14 +56,40 @@ type BuildParams struct { type ModuleBuildParams BuildParams // BaseModuleContext is the same as blueprint.BaseModuleContext except that Config() returns -// a Config instead of an interface{}, plus some extra methods that return Android-specific information +// a Config instead of an interface{}, and some methods have been wrapped to use an android.Module +// instead of a blueprint.Module, plus some extra methods that return Android-specific information // about the current module. type BaseModuleContext interface { + Module() Module ModuleName() string ModuleDir() string ModuleType() string Config() Config + OtherModuleName(m blueprint.Module) string + OtherModuleDir(m blueprint.Module) string + OtherModuleErrorf(m blueprint.Module, fmt string, args ...interface{}) + OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag + OtherModuleExists(name string) bool + + GetDirectDepsWithTag(tag blueprint.DependencyTag) []Module + GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module + GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag) + + VisitDirectDepsBlueprint(visit func(blueprint.Module)) + VisitDirectDeps(visit func(Module)) + VisitDirectDepsWithTag(tag blueprint.DependencyTag, visit func(Module)) + VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) + // Deprecated: use WalkDeps instead to support multiple dependency tags on the same module + VisitDepsDepthFirst(visit func(Module)) + // Deprecated: use WalkDeps instead to support multiple dependency tags on the same module + VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module)) + WalkDeps(visit func(Module, Module) bool) + WalkDepsBlueprint(visit func(blueprint.Module, blueprint.Module) bool) + // GetWalkPath is supposed to be called in visit function passed in WalkDeps() + // and returns a top-down dependency path from a start module to current child module. + GetWalkPath() []Module + ContainsProperty(name string) bool Errorf(pos scanner.Position, fmt string, args ...interface{}) ModuleErrorf(fmt string, args ...interface{}) @@ -76,9 +102,14 @@ type BaseModuleContext interface { // file that does not match the pattern is added to a searched directory. GlobWithDeps(pattern string, excludes []string) ([]string, error) + Glob(globPattern string, excludes []string) Paths + GlobFiles(globPattern string, excludes []string) Paths + Fs() pathtools.FileSystem AddNinjaFileDeps(deps ...string) + AddMissingDependencies(missingDeps []string) + Target() Target TargetPrimary() bool MultiTargets() []Target @@ -114,8 +145,6 @@ type ModuleContext interface { ExpandSources(srcFiles, excludes []string) Paths ExpandSource(srcFile, prop string) Path ExpandOptionalSource(srcFile *string, prop string) OptionalPath - Glob(globPattern string, excludes []string) Paths - GlobFiles(globPattern string, excludes []string) Paths InstallExecutable(installPath OutputPath, name string, srcPath Path, deps ...Path) OutputPath InstallFile(installPath OutputPath, name string, srcPath Path, deps ...Path) OutputPath @@ -123,8 +152,6 @@ type ModuleContext interface { InstallAbsoluteSymlink(installPath OutputPath, name string, absPath string) OutputPath CheckbuildFile(srcPath Path) - AddMissingDependencies(deps []string) - InstallInData() bool InstallInSanitizerDir() bool InstallInRecovery() bool @@ -133,30 +160,8 @@ type ModuleContext interface { HostRequiredModuleNames() []string TargetRequiredModuleNames() []string - // android.ModuleContext methods - // These are duplicated instead of embedded so that can eventually be wrapped to take an - // android.Module instead of a blueprint.Module - OtherModuleName(m blueprint.Module) string - OtherModuleErrorf(m blueprint.Module, fmt string, args ...interface{}) - OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag - - GetDirectDepsWithTag(tag blueprint.DependencyTag) []Module - GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module - GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag) - ModuleSubDir() string - VisitDirectDepsBlueprint(visit func(blueprint.Module)) - VisitDirectDeps(visit func(Module)) - VisitDirectDepsWithTag(tag blueprint.DependencyTag, visit func(Module)) - VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) - // Deprecated: use WalkDeps instead to support multiple dependency tags on the same module - VisitDepsDepthFirst(visit func(Module)) - // Deprecated: use WalkDeps instead to support multiple dependency tags on the same module - VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module)) - WalkDeps(visit func(Module, Module) bool) - WalkDepsBlueprint(visit func(blueprint.Module, blueprint.Module) bool) - Variable(pctx PackageContext, name, value string) Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule // Similar to blueprint.ModuleContext.Build, but takes Paths instead of []string, @@ -839,7 +844,7 @@ func (m *ModuleBase) baseModuleContextFactory(ctx blueprint.BaseModuleContext) b func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) { ctx := &moduleContext{ module: m.module, - ModuleContext: blueprintCtx, + bp: blueprintCtx, baseModuleContext: m.baseModuleContextFactory(blueprintCtx), installDeps: m.computeInstallDeps(blueprintCtx), installFiles: m.installFiles, @@ -851,6 +856,10 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) // TODO: This will be removed once defaults modules handle missing dependency errors blueprintCtx.GetMissingDependencies() + // For the final GenerateAndroidBuildActions pass, require that all visited dependencies Soong modules and + // are enabled. + ctx.baseModuleContext.strictVisitDeps = true + if ctx.config.captureBuild { ctx.ruleParams = make(map[blueprint.Rule]blueprint.RuleParams) } @@ -907,6 +916,12 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) noticePath := filepath.Join(ctx.ModuleDir(), notice) m.noticeFile = ExistentPathForSource(ctx, noticePath) } + } else if ctx.Config().AllowMissingDependencies() { + // If the module is not enabled it will not create any build rules, nothing will call + // ctx.GetMissingDependencies(), and blueprint will consider the missing dependencies to be unhandled + // and report them as an error even when AllowMissingDependencies = true. Call + // ctx.GetMissingDependencies() here to tell blueprint not to handle them. + ctx.GetMissingDependencies() } if m == ctx.FinalModule().(Module).base() { @@ -929,10 +944,14 @@ type baseModuleContext struct { debug bool kind moduleKind config Config + + walkPath []Module + + strictVisitDeps bool // If true, enforce that all dependencies are enabled } type moduleContext struct { - blueprint.ModuleContext + bp blueprint.ModuleContext baseModuleContext installDeps Paths installFiles Paths @@ -957,10 +976,6 @@ func (m *moduleContext) ninjaError(params BuildParams, err error) (PackageContex } } -func (m *moduleContext) Config() Config { - return m.ModuleContext.Config().(Config) -} - func (m *moduleContext) ModuleBuild(pctx PackageContext, params ModuleBuildParams) { m.Build(pctx, BuildParams(params)) } @@ -1010,13 +1025,13 @@ func (m *moduleContext) Variable(pctx PackageContext, name, value string) { m.variables[name] = value } - m.ModuleContext.Variable(pctx.PackageContext, name, value) + m.bp.Variable(pctx.PackageContext, name, value) } func (m *moduleContext) Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule { - rule := m.ModuleContext.Rule(pctx.PackageContext, name, params, argNames...) + rule := m.bp.Rule(pctx.PackageContext, name, params, argNames...) if m.config.captureBuild { m.ruleParams[rule] = params @@ -1039,57 +1054,66 @@ func (m *moduleContext) Build(pctx PackageContext, params BuildParams) { m.buildParams = append(m.buildParams, params) } - m.ModuleContext.Build(pctx.PackageContext, convertBuildParams(params)) + m.bp.Build(pctx.PackageContext, convertBuildParams(params)) } -func (m *moduleContext) Module() Module { - return m.ModuleContext.Module().(Module) +func (b *baseModuleContext) Module() Module { + module, _ := b.BaseModuleContext.Module().(Module) + return module +} + +func (b *baseModuleContext) Config() Config { + return b.BaseModuleContext.Config().(Config) } func (m *moduleContext) GetMissingDependencies() []string { var missingDeps []string missingDeps = append(missingDeps, m.Module().base().commonProperties.MissingDeps...) - missingDeps = append(missingDeps, m.ModuleContext.GetMissingDependencies()...) + missingDeps = append(missingDeps, m.bp.GetMissingDependencies()...) missingDeps = FirstUniqueStrings(missingDeps) return missingDeps } -func (m *moduleContext) AddMissingDependencies(deps []string) { +func (b *baseModuleContext) AddMissingDependencies(deps []string) { if deps != nil { - missingDeps := &m.Module().base().commonProperties.MissingDeps + missingDeps := &b.Module().base().commonProperties.MissingDeps *missingDeps = append(*missingDeps, deps...) *missingDeps = FirstUniqueStrings(*missingDeps) } } -func (m *moduleContext) validateAndroidModule(module blueprint.Module) Module { +func (b *baseModuleContext) validateAndroidModule(module blueprint.Module, strict bool) Module { aModule, _ := module.(Module) + + if !strict { + return aModule + } + if aModule == nil { - m.ModuleErrorf("module %q not an android module", m.OtherModuleName(aModule)) + b.ModuleErrorf("module %q not an android module", b.OtherModuleName(module)) return nil } if !aModule.Enabled() { - if m.Config().AllowMissingDependencies() { - m.AddMissingDependencies([]string{m.OtherModuleName(aModule)}) + if b.Config().AllowMissingDependencies() { + b.AddMissingDependencies([]string{b.OtherModuleName(aModule)}) } else { - m.ModuleErrorf("depends on disabled module %q", m.OtherModuleName(aModule)) + b.ModuleErrorf("depends on disabled module %q", b.OtherModuleName(aModule)) } return nil } - return aModule } -func (m *moduleContext) getDirectDepInternal(name string, tag blueprint.DependencyTag) (blueprint.Module, blueprint.DependencyTag) { +func (b *baseModuleContext) getDirectDepInternal(name string, tag blueprint.DependencyTag) (blueprint.Module, blueprint.DependencyTag) { type dep struct { mod blueprint.Module tag blueprint.DependencyTag } var deps []dep - m.VisitDirectDepsBlueprint(func(module blueprint.Module) { + b.VisitDirectDepsBlueprint(func(module blueprint.Module) { if aModule, _ := module.(Module); aModule != nil && aModule.base().BaseModuleName() == name { - returnedTag := m.ModuleContext.OtherModuleDependencyTag(aModule) + returnedTag := b.BaseModuleContext.OtherModuleDependencyTag(aModule) if tag == nil || returnedTag == tag { deps = append(deps, dep{aModule, returnedTag}) } @@ -1099,17 +1123,17 @@ func (m *moduleContext) getDirectDepInternal(name string, tag blueprint.Dependen return deps[0].mod, deps[0].tag } else if len(deps) >= 2 { panic(fmt.Errorf("Multiple dependencies having same BaseModuleName() %q found from %q", - name, m.ModuleName())) + name, b.ModuleName())) } else { return nil, nil } } -func (m *moduleContext) GetDirectDepsWithTag(tag blueprint.DependencyTag) []Module { +func (b *baseModuleContext) GetDirectDepsWithTag(tag blueprint.DependencyTag) []Module { var deps []Module - m.VisitDirectDepsBlueprint(func(module blueprint.Module) { + b.VisitDirectDepsBlueprint(func(module blueprint.Module) { if aModule, _ := module.(Module); aModule != nil { - if m.ModuleContext.OtherModuleDependencyTag(aModule) == tag { + if b.BaseModuleContext.OtherModuleDependencyTag(aModule) == tag { deps = append(deps, aModule) } } @@ -1122,37 +1146,37 @@ func (m *moduleContext) GetDirectDepWithTag(name string, tag blueprint.Dependenc return module } -func (m *moduleContext) GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag) { - return m.getDirectDepInternal(name, nil) +func (b *baseModuleContext) GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag) { + return b.getDirectDepInternal(name, nil) } -func (m *moduleContext) VisitDirectDepsBlueprint(visit func(blueprint.Module)) { - m.ModuleContext.VisitDirectDeps(visit) +func (b *baseModuleContext) VisitDirectDepsBlueprint(visit func(blueprint.Module)) { + b.BaseModuleContext.VisitDirectDeps(visit) } -func (m *moduleContext) VisitDirectDeps(visit func(Module)) { - m.ModuleContext.VisitDirectDeps(func(module blueprint.Module) { - if aModule := m.validateAndroidModule(module); aModule != nil { +func (b *baseModuleContext) VisitDirectDeps(visit func(Module)) { + b.BaseModuleContext.VisitDirectDeps(func(module blueprint.Module) { + if aModule := b.validateAndroidModule(module, b.strictVisitDeps); aModule != nil { visit(aModule) } }) } -func (m *moduleContext) VisitDirectDepsWithTag(tag blueprint.DependencyTag, visit func(Module)) { - m.ModuleContext.VisitDirectDeps(func(module blueprint.Module) { - if aModule := m.validateAndroidModule(module); aModule != nil { - if m.ModuleContext.OtherModuleDependencyTag(aModule) == tag { +func (b *baseModuleContext) VisitDirectDepsWithTag(tag blueprint.DependencyTag, visit func(Module)) { + b.BaseModuleContext.VisitDirectDeps(func(module blueprint.Module) { + if aModule := b.validateAndroidModule(module, b.strictVisitDeps); aModule != nil { + if b.BaseModuleContext.OtherModuleDependencyTag(aModule) == tag { visit(aModule) } } }) } -func (m *moduleContext) VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) { - m.ModuleContext.VisitDirectDepsIf( +func (b *baseModuleContext) VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) { + b.BaseModuleContext.VisitDirectDepsIf( // pred func(module blueprint.Module) bool { - if aModule := m.validateAndroidModule(module); aModule != nil { + if aModule := b.validateAndroidModule(module, b.strictVisitDeps); aModule != nil { return pred(aModule) } else { return false @@ -1164,19 +1188,19 @@ func (m *moduleContext) VisitDirectDepsIf(pred func(Module) bool, visit func(Mod }) } -func (m *moduleContext) VisitDepsDepthFirst(visit func(Module)) { - m.ModuleContext.VisitDepsDepthFirst(func(module blueprint.Module) { - if aModule := m.validateAndroidModule(module); aModule != nil { +func (b *baseModuleContext) VisitDepsDepthFirst(visit func(Module)) { + b.BaseModuleContext.VisitDepsDepthFirst(func(module blueprint.Module) { + if aModule := b.validateAndroidModule(module, b.strictVisitDeps); aModule != nil { visit(aModule) } }) } -func (m *moduleContext) VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module)) { - m.ModuleContext.VisitDepsDepthFirstIf( +func (b *baseModuleContext) VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module)) { + b.BaseModuleContext.VisitDepsDepthFirstIf( // pred func(module blueprint.Module) bool { - if aModule := m.validateAndroidModule(module); aModule != nil { + if aModule := b.validateAndroidModule(module, b.strictVisitDeps); aModule != nil { return pred(aModule) } else { return false @@ -1188,15 +1212,21 @@ func (m *moduleContext) VisitDepsDepthFirstIf(pred func(Module) bool, visit func }) } -func (m *moduleContext) WalkDepsBlueprint(visit func(blueprint.Module, blueprint.Module) bool) { - m.ModuleContext.WalkDeps(visit) +func (b *baseModuleContext) WalkDepsBlueprint(visit func(blueprint.Module, blueprint.Module) bool) { + b.BaseModuleContext.WalkDeps(visit) } -func (m *moduleContext) WalkDeps(visit func(Module, Module) bool) { - m.ModuleContext.WalkDeps(func(child, parent blueprint.Module) bool { - childAndroidModule := m.validateAndroidModule(child) - parentAndroidModule := m.validateAndroidModule(parent) +func (b *baseModuleContext) WalkDeps(visit func(Module, Module) bool) { + b.walkPath = []Module{b.Module()} + b.BaseModuleContext.WalkDeps(func(child, parent blueprint.Module) bool { + childAndroidModule, _ := child.(Module) + parentAndroidModule, _ := parent.(Module) if childAndroidModule != nil && parentAndroidModule != nil { + // record walkPath before visit + for b.walkPath[len(b.walkPath)-1] != parentAndroidModule { + b.walkPath = b.walkPath[0 : len(b.walkPath)-1] + } + b.walkPath = append(b.walkPath, childAndroidModule) return visit(childAndroidModule, parentAndroidModule) } else { return false @@ -1204,18 +1234,26 @@ func (m *moduleContext) WalkDeps(visit func(Module, Module) bool) { }) } +func (b *baseModuleContext) GetWalkPath() []Module { + return b.walkPath +} + func (m *moduleContext) VisitAllModuleVariants(visit func(Module)) { - m.ModuleContext.VisitAllModuleVariants(func(module blueprint.Module) { + m.bp.VisitAllModuleVariants(func(module blueprint.Module) { visit(module.(Module)) }) } func (m *moduleContext) PrimaryModule() Module { - return m.ModuleContext.PrimaryModule().(Module) + return m.bp.PrimaryModule().(Module) } func (m *moduleContext) FinalModule() Module { - return m.ModuleContext.FinalModule().(Module) + return m.bp.FinalModule().(Module) +} + +func (m *moduleContext) ModuleSubDir() string { + return m.bp.ModuleSubDir() } func (b *baseModuleContext) Target() Target { @@ -1593,20 +1631,20 @@ func (m *moduleContext) TargetRequiredModuleNames() []string { return m.module.base().commonProperties.Target_required } -func (m *moduleContext) Glob(globPattern string, excludes []string) Paths { - ret, err := m.GlobWithDeps(globPattern, excludes) +func (b *baseModuleContext) Glob(globPattern string, excludes []string) Paths { + ret, err := b.GlobWithDeps(globPattern, excludes) if err != nil { - m.ModuleErrorf("glob: %s", err.Error()) + b.ModuleErrorf("glob: %s", err.Error()) } - return pathsForModuleSrcFromFullPath(m, ret, true) + return pathsForModuleSrcFromFullPath(b, ret, true) } -func (m *moduleContext) GlobFiles(globPattern string, excludes []string) Paths { - ret, err := m.GlobWithDeps(globPattern, excludes) +func (b *baseModuleContext) GlobFiles(globPattern string, excludes []string) Paths { + ret, err := b.GlobWithDeps(globPattern, excludes) if err != nil { - m.ModuleErrorf("glob: %s", err.Error()) + b.ModuleErrorf("glob: %s", err.Error()) } - return pathsForModuleSrcFromFullPath(m, ret, false) + return pathsForModuleSrcFromFullPath(b, ret, false) } func init() { diff --git a/android/mutator.go b/android/mutator.go index cd0d152db..081c2b248 100644 --- a/android/mutator.go +++ b/android/mutator.go @@ -115,35 +115,14 @@ type TopDownMutator func(TopDownMutatorContext) type TopDownMutatorContext interface { BaseModuleContext - OtherModuleExists(name string) bool Rename(name string) - Module() Module - - OtherModuleName(m blueprint.Module) string - OtherModuleDir(m blueprint.Module) string - OtherModuleErrorf(m blueprint.Module, fmt string, args ...interface{}) - OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag CreateModule(blueprint.ModuleFactory, ...interface{}) - - GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module - GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag) - - VisitDirectDeps(visit func(Module)) - VisitDirectDepsWithTag(tag blueprint.DependencyTag, visit func(Module)) - VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) - VisitDepsDepthFirst(visit func(Module)) - VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module)) - WalkDeps(visit func(Module, Module) bool) - // GetWalkPath is supposed to be called in visit function passed in WalkDeps() - // and returns a top-down dependency path from a start module to current child module. - GetWalkPath() []Module } type topDownMutatorContext struct { - blueprint.TopDownMutatorContext + bp blueprint.TopDownMutatorContext baseModuleContext - walkPath []Module } type BottomUpMutator func(BottomUpMutatorContext) @@ -151,9 +130,7 @@ type BottomUpMutator func(BottomUpMutatorContext) type BottomUpMutatorContext interface { BaseModuleContext - OtherModuleExists(name string) bool Rename(name string) - Module() blueprint.Module AddDependency(module blueprint.Module, tag blueprint.DependencyTag, name ...string) AddReverseDependency(module blueprint.Module, tag blueprint.DependencyTag, name string) @@ -167,7 +144,7 @@ type BottomUpMutatorContext interface { } type bottomUpMutatorContext struct { - blueprint.BottomUpMutatorContext + bp blueprint.BottomUpMutatorContext baseModuleContext } @@ -175,8 +152,8 @@ func (x *registerMutatorsContext) BottomUp(name string, m BottomUpMutator) Mutat f := func(ctx blueprint.BottomUpMutatorContext) { if a, ok := ctx.Module().(Module); ok { actx := &bottomUpMutatorContext{ - BottomUpMutatorContext: ctx, - baseModuleContext: a.base().baseModuleContextFactory(ctx), + bp: ctx, + baseModuleContext: a.base().baseModuleContextFactory(ctx), } m(actx) } @@ -190,8 +167,8 @@ func (x *registerMutatorsContext) TopDown(name string, m TopDownMutator) Mutator f := func(ctx blueprint.TopDownMutatorContext) { if a, ok := ctx.Module().(Module); ok { actx := &topDownMutatorContext{ - TopDownMutatorContext: ctx, - baseModuleContext: a.base().baseModuleContextFactory(ctx), + bp: ctx, + baseModuleContext: a.base().baseModuleContextFactory(ctx), } m(actx) } @@ -216,99 +193,6 @@ func depsMutator(ctx BottomUpMutatorContext) { } } -func (t *topDownMutatorContext) Config() Config { - return t.config -} - -func (b *bottomUpMutatorContext) Config() Config { - return b.config -} - -func (t *topDownMutatorContext) Module() Module { - module, _ := t.TopDownMutatorContext.Module().(Module) - return module -} - -func (t *topDownMutatorContext) VisitDirectDeps(visit func(Module)) { - t.TopDownMutatorContext.VisitDirectDeps(func(module blueprint.Module) { - if aModule, _ := module.(Module); aModule != nil { - visit(aModule) - } - }) -} - -func (t *topDownMutatorContext) VisitDirectDepsWithTag(tag blueprint.DependencyTag, visit func(Module)) { - t.TopDownMutatorContext.VisitDirectDeps(func(module blueprint.Module) { - if aModule, _ := module.(Module); aModule != nil { - if t.TopDownMutatorContext.OtherModuleDependencyTag(aModule) == tag { - visit(aModule) - } - } - }) -} - -func (t *topDownMutatorContext) VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) { - t.TopDownMutatorContext.VisitDirectDepsIf( - // pred - func(module blueprint.Module) bool { - if aModule, _ := module.(Module); aModule != nil { - return pred(aModule) - } else { - return false - } - }, - // visit - func(module blueprint.Module) { - visit(module.(Module)) - }) -} - -func (t *topDownMutatorContext) VisitDepsDepthFirst(visit func(Module)) { - t.TopDownMutatorContext.VisitDepsDepthFirst(func(module blueprint.Module) { - if aModule, _ := module.(Module); aModule != nil { - visit(aModule) - } - }) -} - -func (t *topDownMutatorContext) VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module)) { - t.TopDownMutatorContext.VisitDepsDepthFirstIf( - // pred - func(module blueprint.Module) bool { - if aModule, _ := module.(Module); aModule != nil { - return pred(aModule) - } else { - return false - } - }, - // visit - func(module blueprint.Module) { - visit(module.(Module)) - }) -} - -func (t *topDownMutatorContext) WalkDeps(visit func(Module, Module) bool) { - t.walkPath = []Module{t.Module()} - t.TopDownMutatorContext.WalkDeps(func(child, parent blueprint.Module) bool { - childAndroidModule, _ := child.(Module) - parentAndroidModule, _ := parent.(Module) - if childAndroidModule != nil && parentAndroidModule != nil { - // record walkPath before visit - for t.walkPath[len(t.walkPath)-1] != parentAndroidModule { - t.walkPath = t.walkPath[0 : len(t.walkPath)-1] - } - t.walkPath = append(t.walkPath, childAndroidModule) - return visit(childAndroidModule, parentAndroidModule) - } else { - return false - } - }) -} - -func (t *topDownMutatorContext) GetWalkPath() []Module { - return t.walkPath -} - func (t *topDownMutatorContext) AppendProperties(props ...interface{}) { for _, p := range props { err := proptools.AppendMatchingProperties(t.Module().base().customizableProperties, @@ -336,3 +220,61 @@ func (t *topDownMutatorContext) PrependProperties(props ...interface{}) { } } } + +// android.topDownMutatorContext either has to embed blueprint.TopDownMutatorContext, in which case every method that +// has an overridden version in android.BaseModuleContext has to be manually forwarded to BaseModuleContext to avoid +// ambiguous method errors, or it has to store a blueprint.TopDownMutatorContext non-embedded, in which case every +// non-overridden method has to be forwarded. There are fewer non-overridden methods, so use the latter. The following +// methods forward to the identical blueprint versions for topDownMutatorContext and bottomUpMutatorContext. + +func (t *topDownMutatorContext) Rename(name string) { + t.bp.Rename(name) +} + +func (t *topDownMutatorContext) CreateModule(factory blueprint.ModuleFactory, props ...interface{}) { + t.bp.CreateModule(factory, props...) +} + +func (b *bottomUpMutatorContext) Rename(name string) { + b.bp.Rename(name) +} + +func (b *bottomUpMutatorContext) AddDependency(module blueprint.Module, tag blueprint.DependencyTag, name ...string) { + b.bp.AddDependency(module, tag, name...) +} + +func (b *bottomUpMutatorContext) AddReverseDependency(module blueprint.Module, tag blueprint.DependencyTag, name string) { + b.bp.AddReverseDependency(module, tag, name) +} + +func (b *bottomUpMutatorContext) CreateVariations(variations ...string) []blueprint.Module { + return b.bp.CreateVariations(variations...) +} + +func (b *bottomUpMutatorContext) CreateLocalVariations(variations ...string) []blueprint.Module { + return b.bp.CreateLocalVariations(variations...) +} + +func (b *bottomUpMutatorContext) SetDependencyVariation(variation string) { + b.bp.SetDependencyVariation(variation) +} + +func (b *bottomUpMutatorContext) AddVariationDependencies(variations []blueprint.Variation, tag blueprint.DependencyTag, + names ...string) { + + b.bp.AddVariationDependencies(variations, tag, names...) +} + +func (b *bottomUpMutatorContext) AddFarVariationDependencies(variations []blueprint.Variation, + tag blueprint.DependencyTag, names ...string) { + + b.bp.AddFarVariationDependencies(variations, tag, names...) +} + +func (b *bottomUpMutatorContext) AddInterVariantDependency(tag blueprint.DependencyTag, from, to blueprint.Module) { + b.bp.AddInterVariantDependency(tag, from, to) +} + +func (b *bottomUpMutatorContext) ReplaceDependencies(name string) { + b.bp.ReplaceDependencies(name) +} diff --git a/android/mutator_test.go b/android/mutator_test.go new file mode 100644 index 000000000..4cef40006 --- /dev/null +++ b/android/mutator_test.go @@ -0,0 +1,99 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package android + +import ( + "io/ioutil" + "os" + "reflect" + "testing" + + "github.com/google/blueprint/proptools" +) + +type mutatorTestModule struct { + ModuleBase + props struct { + } + + missingDeps []string +} + +func mutatorTestModuleFactory() Module { + module := &mutatorTestModule{} + module.AddProperties(&module.props) + InitAndroidModule(module) + return module +} + +func (m *mutatorTestModule) GenerateAndroidBuildActions(ctx ModuleContext) { + ctx.Build(pctx, BuildParams{ + Rule: Touch, + Output: PathForModuleOut(ctx, "output"), + }) + + m.missingDeps = ctx.GetMissingDependencies() +} + +func (m *mutatorTestModule) DepsMutator(ctx BottomUpMutatorContext) { + ctx.AddDependency(ctx.Module(), nil, "regular_missing_dep") +} + +func addMissingDependenciesMutator(ctx TopDownMutatorContext) { + ctx.AddMissingDependencies([]string{"added_missing_dep"}) +} + +func TestMutatorAddMissingDependencies(t *testing.T) { + buildDir, err := ioutil.TempDir("", "soong_mutator_test") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(buildDir) + + config := TestConfig(buildDir, nil) + config.TestProductVariables.Allow_missing_dependencies = proptools.BoolPtr(true) + + ctx := NewTestContext() + ctx.SetAllowMissingDependencies(true) + + ctx.RegisterModuleType("test", ModuleFactoryAdaptor(mutatorTestModuleFactory)) + ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) { + ctx.TopDown("add_missing_dependencies", addMissingDependenciesMutator) + }) + + bp := ` + test { + name: "foo", + } + ` + + mockFS := map[string][]byte{ + "Android.bp": []byte(bp), + } + + ctx.MockFileSystem(mockFS) + + ctx.Register() + _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) + FailIfErrored(t, errs) + _, errs = ctx.PrepareBuildActions(config) + FailIfErrored(t, errs) + + foo := ctx.ModuleForTests("foo", "").Module().(*mutatorTestModule) + + if g, w := foo.missingDeps, []string{"added_missing_dep", "regular_missing_dep"}; !reflect.DeepEqual(g, w) { + t.Errorf("want foo missing deps %q, got %q", w, g) + } +} diff --git a/android/paths.go b/android/paths.go index 52d22d531..20b8b823c 100644 --- a/android/paths.go +++ b/android/paths.go @@ -367,7 +367,7 @@ func expandOneSrcPath(ctx ModuleContext, s string, expandedExcludes []string) (P // each string. If incDirs is false, strip paths with a trailing '/' from the list. // It intended for use in globs that only list files that exist, so it allows '$' in // filenames. -func pathsForModuleSrcFromFullPath(ctx ModuleContext, paths []string, incDirs bool) Paths { +func pathsForModuleSrcFromFullPath(ctx BaseModuleContext, paths []string, incDirs bool) Paths { prefix := filepath.Join(ctx.Config().srcDir, ctx.ModuleDir()) + "/" if prefix == "./" { prefix = ""