Merge "soong: Fix AndroidMk with *Required properties"

am: 0f7dbd0d55

Change-Id: I588aeda47a66334b16294e36333f653001fd37b1
This commit is contained in:
Jooyung Han 2019-07-15 19:31:36 -07:00 committed by android-build-merger
commit 962982a731
6 changed files with 316 additions and 16 deletions

View file

@ -81,6 +81,7 @@ bootstrap_go_package {
],
testSrcs: [
"android/android_test.go",
"android/androidmk_test.go",
"android/arch_test.go",
"android/config_test.go",
"android/expand_test.go",
@ -291,6 +292,7 @@ bootstrap_go_package {
"java/testing.go",
],
testSrcs: [
"java/androidmk_test.go",
"java/app_test.go",
"java/device_host_converter_test.go",
"java/dexpreopt_test.go",

View file

@ -391,6 +391,31 @@ func translateGoBinaryModule(ctx SingletonContext, w io.Writer, mod blueprint.Mo
return nil
}
func (data *AndroidMkData) fillInData(config Config, bpPath string, mod blueprint.Module) {
// Get the preamble content through AndroidMkEntries logic.
entries := AndroidMkEntries{
Class: data.Class,
SubName: data.SubName,
DistFile: data.DistFile,
OutputFile: data.OutputFile,
Disabled: data.Disabled,
Include: data.Include,
Required: data.Required,
Host_required: data.Host_required,
Target_required: data.Target_required,
}
entries.fillInEntries(config, bpPath, mod)
// preamble doesn't need the footer content.
entries.footer = bytes.Buffer{}
entries.write(&data.preamble)
// copy entries back to data since it is used in Custom
data.Required = entries.Required
data.Host_required = entries.Host_required
data.Target_required = entries.Target_required
}
func translateAndroidModule(ctx SingletonContext, w io.Writer, mod blueprint.Module,
provider AndroidMkDataProvider) error {
@ -404,22 +429,7 @@ func translateAndroidModule(ctx SingletonContext, w io.Writer, mod blueprint.Mod
data.Include = "$(BUILD_PREBUILT)"
}
// Get the preamble content through AndroidMkEntries logic.
entries := AndroidMkEntries{
Class: data.Class,
SubName: data.SubName,
DistFile: data.DistFile,
OutputFile: data.OutputFile,
Disabled: data.Disabled,
Include: data.Include,
Required: data.Required,
Host_required: data.Host_required,
Target_required: data.Target_required,
}
entries.fillInEntries(ctx.Config(), ctx.BlueprintFile(mod), mod)
// preamble doesn't need the footer content.
entries.footer = bytes.Buffer{}
entries.write(&data.preamble)
data.fillInData(ctx.Config(), ctx.BlueprintFile(mod), mod)
prefix := ""
if amod.ArchSpecific() {

82
android/androidmk_test.go Normal file
View file

@ -0,0 +1,82 @@
// 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"
"reflect"
"testing"
)
type customModule struct {
ModuleBase
data AndroidMkData
}
func (m *customModule) GenerateAndroidBuildActions(ctx ModuleContext) {
}
func (m *customModule) AndroidMk() AndroidMkData {
return AndroidMkData{
Custom: func(w io.Writer, name, prefix, moduleDir string, data AndroidMkData) {
m.data = data
},
}
}
func customModuleFactory() Module {
module := &customModule{}
InitAndroidModule(module)
return module
}
func TestAndroidMkSingleton_PassesUpdatedAndroidMkDataToCustomCallback(t *testing.T) {
config := TestConfig(buildDir, nil)
config.inMake = true // Enable androidmk Singleton
ctx := NewTestContext()
ctx.RegisterSingletonType("androidmk", SingletonFactoryAdaptor(AndroidMkSingleton))
ctx.RegisterModuleType("custom", ModuleFactoryAdaptor(customModuleFactory))
ctx.Register()
bp := `
custom {
name: "foo",
required: ["bar"],
host_required: ["baz"],
target_required: ["qux"],
}
`
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)
m := ctx.ModuleForTests("foo", "").Module().(*customModule)
assertEqual := func(expected interface{}, actual interface{}) {
if !reflect.DeepEqual(expected, actual) {
t.Errorf("%q expected, but got %q", expected, actual)
}
}
assertEqual([]string{"bar"}, m.data.Required)
assertEqual([]string{"baz"}, m.data.Host_required)
assertEqual([]string{"qux"}, m.data.Target_required)
}

View file

@ -382,3 +382,14 @@ func AndroidMkEntriesForTest(t *testing.T, config Config, bpPath string, mod blu
entries.fillInEntries(config, bpPath, mod)
return entries
}
func AndroidMkDataForTest(t *testing.T, config Config, bpPath string, mod blueprint.Module) AndroidMkData {
var p AndroidMkDataProvider
var ok bool
if p, ok = mod.(AndroidMkDataProvider); !ok {
t.Errorf("module does not implmement AndroidMkDataProvider: " + mod.Name())
}
data := p.AndroidMk()
data.fillInData(config, bpPath, mod)
return data
}

View file

@ -115,6 +115,17 @@ func PrefixInList(s string, list []string) bool {
return false
}
// IndexListPred returns the index of the element which in the given `list` satisfying the predicate, or -1 if there is no such element.
func IndexListPred(pred func(s string) bool, list []string) int {
for i, l := range list {
if pred(l) {
return i
}
}
return -1
}
func FilterList(list []string, filter []string) (remainder []string, filtered []string) {
for _, l := range list {
if InList(l, filter) {

184
java/androidmk_test.go Normal file
View file

@ -0,0 +1,184 @@
// 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 java
import (
"android/soong/android"
"bytes"
"io"
"io/ioutil"
"strings"
"testing"
)
type testAndroidMk struct {
*testing.T
body []byte
}
type testAndroidMkModule struct {
*testing.T
props map[string]string
}
func newTestAndroidMk(t *testing.T, r io.Reader) *testAndroidMk {
t.Helper()
buf, err := ioutil.ReadAll(r)
if err != nil {
t.Fatal("failed to open read Android.mk.", err)
}
return &testAndroidMk{
T: t,
body: buf,
}
}
func parseAndroidMkProps(lines []string) map[string]string {
props := make(map[string]string)
for _, line := range lines {
line = strings.TrimLeft(line, " ")
if line == "" || strings.HasPrefix(line, "#") {
continue
}
tokens := strings.Split(line, " ")
if tokens[1] == "+=" {
props[tokens[0]] += " " + strings.Join(tokens[2:], " ")
} else {
props[tokens[0]] = strings.Join(tokens[2:], " ")
}
}
return props
}
func (t *testAndroidMk) moduleFor(moduleName string) *testAndroidMkModule {
t.Helper()
lines := strings.Split(string(t.body), "\n")
index := android.IndexList("LOCAL_MODULE := "+moduleName, lines)
if index == -1 {
t.Fatalf("%q is not found.", moduleName)
}
lines = lines[index:]
includeIndex := android.IndexListPred(func(line string) bool {
return strings.HasPrefix(line, "include")
}, lines)
if includeIndex == -1 {
t.Fatalf("%q is not properly defined. (\"include\" not found).", moduleName)
}
props := parseAndroidMkProps(lines[:includeIndex])
return &testAndroidMkModule{
T: t.T,
props: props,
}
}
func (t *testAndroidMkModule) hasRequired(dep string) {
t.Helper()
required, ok := t.props["LOCAL_REQUIRED_MODULES"]
if !ok {
t.Error("LOCAL_REQUIRED_MODULES is not found.")
return
}
if !android.InList(dep, strings.Split(required, " ")) {
t.Errorf("%q is expected in LOCAL_REQUIRED_MODULES, but not found in %q.", dep, required)
}
}
func (t *testAndroidMkModule) hasNoRequired(dep string) {
t.Helper()
required, ok := t.props["LOCAL_REQUIRED_MODULES"]
if !ok {
return
}
if android.InList(dep, strings.Split(required, " ")) {
t.Errorf("%q is not expected in LOCAL_REQUIRED_MODULES, but found.", dep)
}
}
func getAndroidMk(t *testing.T, ctx *android.TestContext, config android.Config, name string) *testAndroidMk {
t.Helper()
lib, _ := ctx.ModuleForTests(name, "android_common").Module().(*Library)
data := android.AndroidMkDataForTest(t, config, "", lib)
w := &bytes.Buffer{}
data.Custom(w, name, "", "", data)
return newTestAndroidMk(t, w)
}
func TestRequired(t *testing.T) {
config := testConfig(nil)
ctx := testContext(config, `
java_library {
name: "foo",
srcs: ["a.java"],
required: ["libfoo"],
}
`, nil)
run(t, ctx, config)
mk := getAndroidMk(t, ctx, config, "foo")
mk.moduleFor("foo").hasRequired("libfoo")
}
func TestHostdex(t *testing.T) {
config := testConfig(nil)
ctx := testContext(config, `
java_library {
name: "foo",
srcs: ["a.java"],
hostdex: true,
}
`, nil)
run(t, ctx, config)
mk := getAndroidMk(t, ctx, config, "foo")
mk.moduleFor("foo")
mk.moduleFor("foo-hostdex")
}
func TestHostdexRequired(t *testing.T) {
config := testConfig(nil)
ctx := testContext(config, `
java_library {
name: "foo",
srcs: ["a.java"],
hostdex: true,
required: ["libfoo"],
}
`, nil)
run(t, ctx, config)
mk := getAndroidMk(t, ctx, config, "foo")
mk.moduleFor("foo").hasRequired("libfoo")
mk.moduleFor("foo-hostdex").hasRequired("libfoo")
}
func TestHostdexSpecificRequired(t *testing.T) {
config := testConfig(nil)
ctx := testContext(config, `
java_library {
name: "foo",
srcs: ["a.java"],
hostdex: true,
target: {
hostdex: {
required: ["libfoo"],
},
},
}
`, nil)
run(t, ctx, config)
mk := getAndroidMk(t, ctx, config, "foo")
mk.moduleFor("foo").hasNoRequired("libfoo")
mk.moduleFor("foo-hostdex").hasRequired("libfoo")
}