AndroidProducts.mk file reader
Fixes: 182418325 Test: go test android_products_test.go Change-Id: Ibb6c4aedacb891d5d7e74ce351b2e19c888adc5d
This commit is contained in:
110
mk2rbc/android_products.go
Normal file
110
mk2rbc/android_products.go
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
// Copyright 2021 Google LLC
|
||||||
|
//
|
||||||
|
// 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 mk2rbc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
mkparser "android/soong/androidmk/parser"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Implements mkparser.Scope, to be used by mkparser.Value.Value()
|
||||||
|
type localDirEval struct {
|
||||||
|
localDir string
|
||||||
|
hasErrors bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *localDirEval) Get(name string) string {
|
||||||
|
if name == "LOCAL_DIR" {
|
||||||
|
return l.localDir
|
||||||
|
}
|
||||||
|
l.hasErrors = true
|
||||||
|
return fmt.Sprintf("$(%s)", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *localDirEval) Set(_, _ string) {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *localDirEval) Call(_ string, _ []string) []string {
|
||||||
|
l.hasErrors = true
|
||||||
|
return []string{"$(call ...)"}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *localDirEval) SetFunc(_ string, _ func([]string) []string) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateProductConfigMap builds product configuration map.
|
||||||
|
// The product configuration map maps a product name (i.e., the value of the
|
||||||
|
// TARGET_PRODUCT variable) to the top-level configuration file.
|
||||||
|
// In the Android's Make-based build machinery, the equivalent of the
|
||||||
|
// product configuration map is $(PRODUCT_MAKEFILES), which is the list
|
||||||
|
// of <product>:<configuration makefile> pairs (if <product>: is missing,
|
||||||
|
// <product> is the basename of the configuration makefile).
|
||||||
|
// UpdateProductConfigMap emulates this build logic by processing the
|
||||||
|
// assignments to PRODUCT_MAKEFILES in the file passed to it.
|
||||||
|
func UpdateProductConfigMap(configMap map[string]string, configMakefile string) error {
|
||||||
|
contents, err := ioutil.ReadFile(configMakefile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
parser := mkparser.NewParser(configMakefile, bytes.NewBuffer(contents))
|
||||||
|
nodes, errs := parser.Parse()
|
||||||
|
if len(errs) > 0 {
|
||||||
|
for _, e := range errs {
|
||||||
|
fmt.Fprintln(os.Stderr, "ERROR:", e)
|
||||||
|
}
|
||||||
|
return fmt.Errorf("cannot parse %s", configMakefile)
|
||||||
|
}
|
||||||
|
|
||||||
|
ldEval := &localDirEval{localDir: filepath.Dir(configMakefile)}
|
||||||
|
|
||||||
|
for _, node := range nodes {
|
||||||
|
// We are interested in assignments to 'PRODUCT_MAKEFILES'
|
||||||
|
asgn, ok := node.(*mkparser.Assignment)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !(asgn.Name.Const() && asgn.Name.Strings[0] == "PRODUCT_MAKEFILES") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve the references to $(LOCAL_DIR) in $(PRODUCT_MAKEFILES).
|
||||||
|
ldEval.hasErrors = false
|
||||||
|
value := asgn.Value.Value(ldEval)
|
||||||
|
if ldEval.hasErrors {
|
||||||
|
return fmt.Errorf("cannot evaluate %s", asgn.Value.Dump())
|
||||||
|
}
|
||||||
|
// Each item is either <product>:<configuration makefile>, or
|
||||||
|
// just <configuration makefile>
|
||||||
|
for _, token := range strings.Fields(value) {
|
||||||
|
var product, config_path string
|
||||||
|
if n := strings.Index(token, ":"); n >= 0 {
|
||||||
|
product = token[0:n]
|
||||||
|
config_path = token[n+1:]
|
||||||
|
} else {
|
||||||
|
config_path = token
|
||||||
|
product = filepath.Base(config_path)
|
||||||
|
product = strings.TrimSuffix(product, filepath.Ext(product))
|
||||||
|
}
|
||||||
|
configMap[product] = config_path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
38
mk2rbc/android_products_test.go
Normal file
38
mk2rbc/android_products_test.go
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
// Copyright 2021 Google LLC
|
||||||
|
//
|
||||||
|
// 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 mk2rbc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"path/filepath"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestProductsMakefile(t *testing.T) {
|
||||||
|
testDir := getTestDirectory()
|
||||||
|
abspath := func(relPath string) string { return filepath.Join(testDir, relPath) }
|
||||||
|
actualProducts := make(map[string]string)
|
||||||
|
if err := UpdateProductConfigMap(actualProducts, abspath("android_products.mk.test")); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
expectedProducts := map[string]string{
|
||||||
|
"aosp_cf_x86_tv": abspath("vsoc_x86/tv/device.mk"),
|
||||||
|
"aosp_tv_arm": abspath("aosp_tv_arm.mk"),
|
||||||
|
"aosp_tv_arm64": abspath("aosp_tv_arm64.mk"),
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(actualProducts, expectedProducts) {
|
||||||
|
t.Errorf("\nExpected: %v\n Actual: %v", expectedProducts, actualProducts)
|
||||||
|
}
|
||||||
|
}
|
4
mk2rbc/test/android_products.mk.test
Normal file
4
mk2rbc/test/android_products.mk.test
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
PRODUCT_MAKEFILES := \
|
||||||
|
$(LOCAL_DIR)/aosp_tv_arm.mk \
|
||||||
|
$(LOCAL_DIR)/aosp_tv_arm64.mk \
|
||||||
|
aosp_cf_x86_tv:$(LOCAL_DIR)/vsoc_x86/tv/device.mk
|
Reference in New Issue
Block a user