Merge "Add bool to control if we need generate stubs src files."
diff --git a/Android.bp b/Android.bp
index ec69df8..ad2ad47 100644
--- a/Android.bp
+++ b/Android.bp
@@ -219,6 +219,7 @@
srcs: [
"java/aapt2.go",
"java/aar.go",
+ "java/android_resources.go",
"java/androidmk.go",
"java/app_builder.go",
"java/app.go",
@@ -229,8 +230,8 @@
"java/genrule.go",
"java/jacoco.go",
"java/java.go",
+ "java/java_resources.go",
"java/proto.go",
- "java/resources.go",
"java/system_modules.go",
],
testSrcs: [
diff --git a/android/config.go b/android/config.go
index b89ae48..7122f48 100644
--- a/android/config.go
+++ b/android/config.go
@@ -629,6 +629,10 @@
return c.targetOpenJDK9
}
+func (c *config) UseClangLld() bool {
+ return Bool(c.productVariables.UseClangLld)
+}
+
func (c *config) ClangTidy() bool {
return Bool(c.productVariables.ClangTidy)
}
diff --git a/android/namespace.go b/android/namespace.go
index 1f8ef5a..0230524 100644
--- a/android/namespace.go
+++ b/android/namespace.go
@@ -255,22 +255,7 @@
}
func (r *NameResolver) Rename(oldName string, newName string, namespace blueprint.Namespace) []error {
- oldNs := r.findNamespace(oldName)
- newNs := r.findNamespace(newName)
- if oldNs != newNs {
- return []error{fmt.Errorf("cannot rename %v to %v because the destination is outside namespace %v", oldName, newName, oldNs.Path)}
- }
-
- oldName, err := filepath.Rel(oldNs.Path, oldName)
- if err != nil {
- panic(err)
- }
- newName, err = filepath.Rel(newNs.Path, newName)
- if err != nil {
- panic(err)
- }
-
- return oldNs.moduleContainer.Rename(oldName, newName, nil)
+ return namespace.(*Namespace).moduleContainer.Rename(oldName, newName, namespace)
}
// resolve each element of namespace.importedNamespaceNames and put the result in namespace.visibleNamespaces
diff --git a/android/namespace_test.go b/android/namespace_test.go
index 8bec0ad..9a791a5 100644
--- a/android/namespace_test.go
+++ b/android/namespace_test.go
@@ -582,6 +582,25 @@
}
}
+// so that the generated .ninja file will have consistent names
+func TestRename(t *testing.T) {
+ _ = setupTest(t,
+ map[string]string{
+ "dir1": `
+ soong_namespace {
+ }
+ test_module {
+ name: "a",
+ deps: ["c"],
+ }
+ test_module {
+ name: "b",
+ rename: "c",
+ }
+ `})
+ // setupTest will report any errors
+}
+
// some utils to support the tests
func mockFiles(bps map[string]string) (files map[string][]byte) {
@@ -607,6 +626,9 @@
ctx.RegisterModuleType("test_module", ModuleFactoryAdaptor(newTestModule))
ctx.RegisterModuleType("soong_namespace", ModuleFactoryAdaptor(NamespaceFactory))
ctx.PreArchMutators(RegisterNamespaceMutator)
+ ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
+ ctx.BottomUp("rename", renameMutator)
+ })
ctx.Register()
_, errs = ctx.ParseBlueprintsFiles("Android.bp")
@@ -672,12 +694,16 @@
type testModule struct {
ModuleBase
properties struct {
- Deps []string
- Id string
+ Rename string
+ Deps []string
+ Id string
}
}
func (m *testModule) DepsMutator(ctx BottomUpMutatorContext) {
+ if m.properties.Rename != "" {
+ ctx.Rename(m.properties.Rename)
+ }
for _, d := range m.properties.Deps {
ctx.AddDependency(ctx.Module(), nil, d)
}
@@ -686,6 +712,14 @@
func (m *testModule) GenerateAndroidBuildActions(ModuleContext) {
}
+func renameMutator(ctx BottomUpMutatorContext) {
+ if m, ok := ctx.Module().(*testModule); ok {
+ if m.properties.Rename != "" {
+ ctx.Rename(m.properties.Rename)
+ }
+ }
+}
+
func newTestModule() Module {
m := &testModule{}
m.AddProperties(&m.properties)
diff --git a/android/variable.go b/android/variable.go
index ef7d37b..3eee988 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -176,6 +176,8 @@
OdmPath *string `json:",omitempty"`
ProductPath *string `json:",omitempty"`
+ UseClangLld *bool `json:",omitempty"`
+
ClangTidy *bool `json:",omitempty"`
TidyChecks *string `json:",omitempty"`
diff --git a/androidmk/cmd/androidmk/android.go b/androidmk/cmd/androidmk/android.go
index a578bcf..37877c8 100644
--- a/androidmk/cmd/androidmk/android.go
+++ b/androidmk/cmd/androidmk/android.go
@@ -64,6 +64,9 @@
"LOCAL_MODULE_SUFFIX": skip, // TODO
"LOCAL_PATH": skip, // Nothing to do, except maybe avoid the "./" in paths?
"LOCAL_PRELINK_MODULE": skip, // Already phased out
+ "LOCAL_BUILT_MODULE_STEM": skip,
+ "LOCAL_USE_AAPT2": skip, // Always enabled in Soong
+ "LOCAL_JAR_EXCLUDE_FILES": skip, // Soong never excludes files from jars
}
// adds a group of properties all having the same type
@@ -94,6 +97,7 @@
"LOCAL_NOTICE_FILE": "notice",
"LOCAL_JAVA_LANGUAGE_VERSION": "java_version",
"LOCAL_INSTRUMENTATION_FOR": "instrumentation_for",
+ "LOCAL_MANIFEST_FILE": "manifest",
"LOCAL_DEX_PREOPT_PROFILE_CLASS_LISTING": "dex_preopt.profile",
})
@@ -129,6 +133,7 @@
"LOCAL_RENDERSCRIPT_FLAGS": "renderscript.flags",
"LOCAL_JAVA_RESOURCE_DIRS": "java_resource_dirs",
+ "LOCAL_RESOURCE_DIR": "resource_dirs",
"LOCAL_JAVACFLAGS": "javacflags",
"LOCAL_ERROR_PRONE_FLAGS": "errorprone.javacflags",
"LOCAL_DX_FLAGS": "dxflags",
@@ -143,7 +148,13 @@
"LOCAL_PROGUARD_FLAGS": "optimize.proguard_flags",
"LOCAL_PROGUARD_FLAG_FILES": "optimize.proguard_flag_files",
+
+ // These will be rewritten to libs/static_libs by bpfix, after their presence is used to convert
+ // java_library_static to android_library.
+ "LOCAL_SHARED_ANDROID_LIBRARIES": "android_libs",
+ "LOCAL_STATIC_ANDROID_LIBRARIES": "android_static_libs",
})
+
addStandardProperties(bpparser.BoolType,
map[string]string{
// Bool properties
@@ -157,6 +168,7 @@
"LOCAL_NO_STANDARD_LIBRARIES": "no_standard_libs",
"LOCAL_PACK_MODULE_RELOCATIONS": "pack_relocations",
"LOCAL_TIDY": "tidy",
+ "LOCAL_USE_CLANG_LLD": "use_clang_lld",
"LOCAL_PROPRIETARY_MODULE": "proprietary",
"LOCAL_VENDOR_MODULE": "vendor",
"LOCAL_ODM_MODULE": "device_specific",
diff --git a/androidmk/cmd/androidmk/androidmk.go b/androidmk/cmd/androidmk/androidmk.go
index 6e0b474..b6a973c 100644
--- a/androidmk/cmd/androidmk/androidmk.go
+++ b/androidmk/cmd/androidmk/androidmk.go
@@ -239,7 +239,8 @@
}
// check for common supported but undesirable structures and clean them up
- err := bpfix.FixTree(tree, bpfix.NewFixRequest().AddAll())
+ fixer := bpfix.NewFixer(tree)
+ tree, err := fixer.Fix(bpfix.NewFixRequest().AddAll())
if err != nil {
return "", []error{err}
}
diff --git a/androidmk/cmd/androidmk/androidmk_test.go b/androidmk/cmd/androidmk/androidmk_test.go
index 45df1a5..edf3d42 100644
--- a/androidmk/cmd/androidmk/androidmk_test.go
+++ b/androidmk/cmd/androidmk/androidmk_test.go
@@ -17,11 +17,10 @@
import (
"bytes"
"fmt"
- "os"
"strings"
"testing"
- bpparser "github.com/google/blueprint/parser"
+ "android/soong/bpfix/bpfix"
)
var testCases = []struct {
@@ -498,6 +497,7 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES := test.jar
LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+ LOCAL_STATIC_ANDROID_LIBRARIES :=
include $(BUILD_PREBUILT)
`,
expected: `
@@ -522,28 +522,68 @@
}
`,
},
-}
-func reformatBlueprint(input string) string {
- file, errs := bpparser.Parse("<testcase>", bytes.NewBufferString(input), bpparser.NewScope(nil))
- if len(errs) > 0 {
- for _, err := range errs {
- fmt.Fprintln(os.Stderr, err)
- }
- panic(fmt.Sprintf("%d parsing errors in testcase:\n%s", len(errs), input))
- }
+ {
+ desc: "aar",
+ in: `
+ include $(CLEAR_VARS)
+ LOCAL_SRC_FILES := test.java
+ LOCAL_RESOURCE_DIR := res
+ include $(BUILD_STATIC_JAVA_LIBRARY)
- res, err := bpparser.Print(file)
- if err != nil {
- panic(fmt.Sprintf("Error printing testcase: %q", err))
- }
+ include $(CLEAR_VARS)
+ LOCAL_SRC_FILES := test.java
+ LOCAL_STATIC_LIBRARIES := foo
+ LOCAL_STATIC_ANDROID_LIBRARIES := bar
+ include $(BUILD_STATIC_JAVA_LIBRARY)
- return string(res)
+ include $(CLEAR_VARS)
+ LOCAL_SRC_FILES := test.java
+ LOCAL_SHARED_LIBRARIES := foo
+ LOCAL_SHARED_ANDROID_LIBRARIES := bar
+ include $(BUILD_STATIC_JAVA_LIBRARY)
+
+ include $(CLEAR_VARS)
+ LOCAL_SRC_FILES := test.java
+ LOCAL_STATIC_ANDROID_LIBRARIES :=
+ include $(BUILD_STATIC_JAVA_LIBRARY)
+ `,
+ expected: `
+ android_library {
+ srcs: ["test.java"],
+ resource_dirs: ["res"],
+ }
+
+ android_library {
+ srcs: ["test.java"],
+ static_libs: [
+ "foo",
+ "bar",
+ ],
+ }
+
+ android_library {
+ srcs: ["test.java"],
+ libs: [
+ "foo",
+ "bar",
+ ],
+ }
+
+ java_library_static {
+ srcs: ["test.java"],
+ static_libs: [],
+ }
+ `,
+ },
}
func TestEndToEnd(t *testing.T) {
for i, test := range testCases {
- expected := reformatBlueprint(test.expected)
+ expected, err := bpfix.Reformat(test.expected)
+ if err != nil {
+ t.Error(err)
+ }
got, errs := convertFile(fmt.Sprintf("<testcase %d>", i), bytes.NewBufferString(test.in))
if len(errs) > 0 {
diff --git a/bpfix/bpfix/bpfix.go b/bpfix/bpfix/bpfix.go
index 2c3cc6c..e4d4e34 100644
--- a/bpfix/bpfix/bpfix.go
+++ b/bpfix/bpfix/bpfix.go
@@ -18,17 +18,36 @@
import (
"bytes"
+ "errors"
"fmt"
+ "io"
"path/filepath"
"github.com/google/blueprint/parser"
)
+// Reformat takes a blueprint file as a string and returns a formatted version
+func Reformat(input string) (string, error) {
+ tree, err := parse("<string>", bytes.NewBufferString(input))
+ if err != nil {
+ return "", err
+ }
+
+ res, err := parser.Print(tree)
+ if err != nil {
+ return "", err
+ }
+
+ return string(res), nil
+}
+
// A FixRequest specifies the details of which fixes to apply to an individual file
// A FixRequest doesn't specify whether to do a dry run or where to write the results; that's in cmd/bpfix.go
type FixRequest struct {
- simplifyKnownRedundantVariables bool
- rewriteIncorrectAndroidmkPrebuilts bool
+ simplifyKnownRedundantVariables bool
+ rewriteIncorrectAndroidmkPrebuilts bool
+ rewriteIncorrectAndroidmkAndroidLibraries bool
+ mergeMatchingModuleProperties bool
}
func NewFixRequest() FixRequest {
@@ -39,24 +58,39 @@
result = r
result.simplifyKnownRedundantVariables = true
result.rewriteIncorrectAndroidmkPrebuilts = true
+ result.rewriteIncorrectAndroidmkAndroidLibraries = true
+ result.mergeMatchingModuleProperties = true
return result
}
-// FixTree repeatedly applies the fixes listed in the given FixRequest to the given File
+type Fixer struct {
+ tree *parser.File
+}
+
+func NewFixer(tree *parser.File) *Fixer {
+ fixer := &Fixer{tree}
+
+ // make a copy of the tree
+ fixer.reparse()
+
+ return fixer
+}
+
+// Fix repeatedly applies the fixes listed in the given FixRequest to the given File
// until there is no fix that affects the tree
-func FixTree(tree *parser.File, config FixRequest) error {
- prevIdentifier, err := fingerprint(tree)
+func (f *Fixer) Fix(config FixRequest) (*parser.File, error) {
+ prevIdentifier, err := f.fingerprint()
if err != nil {
- return err
+ return nil, err
}
maxNumIterations := 20
i := 0
for {
- err = fixTreeOnce(tree, config)
- newIdentifier, err := fingerprint(tree)
+ err = f.fixTreeOnce(config)
+ newIdentifier, err := f.fingerprint()
if err != nil {
- return err
+ return nil, err
}
if bytes.Equal(newIdentifier, prevIdentifier) {
break
@@ -67,31 +101,70 @@
// detect infinite loop
i++
if i >= maxNumIterations {
- return fmt.Errorf("Applied fixes %d times and yet the tree continued to change. Is there an infinite loop?", i)
+ return nil, fmt.Errorf("Applied fixes %d times and yet the tree continued to change. Is there an infinite loop?", i)
break
}
}
- return err
+ return f.tree, err
}
// returns a unique identifier for the given tree that can be used to determine whether the tree changed
-func fingerprint(tree *parser.File) (fingerprint []byte, err error) {
- bytes, err := parser.Print(tree)
+func (f *Fixer) fingerprint() (fingerprint []byte, err error) {
+ bytes, err := parser.Print(f.tree)
if err != nil {
return nil, err
}
return bytes, nil
}
-func fixTreeOnce(tree *parser.File, config FixRequest) error {
+func (f *Fixer) reparse() ([]byte, error) {
+ buf, err := parser.Print(f.tree)
+ if err != nil {
+ return nil, err
+ }
+ newTree, err := parse(f.tree.Name, bytes.NewReader(buf))
+ if err != nil {
+ return nil, err
+ }
+ f.tree = newTree
+ return buf, nil
+}
+
+func parse(name string, r io.Reader) (*parser.File, error) {
+ tree, errs := parser.Parse(name, r, parser.NewScope(nil))
+ if errs != nil {
+ s := "parse error: "
+ for _, err := range errs {
+ s += "\n" + err.Error()
+ }
+ return nil, errors.New(s)
+ }
+ return tree, nil
+}
+
+func (f *Fixer) fixTreeOnce(config FixRequest) error {
if config.simplifyKnownRedundantVariables {
- err := simplifyKnownPropertiesDuplicatingEachOther(tree)
+ err := f.simplifyKnownPropertiesDuplicatingEachOther()
if err != nil {
return err
}
}
if config.rewriteIncorrectAndroidmkPrebuilts {
- err := rewriteIncorrectAndroidmkPrebuilts(tree)
+ err := f.rewriteIncorrectAndroidmkPrebuilts()
+ if err != nil {
+ return err
+ }
+ }
+
+ if config.rewriteIncorrectAndroidmkAndroidLibraries {
+ err := f.rewriteIncorrectAndroidmkAndroidLibraries()
+ if err != nil {
+ return err
+ }
+ }
+
+ if config.mergeMatchingModuleProperties {
+ err := f.mergeMatchingModuleProperties()
if err != nil {
return err
}
@@ -99,13 +172,13 @@
return nil
}
-func simplifyKnownPropertiesDuplicatingEachOther(tree *parser.File) error {
+func (f *Fixer) simplifyKnownPropertiesDuplicatingEachOther() error {
// remove from local_include_dirs anything in export_include_dirs
- return removeMatchingModuleListProperties(tree, "export_include_dirs", "local_include_dirs")
+ return f.removeMatchingModuleListProperties("export_include_dirs", "local_include_dirs")
}
-func rewriteIncorrectAndroidmkPrebuilts(tree *parser.File) error {
- for _, def := range tree.Defs {
+func (f *Fixer) rewriteIncorrectAndroidmkPrebuilts() error {
+ for _, def := range f.tree.Defs {
mod, ok := def.(*parser.Module)
if !ok {
continue
@@ -127,6 +200,7 @@
switch filepath.Ext(src.Value) {
case ".jar":
renameProperty(mod, "srcs", "jars")
+
case ".aar":
renameProperty(mod, "srcs", "aars")
mod.Type = "android_library_import"
@@ -139,6 +213,146 @@
return nil
}
+func (f *Fixer) rewriteIncorrectAndroidmkAndroidLibraries() error {
+ for _, def := range f.tree.Defs {
+ mod, ok := def.(*parser.Module)
+ if !ok {
+ continue
+ }
+
+ hasAndroidLibraries := hasNonEmptyLiteralListProperty(mod, "android_libs")
+ hasStaticAndroidLibraries := hasNonEmptyLiteralListProperty(mod, "android_static_libs")
+ hasResourceDirs := hasNonEmptyLiteralListProperty(mod, "resource_dirs")
+
+ if hasAndroidLibraries || hasStaticAndroidLibraries || hasResourceDirs {
+ if mod.Type == "java_library_static" {
+ mod.Type = "android_library"
+ }
+ }
+
+ if mod.Type == "java_import" && !hasStaticAndroidLibraries {
+ removeProperty(mod, "android_static_libs")
+ }
+
+ // These may conflict with existing libs and static_libs properties, but the
+ // mergeMatchingModuleProperties pass will fix it.
+ renameProperty(mod, "shared_libs", "libs")
+ renameProperty(mod, "android_libs", "libs")
+ renameProperty(mod, "android_static_libs", "static_libs")
+ }
+
+ return nil
+}
+
+func (f *Fixer) mergeMatchingModuleProperties() error {
+ // Make sure all the offsets are accurate
+ buf, err := f.reparse()
+ if err != nil {
+ return err
+ }
+
+ var patchlist parser.PatchList
+ for _, def := range f.tree.Defs {
+ mod, ok := def.(*parser.Module)
+ if !ok {
+ continue
+ }
+
+ err := mergeMatchingProperties(&mod.Properties, buf, &patchlist)
+ if err != nil {
+ return err
+ }
+ }
+
+ newBuf := new(bytes.Buffer)
+ err = patchlist.Apply(bytes.NewReader(buf), newBuf)
+ if err != nil {
+ return err
+ }
+
+ newTree, err := parse(f.tree.Name, newBuf)
+ if err != nil {
+ return err
+ }
+
+ f.tree = newTree
+
+ return nil
+}
+
+func mergeMatchingProperties(properties *[]*parser.Property, buf []byte, patchlist *parser.PatchList) error {
+ seen := make(map[string]*parser.Property)
+ for i := 0; i < len(*properties); i++ {
+ property := (*properties)[i]
+ if prev, exists := seen[property.Name]; exists {
+ err := mergeProperties(prev, property, buf, patchlist)
+ if err != nil {
+ return err
+ }
+ *properties = append((*properties)[:i], (*properties)[i+1:]...)
+ } else {
+ seen[property.Name] = property
+ if mapProperty, ok := property.Value.(*parser.Map); ok {
+ err := mergeMatchingProperties(&mapProperty.Properties, buf, patchlist)
+ if err != nil {
+ return err
+ }
+ }
+ }
+ }
+ return nil
+}
+
+func mergeProperties(a, b *parser.Property, buf []byte, patchlist *parser.PatchList) error {
+ if a.Value.Type() != b.Value.Type() {
+ return fmt.Errorf("type mismatch when merging properties %q: %s and %s", a.Name, a.Value.Type(), b.Value.Type())
+ }
+
+ switch a.Value.Type() {
+ case parser.StringType:
+ return fmt.Errorf("conflicting definitions of string property %q", a.Name)
+ case parser.ListType:
+ return mergeListProperties(a, b, buf, patchlist)
+ }
+
+ return nil
+}
+
+func mergeListProperties(a, b *parser.Property, buf []byte, patchlist *parser.PatchList) error {
+ aval, oka := a.Value.(*parser.List)
+ bval, okb := b.Value.(*parser.List)
+ if !oka || !okb {
+ // Merging expressions not supported yet
+ return nil
+ }
+
+ s := string(buf[bval.LBracePos.Offset+1 : bval.RBracePos.Offset])
+ if bval.LBracePos.Line != bval.RBracePos.Line {
+ if s[0] != '\n' {
+ panic("expected \n")
+ }
+ // If B is a multi line list, skip the first "\n" in case A already has a trailing "\n"
+ s = s[1:]
+ }
+ if aval.LBracePos.Line == aval.RBracePos.Line {
+ // A is a single line list with no trailing comma
+ if len(aval.Values) > 0 {
+ s = "," + s
+ }
+ }
+
+ err := patchlist.Add(aval.RBracePos.Offset, aval.RBracePos.Offset, s)
+ if err != nil {
+ return err
+ }
+ err = patchlist.Add(b.NamePos.Offset, b.End().Offset+2, "")
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
// removes from <items> every item present in <removals>
func filterExpressionList(items *parser.List, removals *parser.List) {
writeIndex := 0
@@ -163,8 +377,8 @@
}
// Remove each modules[i].Properties[<legacyName>][j] that matches a modules[i].Properties[<canonicalName>][k]
-func removeMatchingModuleListProperties(tree *parser.File, canonicalName string, legacyName string) error {
- for _, def := range tree.Defs {
+func (f *Fixer) removeMatchingModuleListProperties(canonicalName string, legacyName string) error {
+ for _, def := range f.tree.Defs {
mod, ok := def.(*parser.Module)
if !ok {
continue
@@ -182,6 +396,11 @@
return nil
}
+func hasNonEmptyLiteralListProperty(mod *parser.Module, name string) bool {
+ list, found := getLiteralListProperty(mod, name)
+ return found && len(list.Values) > 0
+}
+
func getLiteralListProperty(mod *parser.Module, name string) (list *parser.List, found bool) {
prop, ok := mod.GetProperty(name)
if !ok {
diff --git a/bpfix/bpfix/bpfix_test.go b/bpfix/bpfix/bpfix_test.go
index e17e815..51708eb 100644
--- a/bpfix/bpfix/bpfix_test.go
+++ b/bpfix/bpfix/bpfix_test.go
@@ -17,6 +17,7 @@
package bpfix
import (
+ "bytes"
"fmt"
"strings"
"testing"
@@ -62,14 +63,16 @@
t.Fatalf("%d parse errors", len(errs))
}
+ fixer := NewFixer(tree)
+
// apply simplifications
- err := simplifyKnownPropertiesDuplicatingEachOther(tree)
+ err := fixer.simplifyKnownPropertiesDuplicatingEachOther()
if len(errs) > 0 {
t.Fatal(err)
}
// lookup legacy property
- mod := tree.Defs[0].(*parser.Module)
+ mod := fixer.tree.Defs[0].(*parser.Module)
_, found := mod.GetProperty("local_include_dirs")
if !found {
t.Fatalf("failed to include key local_include_dirs in parse tree")
@@ -113,3 +116,130 @@
implFilterListTest(t, []string{}, []string{"include"}, []string{})
implFilterListTest(t, []string{}, []string{}, []string{})
}
+
+func TestMergeMatchingProperties(t *testing.T) {
+ tests := []struct {
+ name string
+ in string
+ out string
+ }{
+ {
+ name: "empty",
+ in: `
+ java_library {
+ name: "foo",
+ static_libs: [],
+ static_libs: [],
+ }
+ `,
+ out: `
+ java_library {
+ name: "foo",
+ static_libs: [],
+ }
+ `,
+ },
+ {
+ name: "single line into multiline",
+ in: `
+ java_library {
+ name: "foo",
+ static_libs: [
+ "a",
+ "b",
+ ],
+ //c1
+ static_libs: ["c" /*c2*/],
+ }
+ `,
+ out: `
+ java_library {
+ name: "foo",
+ static_libs: [
+ "a",
+ "b",
+ "c", /*c2*/
+ ],
+ //c1
+ }
+ `,
+ },
+ {
+ name: "multiline into multiline",
+ in: `
+ java_library {
+ name: "foo",
+ static_libs: [
+ "a",
+ "b",
+ ],
+ //c1
+ static_libs: [
+ //c2
+ "c", //c3
+ "d",
+ ],
+ }
+ `,
+ out: `
+ java_library {
+ name: "foo",
+ static_libs: [
+ "a",
+ "b",
+ //c2
+ "c", //c3
+ "d",
+ ],
+ //c1
+ }
+ `,
+ },
+ }
+
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ expected, err := Reformat(test.out)
+ if err != nil {
+ t.Error(err)
+ }
+
+ in, err := Reformat(test.in)
+ if err != nil {
+ t.Error(err)
+ }
+
+ tree, errs := parser.Parse("<testcase>", bytes.NewBufferString(in), parser.NewScope(nil))
+ if errs != nil {
+ t.Fatal(errs)
+ }
+
+ fixer := NewFixer(tree)
+
+ got := ""
+ prev := "foo"
+ passes := 0
+ for got != prev && passes < 10 {
+ err := fixer.mergeMatchingModuleProperties()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ out, err := parser.Print(fixer.tree)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ prev = got
+ got = string(out)
+ passes++
+ }
+
+ if got != expected {
+ t.Errorf("failed testcase '%s'\ninput:\n%s\n\nexpected:\n%s\ngot:\n%s\n",
+ test.name, in, expected, got)
+ }
+
+ })
+ }
+}
diff --git a/bpfix/cmd/bpfix.go b/bpfix/cmd/bpfix.go
index 461f41d..2fde383 100644
--- a/bpfix/cmd/bpfix.go
+++ b/bpfix/cmd/bpfix.go
@@ -75,7 +75,8 @@
}
// compute and apply any requested fixes
- err = bpfix.FixTree(file, fixRequest)
+ fixer := bpfix.NewFixer(file)
+ file, err = fixer.Fix(fixRequest)
if err != nil {
return err
}
diff --git a/cc/cc.go b/cc/cc.go
index 9c86828..8c11429 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -1115,17 +1115,11 @@
toStl := to.stl.Properties.SelectedStl
if fromStl == "" || toStl == "" {
// Libraries that don't use the STL are unrestricted.
- return
- }
-
- if fromStl == "ndk_system" || toStl == "ndk_system" {
+ } else if fromStl == "ndk_system" || toStl == "ndk_system" {
// We can be permissive with the system "STL" since it is only the C++
// ABI layer, but in the future we should make sure that everyone is
// using either libc++ or nothing.
- return
- }
-
- if getNdkStlFamily(ctx, from) != getNdkStlFamily(ctx, to) {
+ } else if getNdkStlFamily(ctx, from) != getNdkStlFamily(ctx, to) {
ctx.ModuleErrorf("uses %q and depends on %q which uses incompatible %q",
from.stl.Properties.SelectedStl, ctx.OtherModuleName(to),
to.stl.Properties.SelectedStl)
diff --git a/cc/config/arm64_device.go b/cc/config/arm64_device.go
index 5bb7749..74c936f 100644
--- a/cc/config/arm64_device.go
+++ b/cc/config/arm64_device.go
@@ -35,6 +35,9 @@
"-Wl,--icf=safe",
}
+ arm64Lldflags = append(ClangFilterUnknownLldflags(arm64Ldflags),
+ "-Wl,-z,max-page-size=4096")
+
arm64Cppflags = []string{}
arm64CpuVariantCflags = map[string][]string{
@@ -81,11 +84,13 @@
pctx.StaticVariable("Arm64Cflags", strings.Join(arm64Cflags, " "))
pctx.StaticVariable("Arm64Ldflags", strings.Join(arm64Ldflags, " "))
+ pctx.StaticVariable("Arm64Lldflags", strings.Join(arm64Lldflags, " "))
pctx.StaticVariable("Arm64Cppflags", strings.Join(arm64Cppflags, " "))
pctx.StaticVariable("Arm64IncludeFlags", bionicHeaders("arm64"))
pctx.StaticVariable("Arm64ClangCflags", strings.Join(ClangFilterUnknownCflags(arm64Cflags), " "))
pctx.StaticVariable("Arm64ClangLdflags", strings.Join(ClangFilterUnknownCflags(arm64Ldflags), " "))
+ pctx.StaticVariable("Arm64ClangLldflags", strings.Join(ClangFilterUnknownCflags(arm64Lldflags), " "))
pctx.StaticVariable("Arm64ClangCppflags", strings.Join(ClangFilterUnknownCflags(arm64Cppflags), " "))
pctx.StaticVariable("Arm64CortexA53Cflags",
@@ -188,6 +193,10 @@
return "${config.Arm64Ldflags}"
}
+func (t *toolchainArm64) ClangLldflags() string {
+ return "${config.Arm64Lldflags}"
+}
+
func (t *toolchainArm64) ToolchainClangCflags() string {
return t.toolchainClangCflags
}
diff --git a/cc/config/arm_device.go b/cc/config/arm_device.go
index 66b3b38..02bd9eb 100644
--- a/cc/config/arm_device.go
+++ b/cc/config/arm_device.go
@@ -39,6 +39,8 @@
"-Wl,-m,armelf",
}
+ armLldflags = ClangFilterUnknownLldflags(armLdflags)
+
armArmCflags = []string{
"-fstrict-aliasing",
}
@@ -169,6 +171,7 @@
pctx.StaticVariable("ArmToolchainCflags", strings.Join(armToolchainCflags, " "))
pctx.StaticVariable("ArmCflags", strings.Join(armCflags, " "))
pctx.StaticVariable("ArmLdflags", strings.Join(armLdflags, " "))
+ pctx.StaticVariable("ArmLldflags", strings.Join(armLldflags, " "))
pctx.StaticVariable("ArmCppflags", strings.Join(armCppflags, " "))
pctx.StaticVariable("ArmIncludeFlags", bionicHeaders("arm"))
@@ -196,6 +199,7 @@
pctx.StaticVariable("ArmToolchainClangCflags", strings.Join(ClangFilterUnknownCflags(armToolchainCflags), " "))
pctx.StaticVariable("ArmClangCflags", strings.Join(ClangFilterUnknownCflags(armCflags), " "))
pctx.StaticVariable("ArmClangLdflags", strings.Join(ClangFilterUnknownCflags(armLdflags), " "))
+ pctx.StaticVariable("ArmClangLldflags", strings.Join(ClangFilterUnknownCflags(armLldflags), " "))
pctx.StaticVariable("ArmClangCppflags", strings.Join(ClangFilterUnknownCflags(armCppflags), " "))
// Clang ARM vs. Thumb instruction set cflags
@@ -274,6 +278,7 @@
type toolchainArm struct {
toolchain32Bit
ldflags string
+ lldflags string
toolchainCflags, toolchainClangCflags string
}
@@ -350,6 +355,10 @@
return t.ldflags
}
+func (t *toolchainArm) ClangLldflags() string {
+ return t.lldflags // TODO: handle V8 cases
+}
+
func (t *toolchainArm) ClangInstructionSetFlags(isa string) (string, error) {
switch isa {
case "arm":
@@ -403,6 +412,7 @@
"${config.ArmLdflags}",
fixCortexA8,
}, " "),
+ lldflags: "${config.ArmLldflags}",
toolchainClangCflags: strings.Join(toolchainClangCflags, " "),
}
}
diff --git a/cc/config/clang.go b/cc/config/clang.go
index 46d6fe2..1323849 100644
--- a/cc/config/clang.go
+++ b/cc/config/clang.go
@@ -83,6 +83,15 @@
"--enable-stdcall-fixup",
})
+// Ldflags that should be filtered out when linking with clang lld
+var ClangUnknownLldflags = sorted([]string{
+ "-fuse-ld=gold",
+ "-Wl,--icf=safe",
+ "-Wl,--fix-cortex-a8",
+ "-Wl,--no-fix-cortex-a8",
+ "-Wl,-m,aarch64_elf64_le_vec",
+})
+
var ClangLibToolingUnknownCflags = []string{
"-flto*",
"-fsanitize*",
@@ -182,6 +191,17 @@
return ret
}
+func ClangFilterUnknownLldflags(lldflags []string) []string {
+ ret := make([]string, 0, len(lldflags))
+ for _, f := range lldflags {
+ if !inListSorted(f, ClangUnknownLldflags) {
+ ret = append(ret, f)
+ }
+ }
+
+ return ret
+}
+
func inListSorted(s string, list []string) bool {
for _, l := range list {
if s == l {
diff --git a/cc/config/global.go b/cc/config/global.go
index 989c7ee..051eba5 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -87,12 +87,20 @@
"-Wl,--no-undefined-version",
}
+ deviceGlobalLldflags = append(ClangFilterUnknownLldflags(deviceGlobalLdflags),
+ []string{
+ "-Wl,--pack-dyn-relocs=android",
+ "-fuse-ld=lld",
+ }...)
+
hostGlobalCflags = []string{}
hostGlobalCppflags = []string{}
hostGlobalLdflags = []string{}
+ hostGlobalLldflags = []string{}
+
commonGlobalCppflags = []string{
"-Wsign-promo",
}
@@ -141,9 +149,11 @@
pctx.StaticVariable("DeviceGlobalCflags", strings.Join(deviceGlobalCflags, " "))
pctx.StaticVariable("DeviceGlobalCppflags", strings.Join(deviceGlobalCppflags, " "))
pctx.StaticVariable("DeviceGlobalLdflags", strings.Join(deviceGlobalLdflags, " "))
+ pctx.StaticVariable("DeviceGlobalLldflags", strings.Join(deviceGlobalLldflags, " "))
pctx.StaticVariable("HostGlobalCflags", strings.Join(hostGlobalCflags, " "))
pctx.StaticVariable("HostGlobalCppflags", strings.Join(hostGlobalCppflags, " "))
pctx.StaticVariable("HostGlobalLdflags", strings.Join(hostGlobalLdflags, " "))
+ pctx.StaticVariable("HostGlobalLldflags", strings.Join(hostGlobalLldflags, " "))
pctx.StaticVariable("NoOverrideGlobalCflags", strings.Join(noOverrideGlobalCflags, " "))
pctx.StaticVariable("CommonGlobalCppflags", strings.Join(commonGlobalCppflags, " "))
diff --git a/cc/config/mips64_device.go b/cc/config/mips64_device.go
index a6191b6..6fa2571 100644
--- a/cc/config/mips64_device.go
+++ b/cc/config/mips64_device.go
@@ -155,6 +155,11 @@
return "${config.Mips64ClangLdflags}"
}
+func (t *toolchainMips64) ClangLldflags() string {
+ // TODO: define and use Mips64ClangLldflags
+ return "${config.Mips64ClangLdflags}"
+}
+
func (toolchainMips64) SanitizerRuntimeLibraryArch() string {
return "mips64"
}
diff --git a/cc/config/mips_device.go b/cc/config/mips_device.go
index 9709ada..b815fc6 100644
--- a/cc/config/mips_device.go
+++ b/cc/config/mips_device.go
@@ -205,6 +205,11 @@
return "${config.MipsClangLdflags}"
}
+func (t *toolchainMips) ClangLldflags() string {
+ // TODO: define and use MipsClangLldflags
+ return "${config.MipsClangLdflags}"
+}
+
func (toolchainMips) SanitizerRuntimeLibraryArch() string {
return "mips"
}
diff --git a/cc/config/toolchain.go b/cc/config/toolchain.go
index 7961575..ca863a7 100644
--- a/cc/config/toolchain.go
+++ b/cc/config/toolchain.go
@@ -66,6 +66,7 @@
ClangCflags() string
ClangCppflags() string
ClangLdflags() string
+ ClangLldflags() string
ClangInstructionSetFlags(string) (string, error)
ndkTriple() string
diff --git a/cc/config/x86_64_device.go b/cc/config/x86_64_device.go
index 12f3e6f..ba03094 100644
--- a/cc/config/x86_64_device.go
+++ b/cc/config/x86_64_device.go
@@ -32,6 +32,8 @@
"-Wl,--hash-style=gnu",
}
+ x86_64Lldflags = ClangFilterUnknownLldflags(x86_64Ldflags)
+
x86_64ArchVariantCflags = map[string][]string{
"": []string{
"-march=x86-64",
@@ -125,12 +127,14 @@
pctx.StaticVariable("X86_64Cflags", strings.Join(x86_64Cflags, " "))
pctx.StaticVariable("X86_64Ldflags", strings.Join(x86_64Ldflags, " "))
+ pctx.StaticVariable("X86_64Lldflags", strings.Join(x86_64Lldflags, " "))
pctx.StaticVariable("X86_64Cppflags", strings.Join(x86_64Cppflags, " "))
pctx.StaticVariable("X86_64IncludeFlags", bionicHeaders("x86"))
// Clang cflags
pctx.StaticVariable("X86_64ClangCflags", strings.Join(ClangFilterUnknownCflags(x86_64Cflags), " "))
pctx.StaticVariable("X86_64ClangLdflags", strings.Join(ClangFilterUnknownCflags(x86_64Ldflags), " "))
+ pctx.StaticVariable("X86_64ClangLldflags", strings.Join(ClangFilterUnknownCflags(x86_64Lldflags), " "))
pctx.StaticVariable("X86_64ClangCppflags", strings.Join(ClangFilterUnknownCflags(x86_64Cppflags), " "))
// Yasm flags
@@ -215,6 +219,10 @@
return "${config.X86_64Ldflags}"
}
+func (t *toolchainX86_64) ClangLldflags() string {
+ return "${config.X86_64Lldflags}"
+}
+
func (t *toolchainX86_64) YasmFlags() string {
return "${config.X86_64YasmFlags}"
}
diff --git a/cc/config/x86_darwin_host.go b/cc/config/x86_darwin_host.go
index cae9757..4aa8242 100644
--- a/cc/config/x86_darwin_host.go
+++ b/cc/config/x86_darwin_host.go
@@ -273,10 +273,20 @@
return "${config.DarwinClangLdflags} ${config.DarwinX86ClangLdflags}"
}
+func (t *toolchainDarwinX86) ClangLldflags() string {
+ // TODO: define and use Darwin*ClangLldflags
+ return "${config.DarwinClangLdflags} ${config.DarwinX86ClangLdflags}"
+}
+
func (t *toolchainDarwinX8664) ClangLdflags() string {
return "${config.DarwinClangLdflags} ${config.DarwinX8664ClangLdflags}"
}
+func (t *toolchainDarwinX8664) ClangLldflags() string {
+ // TODO: define and use Darwin*ClangLldflags
+ return "${config.DarwinClangLdflags} ${config.DarwinX8664ClangLdflags}"
+}
+
func (t *toolchainDarwinX86) YasmFlags() string {
return "${config.DarwinX86YasmFlags}"
}
diff --git a/cc/config/x86_device.go b/cc/config/x86_device.go
index b9ce4af..15188cf 100644
--- a/cc/config/x86_device.go
+++ b/cc/config/x86_device.go
@@ -38,6 +38,8 @@
"-Wl,--hash-style=gnu",
}
+ x86Lldflags = ClangFilterUnknownLldflags(x86Ldflags)
+
x86ArchVariantCflags = map[string][]string{
"": []string{
"-march=prescott",
@@ -149,12 +151,14 @@
pctx.StaticVariable("X86Cflags", strings.Join(x86Cflags, " "))
pctx.StaticVariable("X86Ldflags", strings.Join(x86Ldflags, " "))
+ pctx.StaticVariable("X86Lldflags", strings.Join(x86Lldflags, " "))
pctx.StaticVariable("X86Cppflags", strings.Join(x86Cppflags, " "))
pctx.StaticVariable("X86IncludeFlags", bionicHeaders("x86"))
// Clang cflags
pctx.StaticVariable("X86ClangCflags", strings.Join(ClangFilterUnknownCflags(x86ClangCflags), " "))
pctx.StaticVariable("X86ClangLdflags", strings.Join(ClangFilterUnknownCflags(x86Ldflags), " "))
+ pctx.StaticVariable("X86ClangLldflags", strings.Join(ClangFilterUnknownCflags(x86Lldflags), " "))
pctx.StaticVariable("X86ClangCppflags", strings.Join(ClangFilterUnknownCflags(x86Cppflags), " "))
// Yasm flags
@@ -239,6 +243,10 @@
return "${config.X86Ldflags}"
}
+func (t *toolchainX86) ClangLldflags() string {
+ return "${config.X86Lldflags}"
+}
+
func (t *toolchainX86) YasmFlags() string {
return "${config.X86YasmFlags}"
}
diff --git a/cc/config/x86_linux_bionic_host.go b/cc/config/x86_linux_bionic_host.go
index 9f0bbbd..057e905 100644
--- a/cc/config/x86_linux_bionic_host.go
+++ b/cc/config/x86_linux_bionic_host.go
@@ -126,6 +126,11 @@
return "${config.LinuxBionicLdflags}"
}
+func (t *toolchainLinuxBionic) ClangLldflags() string {
+ // TODO: define and use LinuxBionicLldflags
+ return "${config.LinuxBionicLdflags}"
+}
+
func (t *toolchainLinuxBionic) ToolchainClangCflags() string {
return "-m64 -march=x86-64" +
// TODO: We're not really android, but we don't have a triple yet b/31393676
diff --git a/cc/config/x86_linux_host.go b/cc/config/x86_linux_host.go
index 4f05068..6144fc2 100644
--- a/cc/config/x86_linux_host.go
+++ b/cc/config/x86_linux_host.go
@@ -241,10 +241,20 @@
return "${config.LinuxClangLdflags} ${config.LinuxX86ClangLdflags}"
}
+func (t *toolchainLinuxX86) ClangLldflags() string {
+ // TODO: define and use Linux*ClangLldflags
+ return "${config.LinuxClangLdflags} ${config.LinuxX86ClangLdflags}"
+}
+
func (t *toolchainLinuxX8664) ClangLdflags() string {
return "${config.LinuxClangLdflags} ${config.LinuxX8664ClangLdflags}"
}
+func (t *toolchainLinuxX8664) ClangLldflags() string {
+ // TODO: define and use Linux*ClangLldflags
+ return "${config.LinuxClangLdflags} ${config.LinuxX8664ClangLdflags}"
+}
+
func (t *toolchainLinuxX86) YasmFlags() string {
return "${config.LinuxX86YasmFlags}"
}
diff --git a/cc/config/x86_windows_host.go b/cc/config/x86_windows_host.go
index 016e711..fea6291 100644
--- a/cc/config/x86_windows_host.go
+++ b/cc/config/x86_windows_host.go
@@ -245,10 +245,20 @@
return "${config.WindowsClangLdflags} ${config.WindowsX86ClangLdflags}"
}
+func (t *toolchainWindowsX86) ClangLldflags() string {
+ // TODO: define and use Windows*ClangLldflags
+ return "${config.WindowsClangLdflags} ${config.WindowsX86ClangLdflags}"
+}
+
func (t *toolchainWindowsX8664) ClangLdflags() string {
return "${config.WindowsClangLdflags} ${config.WindowsX8664ClangLdflags}"
}
+func (t *toolchainWindowsX8664) ClangLldflags() string {
+ // TODO: define and use Windows*ClangLldflags
+ return "${config.WindowsClangLdflags} ${config.WindowsX8664ClangLdflags}"
+}
+
func (t *toolchainWindows) ShlibSuffix() string {
return ".dll"
}
diff --git a/cc/linker.go b/cc/linker.go
index bcedc8d..2176306 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -58,6 +58,9 @@
// don't link in libgcc.a
No_libgcc *bool
+ // Use clang lld instead of gnu ld.
+ Use_clang_lld *bool
+
// -l arguments to pass to linker for host-provided shared libraries
Host_ldlibs []string `android:"arch_variant"`
@@ -201,6 +204,15 @@
return deps
}
+func (linker *baseLinker) useClangLld(ctx ModuleContext) bool {
+ if linker.Properties.Use_clang_lld != nil {
+ return Bool(linker.Properties.Use_clang_lld)
+ }
+ return ctx.Config().UseClangLld()
+}
+
+// ModuleContext extends BaseModuleContext
+// BaseModuleContext should know if LLD is used?
func (linker *baseLinker) linkerFlags(ctx ModuleContext, flags Flags) Flags {
toolchain := ctx.toolchain()
@@ -209,7 +221,11 @@
hod = "Device"
}
- flags.LdFlags = append(flags.LdFlags, fmt.Sprintf("${config.%sGlobalLdflags}", hod))
+ if flags.Clang && linker.useClangLld(ctx) {
+ flags.LdFlags = append(flags.LdFlags, fmt.Sprintf("${config.%sGlobalLldflags}", hod))
+ } else {
+ flags.LdFlags = append(flags.LdFlags, fmt.Sprintf("${config.%sGlobalLdflags}", hod))
+ }
if Bool(linker.Properties.Allow_undefined_symbols) {
if ctx.Darwin() {
// darwin defaults to treating undefined symbols as errors
@@ -219,7 +235,9 @@
flags.LdFlags = append(flags.LdFlags, "-Wl,--no-undefined")
}
- if flags.Clang {
+ if flags.Clang && linker.useClangLld(ctx) {
+ flags.LdFlags = append(flags.LdFlags, toolchain.ClangLldflags())
+ } else if flags.Clang {
flags.LdFlags = append(flags.LdFlags, toolchain.ClangLdflags())
} else {
flags.LdFlags = append(flags.LdFlags, toolchain.Ldflags())
diff --git a/cc/lto.go b/cc/lto.go
index 85057cf..fd2a869 100644
--- a/cc/lto.go
+++ b/cc/lto.go
@@ -49,6 +49,9 @@
// since it is an object dependency of an LTO module.
FullDep bool `blueprint:"mutated"`
ThinDep bool `blueprint:"mutated"`
+
+ // Use clang lld instead of gnu ld.
+ Use_clang_lld *bool
}
type lto struct {
@@ -69,6 +72,13 @@
return deps
}
+func (lto *lto) useClangLld(ctx BaseModuleContext) bool {
+ if lto.Properties.Use_clang_lld != nil {
+ return Bool(lto.Properties.Use_clang_lld)
+ }
+ return ctx.Config().UseClangLld()
+}
+
func (lto *lto) flags(ctx BaseModuleContext, flags Flags) Flags {
if lto.LTO() {
var ltoFlag string
@@ -82,7 +92,7 @@
flags.CFlags = append(flags.CFlags, ltoFlag)
flags.LdFlags = append(flags.LdFlags, ltoFlag)
- if ctx.Config().IsEnvTrue("USE_THINLTO_CACHE") && Bool(lto.Properties.Lto.Thin) {
+ if ctx.Config().IsEnvTrue("USE_THINLTO_CACHE") && Bool(lto.Properties.Lto.Thin) && !lto.useClangLld(ctx) {
// Set appropriate ThinLTO cache policy
cacheDirFormat := "-Wl,-plugin-opt,cache-dir="
cacheDir := android.PathForOutput(ctx, "thinlto-cache").String()
@@ -99,7 +109,7 @@
// If the module does not have a profile, be conservative and do not inline
// or unroll loops during LTO, in order to prevent significant size bloat.
- if !ctx.isPgoCompile() {
+ if !ctx.isPgoCompile() && !lto.useClangLld(ctx) {
flags.LdFlags = append(flags.LdFlags, "-Wl,-plugin-opt,-inline-threshold=0")
flags.LdFlags = append(flags.LdFlags, "-Wl,-plugin-opt,-unroll-threshold=0")
}
diff --git a/cc/makevars.go b/cc/makevars.go
index 83a662f..bb81dcb 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -232,6 +232,12 @@
toolchain.ToolchainLdflags(),
productExtraLdflags,
}, " "))
+ ctx.Strict(makePrefix+"GLOBAL_LLDFLAGS", strings.Join([]string{
+ fmt.Sprintf("${config.%sGlobalLldflags}", hod),
+ toolchain.Ldflags(),
+ toolchain.ToolchainLdflags(),
+ productExtraLdflags,
+ }, " "))
includeFlags, err := ctx.Eval(toolchain.IncludeFlags())
if err != nil {
@@ -280,6 +286,13 @@
productExtraLdflags,
clangExtras,
}, " "))
+ ctx.Strict(clangPrefix+"GLOBAL_LLDFLAGS", strings.Join([]string{
+ fmt.Sprintf("${config.%sGlobalLldflags}", hod),
+ toolchain.ClangLldflags(),
+ toolchain.ToolchainClangLdflags(),
+ productExtraLdflags,
+ clangExtras,
+ }, " "))
if target.Os.Class == android.Device {
ctx.Strict(secondPrefix+"ADDRESS_SANITIZER_RUNTIME_LIBRARY", strings.TrimSuffix(config.AddressSanitizerRuntimeLibrary(toolchain), ".so"))
diff --git a/cc/relocation_packer.go b/cc/relocation_packer.go
index 5006623..f6a1fe4 100644
--- a/cc/relocation_packer.go
+++ b/cc/relocation_packer.go
@@ -38,12 +38,22 @@
// This will be true even if we're embedded in Make, in which case
// we'll defer to make to actually do the packing.
PackingRelocations bool `blueprint:"mutated"`
+
+ // Use clang lld instead of gnu ld.
+ Use_clang_lld *bool
}
type relocationPacker struct {
Properties RelocationPackerProperties
}
+func (p *relocationPacker) useClangLld(ctx BaseModuleContext) bool {
+ if p.Properties.Use_clang_lld != nil {
+ return Bool(p.Properties.Use_clang_lld)
+ }
+ return ctx.Config().UseClangLld()
+}
+
func (p *relocationPacker) packingInit(ctx BaseModuleContext) {
enabled := true
// Relocation packer isn't available on Darwin yet
@@ -56,6 +66,11 @@
if ctx.Config().Getenv("DISABLE_RELOCATION_PACKER") == "true" {
enabled = false
}
+ // Relocation packer does not work with lld output files.
+ // Packed files won't load.
+ if p.useClangLld(ctx) {
+ enabled = false
+ }
if ctx.useSdk() {
enabled = false
}
diff --git a/java/aapt2.go b/java/aapt2.go
index fd7388e..61e9451 100644
--- a/java/aapt2.go
+++ b/java/aapt2.go
@@ -111,7 +111,8 @@
var aapt2LinkRule = pctx.AndroidStaticRule("aapt2Link",
blueprint.RuleParams{
- Command: `${config.Aapt2Cmd} link -o $out $flags --java $genDir --proguard $proguardOptions $inFlags && ` +
+ Command: `${config.Aapt2Cmd} link -o $out $flags --java $genDir --proguard $proguardOptions ` +
+ `--output-text-symbols ${rTxt} $inFlags && ` +
`${config.SoongZipCmd} -write_if_changed -jar -o $genJar -C $genDir -D $genDir`,
CommandDeps: []string{
"${config.Aapt2Cmd}",
@@ -119,7 +120,7 @@
},
Restat: true,
},
- "flags", "inFlags", "proguardOptions", "genDir", "genJar")
+ "flags", "inFlags", "proguardOptions", "genDir", "genJar", "rTxt")
var fileListToFileRule = pctx.AndroidStaticRule("fileListToFile",
blueprint.RuleParams{
@@ -129,7 +130,7 @@
})
func aapt2Link(ctx android.ModuleContext,
- packageRes, genJar, proguardOptions android.WritablePath,
+ packageRes, genJar, proguardOptions, rTxt android.WritablePath,
flags []string, deps android.Paths,
compiledRes, compiledOverlay android.Paths) {
@@ -171,13 +172,14 @@
Description: "aapt2 link",
Implicits: deps,
Output: packageRes,
- ImplicitOutputs: android.WritablePaths{proguardOptions, genJar},
+ ImplicitOutputs: android.WritablePaths{proguardOptions, genJar, rTxt},
Args: map[string]string{
"flags": strings.Join(flags, " "),
"inFlags": strings.Join(inFlags, " "),
"proguardOptions": proguardOptions.String(),
"genDir": genDir.String(),
"genJar": genJar.String(),
+ "rTxt": rTxt.String(),
},
})
}
diff --git a/java/aar.go b/java/aar.go
index 0df3632..57c752c 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -16,21 +16,307 @@
import (
"android/soong/android"
+ "strings"
"github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
)
+type AndroidLibraryDependency interface {
+ Dependency
+ ExportPackage() android.Path
+}
+
+func init() {
+ android.RegisterModuleType("android_library_import", AARImportFactory)
+ android.RegisterModuleType("android_library", AndroidLibraryFactory)
+}
+
+//
+// AAR (android library)
+//
+
+type androidLibraryProperties struct {
+ BuildAAR bool `blueprint:"mutated"`
+}
+
+type aaptProperties struct {
+ // flags passed to aapt when creating the apk
+ Aaptflags []string
+
+ // list of directories relative to the Blueprints file containing assets.
+ // Defaults to "assets"
+ Asset_dirs []string
+
+ // list of directories relative to the Blueprints file containing
+ // Android resources
+ Resource_dirs []string
+
+ // path to AndroidManifest.xml. If unset, defaults to "AndroidManifest.xml".
+ Manifest *string
+}
+
+type aapt struct {
+ aaptSrcJar android.Path
+ exportPackage android.Path
+ manifestPath android.Path
+ proguardOptionsFile android.Path
+ rroDirs android.Paths
+ rTxt android.Path
+
+ aaptProperties aaptProperties
+}
+
+func (a *aapt) ExportPackage() android.Path {
+ return a.exportPackage
+}
+
+func (a *aapt) aapt2Flags(ctx android.ModuleContext, sdkVersion string) (flags []string, deps android.Paths,
+ resDirs, overlayDirs []globbedResourceDir, overlayFiles, rroDirs android.Paths, manifestPath android.Path) {
+
+ hasVersionCode := false
+ hasVersionName := false
+ hasProduct := false
+ for _, f := range a.aaptProperties.Aaptflags {
+ if strings.HasPrefix(f, "--version-code") {
+ hasVersionCode = true
+ } else if strings.HasPrefix(f, "--version-name") {
+ hasVersionName = true
+ } else if strings.HasPrefix(f, "--product") {
+ hasProduct = true
+ }
+ }
+
+ var linkFlags []string
+
+ // Flags specified in Android.bp
+ linkFlags = append(linkFlags, a.aaptProperties.Aaptflags...)
+
+ linkFlags = append(linkFlags, "--no-static-lib-packages")
+
+ // Find implicit or explicit asset and resource dirs
+ assetDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Asset_dirs, "assets")
+ resourceDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Resource_dirs, "res")
+
+ var linkDeps android.Paths
+
+ // Glob directories into lists of paths
+ for _, dir := range resourceDirs {
+ resDirs = append(resDirs, globbedResourceDir{
+ dir: dir,
+ files: androidResourceGlob(ctx, dir),
+ })
+ resOverlayDirs, resRRODirs := overlayResourceGlob(ctx, dir)
+ overlayDirs = append(overlayDirs, resOverlayDirs...)
+ rroDirs = append(rroDirs, resRRODirs...)
+ }
+
+ var assetFiles android.Paths
+ for _, dir := range assetDirs {
+ assetFiles = append(assetFiles, androidResourceGlob(ctx, dir)...)
+ }
+
+ // App manifest file
+ manifestFile := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml")
+ manifestPath = android.PathForModuleSrc(ctx, manifestFile)
+ linkFlags = append(linkFlags, "--manifest "+manifestPath.String())
+ linkDeps = append(linkDeps, manifestPath)
+
+ linkFlags = append(linkFlags, android.JoinWithPrefix(assetDirs.Strings(), "-A "))
+ linkDeps = append(linkDeps, assetFiles...)
+
+ staticLibs, libDeps, libFlags := aaptLibs(ctx, sdkVersion)
+
+ overlayFiles = append(overlayFiles, staticLibs...)
+ linkDeps = append(linkDeps, libDeps...)
+ linkFlags = append(linkFlags, libFlags...)
+
+ // SDK version flags
+ switch sdkVersion {
+ case "", "current", "system_current", "test_current":
+ sdkVersion = proptools.NinjaEscape([]string{ctx.Config().AppsDefaultVersionName()})[0]
+ }
+
+ linkFlags = append(linkFlags, "--min-sdk-version "+sdkVersion)
+ linkFlags = append(linkFlags, "--target-sdk-version "+sdkVersion)
+
+ // Product characteristics
+ if !hasProduct && len(ctx.Config().ProductAAPTCharacteristics()) > 0 {
+ linkFlags = append(linkFlags, "--product", ctx.Config().ProductAAPTCharacteristics())
+ }
+
+ // Product AAPT config
+ for _, aaptConfig := range ctx.Config().ProductAAPTConfig() {
+ linkFlags = append(linkFlags, "-c", aaptConfig)
+ }
+
+ // Product AAPT preferred config
+ if len(ctx.Config().ProductAAPTPreferredConfig()) > 0 {
+ linkFlags = append(linkFlags, "--preferred-density", ctx.Config().ProductAAPTPreferredConfig())
+ }
+
+ // Version code
+ if !hasVersionCode {
+ linkFlags = append(linkFlags, "--version-code", ctx.Config().PlatformSdkVersion())
+ }
+
+ if !hasVersionName {
+ versionName := proptools.NinjaEscape([]string{ctx.Config().AppsDefaultVersionName()})[0]
+ linkFlags = append(linkFlags, "--version-name ", versionName)
+ }
+
+ return linkFlags, linkDeps, resDirs, overlayDirs, overlayFiles, rroDirs, manifestPath
+}
+
+func (a *aapt) deps(ctx android.BottomUpMutatorContext, sdkVersion string) {
+ if !ctx.Config().UnbundledBuild() {
+ sdkDep := decodeSdkDep(ctx, sdkVersion)
+ if sdkDep.frameworkResModule != "" {
+ ctx.AddDependency(ctx.Module(), frameworkResTag, sdkDep.frameworkResModule)
+ }
+ }
+}
+
+func (a *aapt) buildActions(ctx android.ModuleContext, sdkVersion string, extraLinkFlags ...string) {
+ linkFlags, linkDeps, resDirs, overlayDirs, overlayFiles, rroDirs, manifestPath := a.aapt2Flags(ctx, sdkVersion)
+
+ linkFlags = append(linkFlags, extraLinkFlags...)
+
+ packageRes := android.PathForModuleOut(ctx, "package-res.apk")
+ srcJar := android.PathForModuleGen(ctx, "R.jar")
+ proguardOptionsFile := android.PathForModuleGen(ctx, "proguard.options")
+ rTxt := android.PathForModuleOut(ctx, "R.txt")
+
+ var compiledRes, compiledOverlay android.Paths
+ for _, dir := range resDirs {
+ compiledRes = append(compiledRes, aapt2Compile(ctx, dir.dir, dir.files).Paths()...)
+ }
+ for _, dir := range overlayDirs {
+ compiledOverlay = append(compiledOverlay, aapt2Compile(ctx, dir.dir, dir.files).Paths()...)
+ }
+
+ compiledOverlay = append(compiledOverlay, overlayFiles...)
+
+ aapt2Link(ctx, packageRes, srcJar, proguardOptionsFile, rTxt,
+ linkFlags, linkDeps, compiledRes, compiledOverlay)
+
+ a.aaptSrcJar = srcJar
+ a.exportPackage = packageRes
+ a.manifestPath = manifestPath
+ a.proguardOptionsFile = proguardOptionsFile
+ a.rroDirs = rroDirs
+ a.rTxt = rTxt
+}
+
+// aaptLibs collects libraries from dependencies and sdk_version and converts them into paths
+func aaptLibs(ctx android.ModuleContext, sdkVersion string) (staticLibs, deps android.Paths, flags []string) {
+ var sharedLibs android.Paths
+
+ sdkDep := decodeSdkDep(ctx, sdkVersion)
+ if sdkDep.useFiles {
+ sharedLibs = append(sharedLibs, sdkDep.jar)
+ }
+
+ ctx.VisitDirectDeps(func(module android.Module) {
+ var exportPackage android.Path
+ if aarDep, ok := module.(AndroidLibraryDependency); ok {
+ exportPackage = aarDep.ExportPackage()
+ }
+
+ switch ctx.OtherModuleDependencyTag(module) {
+ case libTag, frameworkResTag:
+ if exportPackage != nil {
+ sharedLibs = append(sharedLibs, exportPackage)
+ }
+ case staticLibTag:
+ if exportPackage != nil {
+ staticLibs = append(staticLibs, exportPackage)
+ }
+ }
+ })
+
+ deps = append(deps, sharedLibs...)
+ deps = append(deps, staticLibs...)
+
+ if len(staticLibs) > 0 {
+ flags = append(flags, "--auto-add-overlay")
+ }
+
+ for _, sharedLib := range sharedLibs {
+ flags = append(flags, "-I "+sharedLib.String())
+ }
+
+ return staticLibs, deps, flags
+}
+
+type AndroidLibrary struct {
+ Library
+ aapt
+
+ androidLibraryProperties androidLibraryProperties
+
+ aarFile android.WritablePath
+}
+
+var _ AndroidLibraryDependency = (*AndroidLibrary)(nil)
+
+func (a *AndroidLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
+ a.Module.deps(ctx)
+ if !Bool(a.properties.No_framework_libs) && !Bool(a.properties.No_standard_libs) {
+ a.aapt.deps(ctx, String(a.deviceProperties.Sdk_version))
+ }
+}
+
+func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ a.aapt.buildActions(ctx, String(a.deviceProperties.Sdk_version), "--static-lib")
+
+ ctx.CheckbuildFile(a.proguardOptionsFile)
+ ctx.CheckbuildFile(a.exportPackage)
+ ctx.CheckbuildFile(a.aaptSrcJar)
+
+ // apps manifests are handled by aapt, don't let Module see them
+ a.properties.Manifest = nil
+
+ a.Module.extraProguardFlagFiles = append(a.Module.extraProguardFlagFiles,
+ a.proguardOptionsFile)
+
+ a.Module.compile(ctx, a.aaptSrcJar)
+
+ a.aarFile = android.PathForOutput(ctx, ctx.ModuleName()+".aar")
+ var res android.Paths
+ if a.androidLibraryProperties.BuildAAR {
+ BuildAAR(ctx, a.aarFile, a.outputFile, a.manifestPath, a.rTxt, res)
+ ctx.CheckbuildFile(a.aarFile)
+ }
+}
+
+func AndroidLibraryFactory() android.Module {
+ module := &AndroidLibrary{}
+
+ module.AddProperties(
+ &module.Module.properties,
+ &module.Module.deviceProperties,
+ &module.Module.protoProperties,
+ &module.aaptProperties,
+ &module.androidLibraryProperties)
+
+ module.androidLibraryProperties.BuildAAR = true
+
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+ return module
+}
+
//
// AAR (android library) prebuilts
//
-func init() {
- android.RegisterModuleType("android_library_import", AARImportFactory)
-}
type AARImportProperties struct {
Aars []string
Sdk_version *string
+
+ Static_libs []string
+ Libs []string
}
type AARImport struct {
@@ -44,6 +330,12 @@
exportPackage android.WritablePath
}
+var _ AndroidLibraryDependency = (*AARImport)(nil)
+
+func (a *AARImport) ExportPackage() android.Path {
+ return a.exportPackage
+}
+
func (a *AARImport) Prebuilt() *android.Prebuilt {
return &a.prebuilt
}
@@ -53,13 +345,15 @@
}
func (a *AARImport) DepsMutator(ctx android.BottomUpMutatorContext) {
- // TODO: this should use decodeSdkDep once that knows about current
if !ctx.Config().UnbundledBuild() {
- switch String(a.properties.Sdk_version) { // TODO: Res_sdk_version?
- case "current", "system_current", "test_current", "":
- ctx.AddDependency(ctx.Module(), frameworkResTag, "framework-res")
+ sdkDep := decodeSdkDep(ctx, String(a.properties.Sdk_version))
+ if sdkDep.useModule && sdkDep.frameworkResModule != "" {
+ ctx.AddDependency(ctx.Module(), frameworkResTag, sdkDep.frameworkResModule)
}
}
+
+ ctx.AddDependency(ctx.Module(), staticLibTag, a.properties.Libs...)
+ ctx.AddDependency(ctx.Module(), staticLibTag, a.properties.Static_libs...)
}
// Unzip an AAR into its constituent files and directories. Any files in Outputs that don't exist in the AAR will be
@@ -105,6 +399,7 @@
a.exportPackage = android.PathForModuleOut(ctx, "package-res.apk")
srcJar := android.PathForModuleGen(ctx, "R.jar")
proguardOptionsFile := android.PathForModuleGen(ctx, "proguard.options")
+ rTxt := android.PathForModuleOut(ctx, "R.txt")
var linkDeps android.Paths
@@ -117,30 +412,15 @@
linkFlags = append(linkFlags, "--manifest "+manifest.String())
linkDeps = append(linkDeps, manifest)
- // Include dirs
- ctx.VisitDirectDeps(func(module android.Module) {
- var depFiles android.Paths
- if javaDep, ok := module.(Dependency); ok {
- // TODO: shared android libraries
- if ctx.OtherModuleName(module) == "framework-res" {
- depFiles = android.Paths{javaDep.(*AndroidApp).exportPackage}
- }
- }
+ staticLibs, libDeps, libFlags := aaptLibs(ctx, String(a.properties.Sdk_version))
- for _, dep := range depFiles {
- linkFlags = append(linkFlags, "-I "+dep.String())
- }
- linkDeps = append(linkDeps, depFiles...)
- })
+ linkDeps = append(linkDeps, libDeps...)
+ linkFlags = append(linkFlags, libFlags...)
- sdkDep := decodeSdkDep(ctx, String(a.properties.Sdk_version))
- if sdkDep.useFiles {
- linkFlags = append(linkFlags, "-I "+sdkDep.jar.String())
- linkDeps = append(linkDeps, sdkDep.jar)
- }
+ overlayRes := append(android.Paths{flata}, staticLibs...)
- aapt2Link(ctx, a.exportPackage, srcJar, proguardOptionsFile,
- linkFlags, linkDeps, nil, android.Paths{flata})
+ aapt2Link(ctx, a.exportPackage, srcJar, proguardOptionsFile, rTxt,
+ linkFlags, linkDeps, nil, overlayRes)
}
var _ Dependency = (*AARImport)(nil)
diff --git a/java/android_resources.go b/java/android_resources.go
new file mode 100644
index 0000000..47535d2
--- /dev/null
+++ b/java/android_resources.go
@@ -0,0 +1,127 @@
+// Copyright 2018 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 (
+ "path/filepath"
+ "strings"
+
+ "android/soong/android"
+)
+
+func init() {
+ android.RegisterPreSingletonType("overlay", OverlaySingletonFactory)
+}
+
+var androidResourceIgnoreFilenames = []string{
+ ".svn",
+ ".git",
+ ".ds_store",
+ "*.scc",
+ ".*",
+ "CVS",
+ "thumbs.db",
+ "picasa.ini",
+ "*~",
+}
+
+func androidResourceGlob(ctx android.ModuleContext, dir android.Path) android.Paths {
+ return ctx.GlobFiles(filepath.Join(dir.String(), "**/*"), androidResourceIgnoreFilenames)
+}
+
+type overlayGlobResult struct {
+ dir string
+ paths android.DirectorySortedPaths
+
+ // Set to true of the product has selected that values in this overlay should not be moved to
+ // Runtime Resource Overlay (RRO) packages.
+ excludeFromRRO bool
+}
+
+const overlayDataKey = "overlayDataKey"
+
+type globbedResourceDir struct {
+ dir android.Path
+ files android.Paths
+}
+
+func overlayResourceGlob(ctx android.ModuleContext, dir android.Path) (res []globbedResourceDir,
+ rroDirs android.Paths) {
+
+ overlayData := ctx.Config().Get(overlayDataKey).([]overlayGlobResult)
+
+ // Runtime resource overlays (RRO) may be turned on by the product config for some modules
+ rroEnabled := ctx.Config().EnforceRROForModule(ctx.ModuleName())
+
+ for _, data := range overlayData {
+ files := data.paths.PathsInDirectory(filepath.Join(data.dir, dir.String()))
+ if len(files) > 0 {
+ overlayModuleDir := android.PathForSource(ctx, data.dir, dir.String())
+ // If enforce RRO is enabled for this module and this overlay is not in the
+ // exclusion list, ignore the overlay. The list of ignored overlays will be
+ // passed to Make to be turned into an RRO package.
+ if rroEnabled && !data.excludeFromRRO {
+ rroDirs = append(rroDirs, overlayModuleDir)
+ } else {
+ res = append(res, globbedResourceDir{
+ dir: overlayModuleDir,
+ files: files,
+ })
+ }
+ }
+ }
+
+ return res, rroDirs
+}
+
+func OverlaySingletonFactory() android.Singleton {
+ return overlaySingleton{}
+}
+
+type overlaySingleton struct{}
+
+func (overlaySingleton) GenerateBuildActions(ctx android.SingletonContext) {
+ var overlayData []overlayGlobResult
+ overlayDirs := ctx.Config().ResourceOverlays()
+ for i := range overlayDirs {
+ // Iterate backwards through the list of overlay directories so that the later, lower-priority
+ // directories in the list show up earlier in the command line to aapt2.
+ overlay := overlayDirs[len(overlayDirs)-1-i]
+ var result overlayGlobResult
+ result.dir = overlay
+
+ // Mark overlays that will not have Runtime Resource Overlays enforced on them
+ // based on the product config
+ result.excludeFromRRO = ctx.Config().EnforceRROExcludedOverlay(overlay)
+
+ files, err := ctx.GlobWithDeps(filepath.Join(overlay, "**/*"), androidResourceIgnoreFilenames)
+ if err != nil {
+ ctx.Errorf("failed to glob resource dir %q: %s", overlay, err.Error())
+ continue
+ }
+ var paths android.Paths
+ for _, f := range files {
+ if !strings.HasSuffix(f, "/") {
+ paths = append(paths, android.PathForSource(ctx, f))
+ }
+ }
+ result.paths = android.PathsToDirectorySortedPaths(paths)
+ overlayData = append(overlayData, result)
+ }
+
+ ctx.Config().Once(overlayDataKey, func() interface{} {
+ return overlayData
+ })
+}
diff --git a/java/androidmk.go b/java/androidmk.go
index 204b3d9..dfbe7fa 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -223,7 +223,31 @@
},
},
}
+}
+func (a *AndroidLibrary) AndroidMk() android.AndroidMkData {
+ data := a.Library.AndroidMk()
+
+ data.Extra = append(data.Extra, func(w io.Writer, outputFile android.Path) {
+ if a.proguardDictionary != nil {
+ fmt.Fprintln(w, "LOCAL_SOONG_PROGUARD_DICT :=", a.proguardDictionary.String())
+ }
+
+ if a.Name() == "framework-res" {
+ fmt.Fprintln(w, "LOCAL_MODULE_PATH := $(TARGET_OUT_JAVA_LIBRARIES)")
+ // Make base_rules.mk not put framework-res in a subdirectory called
+ // framework_res.
+ fmt.Fprintln(w, "LOCAL_NO_STANDARD_LIBRARIES := true")
+ }
+
+ fmt.Fprintln(w, "LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE :=", a.exportPackage.String())
+ fmt.Fprintln(w, "LOCAL_FULL_MANIFEST_FILE :=", a.manifestPath.String())
+ fmt.Fprintln(w, "LOCAL_SOONG_EXPORT_PROGUARD_FLAGS :=", a.proguardOptionsFile.String())
+ fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
+ fmt.Fprintln(w, "LOCAL_DEX_PREOPT := false")
+ })
+
+ return data
}
func (jd *Javadoc) AndroidMk() android.AndroidMkData {
diff --git a/java/app.go b/java/app.go
index c94d22f..3e24ebc 100644
--- a/java/app.go
+++ b/java/app.go
@@ -17,7 +17,6 @@
// This file contains the module types for compiling Android apps.
import (
- "path/filepath"
"strings"
"github.com/google/blueprint/proptools"
@@ -26,11 +25,9 @@
)
func init() {
- android.RegisterPreSingletonType("overlay", OverlaySingletonFactory)
android.RegisterModuleType("android_app", AndroidAppFactory)
}
-// AAR prebuilts
// AndroidManifest.xml merging
// package splits
@@ -46,91 +43,59 @@
// use to get PRODUCT-agnostic resource data like IDs and type definitions.
Export_package_resources *bool
- // flags passed to aapt when creating the apk
- Aaptflags []string
-
- // list of resource labels to generate individual resource packages
- Package_splits []string
-
- // list of directories relative to the Blueprints file containing assets.
- // Defaults to "assets"
- Asset_dirs []string
-
- // list of directories relative to the Blueprints file containing
- // Android resources
- Resource_dirs []string
-
- Instrumentation_for *string
-
// Specifies that this app should be installed to the priv-app directory,
// where the system will grant it additional privileges not available to
// normal apps.
Privileged *bool
+
+ // list of resource labels to generate individual resource packages
+ Package_splits []string
+
+ Instrumentation_for *string
}
type AndroidApp struct {
- Module
+ Library
+ aapt
+
+ certificate certificate
appProperties appProperties
-
- aaptSrcJar android.Path
- exportPackage android.Path
- rroDirs android.Paths
- manifestPath android.Path
- certificate certificate
}
+var _ AndroidLibraryDependency = (*AndroidApp)(nil)
+
type certificate struct {
pem, key android.Path
}
func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) {
a.Module.deps(ctx)
-
if !Bool(a.properties.No_framework_libs) && !Bool(a.properties.No_standard_libs) {
- switch String(a.deviceProperties.Sdk_version) { // TODO: Res_sdk_version?
- case "current", "system_current", "test_current", "":
- ctx.AddDependency(ctx.Module(), frameworkResTag, "framework-res")
- default:
- // We'll already have a dependency on an sdk prebuilt android.jar
- }
+ a.aapt.deps(ctx, String(a.deviceProperties.Sdk_version))
}
}
func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- linkFlags, linkDeps, resDirs, overlayDirs, rroDirs, manifestPath := a.aapt2Flags(ctx)
-
- packageRes := android.PathForModuleOut(ctx, "package-res.apk")
- srcJar := android.PathForModuleGen(ctx, "R.jar")
- proguardOptionsFile := android.PathForModuleGen(ctx, "proguard.options")
-
- var compiledRes, compiledOverlay android.Paths
- for _, dir := range resDirs {
- compiledRes = append(compiledRes, aapt2Compile(ctx, dir.dir, dir.files).Paths()...)
- }
- for _, dir := range overlayDirs {
- compiledOverlay = append(compiledOverlay, aapt2Compile(ctx, dir.dir, dir.files).Paths()...)
+ var linkFlags []string
+ if String(a.appProperties.Instrumentation_for) != "" {
+ linkFlags = append(linkFlags,
+ "--rename-instrumentation-target-package",
+ String(a.appProperties.Instrumentation_for))
+ } else {
+ a.properties.Instrument = true
}
- aapt2Link(ctx, packageRes, srcJar, proguardOptionsFile,
- linkFlags, linkDeps, compiledRes, compiledOverlay)
+ // TODO: LOCAL_PACKAGE_OVERRIDES
+ // $(addprefix --rename-manifest-package , $(PRIVATE_MANIFEST_PACKAGE_NAME)) \
- a.exportPackage = packageRes
- a.aaptSrcJar = srcJar
-
- ctx.CheckbuildFile(proguardOptionsFile)
- ctx.CheckbuildFile(a.exportPackage)
- ctx.CheckbuildFile(a.aaptSrcJar)
+ a.aapt.buildActions(ctx, String(a.deviceProperties.Sdk_version), linkFlags...)
// apps manifests are handled by aapt, don't let Module see them
a.properties.Manifest = nil
- if String(a.appProperties.Instrumentation_for) == "" {
- a.properties.Instrument = true
- }
-
a.Module.extraProguardFlagFiles = append(a.Module.extraProguardFlagFiles,
- proguardOptionsFile)
+ a.proguardOptionsFile)
if ctx.ModuleName() != "framework-res" {
a.Module.compile(ctx, a.aaptSrcJar)
@@ -167,8 +132,6 @@
CreateAppPackage(ctx, packageFile, a.exportPackage, a.outputFile, certificates)
a.outputFile = packageFile
- a.rroDirs = rroDirs
- a.manifestPath = manifestPath
if ctx.ModuleName() == "framework-res" {
// framework-res.apk is installed as system/framework/framework-res.apk
@@ -180,152 +143,6 @@
}
}
-var aaptIgnoreFilenames = []string{
- ".svn",
- ".git",
- ".ds_store",
- "*.scc",
- ".*",
- "CVS",
- "thumbs.db",
- "picasa.ini",
- "*~",
-}
-
-type globbedResourceDir struct {
- dir android.Path
- files android.Paths
-}
-
-func (a *AndroidApp) aapt2Flags(ctx android.ModuleContext) (flags []string, deps android.Paths,
- resDirs, overlayDirs []globbedResourceDir, rroDirs android.Paths, manifestPath android.Path) {
-
- hasVersionCode := false
- hasVersionName := false
- hasProduct := false
- for _, f := range a.appProperties.Aaptflags {
- if strings.HasPrefix(f, "--version-code") {
- hasVersionCode = true
- } else if strings.HasPrefix(f, "--version-name") {
- hasVersionName = true
- } else if strings.HasPrefix(f, "--product") {
- hasProduct = true
- }
- }
-
- var linkFlags []string
-
- // Flags specified in Android.bp
- linkFlags = append(linkFlags, a.appProperties.Aaptflags...)
-
- linkFlags = append(linkFlags, "--no-static-lib-packages")
-
- // Find implicit or explicit asset and resource dirs
- assetDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.appProperties.Asset_dirs, "assets")
- resourceDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.appProperties.Resource_dirs, "res")
-
- var linkDeps android.Paths
-
- // Glob directories into lists of paths
- for _, dir := range resourceDirs {
- resDirs = append(resDirs, globbedResourceDir{
- dir: dir,
- files: resourceGlob(ctx, dir),
- })
- resOverlayDirs, resRRODirs := overlayResourceGlob(ctx, dir)
- overlayDirs = append(overlayDirs, resOverlayDirs...)
- rroDirs = append(rroDirs, resRRODirs...)
- }
-
- var assetFiles android.Paths
- for _, dir := range assetDirs {
- assetFiles = append(assetFiles, resourceGlob(ctx, dir)...)
- }
-
- // App manifest file
- var manifestFile string
- if a.properties.Manifest == nil {
- manifestFile = "AndroidManifest.xml"
- } else {
- manifestFile = *a.properties.Manifest
- }
-
- manifestPath = android.PathForModuleSrc(ctx, manifestFile)
- linkFlags = append(linkFlags, "--manifest "+manifestPath.String())
- linkDeps = append(linkDeps, manifestPath)
-
- linkFlags = append(linkFlags, android.JoinWithPrefix(assetDirs.Strings(), "-A "))
- linkDeps = append(linkDeps, assetFiles...)
-
- // Include dirs
- ctx.VisitDirectDeps(func(module android.Module) {
- var depFiles android.Paths
- if javaDep, ok := module.(Dependency); ok {
- // TODO: shared android libraries
- if ctx.OtherModuleName(module) == "framework-res" {
- depFiles = android.Paths{javaDep.(*AndroidApp).exportPackage}
- }
- }
-
- for _, dep := range depFiles {
- linkFlags = append(linkFlags, "-I "+dep.String())
- }
- linkDeps = append(linkDeps, depFiles...)
- })
-
- sdkDep := decodeSdkDep(ctx, String(a.deviceProperties.Sdk_version))
- if sdkDep.useFiles {
- linkFlags = append(linkFlags, "-I "+sdkDep.jar.String())
- linkDeps = append(linkDeps, sdkDep.jar)
- }
-
- // SDK version flags
- sdkVersion := String(a.deviceProperties.Sdk_version)
- switch sdkVersion {
- case "", "current", "system_current", "test_current":
- sdkVersion = proptools.NinjaEscape([]string{ctx.Config().AppsDefaultVersionName()})[0]
- }
-
- linkFlags = append(linkFlags, "--min-sdk-version "+sdkVersion)
- linkFlags = append(linkFlags, "--target-sdk-version "+sdkVersion)
-
- // Product characteristics
- if !hasProduct && len(ctx.Config().ProductAAPTCharacteristics()) > 0 {
- linkFlags = append(linkFlags, "--product", ctx.Config().ProductAAPTCharacteristics())
- }
-
- // Product AAPT config
- for _, aaptConfig := range ctx.Config().ProductAAPTConfig() {
- linkFlags = append(linkFlags, "-c", aaptConfig)
- }
-
- // Product AAPT preferred config
- if len(ctx.Config().ProductAAPTPreferredConfig()) > 0 {
- linkFlags = append(linkFlags, "--preferred-density", ctx.Config().ProductAAPTPreferredConfig())
- }
-
- // Version code
- if !hasVersionCode {
- linkFlags = append(linkFlags, "--version-code", ctx.Config().PlatformSdkVersion())
- }
-
- if !hasVersionName {
- versionName := proptools.NinjaEscape([]string{ctx.Config().AppsDefaultVersionName()})[0]
- linkFlags = append(linkFlags, "--version-name ", versionName)
- }
-
- if String(a.appProperties.Instrumentation_for) != "" {
- linkFlags = append(linkFlags,
- "--rename-instrumentation-target-package",
- String(a.appProperties.Instrumentation_for))
- }
-
- // TODO: LOCAL_PACKAGE_OVERRIDES
- // $(addprefix --rename-manifest-package , $(PRIVATE_MANIFEST_PACKAGE_NAME)) \
-
- return linkFlags, linkDeps, resDirs, overlayDirs, rroDirs, manifestPath
-}
-
func AndroidAppFactory() android.Module {
module := &AndroidApp{}
@@ -335,92 +152,10 @@
module.AddProperties(
&module.Module.properties,
&module.Module.deviceProperties,
+ &module.Module.protoProperties,
+ &module.aaptProperties,
&module.appProperties)
android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
return module
}
-
-func resourceGlob(ctx android.ModuleContext, dir android.Path) android.Paths {
- return ctx.GlobFiles(filepath.Join(dir.String(), "**/*"), aaptIgnoreFilenames)
-}
-
-type overlayGlobResult struct {
- dir string
- paths android.DirectorySortedPaths
-
- // Set to true of the product has selected that values in this overlay should not be moved to
- // Runtime Resource Overlay (RRO) packages.
- excludeFromRRO bool
-}
-
-const overlayDataKey = "overlayDataKey"
-
-func overlayResourceGlob(ctx android.ModuleContext, dir android.Path) (res []globbedResourceDir,
- rroDirs android.Paths) {
-
- overlayData := ctx.Config().Get(overlayDataKey).([]overlayGlobResult)
-
- // Runtime resource overlays (RRO) may be turned on by the product config for some modules
- rroEnabled := ctx.Config().EnforceRROForModule(ctx.ModuleName())
-
- for _, data := range overlayData {
- files := data.paths.PathsInDirectory(filepath.Join(data.dir, dir.String()))
- if len(files) > 0 {
- overlayModuleDir := android.PathForSource(ctx, data.dir, dir.String())
- // If enforce RRO is enabled for this module and this overlay is not in the
- // exclusion list, ignore the overlay. The list of ignored overlays will be
- // passed to Make to be turned into an RRO package.
- if rroEnabled && !data.excludeFromRRO {
- rroDirs = append(rroDirs, overlayModuleDir)
- } else {
- res = append(res, globbedResourceDir{
- dir: overlayModuleDir,
- files: files,
- })
- }
- }
- }
-
- return res, rroDirs
-}
-
-func OverlaySingletonFactory() android.Singleton {
- return overlaySingleton{}
-}
-
-type overlaySingleton struct{}
-
-func (overlaySingleton) GenerateBuildActions(ctx android.SingletonContext) {
- var overlayData []overlayGlobResult
- overlayDirs := ctx.Config().ResourceOverlays()
- for i := range overlayDirs {
- // Iterate backwards through the list of overlay directories so that the later, lower-priority
- // directories in the list show up earlier in the command line to aapt2.
- overlay := overlayDirs[len(overlayDirs)-1-i]
- var result overlayGlobResult
- result.dir = overlay
-
- // Mark overlays that will not have Runtime Resource Overlays enforced on them
- // based on the product config
- result.excludeFromRRO = ctx.Config().EnforceRROExcludedOverlay(overlay)
-
- files, err := ctx.GlobWithDeps(filepath.Join(overlay, "**/*"), aaptIgnoreFilenames)
- if err != nil {
- ctx.Errorf("failed to glob resource dir %q: %s", overlay, err.Error())
- continue
- }
- var paths android.Paths
- for _, f := range files {
- if !strings.HasSuffix(f, "/") {
- paths = append(paths, android.PathForSource(ctx, f))
- }
- }
- result.paths = android.PathsToDirectorySortedPaths(paths)
- overlayData = append(overlayData, result)
- }
-
- ctx.Config().Once(overlayDataKey, func() interface{} {
- return overlayData
- })
-}
diff --git a/java/app_builder.go b/java/app_builder.go
index 945d7bd..954ca44 100644
--- a/java/app_builder.go
+++ b/java/app_builder.go
@@ -96,3 +96,39 @@
},
})
}
+
+var buildAAR = pctx.AndroidStaticRule("buildAAR",
+ blueprint.RuleParams{
+ Command: `rm -rf ${outDir} && mkdir -p ${outDir} && ` +
+ `cp ${manifest} ${outDir}/AndroidManifest.xml && ` +
+ `cp ${classesJar} ${outDir}/classes.jar && ` +
+ `cp ${rTxt} ${outDir}/R.txt && ` +
+ `${config.SoongZipCmd} -jar -o $out -C ${outDir} -D ${outDir} ${resArgs}`,
+ CommandDeps: []string{"${config.SoongZipCmd}"},
+ },
+ "manifest", "classesJar", "rTxt", "resArgs", "outDir")
+
+func BuildAAR(ctx android.ModuleContext, outputFile android.WritablePath,
+ classesJar, manifest, rTxt android.Path, res android.Paths) {
+
+ // TODO(ccross): uniquify and copy resources with dependencies
+
+ deps := android.Paths{manifest, rTxt}
+ classesJarPath := ""
+ if classesJar != nil {
+ deps = append(deps, classesJar)
+ classesJarPath = classesJar.String()
+ }
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: buildAAR,
+ Implicits: deps,
+ Output: outputFile,
+ Args: map[string]string{
+ "manifest": manifest.String(),
+ "classesJar": classesJarPath,
+ "rTxt": rTxt.String(),
+ "outDir": android.PathForModuleOut(ctx, "aar").String(),
+ },
+ })
+}
diff --git a/java/app_test.go b/java/app_test.go
index ba017a1..7a61771 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -59,41 +59,44 @@
}
func TestApp(t *testing.T) {
- ctx := testApp(t, `
- android_app {
- name: "foo",
- srcs: ["a.java"],
- }
- `)
+ for _, moduleType := range []string{"android_app", "android_library"} {
+ t.Run(moduleType, func(t *testing.T) {
+ ctx := testApp(t, moduleType+` {
+ name: "foo",
+ srcs: ["a.java"],
+ }
+ `)
- foo := ctx.ModuleForTests("foo", "android_common")
+ foo := ctx.ModuleForTests("foo", "android_common")
- expectedLinkImplicits := []string{"AndroidManifest.xml"}
+ expectedLinkImplicits := []string{"AndroidManifest.xml"}
- frameworkRes := ctx.ModuleForTests("framework-res", "android_common")
- expectedLinkImplicits = append(expectedLinkImplicits,
- frameworkRes.Output("package-res.apk").Output.String())
+ frameworkRes := ctx.ModuleForTests("framework-res", "android_common")
+ expectedLinkImplicits = append(expectedLinkImplicits,
+ frameworkRes.Output("package-res.apk").Output.String())
- // Test the mapping from input files to compiled output file names
- compile := foo.Output(compiledResourceFiles[0])
- if !reflect.DeepEqual(resourceFiles, compile.Inputs.Strings()) {
- t.Errorf("expected aapt2 compile inputs expected:\n %#v\n got:\n %#v",
- resourceFiles, compile.Inputs.Strings())
- }
+ // Test the mapping from input files to compiled output file names
+ compile := foo.Output(compiledResourceFiles[0])
+ if !reflect.DeepEqual(resourceFiles, compile.Inputs.Strings()) {
+ t.Errorf("expected aapt2 compile inputs expected:\n %#v\n got:\n %#v",
+ resourceFiles, compile.Inputs.Strings())
+ }
- compiledResourceOutputs := compile.Outputs.Strings()
- sort.Strings(compiledResourceOutputs)
+ compiledResourceOutputs := compile.Outputs.Strings()
+ sort.Strings(compiledResourceOutputs)
- expectedLinkImplicits = append(expectedLinkImplicits, compiledResourceOutputs...)
+ expectedLinkImplicits = append(expectedLinkImplicits, compiledResourceOutputs...)
- list := foo.Output("aapt2/res.list")
- expectedLinkImplicits = append(expectedLinkImplicits, list.Output.String())
+ list := foo.Output("aapt2/res.list")
+ expectedLinkImplicits = append(expectedLinkImplicits, list.Output.String())
- // Check that the link rule uses
- res := ctx.ModuleForTests("foo", "android_common").Output("package-res.apk")
- if !reflect.DeepEqual(expectedLinkImplicits, res.Implicits.Strings()) {
- t.Errorf("expected aapt2 link implicits expected:\n %#v\n got:\n %#v",
- expectedLinkImplicits, res.Implicits.Strings())
+ // Check that the link rule uses
+ res := ctx.ModuleForTests("foo", "android_common").Output("package-res.apk")
+ if !reflect.DeepEqual(expectedLinkImplicits, res.Implicits.Strings()) {
+ t.Errorf("expected aapt2 link implicits expected:\n %#v\n got:\n %#v",
+ expectedLinkImplicits, res.Implicits.Strings())
+ }
+ })
}
}
diff --git a/java/genrule.go b/java/genrule.go
index 80b7030..8f29482 100644
--- a/java/genrule.go
+++ b/java/genrule.go
@@ -21,6 +21,7 @@
func init() {
android.RegisterModuleType("java_genrule", genRuleFactory)
+ android.RegisterModuleType("java_genrule_host", genRuleFactoryHost)
}
// java_genrule is a genrule that can depend on other java_* objects.
@@ -33,3 +34,14 @@
return module
}
+
+// java_genrule_host is a genrule that can depend on other java_* objects.
+// The cmd may be run multiple times, once for each of the different host/device
+// variations.
+func genRuleFactoryHost() android.Module {
+ module := genrule.NewGenRule()
+
+ android.InitAndroidArchModule(module, android.HostSupported, android.MultilibCommon)
+
+ return module
+}
diff --git a/java/java.go b/java/java.go
index 04ce469..bc58df3 100644
--- a/java/java.go
+++ b/java/java.go
@@ -334,6 +334,8 @@
module string
systemModules string
+ frameworkResModule string
+
jar android.Path
aidl android.Path
}
@@ -423,11 +425,12 @@
}
}
- toModule := func(m string) sdkDep {
+ toModule := func(m, r string) sdkDep {
ret := sdkDep{
- useModule: true,
- module: m,
- systemModules: m + "_system_modules",
+ useModule: true,
+ module: m,
+ systemModules: m + "_system_modules",
+ frameworkResModule: r,
}
if m == "core.current.stubs" {
ret.systemModules = "core-system-modules"
@@ -442,16 +445,17 @@
switch v {
case "":
return sdkDep{
- useDefaultLibs: true,
+ useDefaultLibs: true,
+ frameworkResModule: "framework-res",
}
case "current":
- return toModule("android_stubs_current")
+ return toModule("android_stubs_current", "framework-res")
case "system_current":
- return toModule("android_system_stubs_current")
+ return toModule("android_system_stubs_current", "framework-res")
case "test_current":
- return toModule("android_test_stubs_current")
+ return toModule("android_test_stubs_current", "framework-res")
case "core_current":
- return toModule("core.current.stubs")
+ return toModule("core.current.stubs", "")
default:
return toFile(v)
}
@@ -681,7 +685,10 @@
tag := ctx.OtherModuleDependencyTag(module)
if to, ok := module.(*Library); ok {
- checkLinkType(ctx, j, to, tag.(dependencyTag))
+ switch tag {
+ case bootClasspathTag, libTag, staticLibTag:
+ checkLinkType(ctx, j, to, tag.(dependencyTag))
+ }
}
switch dep := module.(type) {
case Dependency:
diff --git a/java/resources.go b/java/java_resources.go
similarity index 100%
rename from java/resources.go
rename to java/java_resources.go
diff --git a/java/java_test.go b/java/java_test.go
index a85778f..0e7bb18 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -70,6 +70,7 @@
ctx := android.NewTestArchContext()
ctx.RegisterModuleType("android_app", android.ModuleFactoryAdaptor(AndroidAppFactory))
+ ctx.RegisterModuleType("android_library", android.ModuleFactoryAdaptor(AndroidLibraryFactory))
ctx.RegisterModuleType("java_binary_host", android.ModuleFactoryAdaptor(BinaryHostFactory))
ctx.RegisterModuleType("java_library", android.ModuleFactoryAdaptor(LibraryFactory(true)))
ctx.RegisterModuleType("java_library_host", android.ModuleFactoryAdaptor(LibraryHostFactory))