Merge "Switch to toybox find for darwin and linux."
diff --git a/Android.bp b/Android.bp
index 5c76f5a..20d45e5 100644
--- a/Android.bp
+++ b/Android.bp
@@ -45,6 +45,7 @@
"android/api_levels.go",
"android/arch.go",
"android/config.go",
+ "android/csuite_config.go",
"android/defaults.go",
"android/defs.go",
"android/expand.go",
@@ -67,6 +68,7 @@
"android/proto.go",
"android/register.go",
"android/rule_builder.go",
+ "android/sdk.go",
"android/sh_binary.go",
"android/singleton.go",
"android/testing.go",
@@ -84,6 +86,7 @@
"android/androidmk_test.go",
"android/arch_test.go",
"android/config_test.go",
+ "android/csuite_config_test.go",
"android/expand_test.go",
"android/module_test.go",
"android/mutator_test.go",
@@ -171,6 +174,7 @@
"cc/vndk_prebuilt.go",
"cc/xom.go",
+ "cc/cflag_artifacts.go",
"cc/cmakelists.go",
"cc/compdb.go",
"cc/compiler.go",
@@ -208,7 +212,6 @@
"cc/prebuilt_test.go",
"cc/proto_test.go",
"cc/test_data_test.go",
- "cc/util_test.go",
],
pluginFor: ["soong_build"],
}
@@ -293,6 +296,7 @@
"java/support_libraries.go",
"java/system_modules.go",
"java/testing.go",
+ "java/tradefed.go",
],
testSrcs: [
"java/androidmk_test.go",
@@ -304,7 +308,6 @@
"java/jdeps_test.go",
"java/kotlin_test.go",
"java/plugin_test.go",
- "java/robolectric_test.go",
"java/sdk_test.go",
],
pluginFor: ["soong_build"],
@@ -326,6 +329,54 @@
}
bootstrap_go_package {
+ name: "soong-rust-config",
+ pkgPath: "android/soong/rust/config",
+ deps: [
+ "soong-android",
+ "soong-cc-config",
+ ],
+ srcs: [
+ "rust/config/arm_device.go",
+ "rust/config/arm64_device.go",
+ "rust/config/global.go",
+ "rust/config/toolchain.go",
+ "rust/config/whitelist.go",
+ "rust/config/x86_darwin_host.go",
+ "rust/config/x86_linux_host.go",
+ "rust/config/x86_64_device.go",
+ ],
+}
+
+bootstrap_go_package {
+ name: "soong-rust",
+ pkgPath: "android/soong/rust",
+ deps: [
+ "soong",
+ "soong-android",
+ "soong-cc",
+ "soong-rust-config",
+ ],
+ srcs: [
+ "rust/androidmk.go",
+ "rust/compiler.go",
+ "rust/binary.go",
+ "rust/builder.go",
+ "rust/library.go",
+ "rust/prebuilt.go",
+ "rust/proc_macro.go",
+ "rust/rust.go",
+ "rust/testing.go",
+ ],
+ testSrcs: [
+ "rust/binary_test.go",
+ "rust/compiler_test.go",
+ "rust/library_test.go",
+ "rust/rust_test.go",
+ ],
+ pluginFor: ["soong_build"],
+}
+
+bootstrap_go_package {
name: "soong-python",
pkgPath: "android/soong/python",
deps: [
@@ -431,6 +482,27 @@
pluginFor: ["soong_build"],
}
+bootstrap_go_package {
+ name: "soong-sdk",
+ pkgPath: "android/soong/sdk",
+ deps: [
+ "blueprint",
+ "soong",
+ "soong-android",
+ "soong-apex",
+ "soong-cc",
+ "soong-java",
+ ],
+ srcs: [
+ "sdk/sdk.go",
+ "sdk/update.go",
+ ],
+ testSrcs: [
+ "sdk/sdk_test.go",
+ ],
+ pluginFor: ["soong_build"],
+}
+
//
// Defaults to enable various configurations of host bionic
//
@@ -558,7 +630,6 @@
"__gnu_unwind_execute",
"__gnu_unwind_frame",
],
- use_gnu_strip: true,
},
},
arm64: {
@@ -606,7 +677,6 @@
"__register_frame_info_table_bases",
"__register_frame_table",
],
- use_gnu_strip: true,
},
}
diff --git a/OWNERS b/OWNERS
index 4ae045d..797229f 100644
--- a/OWNERS
+++ b/OWNERS
@@ -4,3 +4,4 @@
per-file clang.go,global.go = srhines@google.com, chh@google.com, pirama@google.com, yikong@google.com
per-file tidy.go = srhines@google.com, chh@google.com
per-file lto.go,pgo.go = srhines@google.com, pirama@google.com, yikong@google.com
+per-file rust/config/whitelist.go = chh@google.com, ivanlozano@google.com, jeffv@google.com, jgalenson@google.com, srhines@google.com
diff --git a/android/androidmk.go b/android/androidmk.go
index 1f1bd70..b66fd18 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -79,12 +79,16 @@
header bytes.Buffer
footer bytes.Buffer
- AddCustomEntries func(name, prefix, moduleDir string, entries *AndroidMkEntries)
+ ExtraEntries []AndroidMkExtraEntriesFunc
+ ExtraFooters []AndroidMkExtraFootersFunc
EntryMap map[string][]string
entryOrder []string
}
+type AndroidMkExtraEntriesFunc func(entries *AndroidMkEntries)
+type AndroidMkExtraFootersFunc func(w io.Writer, name, prefix, moduleDir string, entries *AndroidMkEntries)
+
func (a *AndroidMkEntries) SetString(name, value string) {
if _, ok := a.EntryMap[name]; !ok {
a.entryOrder = append(a.entryOrder, name)
@@ -92,6 +96,13 @@
a.EntryMap[name] = []string{value}
}
+func (a *AndroidMkEntries) SetPath(name string, path Path) {
+ if _, ok := a.EntryMap[name]; !ok {
+ a.entryOrder = append(a.entryOrder, name)
+ }
+ a.EntryMap[name] = []string{path.String()}
+}
+
func (a *AndroidMkEntries) SetBoolIfTrue(name string, flag bool) {
if flag {
if _, ok := a.EntryMap[name]; !ok {
@@ -101,6 +112,17 @@
}
}
+func (a *AndroidMkEntries) SetBool(name string, flag bool) {
+ if _, ok := a.EntryMap[name]; !ok {
+ a.entryOrder = append(a.entryOrder, name)
+ }
+ if flag {
+ a.EntryMap[name] = []string{"true"}
+ } else {
+ a.EntryMap[name] = []string{"false"}
+ }
+}
+
func (a *AndroidMkEntries) AddStrings(name string, value ...string) {
if len(value) == 0 {
return
@@ -177,19 +199,19 @@
switch amod.Os().Class {
case Host:
// Make cannot identify LOCAL_MODULE_HOST_ARCH:= common.
- if archStr != "common" {
+ if amod.Arch().ArchType != Common {
a.SetString("LOCAL_MODULE_HOST_ARCH", archStr)
}
host = true
case HostCross:
// Make cannot identify LOCAL_MODULE_HOST_CROSS_ARCH:= common.
- if archStr != "common" {
+ if amod.Arch().ArchType != Common {
a.SetString("LOCAL_MODULE_HOST_CROSS_ARCH", archStr)
}
host = true
case Device:
// Make cannot identify LOCAL_MODULE_TARGET_ARCH:= common.
- if archStr != "common" {
+ if amod.Arch().ArchType != Common {
if amod.Target().NativeBridge {
hostArchStr := amod.Target().NativeBridgeHostArchName
if hostArchStr != "" {
@@ -246,16 +268,27 @@
prefix = "2ND_" + prefix
}
}
- blueprintDir := filepath.Dir(bpPath)
- if a.AddCustomEntries != nil {
- a.AddCustomEntries(name, prefix, blueprintDir, a)
+ for _, extra := range a.ExtraEntries {
+ extra(a)
}
// Write to footer.
fmt.Fprintln(&a.footer, "include "+a.Include)
+ blueprintDir := filepath.Dir(bpPath)
+ for _, footerFunc := range a.ExtraFooters {
+ footerFunc(&a.footer, name, prefix, blueprintDir, a)
+ }
}
func (a *AndroidMkEntries) write(w io.Writer) {
+ if a.Disabled {
+ return
+ }
+
+ if !a.OutputFile.Valid() {
+ return
+ }
+
w.Write(a.header.Bytes())
for _, name := range a.entryOrder {
fmt.Fprintln(w, name+" := "+strings.Join(a.EntryMap[name], " "))
@@ -263,6 +296,10 @@
w.Write(a.footer.Bytes())
}
+func (a *AndroidMkEntries) FooterLinesForTests() []string {
+ return strings.Split(string(a.footer.Bytes()), "\n")
+}
+
func AndroidMkSingleton() Singleton {
return &androidMkSingleton{}
}
diff --git a/android/apex.go b/android/apex.go
index 99b13ab..5118a0a 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -19,7 +19,6 @@
"sync"
"github.com/google/blueprint"
- "github.com/google/blueprint/proptools"
)
// ApexModule is the interface that a module type is expected to implement if
@@ -76,13 +75,21 @@
// CreateApexVariations.
setApexName(apexName string)
- // Return the no_apex property
- NoApex() bool
+ // Tests if this module is available for the specified APEX or ":platform"
+ AvailableFor(what string) bool
+
+ // DepIsInSameApex tests if the other module 'dep' is installed to the same
+ // APEX as this module
+ DepIsInSameApex(ctx BaseModuleContext, dep Module) bool
}
type ApexProperties struct {
- // Whether this module should not be part of any APEX. Default is false.
- No_apex *bool
+ // Availability of this module in APEXes. Only the listed APEXes can include this module.
+ // "//apex_available:anyapex" is a pseudo APEX name that matches to any APEX.
+ // "//apex_available:platform" refers to non-APEX partitions like "system.img".
+ // Default is ["//apex_available:platform", "//apex_available:anyapex"].
+ // TODO(b/128708192) change the default to ["//apex_available:platform"]
+ Apex_available []string
// Name of the apex variant that this module is mutated into
ApexName string `blueprint:"mutated"`
@@ -132,19 +139,57 @@
return false
}
-func (m *ApexModuleBase) NoApex() bool {
- return proptools.Bool(m.ApexProperties.No_apex)
+const (
+ availableToPlatform = "//apex_available:platform"
+ availableToAnyApex = "//apex_available:anyapex"
+)
+
+func CheckAvailableForApex(what string, apex_available []string) bool {
+ if len(apex_available) == 0 {
+ // apex_available defaults to ["//apex_available:platform", "//apex_available:anyapex"],
+ // which means 'available to everybody'.
+ return true
+ }
+ return InList(what, apex_available) ||
+ (what != availableToPlatform && InList(availableToAnyApex, apex_available))
+}
+
+func (m *ApexModuleBase) AvailableFor(what string) bool {
+ return CheckAvailableForApex(what, m.ApexProperties.Apex_available)
+}
+
+func (m *ApexModuleBase) DepIsInSameApex(ctx BaseModuleContext, dep Module) bool {
+ // By default, if there is a dependency from A to B, we try to include both in the same APEX,
+ // unless B is explicitly from outside of the APEX (i.e. a stubs lib). Thus, returning true.
+ // This is overridden by some module types like apex.ApexBundle, cc.Module, java.Module, etc.
+ return true
+}
+
+func (m *ApexModuleBase) checkApexAvailableProperty(mctx BaseModuleContext) {
+ for _, n := range m.ApexProperties.Apex_available {
+ if n == availableToPlatform || n == availableToAnyApex {
+ continue
+ }
+ if !mctx.OtherModuleExists(n) && !mctx.Config().AllowMissingDependencies() {
+ mctx.PropertyErrorf("apex_available", "%q is not a valid module name", n)
+ }
+ }
}
func (m *ApexModuleBase) CreateApexVariations(mctx BottomUpMutatorContext) []blueprint.Module {
if len(m.apexVariations) > 0 {
+ m.checkApexAvailableProperty(mctx)
sort.Strings(m.apexVariations)
- variations := []string{""} // Original variation for platform
+ variations := []string{}
+ availableForPlatform := mctx.Module().(ApexModule).AvailableFor(availableToPlatform)
+ if availableForPlatform {
+ variations = append(variations, "") // Original variation for platform
+ }
variations = append(variations, m.apexVariations...)
modules := mctx.CreateVariations(variations...)
for i, m := range modules {
- if i == 0 {
+ if availableForPlatform && i == 0 {
continue
}
m.(ApexModule).setApexName(variations[i])
diff --git a/android/api_levels.go b/android/api_levels.go
index 961685a..4f6efee 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -71,6 +71,7 @@
"O": 26,
"O-MR1": 27,
"P": 28,
+ "Q": 29,
}
for i, codename := range config.PlatformVersionCombinedCodenames() {
apiLevelsMap[codename] = baseApiLevel + i
diff --git a/android/arch.go b/android/arch.go
index 907c58b..0519e76 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -22,9 +22,12 @@
"strconv"
"strings"
+ "github.com/google/blueprint"
"github.com/google/blueprint/proptools"
)
+const COMMON_VARIANT = "common"
+
var (
archTypeList []ArchType
@@ -36,7 +39,7 @@
X86_64 = newArch("x86_64", "lib64")
Common = ArchType{
- Name: "common",
+ Name: COMMON_VARIANT,
}
)
@@ -527,7 +530,6 @@
CpuVariant string
Abi []string
ArchFeatures []string
- Native bool
}
func (a Arch) String() string {
@@ -703,11 +705,82 @@
}
func (target Target) String() string {
- variant := ""
+ return target.OsVariation() + "_" + target.ArchVariation()
+}
+
+func (target Target) OsVariation() string {
+ return target.Os.String()
+}
+
+func (target Target) ArchVariation() string {
+ var variation string
if target.NativeBridge {
- variant = "native_bridge_"
+ variation = "native_bridge_"
}
- return target.Os.String() + "_" + variant + target.Arch.String()
+ variation += target.Arch.String()
+
+ return variation
+}
+
+func (target Target) Variations() []blueprint.Variation {
+ return []blueprint.Variation{
+ {Mutator: "os", Variation: target.OsVariation()},
+ {Mutator: "arch", Variation: target.ArchVariation()},
+ }
+}
+
+func osMutator(mctx BottomUpMutatorContext) {
+ var module Module
+ var ok bool
+ if module, ok = mctx.Module().(Module); !ok {
+ return
+ }
+
+ base := module.base()
+
+ if !base.ArchSpecific() {
+ return
+ }
+
+ osClasses := base.OsClassSupported()
+
+ var moduleOSList []OsType
+
+ for _, os := range osTypeList {
+ supportedClass := false
+ for _, osClass := range osClasses {
+ if os.Class == osClass {
+ supportedClass = true
+ }
+ }
+ if !supportedClass {
+ continue
+ }
+
+ if len(mctx.Config().Targets[os]) == 0 {
+ continue
+ }
+
+ moduleOSList = append(moduleOSList, os)
+ }
+
+ if len(moduleOSList) == 0 {
+ base.commonProperties.Enabled = boolPtr(false)
+ return
+ }
+
+ osNames := make([]string, len(moduleOSList))
+
+ for i, os := range moduleOSList {
+ osNames[i] = os.String()
+ }
+
+ modules := mctx.CreateVariations(osNames...)
+ for i, m := range modules {
+ m.(Module).base().commonProperties.CompileOS = moduleOSList[i]
+ m.(Module).base().setOSProperties(mctx)
+ }
+
}
// archMutator splits a module into a variant for each Target requested by the module. Target selection
@@ -747,84 +820,63 @@
return
}
- var moduleTargets []Target
- moduleMultiTargets := make(map[int][]Target)
- primaryModules := make(map[int]bool)
- osClasses := base.OsClassSupported()
+ os := base.commonProperties.CompileOS
+ osTargets := mctx.Config().Targets[os]
- for _, os := range osTypeList {
- supportedClass := false
- for _, osClass := range osClasses {
- if os.Class == osClass {
- supportedClass = true
+ // Filter NativeBridge targets unless they are explicitly supported
+ if os == Android && !Bool(base.commonProperties.Native_bridge_supported) {
+ var targets []Target
+ for _, t := range osTargets {
+ if !t.NativeBridge {
+ targets = append(targets, t)
}
}
- if !supportedClass {
- continue
- }
- osTargets := mctx.Config().Targets[os]
- if len(osTargets) == 0 {
- continue
- }
+ osTargets = targets
+ }
- // Filter NativeBridge targets unless they are explicitly supported
- if os == Android && !Bool(base.commonProperties.Native_bridge_supported) {
- var targets []Target
- for _, t := range osTargets {
- if !t.NativeBridge {
- targets = append(targets, t)
- }
- }
+ // only the primary arch in the recovery partition
+ if os == Android && module.InstallInRecovery() {
+ osTargets = []Target{osTargets[0]}
+ }
- osTargets = targets
- }
+ prefer32 := false
+ if base.prefer32 != nil {
+ prefer32 = base.prefer32(mctx, base, os.Class)
+ }
- // only the primary arch in the recovery partition
- if os == Android && module.InstallInRecovery() {
- osTargets = []Target{osTargets[0]}
- }
+ multilib, extraMultilib := decodeMultilib(base, os.Class)
+ targets, err := decodeMultilibTargets(multilib, osTargets, prefer32)
+ if err != nil {
+ mctx.ModuleErrorf("%s", err.Error())
+ }
- prefer32 := false
- if base.prefer32 != nil {
- prefer32 = base.prefer32(mctx, base, os.Class)
- }
-
- multilib, extraMultilib := decodeMultilib(base, os.Class)
- targets, err := decodeMultilibTargets(multilib, osTargets, prefer32)
+ var multiTargets []Target
+ if extraMultilib != "" {
+ multiTargets, err = decodeMultilibTargets(extraMultilib, osTargets, prefer32)
if err != nil {
mctx.ModuleErrorf("%s", err.Error())
}
-
- var multiTargets []Target
- if extraMultilib != "" {
- multiTargets, err = decodeMultilibTargets(extraMultilib, osTargets, prefer32)
- if err != nil {
- mctx.ModuleErrorf("%s", err.Error())
- }
- }
-
- if len(targets) > 0 {
- primaryModules[len(moduleTargets)] = true
- moduleMultiTargets[len(moduleTargets)] = multiTargets
- moduleTargets = append(moduleTargets, targets...)
- }
}
- if len(moduleTargets) == 0 {
+ if len(targets) == 0 {
base.commonProperties.Enabled = boolPtr(false)
return
}
- targetNames := make([]string, len(moduleTargets))
+ targetNames := make([]string, len(targets))
- for i, target := range moduleTargets {
- targetNames[i] = target.String()
+ for i, target := range targets {
+ targetNames[i] = target.ArchVariation()
}
modules := mctx.CreateVariations(targetNames...)
for i, m := range modules {
- m.(Module).base().SetTarget(moduleTargets[i], moduleMultiTargets[i], primaryModules[i])
+ m.(Module).base().commonProperties.CompileTarget = targets[i]
+ m.(Module).base().commonProperties.CompileMultiTargets = multiTargets
+ if i == 0 {
+ m.(Module).base().commonProperties.CompilePrimary = true
+ }
m.(Module).base().setArchProperties(mctx)
}
}
@@ -855,149 +907,11 @@
}
}
-func filterArchStructFields(fields []reflect.StructField) (filteredFields []reflect.StructField, filtered bool) {
- for _, field := range fields {
- if !proptools.HasTag(field, "android", "arch_variant") {
- filtered = true
- continue
- }
-
- // The arch_variant field isn't necessary past this point
- // Instead of wasting space, just remove it. Go also has a
- // 16-bit limit on structure name length. The name is constructed
- // based on the Go source representation of the structure, so
- // the tag names count towards that length.
- //
- // TODO: handle the uncommon case of other tags being involved
- if field.Tag == `android:"arch_variant"` {
- field.Tag = ""
- }
-
- // Recurse into structs
- switch field.Type.Kind() {
- case reflect.Struct:
- var subFiltered bool
- field.Type, subFiltered = filterArchStruct(field.Type)
- filtered = filtered || subFiltered
- if field.Type == nil {
- continue
- }
- case reflect.Ptr:
- if field.Type.Elem().Kind() == reflect.Struct {
- nestedType, subFiltered := filterArchStruct(field.Type.Elem())
- filtered = filtered || subFiltered
- if nestedType == nil {
- continue
- }
- field.Type = reflect.PtrTo(nestedType)
- }
- case reflect.Interface:
- panic("Interfaces are not supported in arch_variant properties")
- }
-
- filteredFields = append(filteredFields, field)
- }
-
- return filteredFields, filtered
-}
-
-// filterArchStruct takes a reflect.Type that is either a sturct or a pointer to a struct, and returns a reflect.Type
-// that only contains the fields in the original type that have an `android:"arch_variant"` struct tag, and a bool
-// that is true if the new struct type has fewer fields than the original type. If there are no fields in the
-// original type with the struct tag it returns nil and true.
-func filterArchStruct(prop reflect.Type) (filteredProp reflect.Type, filtered bool) {
- var fields []reflect.StructField
-
- ptr := prop.Kind() == reflect.Ptr
- if ptr {
- prop = prop.Elem()
- }
-
- for i := 0; i < prop.NumField(); i++ {
- fields = append(fields, prop.Field(i))
- }
-
- filteredFields, filtered := filterArchStructFields(fields)
-
- if len(filteredFields) == 0 {
- return nil, true
- }
-
- if !filtered {
- if ptr {
- return reflect.PtrTo(prop), false
- }
- return prop, false
- }
-
- ret := reflect.StructOf(filteredFields)
- if ptr {
- ret = reflect.PtrTo(ret)
- }
-
- return ret, true
-}
-
-// filterArchStruct takes a reflect.Type that is either a sturct or a pointer to a struct, and returns a list of
-// reflect.Type that only contains the fields in the original type that have an `android:"arch_variant"` struct tag,
-// and a bool that is true if the new struct type has fewer fields than the original type. If there are no fields in
-// the original type with the struct tag it returns nil and true. Each returned struct type will have a maximum of
-// 10 top level fields in it to attempt to avoid hitting the reflect.StructOf name length limit, although the limit
-// can still be reached with a single struct field with many fields in it.
-func filterArchStructSharded(prop reflect.Type) (filteredProp []reflect.Type, filtered bool) {
- var fields []reflect.StructField
-
- ptr := prop.Kind() == reflect.Ptr
- if ptr {
- prop = prop.Elem()
- }
-
- for i := 0; i < prop.NumField(); i++ {
- fields = append(fields, prop.Field(i))
- }
-
- fields, filtered = filterArchStructFields(fields)
- if !filtered {
- if ptr {
- return []reflect.Type{reflect.PtrTo(prop)}, false
- }
- return []reflect.Type{prop}, false
- }
-
- if len(fields) == 0 {
- return nil, true
- }
-
- shards := shardFields(fields, 10)
-
- for _, shard := range shards {
- s := reflect.StructOf(shard)
- if ptr {
- s = reflect.PtrTo(s)
- }
- filteredProp = append(filteredProp, s)
- }
-
- return filteredProp, true
-}
-
-func shardFields(fields []reflect.StructField, shardSize int) [][]reflect.StructField {
- ret := make([][]reflect.StructField, 0, (len(fields)+shardSize-1)/shardSize)
- for len(fields) > shardSize {
- ret = append(ret, fields[0:shardSize])
- fields = fields[shardSize:]
- }
- if len(fields) > 0 {
- ret = append(ret, fields)
- }
- return ret
-}
-
// createArchType takes a reflect.Type that is either a struct or a pointer to a struct, and returns a list of
// reflect.Type that contains the arch-variant properties inside structs for each architecture, os, target, multilib,
// etc.
func createArchType(props reflect.Type) []reflect.Type {
- propShards, _ := filterArchStructSharded(props)
+ propShards, _ := proptools.FilterPropertyStructSharded(props, filterArchStruct)
if len(propShards) == 0 {
return nil
}
@@ -1096,6 +1010,23 @@
return ret
}
+func filterArchStruct(field reflect.StructField, prefix string) (bool, reflect.StructField) {
+ if proptools.HasTag(field, "android", "arch_variant") {
+ // The arch_variant field isn't necessary past this point
+ // Instead of wasting space, just remove it. Go also has a
+ // 16-bit limit on structure name length. The name is constructed
+ // based on the Go source representation of the structure, so
+ // the tag names count towards that length.
+ //
+ // TODO: handle the uncommon case of other tags being involved
+ if field.Tag == `android:"arch_variant"` {
+ field.Tag = ""
+ }
+ return true, field
+ }
+ return false, field
+}
+
var archPropTypeMap OncePer
func InitArchModule(m Module) {
@@ -1172,6 +1103,100 @@
return ret
}
+// Rewrite the module's properties structs to contain os-specific values.
+func (m *ModuleBase) setOSProperties(ctx BottomUpMutatorContext) {
+ os := m.commonProperties.CompileOS
+
+ for i := range m.generalProperties {
+ genProps := m.generalProperties[i]
+ if m.archProperties[i] == nil {
+ continue
+ }
+ for _, archProperties := range m.archProperties[i] {
+ archPropValues := reflect.ValueOf(archProperties).Elem()
+
+ targetProp := archPropValues.FieldByName("Target")
+
+ // Handle host-specific properties in the form:
+ // target: {
+ // host: {
+ // key: value,
+ // },
+ // },
+ if os.Class == Host || os.Class == HostCross {
+ field := "Host"
+ prefix := "target.host"
+ m.appendProperties(ctx, genProps, targetProp, field, prefix)
+ }
+
+ // Handle target OS generalities of the form:
+ // target: {
+ // bionic: {
+ // key: value,
+ // },
+ // }
+ if os.Linux() {
+ field := "Linux"
+ prefix := "target.linux"
+ m.appendProperties(ctx, genProps, targetProp, field, prefix)
+ }
+
+ if os.Bionic() {
+ field := "Bionic"
+ prefix := "target.bionic"
+ m.appendProperties(ctx, genProps, targetProp, field, prefix)
+ }
+
+ // Handle target OS properties in the form:
+ // target: {
+ // linux_glibc: {
+ // key: value,
+ // },
+ // not_windows: {
+ // key: value,
+ // },
+ // android {
+ // key: value,
+ // },
+ // },
+ field := os.Field
+ prefix := "target." + os.Name
+ m.appendProperties(ctx, genProps, targetProp, field, prefix)
+
+ if (os.Class == Host || os.Class == HostCross) && os != Windows {
+ field := "Not_windows"
+ prefix := "target.not_windows"
+ m.appendProperties(ctx, genProps, targetProp, field, prefix)
+ }
+
+ // Handle 64-bit device properties in the form:
+ // target {
+ // android64 {
+ // key: value,
+ // },
+ // android32 {
+ // key: value,
+ // },
+ // },
+ // WARNING: this is probably not what you want to use in your blueprints file, it selects
+ // options for all targets on a device that supports 64-bit binaries, not just the targets
+ // that are being compiled for 64-bit. Its expected use case is binaries like linker and
+ // debuggerd that need to know when they are a 32-bit process running on a 64-bit device
+ if os.Class == Device {
+ if ctx.Config().Android64() {
+ field := "Android64"
+ prefix := "target.android64"
+ m.appendProperties(ctx, genProps, targetProp, field, prefix)
+ } else {
+ field := "Android32"
+ prefix := "target.android32"
+ m.appendProperties(ctx, genProps, targetProp, field, prefix)
+ }
+ }
+ }
+ }
+}
+
// Rewrite the module's properties structs to contain arch-specific values.
func (m *ModuleBase) setArchProperties(ctx BottomUpMutatorContext) {
arch := m.Arch()
@@ -1189,9 +1214,6 @@
multilibProp := archPropValues.FieldByName("Multilib")
targetProp := archPropValues.FieldByName("Target")
- var field string
- var prefix string
-
// Handle arch-specific properties in the form:
// arch: {
// arm64: {
@@ -1256,68 +1278,32 @@
m.appendProperties(ctx, genProps, multilibProp, field, prefix)
}
- // Handle host-specific properties in the form:
+ // Handle combined OS-feature and arch specific properties in the form:
// target: {
- // host: {
- // key: value,
- // },
- // },
- if os.Class == Host || os.Class == HostCross {
- field = "Host"
- prefix = "target.host"
- m.appendProperties(ctx, genProps, targetProp, field, prefix)
- }
-
- // Handle target OS generalities of the form:
- // target: {
- // bionic: {
- // key: value,
- // },
// bionic_x86: {
// key: value,
// },
// }
- if os.Linux() {
- field = "Linux"
- prefix = "target.linux"
+ if os.Linux() && arch.ArchType != Common {
+ field := "Linux_" + arch.ArchType.Name
+ prefix := "target.linux_" + arch.ArchType.Name
m.appendProperties(ctx, genProps, targetProp, field, prefix)
-
- if arch.ArchType != Common {
- field = "Linux_" + arch.ArchType.Name
- prefix = "target.linux_" + arch.ArchType.Name
- m.appendProperties(ctx, genProps, targetProp, field, prefix)
- }
}
- if os.Bionic() {
- field = "Bionic"
- prefix = "target.bionic"
+ if os.Bionic() && arch.ArchType != Common {
+ field := "Bionic_" + t.Name
+ prefix := "target.bionic_" + t.Name
m.appendProperties(ctx, genProps, targetProp, field, prefix)
-
- if arch.ArchType != Common {
- field = "Bionic_" + t.Name
- prefix = "target.bionic_" + t.Name
- m.appendProperties(ctx, genProps, targetProp, field, prefix)
- }
}
- // Handle target OS properties in the form:
+ // Handle combined OS and arch specific properties in the form:
// target: {
- // linux_glibc: {
- // key: value,
- // },
- // not_windows: {
- // key: value,
- // },
// linux_glibc_x86: {
// key: value,
// },
// linux_glibc_arm: {
// key: value,
// },
- // android {
- // key: value,
- // },
// android_arm {
// key: value,
// },
@@ -1325,46 +1311,23 @@
// key: value,
// },
// },
- field = os.Field
- prefix = "target." + os.Name
- m.appendProperties(ctx, genProps, targetProp, field, prefix)
-
if arch.ArchType != Common {
- field = os.Field + "_" + t.Name
- prefix = "target." + os.Name + "_" + t.Name
+ field := os.Field + "_" + t.Name
+ prefix := "target." + os.Name + "_" + t.Name
m.appendProperties(ctx, genProps, targetProp, field, prefix)
}
- if (os.Class == Host || os.Class == HostCross) && os != Windows {
- field := "Not_windows"
- prefix := "target.not_windows"
- m.appendProperties(ctx, genProps, targetProp, field, prefix)
- }
-
- // Handle 64-bit device properties in the form:
+ // Handle arm on x86 properties in the form:
// target {
- // android64 {
+ // arm_on_x86 {
// key: value,
// },
- // android32 {
+ // arm_on_x86_64 {
// key: value,
// },
// },
- // WARNING: this is probably not what you want to use in your blueprints file, it selects
- // options for all targets on a device that supports 64-bit binaries, not just the targets
- // that are being compiled for 64-bit. Its expected use case is binaries like linker and
- // debuggerd that need to know when they are a 32-bit process running on a 64-bit device
+ // TODO(ccross): is this still necessary with native bridge?
if os.Class == Device {
- if ctx.Config().Android64() {
- field := "Android64"
- prefix := "target.android64"
- m.appendProperties(ctx, genProps, targetProp, field, prefix)
- } else {
- field := "Android32"
- prefix := "target.android32"
- m.appendProperties(ctx, genProps, targetProp, field, prefix)
- }
-
if (arch.ArchType == X86 && (hasArmAbi(arch) ||
hasArmAndroidArch(ctx.Config().Targets[Android]))) ||
(arch.ArchType == Arm &&
@@ -1482,11 +1445,6 @@
addTarget(Android, *variables.DeviceSecondaryArch,
variables.DeviceSecondaryArchVariant, variables.DeviceSecondaryCpuVariant,
variables.DeviceSecondaryAbi, NativeBridgeDisabled, nil, nil)
-
- deviceArches := targets[Android]
- if deviceArches[0].Arch.ArchType.Multilib == deviceArches[1].Arch.ArchType.Multilib {
- deviceArches[1].Arch.Native = false
- }
}
if variables.NativeBridgeArch != nil && *variables.NativeBridgeArch != "" {
@@ -1634,7 +1592,7 @@
if err != nil {
return nil, err
}
- arch.Native = false
+
ret = append(ret, Target{
Os: Android,
Arch: arch,
@@ -1663,7 +1621,6 @@
ArchVariant: stringPtr(archVariant),
CpuVariant: stringPtr(cpuVariant),
Abi: abi,
- Native: true,
}
if a.ArchVariant == a.ArchType.Name || a.ArchVariant == "generic" {
diff --git a/android/arch_test.go b/android/arch_test.go
index 0589e6c..52a6684 100644
--- a/android/arch_test.go
+++ b/android/arch_test.go
@@ -16,7 +16,10 @@
import (
"reflect"
+ "runtime"
"testing"
+
+ "github.com/google/blueprint/proptools"
)
type Named struct {
@@ -219,7 +222,7 @@
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
- out, filtered := filterArchStruct(reflect.TypeOf(test.in))
+ out, filtered := proptools.FilterPropertyStruct(reflect.TypeOf(test.in), filterArchStruct)
if filtered != test.filtered {
t.Errorf("expected filtered %v, got %v", test.filtered, filtered)
}
@@ -230,3 +233,139 @@
})
}
}
+
+type archTestModule struct {
+ ModuleBase
+ props struct {
+ Deps []string
+ }
+}
+
+func (m *archTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
+}
+
+func (m *archTestModule) DepsMutator(ctx BottomUpMutatorContext) {
+ ctx.AddDependency(ctx.Module(), nil, m.props.Deps...)
+}
+
+func archTestModuleFactory() Module {
+ m := &archTestModule{}
+ m.AddProperties(&m.props)
+ InitAndroidArchModule(m, HostAndDeviceSupported, MultilibBoth)
+ return m
+}
+
+func TestArchMutator(t *testing.T) {
+ var buildOSVariants []string
+ var buildOS32Variants []string
+ switch runtime.GOOS {
+ case "linux":
+ buildOSVariants = []string{"linux_glibc_x86_64", "linux_glibc_x86"}
+ buildOS32Variants = []string{"linux_glibc_x86"}
+ case "darwin":
+ buildOSVariants = []string{"darwin_x86_64"}
+ buildOS32Variants = nil
+ }
+
+ bp := `
+ module {
+ name: "foo",
+ }
+
+ module {
+ name: "bar",
+ host_supported: true,
+ }
+
+ module {
+ name: "baz",
+ device_supported: false,
+ }
+
+ module {
+ name: "qux",
+ host_supported: true,
+ compile_multilib: "32",
+ }
+ `
+
+ mockFS := map[string][]byte{
+ "Android.bp": []byte(bp),
+ }
+
+ testCases := []struct {
+ name string
+ config func(Config)
+ fooVariants []string
+ barVariants []string
+ bazVariants []string
+ quxVariants []string
+ }{
+ {
+ name: "normal",
+ config: nil,
+ fooVariants: []string{"android_arm64_armv8-a", "android_arm_armv7-a-neon"},
+ barVariants: append(buildOSVariants, "android_arm64_armv8-a", "android_arm_armv7-a-neon"),
+ bazVariants: nil,
+ quxVariants: append(buildOS32Variants, "android_arm_armv7-a-neon"),
+ },
+ {
+ name: "host-only",
+ config: func(config Config) {
+ config.BuildOSTarget = Target{}
+ config.BuildOSCommonTarget = Target{}
+ config.Targets[Android] = nil
+ },
+ fooVariants: nil,
+ barVariants: buildOSVariants,
+ bazVariants: nil,
+ quxVariants: buildOS32Variants,
+ },
+ }
+
+ enabledVariants := func(ctx *TestContext, name string) []string {
+ var ret []string
+ variants := ctx.ModuleVariantsForTests(name)
+ for _, variant := range variants {
+ m := ctx.ModuleForTests(name, variant)
+ if m.Module().Enabled() {
+ ret = append(ret, variant)
+ }
+ }
+ return ret
+ }
+
+ for _, tt := range testCases {
+ t.Run(tt.name, func(t *testing.T) {
+ ctx := NewTestArchContext()
+ ctx.RegisterModuleType("module", ModuleFactoryAdaptor(archTestModuleFactory))
+ ctx.MockFileSystem(mockFS)
+ ctx.Register()
+ config := TestArchConfig(buildDir, nil)
+ if tt.config != nil {
+ tt.config(config)
+ }
+
+ _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+ FailIfErrored(t, errs)
+ _, errs = ctx.PrepareBuildActions(config)
+ FailIfErrored(t, errs)
+
+ if g, w := enabledVariants(ctx, "foo"), tt.fooVariants; !reflect.DeepEqual(w, g) {
+ t.Errorf("want foo variants:\n%q\ngot:\n%q\n", w, g)
+ }
+
+ if g, w := enabledVariants(ctx, "bar"), tt.barVariants; !reflect.DeepEqual(w, g) {
+ t.Errorf("want bar variants:\n%q\ngot:\n%q\n", w, g)
+ }
+
+ if g, w := enabledVariants(ctx, "baz"), tt.bazVariants; !reflect.DeepEqual(w, g) {
+ t.Errorf("want baz variants:\n%q\ngot:\n%q\n", w, g)
+ }
+
+ if g, w := enabledVariants(ctx, "qux"), tt.quxVariants; !reflect.DeepEqual(w, g) {
+ t.Errorf("want qux variants:\n%q\ngot:\n%q\n", w, g)
+ }
+ })
+ }
+}
diff --git a/android/config.go b/android/config.go
index cb1bdf5..e208dcd 100644
--- a/android/config.go
+++ b/android/config.go
@@ -89,9 +89,14 @@
ConfigFileName string
ProductVariablesFileName string
- Targets map[OsType][]Target
- BuildOsVariant string
- BuildOsCommonVariant string
+ Targets map[OsType][]Target
+ BuildOSTarget Target // the Target for tools run on the build machine
+ BuildOSCommonTarget Target // the Target for common (java) tools run on the build machine
+ AndroidCommonTarget Target // the Target for common modules for the Android device
+
+ // multilibConflicts for an ArchType is true if there is earlier configured device architecture with the same
+ // multilib value.
+ multilibConflicts map[ArchType]bool
deviceConfig *deviceConfig
@@ -240,10 +245,10 @@
config := testConfig.config
config.Targets[Android] = []Target{
- {Android, Arch{ArchType: X86_64, ArchVariant: "silvermont", Native: true, Abi: []string{"arm64-v8a"}}, NativeBridgeDisabled, "", ""},
- {Android, Arch{ArchType: X86, ArchVariant: "silvermont", Native: true, Abi: []string{"armeabi-v7a"}}, NativeBridgeDisabled, "", ""},
- {Android, Arch{ArchType: Arm64, ArchVariant: "armv8-a", Native: true, Abi: []string{"arm64-v8a"}}, NativeBridgeEnabled, "x86_64", "arm64"},
- {Android, Arch{ArchType: Arm, ArchVariant: "armv7-a-neon", Native: true, Abi: []string{"armeabi-v7a"}}, NativeBridgeEnabled, "x86", "arm"},
+ {Android, Arch{ArchType: X86_64, ArchVariant: "silvermont", Abi: []string{"arm64-v8a"}}, NativeBridgeDisabled, "", ""},
+ {Android, Arch{ArchType: X86, ArchVariant: "silvermont", Abi: []string{"armeabi-v7a"}}, NativeBridgeDisabled, "", ""},
+ {Android, Arch{ArchType: Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}}, NativeBridgeEnabled, "x86_64", "arm64"},
+ {Android, Arch{ArchType: Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}}, NativeBridgeEnabled, "x86", "arm"},
}
return testConfig
@@ -255,7 +260,7 @@
config.Targets = map[OsType][]Target{
Fuchsia: []Target{
- {Fuchsia, Arch{ArchType: Arm64, ArchVariant: "", Native: true}, NativeBridgeDisabled, "", ""},
+ {Fuchsia, Arch{ArchType: Arm64, ArchVariant: ""}, NativeBridgeDisabled, "", ""},
},
BuildOs: []Target{
{BuildOs, Arch{ArchType: X86_64}, NativeBridgeDisabled, "", ""},
@@ -272,8 +277,8 @@
config.Targets = map[OsType][]Target{
Android: []Target{
- {Android, Arch{ArchType: Arm64, ArchVariant: "armv8-a", Native: true, Abi: []string{"arm64-v8a"}}, NativeBridgeDisabled, "", ""},
- {Android, Arch{ArchType: Arm, ArchVariant: "armv7-a-neon", Native: true, Abi: []string{"armeabi-v7a"}}, NativeBridgeDisabled, "", ""},
+ {Android, Arch{ArchType: Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}}, NativeBridgeDisabled, "", ""},
+ {Android, Arch{ArchType: Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}}, NativeBridgeDisabled, "", ""},
},
BuildOs: []Target{
{BuildOs, Arch{ArchType: X86_64}, NativeBridgeDisabled, "", ""},
@@ -285,8 +290,9 @@
config.Targets[BuildOs] = config.Targets[BuildOs][:1]
}
- config.BuildOsVariant = config.Targets[BuildOs][0].String()
- config.BuildOsCommonVariant = getCommonTargets(config.Targets[BuildOs])[0].String()
+ config.BuildOSTarget = config.Targets[BuildOs][0]
+ config.BuildOSCommonTarget = getCommonTargets(config.Targets[BuildOs])[0]
+ config.AndroidCommonTarget = getCommonTargets(config.Targets[Android])[0]
config.TestProductVariables.DeviceArch = proptools.StringPtr("arm64")
config.TestProductVariables.DeviceArchVariant = proptools.StringPtr("armv8-a")
config.TestProductVariables.DeviceSecondaryArch = proptools.StringPtr("arm")
@@ -305,8 +311,9 @@
env: originalEnv,
- srcDir: srcDir,
- buildDir: buildDir,
+ srcDir: srcDir,
+ buildDir: buildDir,
+ multilibConflicts: make(map[ArchType]bool),
}
config.deviceConfig = &deviceConfig{
@@ -360,9 +367,20 @@
targets[Android] = androidTargets
}
+ multilib := make(map[string]bool)
+ for _, target := range targets[Android] {
+ if seen := multilib[target.Arch.ArchType.Multilib]; seen {
+ config.multilibConflicts[target.Arch.ArchType] = true
+ }
+ multilib[target.Arch.ArchType.Multilib] = true
+ }
+
config.Targets = targets
- config.BuildOsVariant = targets[BuildOs][0].String()
- config.BuildOsCommonVariant = getCommonTargets(targets[BuildOs])[0].String()
+ config.BuildOSTarget = config.Targets[BuildOs][0]
+ config.BuildOSCommonTarget = getCommonTargets(config.Targets[BuildOs])[0]
+ if len(config.Targets[Android]) > 0 {
+ config.AndroidCommonTarget = getCommonTargets(config.Targets[Android])[0]
+ }
if err := config.fromEnv(); err != nil {
return Config{}, err
@@ -373,13 +391,14 @@
func (c *config) fromEnv() error {
switch c.Getenv("EXPERIMENTAL_JAVA_LANGUAGE_LEVEL_9") {
- case "":
- // Nothing, this is the default
- case "true":
- // Use -source 9 -target 9
+ case "", "true":
+ // Use -source 9 -target 9. This is the default.
c.targetOpenJDK9 = true
+ case "false":
+ // Use -source 8 -target 8. This is the legacy behaviour.
+ c.targetOpenJDK9 = false
default:
- return fmt.Errorf(`Invalid value for EXPERIMENTAL_JAVA_LANGUAGE_LEVEL_9, should be "" or "true"`)
+ return fmt.Errorf(`Invalid value for EXPERIMENTAL_JAVA_LANGUAGE_LEVEL_9, should be "", "true", or "false"`)
}
return nil
@@ -800,7 +819,7 @@
func (c *config) EnforceRROForModule(name string) bool {
enforceList := c.productVariables.EnforceRROTargets
if enforceList != nil {
- if len(enforceList) == 1 && (enforceList)[0] == "*" {
+ if InList("*", enforceList) {
return true
}
return InList(name, enforceList)
@@ -852,6 +871,10 @@
return Bool(c.productVariables.VndkSnapshotBuildArtifacts)
}
+func (c *config) HasMultilibConflict(arch ArchType) bool {
+ return c.multilibConflicts[arch]
+}
+
func (c *deviceConfig) Arches() []Arch {
var arches []Arch
for _, target := range c.config.Targets[Android] {
@@ -1009,19 +1032,6 @@
return "", false
}
-// SecondArchIsTranslated returns true if the primary device arch is X86 or X86_64 and the device also has an arch
-// that is Arm or Arm64.
-func (c *config) SecondArchIsTranslated() bool {
- deviceTargets := c.Targets[Android]
- if len(deviceTargets) < 2 {
- return false
- }
-
- arch := deviceTargets[0].Arch
-
- return (arch.ArchType == X86 || arch.ArchType == X86_64) && hasArmAndroidArch(deviceTargets)
-}
-
func (c *config) IntegerOverflowDisabledForPath(path string) bool {
if c.productVariables.IntegerOverflowExcludePaths == nil {
return false
diff --git a/android/csuite_config.go b/android/csuite_config.go
new file mode 100644
index 0000000..15c518a
--- /dev/null
+++ b/android/csuite_config.go
@@ -0,0 +1,70 @@
+// 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 (
+ "fmt"
+ "io"
+)
+
+func init() {
+ RegisterModuleType("csuite_config", CSuiteConfigFactory)
+}
+
+type csuiteConfigProperties struct {
+ // Override the default (AndroidTest.xml) test manifest file name.
+ Test_config *string
+}
+
+type CSuiteConfig struct {
+ ModuleBase
+ properties csuiteConfigProperties
+ OutputFilePath OutputPath
+}
+
+func (me *CSuiteConfig) GenerateAndroidBuildActions(ctx ModuleContext) {
+ me.OutputFilePath = PathForModuleOut(ctx, me.BaseModuleName()).OutputPath
+}
+
+func (me *CSuiteConfig) AndroidMk() AndroidMkData {
+ androidMkData := AndroidMkData{
+ Class: "FAKE",
+ Include: "$(BUILD_SYSTEM)/suite_host_config.mk",
+ OutputFile: OptionalPathForPath(me.OutputFilePath),
+ }
+ androidMkData.Extra = []AndroidMkExtraFunc{
+ func(w io.Writer, outputFile Path) {
+ if me.properties.Test_config != nil {
+ fmt.Fprintf(w, "LOCAL_TEST_CONFIG := %s\n",
+ *me.properties.Test_config)
+ }
+ fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE := csuite")
+ },
+ }
+ return androidMkData
+}
+
+func InitCSuiteConfigModule(me *CSuiteConfig) {
+ me.AddProperties(&me.properties)
+}
+
+// csuite_config generates an App Compatibility Test Suite (C-Suite) configuration file from the
+// <test_config> xml file and stores it in a subdirectory of $(HOST_OUT).
+func CSuiteConfigFactory() Module {
+ module := &CSuiteConfig{}
+ InitCSuiteConfigModule(module)
+ InitAndroidArchModule(module, HostSupported, MultilibFirst)
+ return module
+}
diff --git a/android/csuite_config_test.go b/android/csuite_config_test.go
new file mode 100644
index 0000000..e534bb7
--- /dev/null
+++ b/android/csuite_config_test.go
@@ -0,0 +1,53 @@
+// Copyright 2019 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package android
+
+import (
+ "testing"
+)
+
+func testCSuiteConfig(test *testing.T, bpFileContents string) *TestContext {
+ config := TestArchConfig(buildDir, nil)
+
+ ctx := NewTestArchContext()
+ ctx.RegisterModuleType("csuite_config", ModuleFactoryAdaptor(CSuiteConfigFactory))
+ ctx.Register()
+ mockFiles := map[string][]byte{
+ "Android.bp": []byte(bpFileContents),
+ }
+ ctx.MockFileSystem(mockFiles)
+ _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+ FailIfErrored(test, errs)
+ _, errs = ctx.PrepareBuildActions(config)
+ FailIfErrored(test, errs)
+ return ctx
+}
+
+func TestCSuiteConfig(t *testing.T) {
+ ctx := testCSuiteConfig(t, `
+csuite_config { name: "plain"}
+csuite_config { name: "with_manifest", test_config: "manifest.xml" }
+`)
+
+ variants := ctx.ModuleVariantsForTests("plain")
+ if len(variants) > 1 {
+ t.Errorf("expected 1, got %d", len(variants))
+ }
+ expectedOutputFilename := ctx.ModuleForTests(
+ "plain", variants[0]).Module().(*CSuiteConfig).OutputFilePath.Base()
+ if expectedOutputFilename != "plain" {
+ t.Errorf("expected plain, got %q", expectedOutputFilename)
+ }
+}
diff --git a/android/hooks.go b/android/hooks.go
index 5810996..604cb9c 100644
--- a/android/hooks.go
+++ b/android/hooks.go
@@ -30,7 +30,7 @@
BaseModuleContext
AppendProperties(...interface{})
PrependProperties(...interface{})
- CreateModule(blueprint.ModuleFactory, ...interface{})
+ CreateModule(ModuleFactory, ...interface{}) Module
}
// Arch hooks are run after the module has been split into architecture variants, and can be used
@@ -75,7 +75,7 @@
type InstallHookContext interface {
ModuleContext
- Path() OutputPath
+ Path() InstallPath
Symlink() bool
}
@@ -89,11 +89,11 @@
type installHookContext struct {
ModuleContext
- path OutputPath
+ path InstallPath
symlink bool
}
-func (x *installHookContext) Path() OutputPath {
+func (x *installHookContext) Path() InstallPath {
return x.path
}
@@ -101,7 +101,7 @@
return x.symlink
}
-func (x *hooks) runInstallHooks(ctx ModuleContext, path OutputPath, symlink bool) {
+func (x *hooks) runInstallHooks(ctx ModuleContext, path InstallPath, symlink bool) {
if len(x.install) > 0 {
mctx := &installHookContext{
ModuleContext: ctx,
diff --git a/android/module.go b/android/module.go
index 0ab9be7..70b602b 100644
--- a/android/module.go
+++ b/android/module.go
@@ -147,15 +147,17 @@
ExpandSource(srcFile, prop string) Path
ExpandOptionalSource(srcFile *string, prop string) OptionalPath
- InstallExecutable(installPath OutputPath, name string, srcPath Path, deps ...Path) OutputPath
- InstallFile(installPath OutputPath, name string, srcPath Path, deps ...Path) OutputPath
- InstallSymlink(installPath OutputPath, name string, srcPath OutputPath) OutputPath
- InstallAbsoluteSymlink(installPath OutputPath, name string, absPath string) OutputPath
+ InstallExecutable(installPath InstallPath, name string, srcPath Path, deps ...Path) InstallPath
+ InstallFile(installPath InstallPath, name string, srcPath Path, deps ...Path) InstallPath
+ InstallSymlink(installPath InstallPath, name string, srcPath InstallPath) InstallPath
+ InstallAbsoluteSymlink(installPath InstallPath, name string, absPath string) InstallPath
CheckbuildFile(srcPath Path)
InstallInData() bool
+ InstallInTestcases() bool
InstallInSanitizerDir() bool
InstallInRecovery() bool
+ InstallInRoot() bool
InstallBypassMake() bool
RequiredModuleNames() []string
@@ -192,8 +194,10 @@
Enabled() bool
Target() Target
InstallInData() bool
+ InstallInTestcases() bool
InstallInSanitizerDir() bool
InstallInRecovery() bool
+ InstallInRoot() bool
InstallBypassMake() bool
SkipInstall()
ExportedToMake() bool
@@ -413,6 +417,7 @@
} `android:"arch_variant"`
// Set by TargetMutator
+ CompileOS OsType `blueprint:"mutated"`
CompileTarget Target `blueprint:"mutated"`
CompileMultiTargets []Target `blueprint:"mutated"`
CompilePrimary bool `blueprint:"mutated"`
@@ -510,8 +515,19 @@
m.AddProperties(
&base.nameProperties,
- &base.commonProperties,
- &base.variableProperties)
+ &base.commonProperties)
+
+ // Allow tests to override the default product variables
+ if base.variableProperties == nil {
+ base.variableProperties = zeroProductVariables
+ }
+
+ // Filter the product variables properties to the ones that exist on this module
+ base.variableProperties = createVariableProperties(m.GetProperties(), base.variableProperties)
+ if base.variableProperties != nil {
+ m.AddProperties(base.variableProperties)
+ }
+
base.generalProperties = m.GetProperties()
base.customizableProperties = m.GetProperties()
@@ -593,7 +609,7 @@
nameProperties nameProperties
commonProperties commonProperties
- variableProperties variableProperties
+ variableProperties interface{}
hostAndDeviceProperties hostAndDeviceProperties
generalProperties []interface{}
archProperties [][]interface{}
@@ -704,12 +720,6 @@
}
}
-func (m *ModuleBase) SetTarget(target Target, multiTargets []Target, primary bool) {
- m.commonProperties.CompileTarget = target
- m.commonProperties.CompileMultiTargets = multiTargets
- m.commonProperties.CompilePrimary = primary
-}
-
func (m *ModuleBase) Target() Target {
return m.commonProperties.CompileTarget
}
@@ -832,6 +842,10 @@
return false
}
+func (m *ModuleBase) InstallInTestcases() bool {
+ return false
+}
+
func (m *ModuleBase) InstallInSanitizerDir() bool {
return false
}
@@ -840,6 +854,10 @@
return Bool(m.commonProperties.Recovery)
}
+func (m *ModuleBase) InstallInRoot() bool {
+ return false
+}
+
func (m *ModuleBase) InstallBypassMake() bool {
return false
}
@@ -1038,6 +1056,13 @@
}
if m.Enabled() {
+ // ensure all direct android.Module deps are enabled
+ ctx.VisitDirectDepsBlueprint(func(bm blueprint.Module) {
+ if _, ok := bm.(Module); ok {
+ ctx.validateAndroidModule(bm, ctx.baseModuleContext.strictVisitDeps)
+ }
+ })
+
notice := proptools.StringDefault(m.commonProperties.Notice, "NOTICE")
if module := SrcIsModule(notice); module != "" {
m.noticeFile = ctx.ExpandOptionalSource(¬ice, "notice")
@@ -1170,6 +1195,12 @@
func (m *moduleContext) Rule(pctx PackageContext, name string, params blueprint.RuleParams,
argNames ...string) blueprint.Rule {
+ if m.config.UseGoma() && params.Pool == nil {
+ // When USE_GOMA=true is set and the rule is not supported by goma, restrict jobs to the
+ // local parallelism value
+ params.Pool = localPool
+ }
+
rule := m.bp.Rule(pctx.PackageContext, name, params, argNames...)
if m.config.captureBuild {
@@ -1488,10 +1519,19 @@
m.commonProperties.Native_bridge_supported = boolPtr(true)
}
+// IsNativeBridgeSupported returns true if "native_bridge_supported" is explicitly set as "true"
+func (m *ModuleBase) IsNativeBridgeSupported() bool {
+ return proptools.Bool(m.commonProperties.Native_bridge_supported)
+}
+
func (m *moduleContext) InstallInData() bool {
return m.module.InstallInData()
}
+func (m *moduleContext) InstallInTestcases() bool {
+ return m.module.InstallInTestcases()
+}
+
func (m *moduleContext) InstallInSanitizerDir() bool {
return m.module.InstallInSanitizerDir()
}
@@ -1500,11 +1540,15 @@
return m.module.InstallInRecovery()
}
+func (m *moduleContext) InstallInRoot() bool {
+ return m.module.InstallInRoot()
+}
+
func (m *moduleContext) InstallBypassMake() bool {
return m.module.InstallBypassMake()
}
-func (m *moduleContext) skipInstall(fullInstallPath OutputPath) bool {
+func (m *moduleContext) skipInstall(fullInstallPath InstallPath) bool {
if m.module.base().commonProperties.SkipInstall {
return true
}
@@ -1529,18 +1573,18 @@
return false
}
-func (m *moduleContext) InstallFile(installPath OutputPath, name string, srcPath Path,
- deps ...Path) OutputPath {
+func (m *moduleContext) InstallFile(installPath InstallPath, name string, srcPath Path,
+ deps ...Path) InstallPath {
return m.installFile(installPath, name, srcPath, Cp, deps)
}
-func (m *moduleContext) InstallExecutable(installPath OutputPath, name string, srcPath Path,
- deps ...Path) OutputPath {
+func (m *moduleContext) InstallExecutable(installPath InstallPath, name string, srcPath Path,
+ deps ...Path) InstallPath {
return m.installFile(installPath, name, srcPath, CpExecutable, deps)
}
-func (m *moduleContext) installFile(installPath OutputPath, name string, srcPath Path,
- rule blueprint.Rule, deps []Path) OutputPath {
+func (m *moduleContext) installFile(installPath InstallPath, name string, srcPath Path,
+ rule blueprint.Rule, deps []Path) InstallPath {
fullInstallPath := installPath.Join(m, name)
m.module.base().hooks.runInstallHooks(m, fullInstallPath, false)
@@ -1575,7 +1619,7 @@
return fullInstallPath
}
-func (m *moduleContext) InstallSymlink(installPath OutputPath, name string, srcPath OutputPath) OutputPath {
+func (m *moduleContext) InstallSymlink(installPath InstallPath, name string, srcPath InstallPath) InstallPath {
fullInstallPath := installPath.Join(m, name)
m.module.base().hooks.runInstallHooks(m, fullInstallPath, true)
@@ -1604,7 +1648,7 @@
// installPath/name -> absPath where absPath might be a path that is available only at runtime
// (e.g. /apex/...)
-func (m *moduleContext) InstallAbsoluteSymlink(installPath OutputPath, name string, absPath string) OutputPath {
+func (m *moduleContext) InstallAbsoluteSymlink(installPath InstallPath, name string, absPath string) InstallPath {
fullInstallPath := installPath.Join(m, name)
m.module.base().hooks.runInstallHooks(m, fullInstallPath, true)
diff --git a/android/module_test.go b/android/module_test.go
index c790a68..6dca29f 100644
--- a/android/module_test.go
+++ b/android/module_test.go
@@ -14,7 +14,9 @@
package android
-import "testing"
+import (
+ "testing"
+)
func TestSrcIsModule(t *testing.T) {
type args struct {
@@ -139,3 +141,55 @@
})
}
}
+
+type depsModule struct {
+ ModuleBase
+ props struct {
+ Deps []string
+ }
+}
+
+func (m *depsModule) GenerateAndroidBuildActions(ctx ModuleContext) {
+}
+
+func (m *depsModule) DepsMutator(ctx BottomUpMutatorContext) {
+ ctx.AddDependency(ctx.Module(), nil, m.props.Deps...)
+}
+
+func depsModuleFactory() Module {
+ m := &depsModule{}
+ m.AddProperties(&m.props)
+ InitAndroidModule(m)
+ return m
+}
+
+func TestErrorDependsOnDisabledModule(t *testing.T) {
+ ctx := NewTestContext()
+ ctx.RegisterModuleType("deps", ModuleFactoryAdaptor(depsModuleFactory))
+
+ bp := `
+ deps {
+ name: "foo",
+ deps: ["bar"],
+ }
+ deps {
+ name: "bar",
+ enabled: false,
+ }
+ `
+
+ mockFS := map[string][]byte{
+ "Android.bp": []byte(bp),
+ }
+
+ ctx.MockFileSystem(mockFS)
+
+ ctx.Register()
+
+ config := TestConfig(buildDir, nil)
+
+ _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+ FailIfErrored(t, errs)
+ _, errs = ctx.PrepareBuildActions(config)
+ FailIfNoMatchingErrors(t, `module "foo": depends on disabled module "bar"`, errs)
+}
diff --git a/android/mutator.go b/android/mutator.go
index 8e4343d..4a5338f 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -15,6 +15,8 @@
package android
import (
+ "reflect"
+
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
)
@@ -84,6 +86,7 @@
}
func registerArchMutator(ctx RegisterMutatorsContext) {
+ ctx.BottomUp("os", osMutator).Parallel()
ctx.BottomUp("arch", archMutator).Parallel()
ctx.TopDown("arch_hooks", archHookMutator).Parallel()
}
@@ -121,7 +124,7 @@
Rename(name string)
- CreateModule(blueprint.ModuleFactory, ...interface{})
+ CreateModule(ModuleFactory, ...interface{}) Module
}
type topDownMutatorContext struct {
@@ -243,9 +246,25 @@
t.Module().base().commonProperties.DebugName = name
}
-func (t *topDownMutatorContext) CreateModule(factory blueprint.ModuleFactory, props ...interface{}) {
- common := []interface{}{&t.Module().base().commonProperties}
- t.bp.CreateModule(factory, append(common, props...)...)
+func (t *topDownMutatorContext) CreateModule(factory ModuleFactory, props ...interface{}) Module {
+ inherited := []interface{}{&t.Module().base().commonProperties}
+ module := t.bp.CreateModule(ModuleFactoryAdaptor(factory), append(inherited, props...)...).(Module)
+
+ if t.Module().base().variableProperties != nil && module.base().variableProperties != nil {
+ src := t.Module().base().variableProperties
+ dst := []interface{}{
+ module.base().variableProperties,
+ // Put an empty copy of the src properties into dst so that properties in src that are not in dst
+ // don't cause a "failed to find property to extend" error.
+ proptools.CloneEmptyProperties(reflect.ValueOf(src).Elem()).Interface(),
+ }
+ err := proptools.AppendMatchingProperties(dst, src, nil)
+ if err != nil {
+ panic(err)
+ }
+ }
+
+ return module
}
func (b *bottomUpMutatorContext) MutatorName() string {
diff --git a/android/neverallow.go b/android/neverallow.go
index 8355bb3..aff706c 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -51,6 +51,7 @@
AddNeverAllowRules(createIncludeDirsRules()...)
AddNeverAllowRules(createTrebleRules()...)
AddNeverAllowRules(createLibcoreRules()...)
+ AddNeverAllowRules(createMediaRules()...)
AddNeverAllowRules(createJavaDeviceForHostRules()...)
}
@@ -110,7 +111,7 @@
// TODO(b/67974785): always enforce the manifest
NeverAllow().
- Without("name", "libhidltransport").
+ Without("name", "libhidltransport-impl-internal").
With("product_variables.enforce_vintf_manifest.cflags", "*").
Because("manifest enforcement should be independent of ."),
@@ -151,6 +152,14 @@
return rules
}
+func createMediaRules() []Rule {
+ return []Rule{
+ NeverAllow().
+ With("libs", "updatable-media").
+ Because("updatable-media includes private APIs. Use updatable_media_stubs instead."),
+ }
+}
+
func createJavaDeviceForHostRules() []Rule {
javaDeviceForHostProjectsWhitelist := []string{
"external/guava",
@@ -177,7 +186,7 @@
osClass := ctx.Module().Target().Os.Class
- for _, r := range neverallows {
+ for _, r := range neverallowRules(ctx.Config()) {
n := r.(*rule)
if !n.appliesToPath(dir) {
continue
@@ -551,3 +560,19 @@
panic("Can't handle type: " + value.Kind().String())
}
+
+var neverallowRulesKey = NewOnceKey("neverallowRules")
+
+func neverallowRules(config Config) []Rule {
+ return config.Once(neverallowRulesKey, func() interface{} {
+ // No test rules were set by setTestNeverallowRules, use the global rules
+ return neverallows
+ }).([]Rule)
+}
+
+// Overrides the default neverallow rules for the supplied config.
+//
+// For testing only.
+func setTestNeverallowRules(config Config, testRules []Rule) {
+ config.Once(neverallowRulesKey, func() interface{} { return testRules })
+}
diff --git a/android/neverallow_test.go b/android/neverallow_test.go
index 920b9a5..b75b5b7 100644
--- a/android/neverallow_test.go
+++ b/android/neverallow_test.go
@@ -20,23 +20,29 @@
"github.com/google/blueprint"
)
-func init() {
- // Add extra rules needed for testing.
- AddNeverAllowRules(
- NeverAllow().InDirectDeps("not_allowed_in_direct_deps"),
- )
-}
-
var neverallowTests = []struct {
- name string
- fs map[string][]byte
- expectedError string
+ // The name of the test.
+ name string
+
+ // Optional test specific rules. If specified then they are used instead of the default rules.
+ rules []Rule
+
+ // Additional contents to add to the virtual filesystem used by the tests.
+ fs map[string][]byte
+
+ // The expected error patterns. If empty then no errors are expected, otherwise each error
+ // reported must be matched by at least one of these patterns. A pattern matches if the error
+ // message contains the pattern. A pattern does not have to match the whole error message.
+ expectedErrors []string
}{
// Test General Functionality
// in direct deps tests
{
name: "not_allowed_in_direct_deps",
+ rules: []Rule{
+ NeverAllow().InDirectDeps("not_allowed_in_direct_deps"),
+ },
fs: map[string][]byte{
"top/Blueprints": []byte(`
cc_library {
@@ -48,10 +54,12 @@
static_libs: ["not_allowed_in_direct_deps"],
}`),
},
- expectedError: `module "libother": violates neverallow deps:not_allowed_in_direct_deps`,
+ expectedErrors: []string{
+ `module "libother": violates neverallow deps:not_allowed_in_direct_deps`,
+ },
},
- // Test specific rules
+ // Test android specific rules
// include_dir rule tests
{
@@ -63,7 +71,9 @@
include_dirs: ["art/libdexfile/include"],
}`),
},
- expectedError: "all usages of 'art' have been migrated",
+ expectedErrors: []string{
+ "all usages of 'art' have been migrated",
+ },
},
{
name: "include_dir can reference another location",
@@ -88,7 +98,9 @@
},
}`),
},
- expectedError: "VNDK can never contain a library that is device dependent",
+ expectedErrors: []string{
+ "VNDK can never contain a library that is device dependent",
+ },
},
{
name: "no vndk.enabled under device directory",
@@ -102,7 +114,9 @@
},
}`),
},
- expectedError: "VNDK can never contain a library that is device dependent",
+ expectedErrors: []string{
+ "VNDK can never contain a library that is device dependent",
+ },
},
{
name: "vndk-ext under vendor or device directory",
@@ -124,7 +138,6 @@
},
}`),
},
- expectedError: "",
},
{
@@ -140,22 +153,9 @@
},
}`),
},
- expectedError: "manifest enforcement should be independent",
- },
- {
- name: "libhidltransport enforce_vintf_manifest.cflags",
- fs: map[string][]byte{
- "Blueprints": []byte(`
- cc_library {
- name: "libhidltransport",
- product_variables: {
- enforce_vintf_manifest: {
- cflags: ["-DSHOULD_NOT_EXIST"],
- },
- },
- }`),
+ expectedErrors: []string{
+ "manifest enforcement should be independent",
},
- expectedError: "",
},
{
@@ -171,7 +171,9 @@
},
}`),
},
- expectedError: "nothing should care if linker namespaces are enabled or not",
+ expectedErrors: []string{
+ "nothing should care if linker namespaces are enabled or not",
+ },
},
{
name: "libc_bionic_ndk treble_linker_namespaces.cflags",
@@ -186,7 +188,19 @@
},
}`),
},
- expectedError: "",
+ },
+ {
+ name: "dependency on updatable-media",
+ fs: map[string][]byte{
+ "Blueprints": []byte(`
+ java_library {
+ name: "needs_updatable_media",
+ libs: ["updatable-media"],
+ }`),
+ },
+ expectedErrors: []string{
+ "updatable-media includes private APIs. Use updatable_media_stubs instead.",
+ },
},
{
name: "java_device_for_host",
@@ -197,7 +211,9 @@
libs: ["core-libart"],
}`),
},
- expectedError: "java_device_for_host can only be used in whitelisted projects",
+ expectedErrors: []string{
+ "java_device_for_host can only be used in whitelisted projects",
+ },
},
// Libcore rule tests
{
@@ -219,7 +235,9 @@
sdk_version: "none",
}`),
},
- expectedError: "module \"outside_core_libraries\": violates neverallow",
+ expectedErrors: []string{
+ "module \"outside_core_libraries\": violates neverallow",
+ },
},
{
name: "sdk_version: \"current\"",
@@ -234,22 +252,22 @@
}
func TestNeverallow(t *testing.T) {
- config := TestConfig(buildDir, nil)
-
for _, test := range neverallowTests {
- t.Run(test.name, func(t *testing.T) {
- _, errs := testNeverallow(t, config, test.fs)
+ // Create a test per config to allow for test specific config, e.g. test rules.
+ config := TestConfig(buildDir, nil)
- if test.expectedError == "" {
- FailIfErrored(t, errs)
- } else {
- FailIfNoMatchingErrors(t, test.expectedError, errs)
+ t.Run(test.name, func(t *testing.T) {
+ // If the test has its own rules then use them instead of the default ones.
+ if test.rules != nil {
+ setTestNeverallowRules(config, test.rules)
}
+ _, errs := testNeverallow(config, test.fs)
+ CheckErrorsAgainstExpectations(t, errs, test.expectedErrors)
})
}
}
-func testNeverallow(t *testing.T, config Config, fs map[string][]byte) (*TestContext, []error) {
+func testNeverallow(config Config, fs map[string][]byte) (*TestContext, []error) {
ctx := NewTestContext()
ctx.RegisterModuleType("cc_library", ModuleFactoryAdaptor(newMockCcLibraryModule))
ctx.RegisterModuleType("java_library", ModuleFactoryAdaptor(newMockJavaLibraryModule))
diff --git a/android/notices.go b/android/notices.go
index 7b61d65..bf273b5 100644
--- a/android/notices.go
+++ b/android/notices.go
@@ -60,7 +60,7 @@
})
}
-func BuildNoticeOutput(ctx ModuleContext, installPath OutputPath, installFilename string,
+func BuildNoticeOutput(ctx ModuleContext, installPath InstallPath, installFilename string,
noticePaths []Path) NoticeOutputs {
// Merge all NOTICE files into one.
// TODO(jungjw): We should just produce a well-formatted NOTICE.html file in a single pass.
diff --git a/android/package_ctx.go b/android/package_ctx.go
index 00b99ff..548450e 100644
--- a/android/package_ctx.go
+++ b/android/package_ctx.go
@@ -104,7 +104,8 @@
}
// RuleFunc wraps blueprint.PackageContext.RuleFunc, converting the interface{} config
-// argument to a Context that supports Config().
+// argument to a Context that supports Config(), and provides a default Pool if none is
+// specified.
func (p PackageContext) RuleFunc(name string,
f func(PackageRuleContext) blueprint.RuleParams, argNames ...string) blueprint.Rule {
@@ -114,6 +115,11 @@
if len(ctx.errors) > 0 {
return params, ctx.errors[0]
}
+ if ctx.Config().UseGoma() && params.Pool == nil {
+ // When USE_GOMA=true is set and the rule is not supported by goma, restrict jobs to the
+ // local parallelism value
+ params.Pool = localPool
+ }
return params, nil
}, argNames...)
}
@@ -234,10 +240,16 @@
})
}
-// AndroidStaticRule wraps blueprint.StaticRule and provides a default Pool if none is specified
+// AndroidStaticRule is an alias for StaticRule.
func (p PackageContext) AndroidStaticRule(name string, params blueprint.RuleParams,
argNames ...string) blueprint.Rule {
- return p.AndroidRuleFunc(name, func(PackageRuleContext) blueprint.RuleParams {
+ return p.StaticRule(name, params, argNames...)
+}
+
+// StaticRule wraps blueprint.StaticRule and provides a default Pool if none is specified.
+func (p PackageContext) StaticRule(name string, params blueprint.RuleParams,
+ argNames ...string) blueprint.Rule {
+ return p.RuleFunc(name, func(PackageRuleContext) blueprint.RuleParams {
return params
}, argNames...)
}
@@ -245,18 +257,6 @@
// AndroidGomaStaticRule wraps blueprint.StaticRule but uses goma's parallelism if goma is enabled
func (p PackageContext) AndroidGomaStaticRule(name string, params blueprint.RuleParams,
argNames ...string) blueprint.Rule {
- return p.StaticRule(name, params, argNames...)
-}
-
-func (p PackageContext) AndroidRuleFunc(name string,
- f func(PackageRuleContext) blueprint.RuleParams, argNames ...string) blueprint.Rule {
- return p.RuleFunc(name, func(ctx PackageRuleContext) blueprint.RuleParams {
- params := f(ctx)
- if ctx.Config().UseGoma() && params.Pool == nil {
- // When USE_GOMA=true is set and the rule is not supported by goma, restrict jobs to the
- // local parallelism value
- params.Pool = localPool
- }
- return params
- }, argNames...)
+ // bypass android.PackageContext.StaticRule so that Pool does not get set to local_pool.
+ return p.PackageContext.StaticRule(name, params, argNames...)
}
diff --git a/android/paths.go b/android/paths.go
index 0d64a61..8dbb086 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -44,8 +44,10 @@
BaseModuleContext
InstallInData() bool
+ InstallInTestcases() bool
InstallInSanitizerDir() bool
InstallInRecovery() bool
+ InstallInRoot() bool
InstallBypassMake() bool
}
@@ -791,7 +793,7 @@
return OptionalPathForPath(PathForSource(ctx, relPath))
}
-// OutputPath is a Path representing a file path rooted from the build directory
+// OutputPath is a Path representing an intermediates file path rooted from the build directory
type OutputPath struct {
basePath
}
@@ -819,17 +821,6 @@
return OutputPath{basePath{path, ctx.Config(), ""}}
}
-// pathForInstallInMakeDir is used by PathForModuleInstall when the module returns true
-// for InstallBypassMake to produce an OutputPath that installs to $OUT_DIR instead of
-// $OUT_DIR/soong.
-func pathForInstallInMakeDir(ctx PathContext, pathComponents ...string) OutputPath {
- path, err := validatePath(pathComponents...)
- if err != nil {
- reportPathError(ctx, err)
- }
- return OutputPath{basePath{"../" + path, ctx.Config(), ""}}
-}
-
// PathsForOutput returns Paths rooted from buildDir
func PathsForOutput(ctx PathContext, paths []string) WritablePaths {
ret := make(WritablePaths, len(paths))
@@ -845,10 +836,6 @@
return filepath.Join(p.config.buildDir, p.path)
}
-func (p OutputPath) RelPathString() string {
- return p.path
-}
-
// Join creates a new OutputPath with paths... joined with the current path. The
// provided paths... may not use '..' to escape from the current path.
func (p OutputPath) Join(ctx PathContext, paths ...string) OutputPath {
@@ -1117,9 +1104,44 @@
return ModuleResPath{PathForModuleOut(ctx, "res", p)}
}
+// InstallPath is a Path representing a installed file path rooted from the build directory
+type InstallPath struct {
+ basePath
+
+ baseDir string // "../" for Make paths to convert "out/soong" to "out", "" for Soong paths
+}
+
+func (p InstallPath) writablePath() {}
+
+func (p InstallPath) String() string {
+ return filepath.Join(p.config.buildDir, p.baseDir, p.path)
+}
+
+// Join creates a new InstallPath with paths... joined with the current path. The
+// provided paths... may not use '..' to escape from the current path.
+func (p InstallPath) Join(ctx PathContext, paths ...string) InstallPath {
+ path, err := validatePath(paths...)
+ if err != nil {
+ reportPathError(ctx, err)
+ }
+ return p.withRel(path)
+}
+
+func (p InstallPath) withRel(rel string) InstallPath {
+ p.basePath = p.basePath.withRel(rel)
+ return p
+}
+
+// ToMakePath returns a new InstallPath that points to Make's install directory instead of Soong's,
+// i.e. out/ instead of out/soong/.
+func (p InstallPath) ToMakePath() InstallPath {
+ p.baseDir = "../"
+ return p
+}
+
// PathForModuleInstall returns a Path representing the install path for the
// module appended with paths...
-func PathForModuleInstall(ctx ModuleInstallPathContext, pathComponents ...string) OutputPath {
+func PathForModuleInstall(ctx ModuleInstallPathContext, pathComponents ...string) InstallPath {
var outPaths []string
if ctx.Device() {
partition := modulePartition(ctx)
@@ -1139,13 +1161,30 @@
outPaths = append([]string{"debug"}, outPaths...)
}
outPaths = append(outPaths, pathComponents...)
- if ctx.InstallBypassMake() && ctx.Config().EmbeddedInMake() {
- return pathForInstallInMakeDir(ctx, outPaths...)
+
+ path, err := validatePath(outPaths...)
+ if err != nil {
+ reportPathError(ctx, err)
}
- return PathForOutput(ctx, outPaths...)
+
+ ret := InstallPath{basePath{path, ctx.Config(), ""}, ""}
+ if ctx.InstallBypassMake() && ctx.Config().EmbeddedInMake() {
+ ret = ret.ToMakePath()
+ }
+
+ return ret
}
-func InstallPathToOnDevicePath(ctx PathContext, path OutputPath) string {
+func PathForNdkInstall(ctx PathContext, paths ...string) InstallPath {
+ paths = append([]string{"ndk"}, paths...)
+ path, err := validatePath(paths...)
+ if err != nil {
+ reportPathError(ctx, err)
+ }
+ return InstallPath{basePath{path, ctx.Config(), ""}, ""}
+}
+
+func InstallPathToOnDevicePath(ctx PathContext, path InstallPath) string {
rel := Rel(ctx, PathForOutput(ctx, "target", "product", ctx.Config().DeviceName()).String(), path.String())
return "/" + rel
@@ -1155,9 +1194,15 @@
var partition string
if ctx.InstallInData() {
partition = "data"
+ } else if ctx.InstallInTestcases() {
+ partition = "testcases"
} else if ctx.InstallInRecovery() {
- // the layout of recovery partion is the same as that of system partition
- partition = "recovery/root/system"
+ if ctx.InstallInRoot() {
+ partition = "recovery/root"
+ } else {
+ // the layout of recovery partion is the same as that of system partition
+ partition = "recovery/root/system"
+ }
} else if ctx.SocSpecific() {
partition = ctx.DeviceConfig().VendorPath()
} else if ctx.DeviceSpecific() {
@@ -1166,6 +1211,8 @@
partition = ctx.DeviceConfig().ProductPath()
} else if ctx.SystemExtSpecific() {
partition = ctx.DeviceConfig().SystemExtPath()
+ } else if ctx.InstallInRoot() {
+ partition = "root"
} else {
partition = "system"
}
diff --git a/android/paths_test.go b/android/paths_test.go
index f2996bf..2e67272 100644
--- a/android/paths_test.go
+++ b/android/paths_test.go
@@ -201,8 +201,10 @@
baseModuleContext
inData bool
+ inTestcases bool
inSanitizerDir bool
inRecovery bool
+ inRoot bool
}
func (moduleInstallPathContextImpl) Fs() pathtools.FileSystem {
@@ -219,6 +221,10 @@
return m.inData
}
+func (m moduleInstallPathContextImpl) InstallInTestcases() bool {
+ return m.inTestcases
+}
+
func (m moduleInstallPathContextImpl) InstallInSanitizerDir() bool {
return m.inSanitizerDir
}
@@ -227,6 +233,10 @@
return m.inRecovery
}
+func (m moduleInstallPathContextImpl) InstallInRoot() bool {
+ return m.inRoot
+}
+
func (m moduleInstallPathContextImpl) InstallBypassMake() bool {
return false
}
@@ -308,6 +318,40 @@
in: []string{"bin", "my_test"},
out: "target/product/test_device/system_ext/bin/my_test",
},
+ {
+ name: "root binary",
+ ctx: &moduleInstallPathContextImpl{
+ baseModuleContext: baseModuleContext{
+ target: deviceTarget,
+ },
+ inRoot: true,
+ },
+ in: []string{"my_test"},
+ out: "target/product/test_device/root/my_test",
+ },
+ {
+ name: "recovery binary",
+ ctx: &moduleInstallPathContextImpl{
+ baseModuleContext: baseModuleContext{
+ target: deviceTarget,
+ },
+ inRecovery: true,
+ },
+ in: []string{"bin/my_test"},
+ out: "target/product/test_device/recovery/root/system/bin/my_test",
+ },
+ {
+ name: "recovery root binary",
+ ctx: &moduleInstallPathContextImpl{
+ baseModuleContext: baseModuleContext{
+ target: deviceTarget,
+ },
+ inRecovery: true,
+ inRoot: true,
+ },
+ in: []string{"my_test"},
+ out: "target/product/test_device/recovery/root/my_test",
+ },
{
name: "system native test binary",
diff --git a/android/prebuilt_etc.go b/android/prebuilt_etc.go
index 9722a25..6c4813b 100644
--- a/android/prebuilt_etc.go
+++ b/android/prebuilt_etc.go
@@ -65,7 +65,7 @@
installDirBase string
// The base install location when soc_specific property is set to true, e.g. "firmware" for prebuilt_firmware.
socInstallDirBase string
- installDirPath OutputPath
+ installDirPath InstallPath
additionalDependencies *Paths
}
@@ -91,7 +91,7 @@
return PathForModuleSrc(ctx, String(p.properties.Src))
}
-func (p *PrebuiltEtc) InstallDirPath() OutputPath {
+func (p *PrebuiltEtc) InstallDirPath() InstallPath {
return p.installDirPath
}
@@ -155,16 +155,18 @@
Class: "ETC",
SubName: nameSuffix,
OutputFile: OptionalPathForPath(p.outputFilePath),
- AddCustomEntries: func(name, prefix, moduleDir string, entries *AndroidMkEntries) {
- entries.SetString("LOCAL_MODULE_TAGS", "optional")
- entries.SetString("LOCAL_MODULE_PATH", "$(OUT_DIR)/"+p.installDirPath.RelPathString())
- entries.SetString("LOCAL_INSTALLED_MODULE_STEM", p.outputFilePath.Base())
- entries.SetString("LOCAL_UNINSTALLABLE_MODULE", strconv.FormatBool(!p.Installable()))
- if p.additionalDependencies != nil {
- for _, path := range *p.additionalDependencies {
- entries.SetString("LOCAL_ADDITIONAL_DEPENDENCIES", path.String())
+ ExtraEntries: []AndroidMkExtraEntriesFunc{
+ func(entries *AndroidMkEntries) {
+ entries.SetString("LOCAL_MODULE_TAGS", "optional")
+ entries.SetString("LOCAL_MODULE_PATH", p.installDirPath.ToMakePath().String())
+ entries.SetString("LOCAL_INSTALLED_MODULE_STEM", p.outputFilePath.Base())
+ entries.SetString("LOCAL_UNINSTALLABLE_MODULE", strconv.FormatBool(!p.Installable()))
+ if p.additionalDependencies != nil {
+ for _, path := range *p.additionalDependencies {
+ entries.SetString("LOCAL_ADDITIONAL_DEPENDENCIES", path.String())
+ }
}
- }
+ },
},
}
}
diff --git a/android/prebuilt_etc_test.go b/android/prebuilt_etc_test.go
index 0a2c7a4..f675ea3 100644
--- a/android/prebuilt_etc_test.go
+++ b/android/prebuilt_etc_test.go
@@ -182,9 +182,9 @@
`)
p := ctx.ModuleForTests("foo.conf", "android_arm64_armv8-a_core").Module().(*PrebuiltEtc)
- expected := "target/product/test_device/system/usr/share/bar"
- if p.installDirPath.RelPathString() != expected {
- t.Errorf("expected %q, got %q", expected, p.installDirPath.RelPathString())
+ expected := buildDir + "/target/product/test_device/system/usr/share/bar"
+ if p.installDirPath.String() != expected {
+ t.Errorf("expected %q, got %q", expected, p.installDirPath.String())
}
}
@@ -199,9 +199,9 @@
buildOS := BuildOs.String()
p := ctx.ModuleForTests("foo.conf", buildOS+"_common").Module().(*PrebuiltEtc)
- expected := filepath.Join("host", config.PrebuiltOS(), "usr", "share", "bar")
- if p.installDirPath.RelPathString() != expected {
- t.Errorf("expected %q, got %q", expected, p.installDirPath.RelPathString())
+ expected := filepath.Join(buildDir, "host", config.PrebuiltOS(), "usr", "share", "bar")
+ if p.installDirPath.String() != expected {
+ t.Errorf("expected %q, got %q", expected, p.installDirPath.String())
}
}
@@ -214,14 +214,14 @@
`)
p := ctx.ModuleForTests("foo.conf", "android_arm64_armv8-a_core").Module().(*PrebuiltEtc)
- expected := "target/product/test_device/system/fonts"
- if p.installDirPath.RelPathString() != expected {
- t.Errorf("expected %q, got %q", expected, p.installDirPath.RelPathString())
+ expected := buildDir + "/target/product/test_device/system/fonts"
+ if p.installDirPath.String() != expected {
+ t.Errorf("expected %q, got %q", expected, p.installDirPath.String())
}
}
func TestPrebuiltFirmwareDirPath(t *testing.T) {
- targetPath := "target/product/test_device"
+ targetPath := buildDir + "/target/product/test_device"
tests := []struct {
description string
config string
@@ -249,7 +249,7 @@
t.Run(tt.description, func(t *testing.T) {
ctx, _ := testPrebuiltEtc(t, tt.config)
p := ctx.ModuleForTests("foo.conf", "android_arm64_armv8-a_core").Module().(*PrebuiltEtc)
- if p.installDirPath.RelPathString() != tt.expectedPath {
+ if p.installDirPath.String() != tt.expectedPath {
t.Errorf("expected %q, got %q", tt.expectedPath, p.installDirPath)
}
})
diff --git a/android/proto.go b/android/proto.go
index c8ade45..b712258 100644
--- a/android/proto.go
+++ b/android/proto.go
@@ -52,9 +52,8 @@
}
if plugin := String(p.Proto.Plugin); plugin != "" {
- ctx.AddFarVariationDependencies([]blueprint.Variation{
- {Mutator: "arch", Variation: ctx.Config().BuildOsVariant},
- }, ProtoPluginDepTag, "protoc-gen-"+plugin)
+ ctx.AddFarVariationDependencies(ctx.Config().BuildOSTarget.Variations(),
+ ProtoPluginDepTag, "protoc-gen-"+plugin)
}
}
diff --git a/android/rule_builder.go b/android/rule_builder.go
index 48d070e..6f04672 100644
--- a/android/rule_builder.go
+++ b/android/rule_builder.go
@@ -367,10 +367,6 @@
sboxOutputs[i] = "__SBOX_OUT_DIR__/" + Rel(ctx, r.sboxOutDir.String(), output.String())
}
- if depFile != nil {
- sboxOutputs = append(sboxOutputs, "__SBOX_OUT_DIR__/"+Rel(ctx, r.sboxOutDir.String(), depFile.String()))
- }
-
commandString = proptools.ShellEscape(commandString)
if !strings.HasPrefix(commandString, `'`) {
commandString = `'` + commandString + `'`
@@ -380,8 +376,13 @@
sboxCmd.BuiltTool(ctx, "sbox").
Flag("-c").Text(commandString).
Flag("--sandbox-path").Text(shared.TempDirForOutDir(PathForOutput(ctx).String())).
- Flag("--output-root").Text(r.sboxOutDir.String()).
- Flags(sboxOutputs)
+ Flag("--output-root").Text(r.sboxOutDir.String())
+
+ if depFile != nil {
+ sboxCmd.Flag("--depfile-out").Text(depFile.String())
+ }
+
+ sboxCmd.Flags(sboxOutputs)
commandString = sboxCmd.buf.String()
tools = append(tools, sboxCmd.tools...)
diff --git a/android/rule_builder_test.go b/android/rule_builder_test.go
index 6eba4f1..b484811 100644
--- a/android/rule_builder_test.go
+++ b/android/rule_builder_test.go
@@ -475,6 +475,7 @@
FailIfErrored(t, errs)
check := func(t *testing.T, params TestingBuildParams, wantCommand, wantOutput, wantDepfile string, wantRestat bool, extraCmdDeps []string) {
+ t.Helper()
if params.RuleParams.Command != wantCommand {
t.Errorf("\nwant RuleParams.Command = %q\n got %q", wantCommand, params.RuleParams.Command)
}
@@ -518,13 +519,14 @@
t.Run("sbox", func(t *testing.T) {
outDir := filepath.Join(buildDir, ".intermediates", "foo_sbox")
outFile := filepath.Join(outDir, "foo_sbox")
+ depFile := filepath.Join(outDir, "foo_sbox.d")
sbox := filepath.Join(buildDir, "host", config.PrebuiltOS(), "bin/sbox")
sandboxPath := shared.TempDirForOutDir(buildDir)
- cmd := sbox + ` -c 'cp bar __SBOX_OUT_DIR__/foo_sbox' --sandbox-path ` + sandboxPath + " --output-root " + outDir + " __SBOX_OUT_DIR__/foo_sbox __SBOX_OUT_DIR__/foo_sbox.d"
+ cmd := sbox + ` -c 'cp bar __SBOX_OUT_DIR__/foo_sbox' --sandbox-path ` + sandboxPath + " --output-root " + outDir + " --depfile-out " + depFile + " __SBOX_OUT_DIR__/foo_sbox"
check(t, ctx.ModuleForTests("foo_sbox", "").Rule("rule"),
- cmd, outFile, outFile+".d", false, []string{sbox})
+ cmd, outFile, depFile, false, []string{sbox})
})
t.Run("singleton", func(t *testing.T) {
outFile := filepath.Join(buildDir, "baz")
diff --git a/android/sdk.go b/android/sdk.go
new file mode 100644
index 0000000..8e1e106
--- /dev/null
+++ b/android/sdk.go
@@ -0,0 +1,150 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// 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 (
+ "strings"
+
+ "github.com/google/blueprint/proptools"
+)
+
+// SdkAware is the interface that must be supported by any module to become a member of SDK or to be
+// built with SDK
+type SdkAware interface {
+ Module
+ sdkBase() *SdkBase
+ MakeMemberOf(sdk SdkRef)
+ IsInAnySdk() bool
+ ContainingSdk() SdkRef
+ MemberName() string
+ BuildWithSdks(sdks SdkRefs)
+ RequiredSdks() SdkRefs
+}
+
+// SdkRef refers to a version of an SDK
+type SdkRef struct {
+ Name string
+ Version string
+}
+
+// Unversioned determines if the SdkRef is referencing to the unversioned SDK module
+func (s SdkRef) Unversioned() bool {
+ return s.Version == ""
+}
+
+// String returns string representation of this SdkRef for debugging purpose
+func (s SdkRef) String() string {
+ if s.Name == "" {
+ return "(No Sdk)"
+ }
+ if s.Unversioned() {
+ return s.Name
+ }
+ return s.Name + string(SdkVersionSeparator) + s.Version
+}
+
+// SdkVersionSeparator is a character used to separate an sdk name and its version
+const SdkVersionSeparator = '@'
+
+// ParseSdkRef parses a `name@version` style string into a corresponding SdkRef struct
+func ParseSdkRef(ctx BaseModuleContext, str string, property string) SdkRef {
+ tokens := strings.Split(str, string(SdkVersionSeparator))
+ if len(tokens) < 1 || len(tokens) > 2 {
+ ctx.PropertyErrorf(property, "%q does not follow name#version syntax", str)
+ return SdkRef{Name: "invalid sdk name", Version: "invalid sdk version"}
+ }
+
+ name := tokens[0]
+
+ var version string
+ if len(tokens) == 2 {
+ version = tokens[1]
+ }
+
+ return SdkRef{Name: name, Version: version}
+}
+
+type SdkRefs []SdkRef
+
+// Contains tells if the given SdkRef is in this list of SdkRef's
+func (refs SdkRefs) Contains(s SdkRef) bool {
+ for _, r := range refs {
+ if r == s {
+ return true
+ }
+ }
+ return false
+}
+
+type sdkProperties struct {
+ // The SDK that this module is a member of. nil if it is not a member of any SDK
+ ContainingSdk *SdkRef `blueprint:"mutated"`
+
+ // The list of SDK names and versions that are used to build this module
+ RequiredSdks SdkRefs `blueprint:"mutated"`
+
+ // Name of the module that this sdk member is representing
+ Sdk_member_name *string
+}
+
+// SdkBase is a struct that is expected to be included in module types to implement the SdkAware
+// interface. InitSdkAwareModule should be called to initialize this struct.
+type SdkBase struct {
+ properties sdkProperties
+}
+
+func (s *SdkBase) sdkBase() *SdkBase {
+ return s
+}
+
+// MakeMemberOf sets this module to be a member of a specific SDK
+func (s *SdkBase) MakeMemberOf(sdk SdkRef) {
+ s.properties.ContainingSdk = &sdk
+}
+
+// IsInAnySdk returns true if this module is a member of any SDK
+func (s *SdkBase) IsInAnySdk() bool {
+ return s.properties.ContainingSdk != nil
+}
+
+// ContainingSdk returns the SDK that this module is a member of
+func (s *SdkBase) ContainingSdk() SdkRef {
+ if s.properties.ContainingSdk != nil {
+ return *s.properties.ContainingSdk
+ }
+ return SdkRef{Name: "", Version: ""}
+}
+
+// MemberName returns the name of the module that this SDK member is overriding
+func (s *SdkBase) MemberName() string {
+ return proptools.String(s.properties.Sdk_member_name)
+}
+
+// BuildWithSdks is used to mark that this module has to be built with the given SDK(s).
+func (s *SdkBase) BuildWithSdks(sdks SdkRefs) {
+ s.properties.RequiredSdks = sdks
+}
+
+// RequiredSdks returns the SDK(s) that this module has to be built with
+func (s *SdkBase) RequiredSdks() SdkRefs {
+ return s.properties.RequiredSdks
+}
+
+// InitSdkAwareModule initializes the SdkBase struct. This must be called by all modules including
+// SdkBase.
+func InitSdkAwareModule(m SdkAware) {
+ base := m.sdkBase()
+ m.AddProperties(&base.properties)
+}
diff --git a/android/sh_binary.go b/android/sh_binary.go
index 2855aa0..6db9892 100644
--- a/android/sh_binary.go
+++ b/android/sh_binary.go
@@ -48,6 +48,9 @@
// Whether this module is directly installable to one of the partitions. Default: true.
Installable *bool
+
+ // install symlinks to the binary
+ Symlinks []string `android:"arch_variant"`
}
type TestProperties struct {
@@ -103,6 +106,10 @@
return s.properties.Installable == nil || Bool(s.properties.Installable)
}
+func (s *ShBinary) Symlinks() []string {
+ return s.properties.Symlinks
+}
+
func (s *ShBinary) GenerateAndroidBuildActions(ctx ModuleContext) {
s.sourceFilePath = PathForModuleSrc(ctx, String(s.properties.Src))
filename := String(s.properties.Filename)
@@ -133,8 +140,10 @@
Class: "EXECUTABLES",
OutputFile: OptionalPathForPath(s.outputFilePath),
Include: "$(BUILD_SYSTEM)/soong_cc_prebuilt.mk",
- AddCustomEntries: func(name, prefix, moduleDir string, entries *AndroidMkEntries) {
- s.customAndroidMkEntries(entries)
+ ExtraEntries: []AndroidMkExtraEntriesFunc{
+ func(entries *AndroidMkEntries) {
+ s.customAndroidMkEntries(entries)
+ },
},
}
}
@@ -143,6 +152,9 @@
entries.SetString("LOCAL_MODULE_RELATIVE_PATH", String(s.properties.Sub_dir))
entries.SetString("LOCAL_MODULE_SUFFIX", "")
entries.SetString("LOCAL_MODULE_STEM", s.outputFilePath.Rel())
+ if len(s.properties.Symlinks) > 0 {
+ entries.SetString("LOCAL_MODULE_SYMLINKS", strings.Join(s.properties.Symlinks, " "))
+ }
}
func (s *ShTest) GenerateAndroidBuildActions(ctx ModuleContext) {
@@ -156,20 +168,22 @@
Class: "NATIVE_TESTS",
OutputFile: OptionalPathForPath(s.outputFilePath),
Include: "$(BUILD_SYSTEM)/soong_cc_prebuilt.mk",
- AddCustomEntries: func(name, prefix, moduleDir string, entries *AndroidMkEntries) {
- s.customAndroidMkEntries(entries)
+ ExtraEntries: []AndroidMkExtraEntriesFunc{
+ func(entries *AndroidMkEntries) {
+ s.customAndroidMkEntries(entries)
- entries.AddStrings("LOCAL_COMPATIBILITY_SUITE", s.testProperties.Test_suites...)
- entries.SetString("LOCAL_TEST_CONFIG", String(s.testProperties.Test_config))
- for _, d := range s.data {
- rel := d.Rel()
- path := d.String()
- if !strings.HasSuffix(path, rel) {
- panic(fmt.Errorf("path %q does not end with %q", path, rel))
+ entries.AddStrings("LOCAL_COMPATIBILITY_SUITE", s.testProperties.Test_suites...)
+ entries.SetString("LOCAL_TEST_CONFIG", String(s.testProperties.Test_config))
+ for _, d := range s.data {
+ rel := d.Rel()
+ path := d.String()
+ if !strings.HasSuffix(path, rel) {
+ panic(fmt.Errorf("path %q does not end with %q", path, rel))
+ }
+ path = strings.TrimSuffix(path, rel)
+ entries.AddStrings("LOCAL_TEST_DATA", path+":"+rel)
}
- path = strings.TrimSuffix(path, rel)
- entries.AddStrings("LOCAL_TEST_DATA", path+":"+rel)
- }
+ },
},
}
}
diff --git a/android/singleton.go b/android/singleton.go
index a59d54a..33bc6d1 100644
--- a/android/singleton.go
+++ b/android/singleton.go
@@ -52,6 +52,10 @@
VisitAllModulesBlueprint(visit func(blueprint.Module))
VisitAllModules(visit func(Module))
VisitAllModulesIf(pred func(Module) bool, visit func(Module))
+
+ VisitDirectDeps(module Module, visit func(Module))
+ VisitDirectDepsIf(module Module, pred func(Module) bool, visit func(Module))
+
// Deprecated: use WalkDeps instead to support multiple dependency tags on the same module
VisitDepsDepthFirst(module Module, visit func(Module))
// Deprecated: use WalkDeps instead to support multiple dependency tags on the same module
@@ -127,6 +131,11 @@
}
func (s *singletonContextAdaptor) Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule {
+ if s.Config().UseGoma() && params.Pool == nil {
+ // When USE_GOMA=true is set and the rule is not supported by goma, restrict jobs to the
+ // local parallelism value
+ params.Pool = localPool
+ }
rule := s.SingletonContext.Rule(pctx.PackageContext, name, params, argNames...)
if s.Config().captureBuild {
s.ruleParams[rule] = params
@@ -187,6 +196,14 @@
s.SingletonContext.VisitAllModulesIf(predAdaptor(pred), visitAdaptor(visit))
}
+func (s *singletonContextAdaptor) VisitDirectDeps(module Module, visit func(Module)) {
+ s.SingletonContext.VisitDirectDeps(module, visitAdaptor(visit))
+}
+
+func (s *singletonContextAdaptor) VisitDirectDepsIf(module Module, pred func(Module) bool, visit func(Module)) {
+ s.SingletonContext.VisitDirectDepsIf(module, predAdaptor(pred), visitAdaptor(visit))
+}
+
func (s *singletonContextAdaptor) VisitDepsDepthFirst(module Module, visit func(Module)) {
s.SingletonContext.VisitDepsDepthFirst(module, visitAdaptor(visit))
}
diff --git a/android/testing.go b/android/testing.go
index b59f399..447ffd6 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -372,6 +372,29 @@
}
}
+func CheckErrorsAgainstExpectations(t *testing.T, errs []error, expectedErrorPatterns []string) {
+ t.Helper()
+
+ if expectedErrorPatterns == nil {
+ FailIfErrored(t, errs)
+ } else {
+ for _, expectedError := range expectedErrorPatterns {
+ FailIfNoMatchingErrors(t, expectedError, errs)
+ }
+ if len(errs) > len(expectedErrorPatterns) {
+ t.Errorf("additional errors found, expected %d, found %d",
+ len(expectedErrorPatterns), len(errs))
+ for i, expectedError := range expectedErrorPatterns {
+ t.Errorf("expectedErrors[%d] = %s", i, expectedError)
+ }
+ for i, err := range errs {
+ t.Errorf("errs[%d] = %s", i, err)
+ }
+ }
+ }
+
+}
+
func AndroidMkEntriesForTest(t *testing.T, config Config, bpPath string, mod blueprint.Module) AndroidMkEntries {
var p AndroidMkEntriesProvider
var ok bool
diff --git a/android/util.go b/android/util.go
index e02cca1..71ded5e 100644
--- a/android/util.go
+++ b/android/util.go
@@ -16,6 +16,7 @@
import (
"fmt"
+ "path/filepath"
"reflect"
"regexp"
"runtime"
@@ -292,3 +293,62 @@
}
return strings.HasPrefix(str, pat[:i]) && strings.HasSuffix(str, pat[i+1:])
}
+
+var shlibVersionPattern = regexp.MustCompile("(?:\\.\\d+(?:svn)?)+")
+
+// splitFileExt splits a file name into root, suffix and ext. root stands for the file name without
+// the file extension and the version number (e.g. "libexample"). suffix stands for the
+// concatenation of the file extension and the version number (e.g. ".so.1.0"). ext stands for the
+// file extension after the version numbers are trimmed (e.g. ".so").
+func SplitFileExt(name string) (string, string, string) {
+ // Extract and trim the shared lib version number if the file name ends with dot digits.
+ suffix := ""
+ matches := shlibVersionPattern.FindAllStringIndex(name, -1)
+ if len(matches) > 0 {
+ lastMatch := matches[len(matches)-1]
+ if lastMatch[1] == len(name) {
+ suffix = name[lastMatch[0]:lastMatch[1]]
+ name = name[0:lastMatch[0]]
+ }
+ }
+
+ // Extract the file name root and the file extension.
+ ext := filepath.Ext(name)
+ root := strings.TrimSuffix(name, ext)
+ suffix = ext + suffix
+
+ return root, suffix, ext
+}
+
+// ShardPaths takes a Paths, and returns a slice of Paths where each one has at most shardSize paths.
+func ShardPaths(paths Paths, shardSize int) []Paths {
+ if len(paths) == 0 {
+ return nil
+ }
+ ret := make([]Paths, 0, (len(paths)+shardSize-1)/shardSize)
+ for len(paths) > shardSize {
+ ret = append(ret, paths[0:shardSize])
+ paths = paths[shardSize:]
+ }
+ if len(paths) > 0 {
+ ret = append(ret, paths)
+ }
+ return ret
+}
+
+// ShardStrings takes a slice of strings, and returns a slice of slices of strings where each one has at most shardSize
+// elements.
+func ShardStrings(s []string, shardSize int) [][]string {
+ if len(s) == 0 {
+ return nil
+ }
+ ret := make([][]string, 0, (len(s)+shardSize-1)/shardSize)
+ for len(s) > shardSize {
+ ret = append(ret, s[0:shardSize])
+ s = s[shardSize:]
+ }
+ if len(s) > 0 {
+ ret = append(ret, s)
+ }
+ return ret
+}
diff --git a/android/util_test.go b/android/util_test.go
index 2e5eb07..90fefee 100644
--- a/android/util_test.go
+++ b/android/util_test.go
@@ -404,3 +404,167 @@
// b = ["foo" "bar"]
// c = ["foo" "baz"]
}
+
+func TestSplitFileExt(t *testing.T) {
+ t.Run("soname with version", func(t *testing.T) {
+ root, suffix, ext := SplitFileExt("libtest.so.1.0.30")
+ expected := "libtest"
+ if root != expected {
+ t.Errorf("root should be %q but got %q", expected, root)
+ }
+ expected = ".so.1.0.30"
+ if suffix != expected {
+ t.Errorf("suffix should be %q but got %q", expected, suffix)
+ }
+ expected = ".so"
+ if ext != expected {
+ t.Errorf("ext should be %q but got %q", expected, ext)
+ }
+ })
+
+ t.Run("soname with svn version", func(t *testing.T) {
+ root, suffix, ext := SplitFileExt("libtest.so.1svn")
+ expected := "libtest"
+ if root != expected {
+ t.Errorf("root should be %q but got %q", expected, root)
+ }
+ expected = ".so.1svn"
+ if suffix != expected {
+ t.Errorf("suffix should be %q but got %q", expected, suffix)
+ }
+ expected = ".so"
+ if ext != expected {
+ t.Errorf("ext should be %q but got %q", expected, ext)
+ }
+ })
+
+ t.Run("version numbers in the middle should be ignored", func(t *testing.T) {
+ root, suffix, ext := SplitFileExt("libtest.1.0.30.so")
+ expected := "libtest.1.0.30"
+ if root != expected {
+ t.Errorf("root should be %q but got %q", expected, root)
+ }
+ expected = ".so"
+ if suffix != expected {
+ t.Errorf("suffix should be %q but got %q", expected, suffix)
+ }
+ expected = ".so"
+ if ext != expected {
+ t.Errorf("ext should be %q but got %q", expected, ext)
+ }
+ })
+
+ t.Run("no known file extension", func(t *testing.T) {
+ root, suffix, ext := SplitFileExt("test.exe")
+ expected := "test"
+ if root != expected {
+ t.Errorf("root should be %q but got %q", expected, root)
+ }
+ expected = ".exe"
+ if suffix != expected {
+ t.Errorf("suffix should be %q but got %q", expected, suffix)
+ }
+ if ext != expected {
+ t.Errorf("ext should be %q but got %q", expected, ext)
+ }
+ })
+}
+
+func Test_Shard(t *testing.T) {
+ type args struct {
+ strings []string
+ shardSize int
+ }
+ tests := []struct {
+ name string
+ args args
+ want [][]string
+ }{
+ {
+ name: "empty",
+ args: args{
+ strings: nil,
+ shardSize: 1,
+ },
+ want: [][]string(nil),
+ },
+ {
+ name: "single shard",
+ args: args{
+ strings: []string{"a", "b"},
+ shardSize: 2,
+ },
+ want: [][]string{{"a", "b"}},
+ },
+ {
+ name: "single short shard",
+ args: args{
+ strings: []string{"a", "b"},
+ shardSize: 3,
+ },
+ want: [][]string{{"a", "b"}},
+ },
+ {
+ name: "shard per input",
+ args: args{
+ strings: []string{"a", "b", "c"},
+ shardSize: 1,
+ },
+ want: [][]string{{"a"}, {"b"}, {"c"}},
+ },
+ {
+ name: "balanced shards",
+ args: args{
+ strings: []string{"a", "b", "c", "d"},
+ shardSize: 2,
+ },
+ want: [][]string{{"a", "b"}, {"c", "d"}},
+ },
+ {
+ name: "unbalanced shards",
+ args: args{
+ strings: []string{"a", "b", "c"},
+ shardSize: 2,
+ },
+ want: [][]string{{"a", "b"}, {"c"}},
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ t.Run("strings", func(t *testing.T) {
+ if got := ShardStrings(tt.args.strings, tt.args.shardSize); !reflect.DeepEqual(got, tt.want) {
+ t.Errorf("ShardStrings(%v, %v) = %v, want %v",
+ tt.args.strings, tt.args.shardSize, got, tt.want)
+ }
+ })
+
+ t.Run("paths", func(t *testing.T) {
+ stringsToPaths := func(strings []string) Paths {
+ if strings == nil {
+ return nil
+ }
+ paths := make(Paths, len(strings))
+ for i, s := range strings {
+ paths[i] = PathForTesting(s)
+ }
+ return paths
+ }
+
+ paths := stringsToPaths(tt.args.strings)
+
+ var want []Paths
+ if sWant := tt.want; sWant != nil {
+ want = make([]Paths, len(sWant))
+ for i, w := range sWant {
+ want[i] = stringsToPaths(w)
+ }
+ }
+
+ if got := ShardPaths(paths, tt.args.shardSize); !reflect.DeepEqual(got, want) {
+ t.Errorf("ShardPaths(%v, %v) = %v, want %v",
+ paths, tt.args.shardSize, got, want)
+ }
+ })
+ })
+ }
+}
diff --git a/android/variable.go b/android/variable.go
index 0931db8..41943b0 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -115,10 +115,14 @@
Static_libs []string
Srcs []string
}
+
+ Flatten_apex struct {
+ Enabled *bool
+ }
} `android:"arch_variant"`
}
-var zeroProductVariables variableProperties
+var zeroProductVariables interface{} = variableProperties{}
type productVariables struct {
// Suffix to add to generated Makefiles
@@ -362,8 +366,13 @@
// TODO: depend on config variable, create variants, propagate variants up tree
a := module.base()
- variableValues := reflect.ValueOf(&a.variableProperties.Product_variables).Elem()
- zeroValues := reflect.ValueOf(zeroProductVariables.Product_variables)
+
+ if a.variableProperties == nil {
+ return
+ }
+
+ variableValues := reflect.ValueOf(a.variableProperties).Elem().FieldByName("Product_variables")
+ zeroValues := reflect.ValueOf(zeroProductVariables).FieldByName("Product_variables")
for i := 0; i < variableValues.NumField(); i++ {
variableValue := variableValues.Field(i)
@@ -492,3 +501,106 @@
return nil
}
+
+var variablePropTypeMap OncePer
+
+// sliceToTypeArray takes a slice of property structs and returns a reflection created array containing the
+// reflect.Types of each property struct. The result can be used as a key in a map.
+func sliceToTypeArray(s []interface{}) interface{} {
+ // Create an array using reflection whose length is the length of the input slice
+ ret := reflect.New(reflect.ArrayOf(len(s), reflect.TypeOf(reflect.TypeOf(0)))).Elem()
+ for i, e := range s {
+ ret.Index(i).Set(reflect.ValueOf(reflect.TypeOf(e)))
+ }
+ return ret.Interface()
+}
+
+// createVariableProperties takes the list of property structs for a module and returns a property struct that
+// contains the product variable properties that exist in the property structs, or nil if there are none. It
+// caches the result.
+func createVariableProperties(moduleTypeProps []interface{}, productVariables interface{}) interface{} {
+ // Convert the moduleTypeProps to an array of reflect.Types that can be used as a key in the OncePer.
+ key := sliceToTypeArray(moduleTypeProps)
+
+ // Use the variablePropTypeMap OncePer to cache the result for each set of property struct types.
+ typ, _ := variablePropTypeMap.Once(NewCustomOnceKey(key), func() interface{} {
+ // Compute the filtered property struct type.
+ return createVariablePropertiesType(moduleTypeProps, productVariables)
+ }).(reflect.Type)
+
+ if typ == nil {
+ return nil
+ }
+
+ // Create a new pointer to a filtered property struct.
+ return reflect.New(typ).Interface()
+}
+
+// createVariablePropertiesType creates a new type that contains only the product variable properties that exist in
+// a list of property structs.
+func createVariablePropertiesType(moduleTypeProps []interface{}, productVariables interface{}) reflect.Type {
+ typ, _ := proptools.FilterPropertyStruct(reflect.TypeOf(productVariables),
+ func(field reflect.StructField, prefix string) (bool, reflect.StructField) {
+ // Filter function, returns true if the field should be in the resulting struct
+ if prefix == "" {
+ // Keep the top level Product_variables field
+ return true, field
+ }
+ _, rest := splitPrefix(prefix)
+ if rest == "" {
+ // Keep the 2nd level field (i.e. Product_variables.Eng)
+ return true, field
+ }
+
+ // Strip off the first 2 levels of the prefix
+ _, prefix = splitPrefix(rest)
+
+ for _, p := range moduleTypeProps {
+ if fieldExistsByNameRecursive(reflect.TypeOf(p).Elem(), prefix, field.Name) {
+ // Keep any fields that exist in one of the property structs
+ return true, field
+ }
+ }
+
+ return false, field
+ })
+ return typ
+}
+
+func splitPrefix(prefix string) (first, rest string) {
+ index := strings.IndexByte(prefix, '.')
+ if index == -1 {
+ return prefix, ""
+ }
+ return prefix[:index], prefix[index+1:]
+}
+
+func fieldExistsByNameRecursive(t reflect.Type, prefix, name string) bool {
+ if t.Kind() != reflect.Struct {
+ panic(fmt.Errorf("fieldExistsByNameRecursive can only be called on a reflect.Struct"))
+ }
+
+ if prefix != "" {
+ split := strings.SplitN(prefix, ".", 2)
+ firstPrefix := split[0]
+ rest := ""
+ if len(split) > 1 {
+ rest = split[1]
+ }
+ f, exists := t.FieldByName(firstPrefix)
+ if !exists {
+ return false
+ }
+ ft := f.Type
+ if ft.Kind() == reflect.Ptr {
+ ft = ft.Elem()
+ }
+ if ft.Kind() != reflect.Struct {
+ panic(fmt.Errorf("field %q in %q is not a struct", firstPrefix, t))
+ }
+ return fieldExistsByNameRecursive(ft, rest, name)
+ } else {
+ _, exists := t.FieldByName(name)
+ return exists
+ }
+}
diff --git a/android/variable_test.go b/android/variable_test.go
index ce9ba54..c1910fe 100644
--- a/android/variable_test.go
+++ b/android/variable_test.go
@@ -16,7 +16,10 @@
import (
"reflect"
+ "strconv"
"testing"
+
+ "github.com/google/blueprint/proptools"
)
type printfIntoPropertyTestCase struct {
@@ -122,3 +125,111 @@
}
}
}
+
+type testProductVariableModule struct {
+ ModuleBase
+}
+
+func (m *testProductVariableModule) GenerateAndroidBuildActions(ctx ModuleContext) {
+}
+
+var testProductVariableProperties = struct {
+ Product_variables struct {
+ Eng struct {
+ Srcs []string
+ Cflags []string
+ }
+ }
+}{}
+
+func testProductVariableModuleFactoryFactory(props interface{}) func() Module {
+ return func() Module {
+ m := &testProductVariableModule{}
+ clonedProps := proptools.CloneProperties(reflect.ValueOf(props)).Interface()
+ m.AddProperties(clonedProps)
+
+ // Set a default variableProperties, this will be used as the input to the property struct filter
+ // for this test module.
+ m.variableProperties = testProductVariableProperties
+ InitAndroidModule(m)
+ return m
+ }
+}
+
+func TestProductVariables(t *testing.T) {
+ ctx := NewTestContext()
+ // A module type that has a srcs property but not a cflags property.
+ ctx.RegisterModuleType("module1", ModuleFactoryAdaptor(testProductVariableModuleFactoryFactory(struct {
+ Srcs []string
+ }{})))
+ // A module type that has a cflags property but not a srcs property.
+ ctx.RegisterModuleType("module2", ModuleFactoryAdaptor(testProductVariableModuleFactoryFactory(struct {
+ Cflags []string
+ }{})))
+ // A module type that does not have any properties that match product_variables.
+ ctx.RegisterModuleType("module3", ModuleFactoryAdaptor(testProductVariableModuleFactoryFactory(struct {
+ Foo []string
+ }{})))
+ ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
+ ctx.BottomUp("variable", variableMutator).Parallel()
+ })
+
+ // Test that a module can use one product variable even if it doesn't have all the properties
+ // supported by that product variable.
+ bp := `
+ module1 {
+ name: "foo",
+ product_variables: {
+ eng: {
+ srcs: ["foo.c"],
+ },
+ },
+ }
+ module2 {
+ name: "bar",
+ product_variables: {
+ eng: {
+ cflags: ["-DBAR"],
+ },
+ },
+ }
+
+ module3 {
+ name: "baz",
+ }
+ `
+
+ mockFS := map[string][]byte{
+ "Android.bp": []byte(bp),
+ }
+
+ ctx.MockFileSystem(mockFS)
+
+ ctx.Register()
+
+ config := TestConfig(buildDir, nil)
+ config.TestProductVariables.Eng = proptools.BoolPtr(true)
+
+ _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+ FailIfErrored(t, errs)
+ _, errs = ctx.PrepareBuildActions(config)
+ FailIfErrored(t, errs)
+}
+
+func BenchmarkSliceToTypeArray(b *testing.B) {
+ for _, n := range []int{1, 2, 4, 8, 100} {
+ var propStructs []interface{}
+ for i := 0; i < n; i++ {
+ propStructs = append(propStructs, &struct {
+ A *string
+ B string
+ }{})
+
+ }
+ b.Run(strconv.Itoa(n), func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ _ = sliceToTypeArray(propStructs)
+ }
+ })
+ }
+}
diff --git a/android/visibility_test.go b/android/visibility_test.go
index c44dc9e..d13fadf 100644
--- a/android/visibility_test.go
+++ b/android/visibility_test.go
@@ -860,23 +860,7 @@
t.Run(test.name, func(t *testing.T) {
_, errs := testVisibility(buildDir, test.fs)
- expectedErrors := test.expectedErrors
- if expectedErrors == nil {
- FailIfErrored(t, errs)
- } else {
- for _, expectedError := range expectedErrors {
- FailIfNoMatchingErrors(t, expectedError, errs)
- }
- if len(errs) > len(expectedErrors) {
- t.Errorf("additional errors found, expected %d, found %d", len(expectedErrors), len(errs))
- for i, expectedError := range expectedErrors {
- t.Errorf("expectedErrors[%d] = %s", i, expectedError)
- }
- for i, err := range errs {
- t.Errorf("errs[%d] = %s", i, err)
- }
- }
- }
+ CheckErrorsAgainstExpectations(t, errs, test.expectedErrors)
})
}
}
diff --git a/android/vts_config.go b/android/vts_config.go
index c44b3a3..86f6e72 100644
--- a/android/vts_config.go
+++ b/android/vts_config.go
@@ -41,16 +41,17 @@
func (me *VtsConfig) AndroidMk() AndroidMkData {
androidMkData := AndroidMkData{
Class: "FAKE",
- Include: "$(BUILD_SYSTEM)/android_vts_host_config.mk",
+ Include: "$(BUILD_SYSTEM)/suite_host_config.mk",
OutputFile: OptionalPathForPath(me.OutputFilePath),
}
- if me.properties.Test_config != nil {
- androidMkData.Extra = []AndroidMkExtraFunc{
- func(w io.Writer, outputFile Path) {
+ androidMkData.Extra = []AndroidMkExtraFunc{
+ func(w io.Writer, outputFile Path) {
+ if me.properties.Test_config != nil {
fmt.Fprintf(w, "LOCAL_TEST_CONFIG := %s\n",
*me.properties.Test_config)
- },
- }
+ }
+ fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE := vts")
+ },
}
return androidMkData
}
diff --git a/apex/apex.go b/apex/apex.go
index 2ce0d01..c9b989a 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -21,6 +21,7 @@
"runtime"
"sort"
"strings"
+ "sync"
"android/soong/android"
"android/soong/cc"
@@ -46,13 +47,15 @@
Description: "fs_config ${out}",
}, "ro_paths", "exec_paths")
- injectApexDependency = pctx.StaticRule("injectApexDependency", blueprint.RuleParams{
+ apexManifestRule = pctx.StaticRule("apexManifestRule", blueprint.RuleParams{
Command: `rm -f $out && ${jsonmodify} $in ` +
`-a provideNativeLibs ${provideNativeLibs} ` +
- `-a requireNativeLibs ${requireNativeLibs} -o $out`,
+ `-a requireNativeLibs ${requireNativeLibs} ` +
+ `${opt} ` +
+ `-o $out`,
CommandDeps: []string{"${jsonmodify}"},
- Description: "Inject dependency into ${out}",
- }, "provideNativeLibs", "requireNativeLibs")
+ Description: "prepare ${out}",
+ }, "provideNativeLibs", "requireNativeLibs", "opt")
// TODO(b/113233103): make sure that file_contexts is sane, i.e., validate
// against the binary policy using sefcontext_compiler -p <policy>.
@@ -98,10 +101,29 @@
Command: `${zip2zip} -i $in -o $out ` +
`apex_payload.img:apex/${abi}.img ` +
`apex_manifest.json:root/apex_manifest.json ` +
- `AndroidManifest.xml:manifest/AndroidManifest.xml`,
+ `AndroidManifest.xml:manifest/AndroidManifest.xml ` +
+ `assets/NOTICE.html.gz:assets/NOTICE.html.gz`,
CommandDeps: []string{"${zip2zip}"},
Description: "app bundle",
}, "abi")
+
+ emitApexContentRule = pctx.StaticRule("emitApexContentRule", blueprint.RuleParams{
+ Command: `rm -f ${out} && touch ${out} && (. ${out}.emit_commands)`,
+ Rspfile: "${out}.emit_commands",
+ RspfileContent: "${emit_commands}",
+ Description: "Emit APEX image content",
+ }, "emit_commands")
+
+ diffApexContentRule = pctx.StaticRule("diffApexContentRule", blueprint.RuleParams{
+ Command: `diff --unchanged-group-format='' \` +
+ `--changed-group-format='%<' \` +
+ `${image_content_file} ${whitelisted_files_file} || (` +
+ `echo -e "New unexpected files were added to ${apex_module_name}." ` +
+ ` "To fix the build run following command:" && ` +
+ `echo "system/apex/tools/update_whitelist.sh ${whitelisted_files_file} ${image_content_file}" && ` +
+ `exit 1)`,
+ Description: "Diff ${image_content_file} and ${whitelisted_files_file}",
+ }, "image_content_file", "whitelisted_files_file", "apex_module_name")
)
var imageApexSuffix = ".apex"
@@ -124,16 +146,7 @@
keyTag = dependencyTag{name: "key"}
certificateTag = dependencyTag{name: "certificate"}
usesTag = dependencyTag{name: "uses"}
-)
-
-var (
- whitelistNoApex = map[string][]string{
- "apex_test_build_features": []string{"libbinder"},
- "com.android.neuralnetworks": []string{"libbinder"},
- "com.android.media": []string{"libbinder"},
- "com.android.media.swcodec": []string{"libbinder"},
- "test_com.android.media.swcodec": []string{"libbinder"},
- }
+ androidAppTag = dependencyTag{name: "androidApp"}
)
func init() {
@@ -163,16 +176,77 @@
pctx.HostBinToolVariable("zipalign", "zipalign")
pctx.HostBinToolVariable("jsonmodify", "jsonmodify")
- android.RegisterModuleType("apex", apexBundleFactory)
+ android.RegisterModuleType("apex", BundleFactory)
android.RegisterModuleType("apex_test", testApexBundleFactory)
+ android.RegisterModuleType("apex_vndk", vndkApexBundleFactory)
android.RegisterModuleType("apex_defaults", defaultsFactory)
android.RegisterModuleType("prebuilt_apex", PrebuiltFactory)
- android.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
- ctx.TopDown("apex_deps", apexDepsMutator)
- ctx.BottomUp("apex", apexMutator).Parallel()
- ctx.BottomUp("apex_uses", apexUsesMutator).Parallel()
+ android.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.TopDown("apex_vndk_gather", apexVndkGatherMutator).Parallel()
+ ctx.BottomUp("apex_vndk_add_deps", apexVndkAddDepsMutator).Parallel()
})
+ android.PostDepsMutators(RegisterPostDepsMutators)
+
+ android.RegisterMakeVarsProvider(pctx, func(ctx android.MakeVarsContext) {
+ apexFileContextsInfos := apexFileContextsInfos(ctx.Config())
+ sort.Strings(*apexFileContextsInfos)
+ ctx.Strict("APEX_FILE_CONTEXTS_INFOS", strings.Join(*apexFileContextsInfos, " "))
+ })
+}
+
+func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) {
+ ctx.TopDown("apex_deps", apexDepsMutator)
+ ctx.BottomUp("apex", apexMutator).Parallel()
+ ctx.BottomUp("apex_flattened", apexFlattenedMutator).Parallel()
+ ctx.BottomUp("apex_uses", apexUsesMutator).Parallel()
+}
+
+var (
+ vndkApexListKey = android.NewOnceKey("vndkApexList")
+ vndkApexListMutex sync.Mutex
+)
+
+func vndkApexList(config android.Config) map[string]*apexBundle {
+ return config.Once(vndkApexListKey, func() interface{} {
+ return map[string]*apexBundle{}
+ }).(map[string]*apexBundle)
+}
+
+// apexVndkGatherMutator gathers "apex_vndk" modules and puts them in a map with vndk_version as a key.
+func apexVndkGatherMutator(mctx android.TopDownMutatorContext) {
+ if ab, ok := mctx.Module().(*apexBundle); ok && ab.vndkApex {
+ if ab.IsNativeBridgeSupported() {
+ mctx.PropertyErrorf("native_bridge_supported", "%q doesn't support native bridge binary.", mctx.ModuleType())
+ }
+
+ vndkVersion := proptools.String(ab.vndkProperties.Vndk_version)
+
+ vndkApexListMutex.Lock()
+ defer vndkApexListMutex.Unlock()
+ vndkApexList := vndkApexList(mctx.Config())
+ if other, ok := vndkApexList[vndkVersion]; ok {
+ mctx.PropertyErrorf("vndk_version", "%v is already defined in %q", vndkVersion, other.BaseModuleName())
+ }
+ vndkApexList[vndkVersion] = ab
+ }
+}
+
+// apexVndkAddDepsMutator adds (reverse) dependencies from vndk libs to apex_vndk modules.
+// It filters only libs with matching targets.
+func apexVndkAddDepsMutator(mctx android.BottomUpMutatorContext) {
+ if cc, ok := mctx.Module().(*cc.Module); ok && cc.IsVndkOnSystem() {
+ vndkApexList := vndkApexList(mctx.Config())
+ if ab, ok := vndkApexList[cc.VndkVersion()]; ok {
+ targetArch := cc.Target().String()
+ for _, target := range ab.MultiTargets() {
+ if target.String() == targetArch {
+ mctx.AddReverseDependency(mctx.Module(), sharedLibTag, ab.Name())
+ break
+ }
+ }
+ }
+ }
}
// Mark the direct and transitive dependencies of apex bundles so that they
@@ -205,13 +279,53 @@
func apexMutator(mctx android.BottomUpMutatorContext) {
if am, ok := mctx.Module().(android.ApexModule); ok && am.CanHaveApexVariants() {
am.CreateApexVariations(mctx)
- } else if _, ok := mctx.Module().(*apexBundle); ok {
+ } else if a, ok := mctx.Module().(*apexBundle); ok {
// apex bundle itself is mutated so that it and its modules have same
// apex variant.
apexBundleName := mctx.ModuleName()
mctx.CreateVariations(apexBundleName)
+
+ // collects APEX list
+ if mctx.Device() && a.installable() {
+ addApexFileContextsInfos(mctx, a)
+ }
}
}
+
+var (
+ apexFileContextsInfosKey = android.NewOnceKey("apexFileContextsInfosKey")
+ apexFileContextsInfosMutex sync.Mutex
+)
+
+func apexFileContextsInfos(config android.Config) *[]string {
+ return config.Once(apexFileContextsInfosKey, func() interface{} {
+ return &[]string{}
+ }).(*[]string)
+}
+
+func addApexFileContextsInfos(ctx android.BaseModuleContext, a *apexBundle) {
+ apexName := proptools.StringDefault(a.properties.Apex_name, ctx.ModuleName())
+ fileContextsName := proptools.StringDefault(a.properties.File_contexts, ctx.ModuleName())
+
+ apexFileContextsInfosMutex.Lock()
+ defer apexFileContextsInfosMutex.Unlock()
+ apexFileContextsInfos := apexFileContextsInfos(ctx.Config())
+ *apexFileContextsInfos = append(*apexFileContextsInfos, apexName+":"+fileContextsName)
+}
+
+func apexFlattenedMutator(mctx android.BottomUpMutatorContext) {
+ if ab, ok := mctx.Module().(*apexBundle); ok {
+ if !mctx.Config().FlattenApex() || mctx.Config().UnbundledBuild() {
+ modules := mctx.CreateLocalVariations("", "flattened")
+ modules[0].(*apexBundle).SetFlattened(false)
+ modules[1].(*apexBundle).SetFlattened(true)
+ } else {
+ ab.SetFlattened(true)
+ ab.SetFlattenedConfigValue()
+ }
+ }
+}
+
func apexUsesMutator(mctx android.BottomUpMutatorContext) {
if ab, ok := mctx.Module().(*apexBundle); ok {
mctx.AddFarVariationDependencies(nil, usesTag, ab.properties.Uses...)
@@ -221,11 +335,14 @@
type apexNativeDependencies struct {
// List of native libraries
Native_shared_libs []string
+
// List of native executables
Binaries []string
+
// List of native tests
Tests []string
}
+
type apexMultilibProperties struct {
// Native dependencies whose compile_multilib is "first"
First apexNativeDependencies
@@ -252,8 +369,9 @@
// If unspecified, a default one is automatically generated.
AndroidManifest *string `android:"path"`
- // Canonical name of the APEX bundle in the manifest file.
- // If unspecified, defaults to the value of name
+ // Canonical name of the APEX bundle. Used to determine the path to the activated APEX on
+ // device (/apex/<apex_name>).
+ // If unspecified, defaults to the value of name.
Apex_name *string
// Determines the file contexts file for setting security context to each file in this APEX bundle.
@@ -312,6 +430,26 @@
// List of providing APEXes' names so that this APEX can depend on provided shared libraries.
Uses []string
+
+ // A txt file containing list of files that are whitelisted to be included in this APEX.
+ Whitelisted_files *string
+
+ // List of APKs to package inside APEX
+ Apps []string
+
+ // To distinguish between flattened and non-flattened apex.
+ // if set true, then output files are flattened.
+ Flattened bool `blueprint:"mutated"`
+
+ // if true, it means that TARGET_FLATTEN_APEX is true and
+ // TARGET_BUILD_APPS is false
+ FlattenedConfigValue bool `blueprint:"mutated"`
+
+ // List of SDKs that are used to build this APEX. A reference to an SDK should be either
+ // `name#version` or `name` which is an alias for `name#current`. If left empty, `platform#current`
+ // is implied. This value affects all modules included in this APEX. In other words, they are
+ // also built with the SDKs specified here.
+ Uses_sdks []string
}
type apexTargetBundleProperties struct {
@@ -320,14 +458,17 @@
Android struct {
Multilib apexMultilibProperties
}
+
// Multilib properties only for host.
Host struct {
Multilib apexMultilibProperties
}
+
// Multilib properties only for host linux_bionic.
Linux_bionic struct {
Multilib apexMultilibProperties
}
+
// Multilib properties only for host linux_glibc.
Linux_glibc struct {
Multilib apexMultilibProperties
@@ -335,6 +476,11 @@
}
}
+type apexVndkProperties struct {
+ // Indicates VNDK version of which this VNDK APEX bundles VNDK libs. Default is Platform VNDK Version.
+ Vndk_version *string
+}
+
type apexFileClass int
const (
@@ -346,6 +492,7 @@
goBinary
javaSharedLib
nativeTest
+ app
)
type apexPackaging int
@@ -410,6 +557,15 @@
return "JAVA_LIBRARIES"
case nativeTest:
return "NATIVE_TESTS"
+ case app:
+ // b/142537672 Why isn't this APP? We want to have full control over
+ // the paths and file names of the apk file under the flattend APEX.
+ // If this is set to APP, then the paths and file names are modified
+ // by the Make build system. For example, it is installed to
+ // /system/apex/<apexname>/app/<Appname>/<apexname>.<Appname>/ instead of
+ // /system/apex/<apexname>/app/<Appname> because the build system automatically
+ // appends module name (which is <apexname>.<Appname> to the path.
+ return "ETC"
default:
panic(fmt.Errorf("unknown class %d", class))
}
@@ -427,15 +583,18 @@
type apexBundle struct {
android.ModuleBase
android.DefaultableModuleBase
+ android.SdkBase
properties apexBundleProperties
targetProperties apexTargetBundleProperties
+ vndkProperties apexVndkProperties
apexTypes apexPackaging
bundleModuleFile android.WritablePath
outputFiles map[apexPackaging]android.WritablePath
- installDir android.OutputPath
+ flattenedOutput android.InstallPath
+ installDir android.InstallPath
prebuiltFileToDelete string
@@ -451,9 +610,8 @@
// list of module names that this APEX is depending on
externalDeps []string
- flattened bool
-
testApex bool
+ vndkApex bool
// intermediate path for apex_manifest.json
manifestOut android.WritablePath
@@ -461,28 +619,25 @@
func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext,
native_shared_libs []string, binaries []string, tests []string,
- arch string, imageVariation string) {
+ target android.Target, imageVariation string) {
// Use *FarVariation* to be able to depend on modules having
// conflicting variations with this module. This is required since
// arch variant of an APEX bundle is 'common' but it is 'arm' or 'arm64'
// for native shared libs.
- ctx.AddFarVariationDependencies([]blueprint.Variation{
- {Mutator: "arch", Variation: arch},
+ ctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
{Mutator: "image", Variation: imageVariation},
{Mutator: "link", Variation: "shared"},
{Mutator: "version", Variation: ""}, // "" is the non-stub variant
- }, sharedLibTag, native_shared_libs...)
+ }...), sharedLibTag, native_shared_libs...)
- ctx.AddFarVariationDependencies([]blueprint.Variation{
- {Mutator: "arch", Variation: arch},
- {Mutator: "image", Variation: imageVariation},
- }, executableTag, binaries...)
+ ctx.AddFarVariationDependencies(append(target.Variations(),
+ blueprint.Variation{Mutator: "image", Variation: imageVariation}),
+ executableTag, binaries...)
- ctx.AddFarVariationDependencies([]blueprint.Variation{
- {Mutator: "arch", Variation: arch},
+ ctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
{Mutator: "image", Variation: imageVariation},
{Mutator: "test_per_src", Variation: ""}, // "" is the all-tests variant
- }, testTag, tests...)
+ }...), testTag, tests...)
}
func (a *apexBundle) combineProperties(ctx android.BottomUpMutatorContext) {
@@ -514,49 +669,45 @@
for i, target := range targets {
// When multilib.* is omitted for native_shared_libs, it implies
// multilib.both.
- ctx.AddFarVariationDependencies([]blueprint.Variation{
- {Mutator: "arch", Variation: target.String()},
+ ctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
{Mutator: "image", Variation: a.getImageVariation(config)},
{Mutator: "link", Variation: "shared"},
- }, sharedLibTag, a.properties.Native_shared_libs...)
+ }...), sharedLibTag, a.properties.Native_shared_libs...)
// When multilib.* is omitted for tests, it implies
// multilib.both.
- ctx.AddFarVariationDependencies([]blueprint.Variation{
- {Mutator: "arch", Variation: target.String()},
+ ctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
{Mutator: "image", Variation: a.getImageVariation(config)},
{Mutator: "test_per_src", Variation: ""}, // "" is the all-tests variant
- }, testTag, a.properties.Tests...)
+ }...), testTag, a.properties.Tests...)
// Add native modules targetting both ABIs
addDependenciesForNativeModules(ctx,
a.properties.Multilib.Both.Native_shared_libs,
a.properties.Multilib.Both.Binaries,
a.properties.Multilib.Both.Tests,
- target.String(),
+ target,
a.getImageVariation(config))
isPrimaryAbi := i == 0
if isPrimaryAbi {
// When multilib.* is omitted for binaries, it implies
// multilib.first.
- ctx.AddFarVariationDependencies([]blueprint.Variation{
- {Mutator: "arch", Variation: target.String()},
- {Mutator: "image", Variation: a.getImageVariation(config)},
- }, executableTag, a.properties.Binaries...)
+ ctx.AddFarVariationDependencies(append(target.Variations(),
+ blueprint.Variation{Mutator: "image", Variation: a.getImageVariation(config)}),
+ executableTag, a.properties.Binaries...)
// Add native modules targetting the first ABI
addDependenciesForNativeModules(ctx,
a.properties.Multilib.First.Native_shared_libs,
a.properties.Multilib.First.Binaries,
a.properties.Multilib.First.Tests,
- target.String(),
+ target,
a.getImageVariation(config))
// When multilib.* is omitted for prebuilts, it implies multilib.first.
- ctx.AddFarVariationDependencies([]blueprint.Variation{
- {Mutator: "arch", Variation: target.String()},
- }, prebuiltTag, a.properties.Prebuilts...)
+ ctx.AddFarVariationDependencies(target.Variations(),
+ prebuiltTag, a.properties.Prebuilts...)
}
switch target.Arch.ArchType.Multilib {
@@ -566,14 +717,14 @@
a.properties.Multilib.Lib32.Native_shared_libs,
a.properties.Multilib.Lib32.Binaries,
a.properties.Multilib.Lib32.Tests,
- target.String(),
+ target,
a.getImageVariation(config))
addDependenciesForNativeModules(ctx,
a.properties.Multilib.Prefer32.Native_shared_libs,
a.properties.Multilib.Prefer32.Binaries,
a.properties.Multilib.Prefer32.Tests,
- target.String(),
+ target,
a.getImageVariation(config))
case "lib64":
// Add native modules targetting 64-bit ABI
@@ -581,7 +732,7 @@
a.properties.Multilib.Lib64.Native_shared_libs,
a.properties.Multilib.Lib64.Binaries,
a.properties.Multilib.Lib64.Tests,
- target.String(),
+ target,
a.getImageVariation(config))
if !has32BitTarget {
@@ -589,7 +740,7 @@
a.properties.Multilib.Prefer32.Native_shared_libs,
a.properties.Multilib.Prefer32.Binaries,
a.properties.Multilib.Prefer32.Tests,
- target.String(),
+ target,
a.getImageVariation(config))
}
@@ -598,7 +749,7 @@
if sanitizer == "hwaddress" {
addDependenciesForNativeModules(ctx,
[]string{"libclang_rt.hwasan-aarch64-android"},
- nil, nil, target.String(), a.getImageVariation(config))
+ nil, nil, target, a.getImageVariation(config))
break
}
}
@@ -607,9 +758,11 @@
}
- ctx.AddFarVariationDependencies([]blueprint.Variation{
- {Mutator: "arch", Variation: "android_common"},
- }, javaLibTag, a.properties.Java_libs...)
+ ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(),
+ javaLibTag, a.properties.Java_libs...)
+
+ ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(),
+ androidAppTag, a.properties.Apps...)
if String(a.properties.Key) == "" {
ctx.ModuleErrorf("key is missing")
@@ -621,6 +774,21 @@
if cert != "" {
ctx.AddDependency(ctx.Module(), certificateTag, cert)
}
+
+ // TODO(jiyong): ensure that all apexes are with non-empty uses_sdks
+ if len(a.properties.Uses_sdks) > 0 {
+ sdkRefs := []android.SdkRef{}
+ for _, str := range a.properties.Uses_sdks {
+ parsed := android.ParseSdkRef(ctx, str, "uses_sdks")
+ sdkRefs = append(sdkRefs, parsed)
+ }
+ a.BuildWithSdks(sdkRefs)
+ }
+}
+
+func (a *apexBundle) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
+ // direct deps of an APEX bundle are all part of the APEX bundle
+ return true
}
func (a *apexBundle) getCertString(ctx android.BaseModuleContext) string {
@@ -639,6 +807,13 @@
} else {
return nil, nil
}
+ case ".flattened":
+ if a.properties.Flattened {
+ flattenedApexPath := a.flattenedOutput
+ return android.Paths{flattenedApexPath}, nil
+ } else {
+ return nil, nil
+ }
default:
return nil, fmt.Errorf("unsupported module reference tag %q", tag)
}
@@ -650,7 +825,7 @@
func (a *apexBundle) getImageVariation(config android.DeviceConfig) string {
if config.VndkVersion() != "" && proptools.Bool(a.properties.Use_vendor) {
- return "vendor"
+ return "vendor." + config.PlatformVndkVersion()
} else {
return "core"
}
@@ -692,46 +867,58 @@
a.properties.HideFromMake = true
}
-func getCopyManifestForNativeLibrary(cc *cc.Module, handleSpecialLibs bool) (fileToCopy android.Path, dirInApex string) {
+func (a *apexBundle) SetFlattened(flattened bool) {
+ a.properties.Flattened = flattened
+}
+
+func (a *apexBundle) SetFlattenedConfigValue() {
+ a.properties.FlattenedConfigValue = true
+}
+
+// isFlattenedVariant returns true when the current module is the flattened
+// variant of an apex that has both a flattened and an unflattened variant.
+// It returns false when the current module is flattened but there is no
+// unflattened variant, which occurs when ctx.Config().FlattenedApex() returns
+// true. It can be used to avoid collisions between the install paths of the
+// flattened and unflattened variants.
+func (a *apexBundle) isFlattenedVariant() bool {
+ return a.properties.Flattened && !a.properties.FlattenedConfigValue
+}
+
+func getCopyManifestForNativeLibrary(ccMod *cc.Module, config android.Config, handleSpecialLibs bool) (fileToCopy android.Path, dirInApex string) {
// Decide the APEX-local directory by the multilib of the library
// In the future, we may query this to the module.
- switch cc.Arch().ArchType.Multilib {
+ switch ccMod.Arch().ArchType.Multilib {
case "lib32":
dirInApex = "lib"
case "lib64":
dirInApex = "lib64"
}
- dirInApex = filepath.Join(dirInApex, cc.RelativeInstallPath())
- if !cc.Arch().Native {
- dirInApex = filepath.Join(dirInApex, cc.Arch().ArchType.String())
- } else if cc.Target().NativeBridge == android.NativeBridgeEnabled {
- dirInApex = filepath.Join(dirInApex, cc.Target().NativeBridgeRelativePath)
+ dirInApex = filepath.Join(dirInApex, ccMod.RelativeInstallPath())
+ if ccMod.Target().NativeBridge == android.NativeBridgeEnabled {
+ dirInApex = filepath.Join(dirInApex, ccMod.Target().NativeBridgeRelativePath)
}
- if handleSpecialLibs {
- switch cc.Name() {
- case "libc", "libm", "libdl":
- // Special case for bionic libs. This is to prevent the bionic libs
- // from being included in the search path /apex/com.android.apex/lib.
- // This exclusion is required because bionic libs in the runtime APEX
- // are available via the legacy paths /system/lib/libc.so, etc. By the
- // init process, the bionic libs in the APEX are bind-mounted to the
- // legacy paths and thus will be loaded into the default linker namespace.
- // If the bionic libs are directly in /apex/com.android.apex/lib then
- // the same libs will be again loaded to the runtime linker namespace,
- // which will result double loading of bionic libs that isn't supported.
- dirInApex = filepath.Join(dirInApex, "bionic")
- }
+ if handleSpecialLibs && cc.InstallToBootstrap(ccMod.BaseModuleName(), config) {
+ // Special case for Bionic libs and other libs installed with them. This is
+ // to prevent those libs from being included in the search path
+ // /apex/com.android.runtime/${LIB}. This exclusion is required because
+ // those libs in the Runtime APEX are available via the legacy paths in
+ // /system/lib/. By the init process, the libs in the APEX are bind-mounted
+ // to the legacy paths and thus will be loaded into the default linker
+ // namespace (aka "platform" namespace). If the libs are directly in
+ // /apex/com.android.runtime/${LIB} then the same libs will be loaded again
+ // into the runtime linker namespace, which will result in double loading of
+ // them, which isn't supported.
+ dirInApex = filepath.Join(dirInApex, "bionic")
}
- fileToCopy = cc.OutputFile().Path()
+ fileToCopy = ccMod.OutputFile().Path()
return
}
func getCopyManifestForExecutable(cc *cc.Module) (fileToCopy android.Path, dirInApex string) {
dirInApex = filepath.Join("bin", cc.RelativeInstallPath())
- if !cc.Arch().Native {
- dirInApex = filepath.Join(dirInApex, cc.Arch().ArchType.String())
- } else if cc.Target().NativeBridge == android.NativeBridgeEnabled {
+ if cc.Target().NativeBridge == android.NativeBridgeEnabled {
dirInApex = filepath.Join(dirInApex, cc.Target().NativeBridgeRelativePath)
}
fileToCopy = cc.OutputFile().Path()
@@ -784,6 +971,25 @@
return
}
+func getCopyManifestForAndroidApp(app *java.AndroidApp, pkgName string) (fileToCopy android.Path, dirInApex string) {
+ appDir := "app"
+ if app.Privileged() {
+ appDir = "priv-app"
+ }
+ dirInApex = filepath.Join(appDir, pkgName)
+ fileToCopy = app.OutputFile()
+ return
+}
+
+// Context "decorator", overriding the InstallBypassMake method to always reply `true`.
+type flattenedApexContext struct {
+ android.ModuleContext
+}
+
+func (c *flattenedApexContext) InstallBypassMake() bool {
+ return true
+}
+
func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
filesInfo := []apexFile{}
@@ -844,7 +1050,7 @@
if cc.HasStubsVariants() {
provideNativeLibs = append(provideNativeLibs, cc.OutputFile().Path().Base())
}
- fileToCopy, dirInApex := getCopyManifestForNativeLibrary(cc, handleSpecialLibs)
+ fileToCopy, dirInApex := getCopyManifestForNativeLibrary(cc, ctx.Config(), handleSpecialLibs)
filesInfo = append(filesInfo, apexFile{fileToCopy, depName, dirInApex, nativeSharedLib, cc, nil})
return true
} else {
@@ -857,7 +1063,7 @@
return true
} else if sh, ok := child.(*android.ShBinary); ok {
fileToCopy, dirInApex := getCopyManifestForShBinary(sh)
- filesInfo = append(filesInfo, apexFile{fileToCopy, depName, dirInApex, shBinary, sh, nil})
+ filesInfo = append(filesInfo, apexFile{fileToCopy, depName, dirInApex, shBinary, sh, sh.Symlinks()})
} else if py, ok := child.(*python.Module); ok && py.HostToolPath().Valid() {
fileToCopy, dirInApex := getCopyManifestForPyBinary(py)
filesInfo = append(filesInfo, apexFile{fileToCopy, depName, dirInApex, pyBinary, py, nil})
@@ -939,6 +1145,14 @@
if prebuilt, ok := child.(*Prebuilt); ok && prebuilt.isForceDisabled() {
a.prebuiltFileToDelete = prebuilt.InstallFilename()
}
+ case androidAppTag:
+ if ap, ok := child.(*java.AndroidApp); ok {
+ fileToCopy, dirInApex := getCopyManifestForAndroidApp(ap, ctx.DeviceConfig().OverridePackageNameFor(depName))
+ filesInfo = append(filesInfo, apexFile{fileToCopy, depName, dirInApex, app, ap, nil})
+ return true
+ } else {
+ ctx.PropertyErrorf("apps", "%q is not an android_app module", depName)
+ }
}
} else {
// indirect dependencies
@@ -967,7 +1181,7 @@
// Don't track further
return false
}
- fileToCopy, dirInApex := getCopyManifestForNativeLibrary(cc, handleSpecialLibs)
+ fileToCopy, dirInApex := getCopyManifestForNativeLibrary(cc, ctx.Config(), handleSpecialLibs)
filesInfo = append(filesInfo, apexFile{fileToCopy, depName, dirInApex, nativeSharedLib, cc, nil})
return true
}
@@ -984,15 +1198,12 @@
}
} else if am.CanHaveApexVariants() && am.IsInstallableToApex() {
ctx.ModuleErrorf("unexpected tag %q for indirect dependency %q", depTag, depName)
- } else if am.NoApex() && !android.InList(depName, whitelistNoApex[ctx.ModuleName()]) {
- ctx.ModuleErrorf("tries to include no_apex module %s", depName)
}
}
}
return false
})
- a.flattened = ctx.Config().FlattenApex() && !ctx.Config().UnbundledBuild()
if a.private_key_file == nil {
ctx.PropertyErrorf("key", "private_key for %q could not be found", String(a.properties.Key))
return
@@ -1000,11 +1211,12 @@
// remove duplicates in filesInfo
removeDup := func(filesInfo []apexFile) []apexFile {
- encountered := make(map[android.Path]bool)
+ encountered := make(map[string]bool)
result := []apexFile{}
for _, f := range filesInfo {
- if !encountered[f.builtFile] {
- encountered[f.builtFile] = true
+ dest := filepath.Join(f.installDir, f.builtFile.Base())
+ if !encountered[dest] {
+ encountered[dest] = true
result = append(result, f)
}
}
@@ -1017,12 +1229,14 @@
return filesInfo[i].builtFile.String() < filesInfo[j].builtFile.String()
})
- // check no_apex modules
- whitelist := whitelistNoApex[ctx.ModuleName()]
- for i := range filesInfo {
- if am, ok := filesInfo[i].module.(android.ApexModule); ok {
- if am.NoApex() && !android.InList(filesInfo[i].moduleName, whitelist) {
- ctx.ModuleErrorf("tries to include no_apex module %s", filesInfo[i].moduleName)
+ // check apex_available requirements
+ if !ctx.Host() {
+ for _, fi := range filesInfo {
+ if am, ok := fi.module.(android.ApexModule); ok {
+ if !am.AvailableFor(ctx.ModuleName()) {
+ ctx.ModuleErrorf("requires %q that is not available for the APEX", fi.module.Name())
+ return
+ }
}
}
}
@@ -1036,21 +1250,40 @@
a.installDir = android.PathForModuleInstall(ctx, "apex")
a.filesInfo = filesInfo
+ // prepare apex_manifest.json
a.manifestOut = android.PathForModuleOut(ctx, "apex_manifest.json")
- // put dependency({provide|require}NativeLibs) in apex_manifest.json
manifestSrc := android.PathForModuleSrc(ctx, proptools.StringDefault(a.properties.Manifest, "apex_manifest.json"))
+
+ // put dependency({provide|require}NativeLibs) in apex_manifest.json
provideNativeLibs = android.SortedUniqueStrings(provideNativeLibs)
requireNativeLibs = android.SortedUniqueStrings(android.RemoveListFromList(requireNativeLibs, provideNativeLibs))
+
+ // apex name can be overridden
+ optCommands := []string{}
+ if a.properties.Apex_name != nil {
+ optCommands = append(optCommands, "-v name "+*a.properties.Apex_name)
+ }
+
ctx.Build(pctx, android.BuildParams{
- Rule: injectApexDependency,
+ Rule: apexManifestRule,
Input: manifestSrc,
Output: a.manifestOut,
Args: map[string]string{
"provideNativeLibs": strings.Join(provideNativeLibs, " "),
"requireNativeLibs": strings.Join(requireNativeLibs, " "),
+ "opt": strings.Join(optCommands, " "),
},
})
+ // Temporarily wrap the original `ctx` into a `flattenedApexContext` to have it
+ // reply true to `InstallBypassMake()` (thus making the call
+ // `android.PathForModuleInstall` below use `android.pathForInstallInMakeDir`
+ // instead of `android.PathForOutput`) to return the correct path to the flattened
+ // APEX (as its contents is installed by Make, not Soong).
+ factx := flattenedApexContext{ctx}
+ apexName := proptools.StringDefault(a.properties.Apex_name, ctx.ModuleName())
+ a.flattenedOutput = android.PathForModuleInstall(&factx, "apex", apexName)
+
if a.apexTypes.zip() {
a.buildUnflattenedApex(ctx, zipApex)
}
@@ -1116,8 +1349,12 @@
}
copyCommands := []string{}
+ emitCommands := []string{}
+ imageContentFile := android.PathForModuleOut(ctx, ctx.ModuleName()+"-content.txt")
+ emitCommands = append(emitCommands, "echo ./apex_manifest.json >> "+imageContentFile.String())
for i, src := range filesToCopy {
dest := filepath.Join(a.filesInfo[i].installDir, src.Base())
+ emitCommands = append(emitCommands, "echo './"+dest+"' >> "+imageContentFile.String())
dest_path := filepath.Join(android.PathForModuleOut(ctx, "image"+suffix).String(), dest)
copyCommands = append(copyCommands, "mkdir -p "+filepath.Dir(dest_path))
copyCommands = append(copyCommands, "cp "+src.String()+" "+dest_path)
@@ -1129,6 +1366,35 @@
implicitInputs := append(android.Paths(nil), filesToCopy...)
implicitInputs = append(implicitInputs, a.manifestOut)
+ if a.properties.Whitelisted_files != nil {
+ ctx.Build(pctx, android.BuildParams{
+ Rule: emitApexContentRule,
+ Implicits: implicitInputs,
+ Output: imageContentFile,
+ Description: "emit apex image content",
+ Args: map[string]string{
+ "emit_commands": strings.Join(emitCommands, " && "),
+ },
+ })
+ implicitInputs = append(implicitInputs, imageContentFile)
+ whitelistedFilesFile := android.PathForModuleSrc(ctx, proptools.String(a.properties.Whitelisted_files))
+
+ phonyOutput := android.PathForModuleOut(ctx, ctx.ModuleName()+"-diff-phony-output")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: diffApexContentRule,
+ Implicits: implicitInputs,
+ Output: phonyOutput,
+ Description: "diff apex image content",
+ Args: map[string]string{
+ "whitelisted_files_file": whitelistedFilesFile.String(),
+ "image_content_file": imageContentFile.String(),
+ "apex_module_name": ctx.ModuleName(),
+ },
+ })
+
+ implicitInputs = append(implicitInputs, phonyOutput)
+ }
+
outHostBinDir := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "bin").String()
prebuiltSdkToolsBinDir := filepath.Join("prebuilts", "sdk", "tools", runtime.GOOS, "bin")
@@ -1213,6 +1479,19 @@
optFlags = append(optFlags, "--assets_dir "+filepath.Dir(noticeFile.String()))
}
+ if !ctx.Config().UnbundledBuild() && a.installable() {
+ // Apexes which are supposed to be installed in builtin dirs(/system, etc)
+ // don't need hashtree for activation. Therefore, by removing hashtree from
+ // apex bundle (filesystem image in it, to be specific), we can save storage.
+ optFlags = append(optFlags, "--no_hashtree")
+ }
+
+ if a.properties.Apex_name != nil {
+ // If apex_name is set, apexer can skip checking if key name matches with apex name.
+ // Note that apex_manifest is also mended.
+ optFlags = append(optFlags, "--do_not_check_keyname")
+ }
+
ctx.Build(pctx, android.BuildParams{
Rule: apexRule,
Implicits: implicitInputs,
@@ -1282,7 +1561,7 @@
})
// Install to $OUT/soong/{target,host}/.../apex
- if a.installable() && (!ctx.Config().FlattenApex() || apexType.zip()) {
+ if a.installable() && (!ctx.Config().FlattenApex() || apexType.zip()) && !a.isFlattenedVariant() {
ctx.InstallFile(a.installDir, ctx.ModuleName()+suffix, a.outputFiles[apexType])
}
}
@@ -1303,8 +1582,9 @@
a.filesInfo = append(a.filesInfo, apexFile{copiedPubkey, ctx.ModuleName() + ".apex_pubkey", ".", etc, nil, nil})
if ctx.Config().FlattenApex() {
+ apexName := proptools.StringDefault(a.properties.Apex_name, ctx.ModuleName())
for _, fi := range a.filesInfo {
- dir := filepath.Join("apex", ctx.ModuleName(), fi.installDir)
+ dir := filepath.Join("apex", apexName, fi.installDir)
target := ctx.InstallFile(android.PathForModuleInstall(ctx, dir), fi.builtFile.Base(), fi.builtFile)
for _, sym := range fi.symlinks {
ctx.InstallSymlink(android.PathForModuleInstall(ctx, dir), sym, target)
@@ -1335,27 +1615,38 @@
}}
}
-func (a *apexBundle) androidMkForFiles(w io.Writer, name, moduleDir string, apexType apexPackaging) []string {
+func (a *apexBundle) androidMkForFiles(w io.Writer, apexName, moduleDir string, apexType apexPackaging) []string {
moduleNames := []string{}
for _, fi := range a.filesInfo {
if cc, ok := fi.module.(*cc.Module); ok && cc.Properties.HideFromMake {
continue
}
- if !android.InList(fi.moduleName, moduleNames) {
- moduleNames = append(moduleNames, fi.moduleName)
+ if a.properties.Flattened && !apexType.image() {
+ continue
}
+
+ var suffix string
+ if a.isFlattenedVariant() {
+ suffix = ".flattened"
+ }
+
+ if !android.InList(fi.moduleName, moduleNames) {
+ moduleNames = append(moduleNames, fi.moduleName+suffix)
+ }
+
fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)")
fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
- fmt.Fprintln(w, "LOCAL_MODULE :=", fi.moduleName)
- // /apex/<name>/{lib|framework|...}
- pathWhenActivated := filepath.Join("$(PRODUCT_OUT)", "apex",
- proptools.StringDefault(a.properties.Apex_name, name), fi.installDir)
- if a.flattened && apexType.image() {
+ fmt.Fprintln(w, "LOCAL_MODULE :=", fi.moduleName+suffix)
+ // /apex/<apex_name>/{lib|framework|...}
+ pathWhenActivated := filepath.Join("$(PRODUCT_OUT)", "apex", apexName, fi.installDir)
+ if a.properties.Flattened && apexType.image() {
// /system/apex/<name>/{lib|framework|...}
- fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", filepath.Join("$(OUT_DIR)",
- a.installDir.RelPathString(), name, fi.installDir))
- fmt.Fprintln(w, "LOCAL_SOONG_SYMBOL_PATH :=", pathWhenActivated)
+ fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", filepath.Join(a.installDir.ToMakePath().String(),
+ apexName, fi.installDir))
+ if !a.isFlattenedVariant() {
+ fmt.Fprintln(w, "LOCAL_SOONG_SYMBOL_PATH :=", pathWhenActivated)
+ }
if len(fi.symlinks) > 0 {
fmt.Fprintln(w, "LOCAL_MODULE_SYMLINKS :=", strings.Join(fi.symlinks, " "))
}
@@ -1373,17 +1664,17 @@
host := false
switch fi.module.Target().Os.Class {
case android.Host:
- if archStr != "common" {
+ if fi.module.Target().Arch.ArchType != android.Common {
fmt.Fprintln(w, "LOCAL_MODULE_HOST_ARCH :=", archStr)
}
host = true
case android.HostCross:
- if archStr != "common" {
+ if fi.module.Target().Arch.ArchType != android.Common {
fmt.Fprintln(w, "LOCAL_MODULE_HOST_CROSS_ARCH :=", archStr)
}
host = true
case android.Device:
- if archStr != "common" {
+ if fi.module.Target().Arch.ArchType != android.Common {
fmt.Fprintln(w, "LOCAL_MODULE_TARGET_ARCH :=", archStr)
}
}
@@ -1407,7 +1698,7 @@
fmt.Fprintln(w, "LOCAL_SOONG_DEX_JAR :=", fi.builtFile.String())
fmt.Fprintln(w, "LOCAL_DEX_PREOPT := false")
fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_java_prebuilt.mk")
- } else if fi.class == nativeSharedLib || fi.class == nativeExecutable {
+ } else if fi.class == nativeSharedLib || fi.class == nativeExecutable || fi.class == nativeTest {
fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", fi.builtFile.Base())
if cc, ok := fi.module.(*cc.Module); ok {
if cc.UnstrippedOutputFile() != nil {
@@ -1432,10 +1723,15 @@
Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
moduleNames := []string{}
if a.installable() {
- moduleNames = a.androidMkForFiles(w, name, moduleDir, apexType)
+ apexName := proptools.StringDefault(a.properties.Apex_name, name)
+ moduleNames = a.androidMkForFiles(w, apexName, moduleDir, apexType)
}
- if a.flattened && apexType.image() {
+ if a.isFlattenedVariant() {
+ name = name + ".flattened"
+ }
+
+ if a.properties.Flattened && apexType.image() {
// Only image APEXes can be flattened.
fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)")
fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
@@ -1444,7 +1740,9 @@
fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", strings.Join(moduleNames, " "))
}
fmt.Fprintln(w, "include $(BUILD_PHONY_PACKAGE)")
- } else {
+ fmt.Fprintln(w, "$(LOCAL_INSTALLED_MODULE): .KATI_IMPLICIT_OUTPUTS :=", a.flattenedOutput.String())
+
+ } else if !a.isFlattenedVariant() {
// zip-apex is the less common type so have the name refer to the image-apex
// only and use {name}.zip if you want the zip-apex
if apexType == zipApex && a.apexTypes == both {
@@ -1455,7 +1753,7 @@
fmt.Fprintln(w, "LOCAL_MODULE :=", name)
fmt.Fprintln(w, "LOCAL_MODULE_CLASS := ETC") // do we need a new class?
fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", a.outputFiles[apexType].String())
- fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", filepath.Join("$(OUT_DIR)", a.installDir.RelPathString()))
+ fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", a.installDir.ToMakePath().String())
fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", name+apexType.suffix())
fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE :=", !a.installable())
if len(moduleNames) > 0 {
@@ -1466,7 +1764,7 @@
}
if a.prebuiltFileToDelete != "" {
fmt.Fprintln(w, "LOCAL_POST_INSTALL_CMD :=", "rm -rf "+
- filepath.Join("$(OUT_DIR)", a.installDir.RelPathString(), a.prebuiltFileToDelete))
+ filepath.Join(a.installDir.ToMakePath().String(), a.prebuiltFileToDelete))
}
fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
@@ -1477,18 +1775,9 @@
}}
}
-func testApexBundleFactory() android.Module {
- return ApexBundleFactory(true /*testApex*/)
-}
-
-func apexBundleFactory() android.Module {
- return ApexBundleFactory(false /*testApex*/)
-}
-
-func ApexBundleFactory(testApex bool) android.Module {
+func newApexBundle() *apexBundle {
module := &apexBundle{
outputFiles: map[apexPackaging]android.WritablePath{},
- testApex: testApex,
}
module.AddProperties(&module.properties)
module.AddProperties(&module.targetProperties)
@@ -1497,9 +1786,52 @@
})
android.InitAndroidMultiTargetsArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
android.InitDefaultableModule(module)
+ android.InitSdkAwareModule(module)
return module
}
+func ApexBundleFactory(testApex bool) android.Module {
+ bundle := newApexBundle()
+ bundle.testApex = testApex
+ return bundle
+}
+
+func testApexBundleFactory() android.Module {
+ bundle := newApexBundle()
+ bundle.testApex = true
+ return bundle
+}
+
+func BundleFactory() android.Module {
+ return newApexBundle()
+}
+
+// apex_vndk creates a special variant of apex modules which contains only VNDK libraries.
+// If `vndk_version` is specified, the VNDK libraries of the specified VNDK version are gathered automatically.
+// If not specified, then the "current" versions are gathered.
+func vndkApexBundleFactory() android.Module {
+ bundle := newApexBundle()
+ bundle.vndkApex = true
+ bundle.AddProperties(&bundle.vndkProperties)
+ android.AddLoadHook(bundle, func(ctx android.LoadHookContext) {
+ ctx.AppendProperties(&struct {
+ Compile_multilib *string
+ }{
+ proptools.StringPtr("both"),
+ })
+
+ vndkVersion := proptools.StringDefault(bundle.vndkProperties.Vndk_version, "current")
+ if vndkVersion == "current" {
+ vndkVersion = ctx.DeviceConfig().PlatformVndkVersion()
+ bundle.vndkProperties.Vndk_version = proptools.StringPtr(vndkVersion)
+ }
+
+ // Ensure VNDK APEX mount point is formatted as com.android.vndk.v###
+ bundle.properties.Apex_name = proptools.StringPtr("com.android.vndk.v" + vndkVersion)
+ })
+ return bundle
+}
+
//
// Defaults
//
@@ -1535,7 +1867,7 @@
properties PrebuiltProperties
inputApex android.Path
- installDir android.OutputPath
+ installDir android.InstallPath
installFilename string
outputApex android.WritablePath
}
@@ -1680,11 +2012,13 @@
Class: "ETC",
OutputFile: android.OptionalPathForPath(p.inputApex),
Include: "$(BUILD_PREBUILT)",
- AddCustomEntries: func(name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
- entries.SetString("LOCAL_MODULE_PATH", filepath.Join("$(OUT_DIR)", p.installDir.RelPathString()))
- entries.SetString("LOCAL_MODULE_STEM", p.installFilename)
- entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", !p.installable())
- entries.AddStrings("LOCAL_OVERRIDES_PACKAGES", p.properties.Overrides...)
+ ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+ func(entries *android.AndroidMkEntries) {
+ entries.SetString("LOCAL_MODULE_PATH", p.installDir.ToMakePath().String())
+ entries.SetString("LOCAL_MODULE_STEM", p.installFilename)
+ entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", !p.installable())
+ entries.AddStrings("LOCAL_OVERRIDES_PACKAGES", p.properties.Overrides...)
+ },
},
}
}
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 0845b20..7a51bb6 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -40,8 +40,9 @@
return
}
-func testApexError(t *testing.T, pattern, bp string) {
- ctx, config := testApexContext(t, bp)
+func testApexError(t *testing.T, pattern, bp string, handlers ...testCustomizer) {
+ t.Helper()
+ ctx, config := testApexContext(t, bp, handlers...)
_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
if len(errs) > 0 {
android.FailIfNoMatchingErrors(t, pattern, errs)
@@ -56,8 +57,9 @@
t.Fatalf("missing expected error %q (0 errors are returned)", pattern)
}
-func testApex(t *testing.T, bp string) (*android.TestContext, android.Config) {
- ctx, config := testApexContext(t, bp)
+func testApex(t *testing.T, bp string, handlers ...testCustomizer) (*android.TestContext, android.Config) {
+ t.Helper()
+ ctx, config := testApexContext(t, bp, handlers...)
_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
android.FailIfErrored(t, errs)
_, errs = ctx.PrepareBuildActions(config)
@@ -65,37 +67,51 @@
return ctx, config
}
-func testApexContext(t *testing.T, bp string) (*android.TestContext, android.Config) {
+type testCustomizer func(fs map[string][]byte, config android.Config)
+
+func withFiles(files map[string][]byte) testCustomizer {
+ return func(fs map[string][]byte, config android.Config) {
+ for k, v := range files {
+ fs[k] = v
+ }
+ }
+}
+
+func withTargets(targets map[android.OsType][]android.Target) testCustomizer {
+ return func(fs map[string][]byte, config android.Config) {
+ for k, v := range targets {
+ config.Targets[k] = v
+ }
+ }
+}
+
+func testApexContext(t *testing.T, bp string, handlers ...testCustomizer) (*android.TestContext, android.Config) {
config := android.TestArchConfig(buildDir, nil)
config.TestProductVariables.DeviceVndkVersion = proptools.StringPtr("current")
config.TestProductVariables.DefaultAppCertificate = proptools.StringPtr("vendor/foo/devkeys/test")
config.TestProductVariables.CertificateOverrides = []string{"myapex_keytest:myapex.certificate.override"}
config.TestProductVariables.Platform_sdk_codename = proptools.StringPtr("Q")
config.TestProductVariables.Platform_sdk_final = proptools.BoolPtr(false)
+ config.TestProductVariables.Platform_vndk_version = proptools.StringPtr("VER")
ctx := android.NewTestArchContext()
- ctx.RegisterModuleType("apex", android.ModuleFactoryAdaptor(apexBundleFactory))
+ ctx.RegisterModuleType("apex", android.ModuleFactoryAdaptor(BundleFactory))
ctx.RegisterModuleType("apex_test", android.ModuleFactoryAdaptor(testApexBundleFactory))
- ctx.RegisterModuleType("apex_key", android.ModuleFactoryAdaptor(apexKeyFactory))
+ ctx.RegisterModuleType("apex_vndk", android.ModuleFactoryAdaptor(vndkApexBundleFactory))
+ ctx.RegisterModuleType("apex_key", android.ModuleFactoryAdaptor(ApexKeyFactory))
ctx.RegisterModuleType("apex_defaults", android.ModuleFactoryAdaptor(defaultsFactory))
ctx.RegisterModuleType("prebuilt_apex", android.ModuleFactoryAdaptor(PrebuiltFactory))
- ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
-
- ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
- ctx.TopDown("apex_deps", apexDepsMutator)
- ctx.BottomUp("apex", apexMutator)
- ctx.BottomUp("apex_uses", apexUsesMutator)
- ctx.TopDown("prebuilt_select", android.PrebuiltSelectModuleMutator).Parallel()
- ctx.BottomUp("prebuilt_postdeps", android.PrebuiltPostDepsMutator).Parallel()
- })
ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(cc.LibraryFactory))
ctx.RegisterModuleType("cc_library_shared", android.ModuleFactoryAdaptor(cc.LibrarySharedFactory))
ctx.RegisterModuleType("cc_library_headers", android.ModuleFactoryAdaptor(cc.LibraryHeaderFactory))
+ ctx.RegisterModuleType("cc_prebuilt_library_shared", android.ModuleFactoryAdaptor(cc.PrebuiltSharedLibraryFactory))
+ ctx.RegisterModuleType("cc_prebuilt_library_static", android.ModuleFactoryAdaptor(cc.PrebuiltStaticLibraryFactory))
ctx.RegisterModuleType("cc_binary", android.ModuleFactoryAdaptor(cc.BinaryFactory))
ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(cc.ObjectFactory))
ctx.RegisterModuleType("cc_test", android.ModuleFactoryAdaptor(cc.TestFactory))
ctx.RegisterModuleType("llndk_library", android.ModuleFactoryAdaptor(cc.LlndkLibraryFactory))
+ ctx.RegisterModuleType("vndk_prebuilt_shared", android.ModuleFactoryAdaptor(cc.VndkPrebuiltSharedFactory))
ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(cc.ToolchainLibraryFactory))
ctx.RegisterModuleType("prebuilt_etc", android.ModuleFactoryAdaptor(android.PrebuiltEtcFactory))
ctx.RegisterModuleType("sh_binary", android.ModuleFactoryAdaptor(android.ShBinaryFactory))
@@ -103,7 +119,9 @@
ctx.RegisterModuleType("filegroup", android.ModuleFactoryAdaptor(android.FileGroupFactory))
ctx.RegisterModuleType("java_library", android.ModuleFactoryAdaptor(java.LibraryFactory))
ctx.RegisterModuleType("java_import", android.ModuleFactoryAdaptor(java.ImportFactory))
+ ctx.RegisterModuleType("android_app", android.ModuleFactoryAdaptor(java.AndroidAppFactory))
+ ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
ctx.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
ctx.BottomUp("prebuilts", android.PrebuiltMutator).Parallel()
})
@@ -114,6 +132,15 @@
ctx.BottomUp("test_per_src", cc.TestPerSrcMutator).Parallel()
ctx.BottomUp("version", cc.VersionMutator).Parallel()
ctx.BottomUp("begin", cc.BeginMutator).Parallel()
+ ctx.TopDown("apex_vndk_gather", apexVndkGatherMutator)
+ ctx.BottomUp("apex_vndk_add_deps", apexVndkAddDepsMutator)
+ })
+ ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.TopDown("apex_deps", apexDepsMutator)
+ ctx.BottomUp("apex", apexMutator)
+ ctx.BottomUp("apex_uses", apexUsesMutator)
+ ctx.TopDown("prebuilt_select", android.PrebuiltSelectModuleMutator).Parallel()
+ ctx.BottomUp("prebuilt_postdeps", android.PrebuiltPostDepsMutator).Parallel()
})
ctx.Register()
@@ -131,6 +158,7 @@
src: "",
vendor_available: true,
recovery_available: true,
+ native_bridge_supported: true,
}
toolchain_library {
@@ -145,6 +173,7 @@
src: "",
vendor_available: true,
recovery_available: true,
+ native_bridge_supported: true,
}
toolchain_library {
@@ -152,6 +181,7 @@
src: "",
vendor_available: true,
recovery_available: true,
+ native_bridge_supported: true,
}
toolchain_library {
@@ -159,6 +189,23 @@
src: "",
vendor_available: true,
recovery_available: true,
+ native_bridge_supported: true,
+ }
+
+ toolchain_library {
+ name: "libclang_rt.builtins-x86_64-android",
+ src: "",
+ vendor_available: true,
+ recovery_available: true,
+ native_bridge_supported: true,
+ }
+
+ toolchain_library {
+ name: "libclang_rt.builtins-i686-android",
+ src: "",
+ vendor_available: true,
+ recovery_available: true,
+ native_bridge_supported: true,
}
cc_object {
@@ -166,6 +213,7 @@
stl: "none",
vendor_available: true,
recovery_available: true,
+ native_bridge_supported: true,
}
cc_object {
@@ -173,6 +221,7 @@
stl: "none",
vendor_available: true,
recovery_available: true,
+ native_bridge_supported: true,
}
cc_object {
@@ -188,20 +237,23 @@
llndk_library {
name: "libc",
symbol_file: "",
+ native_bridge_supported: true,
}
llndk_library {
name: "libm",
symbol_file: "",
+ native_bridge_supported: true,
}
llndk_library {
name: "libdl",
symbol_file: "",
+ native_bridge_supported: true,
}
`
- ctx.MockFileSystem(map[string][]byte{
+ fs := map[string][]byte{
"Android.bp": []byte(bp),
"build/make/target/product/security": nil,
"apex_manifest.json": nil,
@@ -210,32 +262,40 @@
"system/sepolicy/apex/myapex_keytest-file_contexts": nil,
"system/sepolicy/apex/otherapex-file_contexts": nil,
"system/sepolicy/apex/commonapex-file_contexts": nil,
- "mylib.cpp": nil,
- "mylib_common.cpp": nil,
- "mytest.cpp": nil,
- "mytest1.cpp": nil,
- "mytest2.cpp": nil,
- "mytest3.cpp": nil,
- "myprebuilt": nil,
- "my_include": nil,
- "foo/bar/MyClass.java": nil,
- "prebuilt.jar": nil,
- "vendor/foo/devkeys/test.x509.pem": nil,
- "vendor/foo/devkeys/test.pk8": nil,
- "testkey.x509.pem": nil,
- "testkey.pk8": nil,
- "testkey.override.x509.pem": nil,
- "testkey.override.pk8": nil,
- "vendor/foo/devkeys/testkey.avbpubkey": nil,
- "vendor/foo/devkeys/testkey.pem": nil,
- "NOTICE": nil,
- "custom_notice": nil,
- "testkey2.avbpubkey": nil,
- "testkey2.pem": nil,
- "myapex-arm64.apex": nil,
- "myapex-arm.apex": nil,
- "frameworks/base/api/current.txt": nil,
- })
+ "mylib.cpp": nil,
+ "mylib_common.cpp": nil,
+ "mytest.cpp": nil,
+ "mytest1.cpp": nil,
+ "mytest2.cpp": nil,
+ "mytest3.cpp": nil,
+ "myprebuilt": nil,
+ "my_include": nil,
+ "foo/bar/MyClass.java": nil,
+ "prebuilt.jar": nil,
+ "vendor/foo/devkeys/test.x509.pem": nil,
+ "vendor/foo/devkeys/test.pk8": nil,
+ "testkey.x509.pem": nil,
+ "testkey.pk8": nil,
+ "testkey.override.x509.pem": nil,
+ "testkey.override.pk8": nil,
+ "vendor/foo/devkeys/testkey.avbpubkey": nil,
+ "vendor/foo/devkeys/testkey.pem": nil,
+ "NOTICE": nil,
+ "custom_notice": nil,
+ "testkey2.avbpubkey": nil,
+ "testkey2.pem": nil,
+ "myapex-arm64.apex": nil,
+ "myapex-arm.apex": nil,
+ "frameworks/base/api/current.txt": nil,
+ "build/make/core/proguard.flags": nil,
+ "build/make/core/proguard_basic_keeps.flags": nil,
+ }
+
+ for _, handler := range handlers {
+ handler(fs, config)
+ }
+
+ ctx.MockFileSystem(fs)
return ctx, config
}
@@ -708,9 +768,9 @@
// Ensure that runtime_libs dep in included
ensureContains(t, copyCmds, "image.apex/lib64/libbar.so")
- injectRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("injectApexDependency")
- ensureListEmpty(t, names(injectRule.Args["provideNativeLibs"]))
- ensureListContains(t, names(injectRule.Args["requireNativeLibs"]), "libfoo.so")
+ apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexManifestRule")
+ ensureListEmpty(t, names(apexManifestRule.Args["provideNativeLibs"]))
+ ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libfoo.so")
}
@@ -758,11 +818,11 @@
// Ensure that LLNDK dep is not included
ensureNotContains(t, copyCmds, "image.apex/lib64/libbar.so")
- injectRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("injectApexDependency")
- ensureListEmpty(t, names(injectRule.Args["provideNativeLibs"]))
+ apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexManifestRule")
+ ensureListEmpty(t, names(apexManifestRule.Args["provideNativeLibs"]))
// Ensure that LLNDK dep is required
- ensureListContains(t, names(injectRule.Args["requireNativeLibs"]), "libbar.so")
+ ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libbar.so")
}
@@ -989,8 +1049,8 @@
inputsString := strings.Join(inputsList, " ")
// ensure that the apex includes vendor variants of the direct and indirect deps
- ensureContains(t, inputsString, "android_arm64_armv8-a_vendor_shared_myapex/mylib.so")
- ensureContains(t, inputsString, "android_arm64_armv8-a_vendor_shared_myapex/mylib2.so")
+ ensureContains(t, inputsString, "android_arm64_armv8-a_vendor.VER_shared_myapex/mylib.so")
+ ensureContains(t, inputsString, "android_arm64_armv8-a_vendor.VER_shared_myapex/mylib2.so")
// ensure that the apex does not include core variants
ensureNotContains(t, inputsString, "android_arm64_armv8-a_core_shared_myapex/mylib.so")
@@ -1207,6 +1267,284 @@
ensureContains(t, cFlags, "-Imy_include")
}
+func TestVndkApexCurrent(t *testing.T) {
+ ctx, _ := testApex(t, `
+ apex_vndk {
+ name: "myapex",
+ key: "myapex.key",
+ file_contexts: "myapex",
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "libvndk",
+ srcs: ["mylib.cpp"],
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ system_shared_libs: [],
+ stl: "none",
+ }
+
+ cc_library {
+ name: "libvndksp",
+ srcs: ["mylib.cpp"],
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ support_system_process: true,
+ },
+ system_shared_libs: [],
+ stl: "none",
+ }
+ `)
+
+ apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
+ copyCmds := apexRule.Args["copy_commands"]
+ ensureContains(t, copyCmds, "image.apex/lib/libvndk.so")
+ ensureContains(t, copyCmds, "image.apex/lib/libvndksp.so")
+ ensureContains(t, copyCmds, "image.apex/lib64/libvndk.so")
+ ensureContains(t, copyCmds, "image.apex/lib64/libvndksp.so")
+}
+
+func TestVndkApexWithPrebuilt(t *testing.T) {
+ ctx, _ := testApex(t, `
+ apex_vndk {
+ name: "myapex",
+ key: "myapex.key",
+ file_contexts: "myapex",
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_prebuilt_library_shared {
+ name: "libvndkshared",
+ srcs: ["libvndkshared.so"],
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ system_shared_libs: [],
+ stl: "none",
+ }
+ `, withFiles(map[string][]byte{
+ "libvndkshared.so": nil,
+ }))
+
+ apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
+ copyCmds := apexRule.Args["copy_commands"]
+ ensureContains(t, copyCmds, "image.apex/lib/libvndkshared.so")
+}
+
+func TestVndkApexVersion(t *testing.T) {
+ ctx, _ := testApex(t, `
+ apex_vndk {
+ name: "myapex_v27",
+ key: "myapex.key",
+ file_contexts: "myapex",
+ vndk_version: "27",
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "libvndk",
+ srcs: ["mylib.cpp"],
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ system_shared_libs: [],
+ stl: "none",
+ }
+
+ vndk_prebuilt_shared {
+ name: "libvndk27",
+ version: "27",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ target_arch: "arm64",
+ srcs: ["libvndk27.so"],
+ }
+ `, withFiles(map[string][]byte{
+ "libvndk27.so": nil,
+ }))
+
+ apexRule := ctx.ModuleForTests("myapex_v27", "android_common_myapex_v27").Rule("apexRule")
+ copyCmds := apexRule.Args["copy_commands"]
+ ensureContains(t, copyCmds, "image.apex/lib/libvndk27.so")
+ ensureContains(t, copyCmds, "image.apex/lib64/libvndk27.so")
+ ensureNotContains(t, copyCmds, "image.apex/lib/libvndk.so")
+}
+
+func TestVndkApexErrorWithDuplicateVersion(t *testing.T) {
+ testApexError(t, `module "myapex_v27.*" .*: vndk_version: 27 is already defined in "myapex_v27.*"`, `
+ apex_vndk {
+ name: "myapex_v27",
+ key: "myapex.key",
+ file_contexts: "myapex",
+ vndk_version: "27",
+ }
+ apex_vndk {
+ name: "myapex_v27_other",
+ key: "myapex.key",
+ file_contexts: "myapex",
+ vndk_version: "27",
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "libvndk",
+ srcs: ["mylib.cpp"],
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ system_shared_libs: [],
+ stl: "none",
+ }
+
+ vndk_prebuilt_shared {
+ name: "libvndk",
+ version: "27",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ srcs: ["libvndk.so"],
+ }
+ `, withFiles(map[string][]byte{
+ "libvndk.so": nil,
+ }))
+}
+
+func TestVndkApexNameRule(t *testing.T) {
+ ctx, _ := testApex(t, `
+ apex_vndk {
+ name: "myapex",
+ key: "myapex.key",
+ file_contexts: "myapex",
+ }
+ apex_vndk {
+ name: "myapex_v28",
+ key: "myapex.key",
+ file_contexts: "myapex",
+ vndk_version: "28",
+ }
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }`)
+
+ assertApexName := func(expected, moduleName string) {
+ bundle := ctx.ModuleForTests(moduleName, "android_common_"+moduleName).Module().(*apexBundle)
+ actual := proptools.String(bundle.properties.Apex_name)
+ if !reflect.DeepEqual(actual, expected) {
+ t.Errorf("Got '%v', expected '%v'", actual, expected)
+ }
+ }
+
+ assertApexName("com.android.vndk.vVER", "myapex")
+ assertApexName("com.android.vndk.v28", "myapex_v28")
+}
+
+func TestVndkApexSkipsNativeBridgeSupportedModules(t *testing.T) {
+ ctx, _ := testApex(t, `
+ apex_vndk {
+ name: "myapex",
+ key: "myapex.key",
+ file_contexts: "myapex",
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "libvndk",
+ srcs: ["mylib.cpp"],
+ vendor_available: true,
+ native_bridge_supported: true,
+ host_supported: true,
+ vndk: {
+ enabled: true,
+ },
+ system_shared_libs: [],
+ stl: "none",
+ }
+ `, withTargets(map[android.OsType][]android.Target{
+ android.Android: []android.Target{
+ {Os: android.Android, Arch: android.Arch{ArchType: android.Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}}, NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""},
+ {Os: android.Android, Arch: android.Arch{ArchType: android.Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}}, NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""},
+ {Os: android.Android, Arch: android.Arch{ArchType: android.X86_64, ArchVariant: "silvermont", Abi: []string{"arm64-v8a"}}, NativeBridge: android.NativeBridgeEnabled, NativeBridgeHostArchName: "arm64", NativeBridgeRelativePath: "x86_64"},
+ {Os: android.Android, Arch: android.Arch{ArchType: android.X86, ArchVariant: "silvermont", Abi: []string{"armeabi-v7a"}}, NativeBridge: android.NativeBridgeEnabled, NativeBridgeHostArchName: "arm", NativeBridgeRelativePath: "x86"},
+ },
+ }))
+
+ apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
+ copyCmds := apexRule.Args["copy_commands"]
+ ensureContains(t, copyCmds, "image.apex/lib/libvndk.so")
+ ensureContains(t, copyCmds, "image.apex/lib64/libvndk.so")
+
+ // apex
+ ensureNotContains(t, copyCmds, "image.apex/lib/x86/libvndk.so")
+ ensureNotContains(t, copyCmds, "image.apex/lib64/x86_64/libvndk.so")
+}
+
+func TestVndkApexDoesntSupportNativeBridgeSupported(t *testing.T) {
+ testApexError(t, `module "myapex" .*: native_bridge_supported: .* doesn't support native bridge binary`, `
+ apex_vndk {
+ name: "myapex",
+ key: "myapex.key",
+ file_contexts: "myapex",
+ native_bridge_supported: true,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "libvndk",
+ srcs: ["mylib.cpp"],
+ vendor_available: true,
+ native_bridge_supported: true,
+ host_supported: true,
+ vndk: {
+ enabled: true,
+ },
+ system_shared_libs: [],
+ stl: "none",
+ }
+ `)
+}
+
func TestDependenciesInApexManifest(t *testing.T) {
ctx, _ := testApex(t, `
apex {
@@ -1273,34 +1611,56 @@
}
`)
- var injectRule android.TestingBuildParams
+ var apexManifestRule android.TestingBuildParams
var provideNativeLibs, requireNativeLibs []string
- injectRule = ctx.ModuleForTests("myapex_nodep", "android_common_myapex_nodep").Rule("injectApexDependency")
- provideNativeLibs = names(injectRule.Args["provideNativeLibs"])
- requireNativeLibs = names(injectRule.Args["requireNativeLibs"])
+ apexManifestRule = ctx.ModuleForTests("myapex_nodep", "android_common_myapex_nodep").Rule("apexManifestRule")
+ provideNativeLibs = names(apexManifestRule.Args["provideNativeLibs"])
+ requireNativeLibs = names(apexManifestRule.Args["requireNativeLibs"])
ensureListEmpty(t, provideNativeLibs)
ensureListEmpty(t, requireNativeLibs)
- injectRule = ctx.ModuleForTests("myapex_dep", "android_common_myapex_dep").Rule("injectApexDependency")
- provideNativeLibs = names(injectRule.Args["provideNativeLibs"])
- requireNativeLibs = names(injectRule.Args["requireNativeLibs"])
+ apexManifestRule = ctx.ModuleForTests("myapex_dep", "android_common_myapex_dep").Rule("apexManifestRule")
+ provideNativeLibs = names(apexManifestRule.Args["provideNativeLibs"])
+ requireNativeLibs = names(apexManifestRule.Args["requireNativeLibs"])
ensureListEmpty(t, provideNativeLibs)
ensureListContains(t, requireNativeLibs, "libfoo.so")
- injectRule = ctx.ModuleForTests("myapex_provider", "android_common_myapex_provider").Rule("injectApexDependency")
- provideNativeLibs = names(injectRule.Args["provideNativeLibs"])
- requireNativeLibs = names(injectRule.Args["requireNativeLibs"])
+ apexManifestRule = ctx.ModuleForTests("myapex_provider", "android_common_myapex_provider").Rule("apexManifestRule")
+ provideNativeLibs = names(apexManifestRule.Args["provideNativeLibs"])
+ requireNativeLibs = names(apexManifestRule.Args["requireNativeLibs"])
ensureListContains(t, provideNativeLibs, "libfoo.so")
ensureListEmpty(t, requireNativeLibs)
- injectRule = ctx.ModuleForTests("myapex_selfcontained", "android_common_myapex_selfcontained").Rule("injectApexDependency")
- provideNativeLibs = names(injectRule.Args["provideNativeLibs"])
- requireNativeLibs = names(injectRule.Args["requireNativeLibs"])
+ apexManifestRule = ctx.ModuleForTests("myapex_selfcontained", "android_common_myapex_selfcontained").Rule("apexManifestRule")
+ provideNativeLibs = names(apexManifestRule.Args["provideNativeLibs"])
+ requireNativeLibs = names(apexManifestRule.Args["requireNativeLibs"])
ensureListContains(t, provideNativeLibs, "libfoo.so")
ensureListEmpty(t, requireNativeLibs)
}
+func TestApexName(t *testing.T) {
+ ctx, _ := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ apex_name: "com.android.myapex",
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+ `)
+
+ module := ctx.ModuleForTests("myapex", "android_common_myapex")
+ apexManifestRule := module.Rule("apexManifestRule")
+ ensureContains(t, apexManifestRule.Args["opt"], "-v name com.android.myapex")
+ apexRule := module.Rule("apexRule")
+ ensureContains(t, apexRule.Args["opt_flags"], "--do_not_check_keyname")
+}
+
func TestNonTestApex(t *testing.T) {
ctx, _ := testApex(t, `
apex {
@@ -1533,8 +1893,8 @@
`)
apex := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle)
- expected := "target/product/test_device/product/apex"
- actual := apex.installDir.RelPathString()
+ expected := buildDir + "/target/product/test_device/product/apex"
+ actual := apex.installDir.String()
if actual != expected {
t.Errorf("wrong install path. expected %q. actual %q", expected, actual)
}
@@ -1820,12 +2180,12 @@
`)
}
-func TestApexUsesFailsIfUseNoApex(t *testing.T) {
- testApexError(t, `tries to include no_apex module mylib2`, `
+func TestErrorsIfDepsAreNotEnabled(t *testing.T) {
+ testApexError(t, `module "myapex" .* depends on disabled module "libfoo"`, `
apex {
- name: "commonapex",
+ name: "myapex",
key: "myapex.key",
- native_shared_libs: ["mylib"],
+ native_shared_libs: ["libfoo"],
}
apex_key {
@@ -1835,27 +2195,17 @@
}
cc_library {
- name: "mylib",
- srcs: ["mylib.cpp"],
- shared_libs: ["mylib2"],
- system_shared_libs: [],
+ name: "libfoo",
stl: "none",
- }
-
- cc_library {
- name: "mylib2",
- srcs: ["mylib.cpp"],
system_shared_libs: [],
- stl: "none",
- no_apex: true,
+ enabled: false,
}
`)
-
- testApexError(t, `tries to include no_apex module mylib2`, `
+ testApexError(t, `module "myapex" .* depends on disabled module "myjar"`, `
apex {
- name: "commonapex",
+ name: "myapex",
key: "myapex.key",
- native_shared_libs: ["mylib"],
+ java_libs: ["myjar"],
}
apex_key {
@@ -1864,28 +2214,26 @@
private_key: "testkey.pem",
}
- cc_library {
- name: "mylib",
- srcs: ["mylib.cpp"],
- static_libs: ["mylib2"],
- system_shared_libs: [],
- stl: "none",
- }
-
- cc_library {
- name: "mylib2",
- srcs: ["mylib.cpp"],
- system_shared_libs: [],
- stl: "none",
- no_apex: true,
+ java_library {
+ name: "myjar",
+ srcs: ["foo/bar/MyClass.java"],
+ sdk_version: "none",
+ system_modules: "none",
+ compile_dex: true,
+ enabled: false,
}
`)
+}
+func TestApexWithApps(t *testing.T) {
ctx, _ := testApex(t, `
apex {
name: "myapex",
key: "myapex.key",
- native_shared_libs: ["mylib"],
+ apps: [
+ "AppFoo",
+ "AppFooPriv",
+ ],
}
apex_key {
@@ -1894,31 +2242,19 @@
private_key: "testkey.pem",
}
- cc_library {
- name: "mylib",
- srcs: ["mylib.cpp"],
- shared_libs: ["mylib2"],
- system_shared_libs: [],
- stl: "none",
+ android_app {
+ name: "AppFoo",
+ srcs: ["foo/bar/MyClass.java"],
+ sdk_version: "none",
+ system_modules: "none",
}
- cc_library {
- name: "mylib2",
- srcs: ["mylib.cpp"],
- shared_libs: ["mylib3"],
- system_shared_libs: [],
- stl: "none",
- stubs: {
- versions: ["1", "2", "3"],
- },
- }
-
- cc_library {
- name: "mylib3",
- srcs: ["mylib.cpp"],
- system_shared_libs: [],
- stl: "none",
- no_apex: true,
+ android_app {
+ name: "AppFooPriv",
+ srcs: ["foo/bar/MyClass.java"],
+ sdk_version: "none",
+ system_modules: "none",
+ privileged: true,
}
`)
@@ -1926,12 +2262,193 @@
apexRule := module.Rule("apexRule")
copyCmds := apexRule.Args["copy_commands"]
- ensureContains(t, copyCmds, "image.apex/lib64/mylib.so")
- ensureNotContains(t, copyCmds, "image.apex/lib64/mylib2.so")
- ensureNotContains(t, copyCmds, "image.apex/lib64/mylib3.so")
+ ensureContains(t, copyCmds, "image.apex/app/AppFoo/AppFoo.apk")
+ ensureContains(t, copyCmds, "image.apex/priv-app/AppFooPriv/AppFooPriv.apk")
}
+func TestApexAvailable(t *testing.T) {
+ // libfoo is not available to myapex, but only to otherapex
+ testApexError(t, "requires \"libfoo\" that is not available for the APEX", `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["libfoo"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ apex {
+ name: "otherapex",
+ key: "otherapex.key",
+ native_shared_libs: ["libfoo"],
+ }
+
+ apex_key {
+ name: "otherapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "libfoo",
+ stl: "none",
+ system_shared_libs: [],
+ apex_available: ["otherapex"],
+ }`)
+
+ // libbar is an indirect dep
+ testApexError(t, "requires \"libbar\" that is not available for the APEX", `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["libfoo"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ apex {
+ name: "otherapex",
+ key: "otherapex.key",
+ native_shared_libs: ["libfoo"],
+ }
+
+ apex_key {
+ name: "otherapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "libfoo",
+ stl: "none",
+ shared_libs: ["libbar"],
+ system_shared_libs: [],
+ apex_available: ["myapex", "otherapex"],
+ }
+
+ cc_library {
+ name: "libbar",
+ stl: "none",
+ system_shared_libs: [],
+ apex_available: ["otherapex"],
+ }`)
+
+ testApexError(t, "\"otherapex\" is not a valid module name", `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["libfoo"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "libfoo",
+ stl: "none",
+ system_shared_libs: [],
+ apex_available: ["otherapex"],
+ }`)
+
+ ctx, _ := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["libfoo", "libbar"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "libfoo",
+ stl: "none",
+ system_shared_libs: [],
+ apex_available: ["myapex"],
+ }
+
+ cc_library {
+ name: "libbar",
+ stl: "none",
+ system_shared_libs: [],
+ apex_available: ["//apex_available:anyapex"],
+ }`)
+
+ // check that libfoo and libbar are created only for myapex, but not for the platform
+ ensureListContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_core_shared_myapex")
+ ensureListNotContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_core_shared")
+ ensureListContains(t, ctx.ModuleVariantsForTests("libbar"), "android_arm64_armv8-a_core_shared_myapex")
+ ensureListNotContains(t, ctx.ModuleVariantsForTests("libbar"), "android_arm64_armv8-a_core_shared")
+
+ ctx, _ = testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "libfoo",
+ stl: "none",
+ system_shared_libs: [],
+ apex_available: ["//apex_available:platform"],
+ }`)
+
+ // check that libfoo is created only for the platform
+ ensureListNotContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_core_shared_myapex")
+ ensureListContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_core_shared")
+
+ ctx, _ = testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["libfoo"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "libfoo",
+ stl: "none",
+ system_shared_libs: [],
+ apex_available: ["myapex"],
+ static: {
+ apex_available: ["//apex_available:platform"],
+ },
+ }`)
+
+ // shared variant of libfoo is only available to myapex
+ ensureListContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_core_shared_myapex")
+ ensureListNotContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_core_shared")
+ // but the static variant is available to both myapex and the platform
+ ensureListContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_core_static_myapex")
+ ensureListContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_core_static")
+}
+
func TestMain(m *testing.M) {
run := func() int {
setUp()
diff --git a/apex/key.go b/apex/key.go
index 08cd45e..ffde315 100644
--- a/apex/key.go
+++ b/apex/key.go
@@ -27,7 +27,7 @@
var String = proptools.String
func init() {
- android.RegisterModuleType("apex_key", apexKeyFactory)
+ android.RegisterModuleType("apex_key", ApexKeyFactory)
android.RegisterSingletonType("apex_keys_text", apexKeysTextFactory)
}
@@ -53,7 +53,7 @@
Installable *bool
}
-func apexKeyFactory() android.Module {
+func ApexKeyFactory() android.Module {
module := &apexKey{}
module.AddProperties(&module.properties)
android.InitAndroidArchModule(module, android.HostAndDeviceDefault, android.MultilibCommon)
diff --git a/build_kzip.bash b/build_kzip.bash
index 5364e7f..1e0d48f 100755
--- a/build_kzip.bash
+++ b/build_kzip.bash
@@ -1,25 +1,27 @@
-# /bin/bash -uv
+#! /bin/bash -uv
#
# Build kzip files (source files for the indexing pipeline) for the given configuration,
# merge them and place the resulting all.kzip into $DIST_DIR.
# It is assumed that the current directory is the top of the source tree.
-# The following enviromnet variables affect the result:
-# TARGET_PRODUCT target device name, e.g., `aosp_blueline`
-# TARGET_BUILD_VARIANT variant, e.g., `userdebug`
-# OUT_DIR where the build is happening (./out if not specified)
+# The following environment variables affect the result:
+# BUILD_NUMBER build number, used to generate unique ID (will use UUID if not set)
# DIST_DIR where the resulting all.kzip will be placed
-# XREF_CORPUS source code repository URI, e.g.,
-# `android.googlesource.com/platform/superproject`
+# OUT_DIR output directory (out if not specified})
+# TARGET_BUILD_VARIANT variant, e.g., `userdebug`
+# TARGET_PRODUCT target device name, e.g., 'aosp_blueline'
+# XREF_CORPUS source code repository URI, e.g., 'android.googlesource.com/platform/superproject'
-# The extraction might fail for some source files, so run with -k
+: ${BUILD_NUMBER:=$(uuidgen)}
+
+# The extraction might fail for some source files, so run with -k and then check that
+# sufficiently many files were generated.
build/soong/soong_ui.bash --build-mode --all-modules --dir=$PWD -k merge_zips xref_cxx xref_java
-
-# We build with -k, so check that we have generated at least 100K files
-# (the actual number is 180K+)
-declare -r kzip_count=$(find $OUT_DIR -name '*.kzip' | wc -l)
+declare -r out="${OUT_DIR:-out}"
+declare -r kzip_count=$(find "$out" -name '*.kzip' | wc -l)
(($kzip_count>100000)) || { printf "Too few kzip files were generated: %d\n" $kzip_count; exit 1; }
# Pack
# TODO(asmundak): this should be done by soong.
-declare -r allkzip=all.kzip
-"${OUT_DIR:-out}/soong/host/linux-x86/bin/merge_zips" "$DIST_DIR/$allkzip" @<(find $OUT_DIR -name '*.kzip')
+declare -r allkzip="$BUILD_NUMBER.kzip"
+"$out/soong/host/linux-x86/bin/merge_zips" "$DIST_DIR/$allkzip" @<(find "$out" -name '*.kzip')
+
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 272d3d4..9a98b0e 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -37,6 +37,7 @@
Os() android.OsType
Host() bool
useVndk() bool
+ vndkVersion() string
static() bool
inRecovery() bool
}
@@ -68,7 +69,7 @@
OutputFile: c.outputFile,
// TODO(jiyong): add the APEXes providing shared libs to the required modules
// Currently, adding c.Properties.ApexesProvidingSharedLibs is causing multiple
- // runtime APEXes (com.android.runtime.debug|release) to be installed. And this
+ // ART APEXes (com.android.art.debug|release) to be installed. And this
// is breaking some older devices (like marlin) where system.img is small.
Required: c.Properties.AndroidMkRuntimeLibs,
Include: "$(BUILD_SYSTEM)/soong_cc_prebuilt.mk",
@@ -109,17 +110,7 @@
}
c.subAndroidMk(&ret, c.installer)
- if c.Target().NativeBridge == android.NativeBridgeEnabled {
- ret.SubName += nativeBridgeSuffix
- }
-
- if c.useVndk() && c.hasVendorVariant() {
- // .vendor suffix is added only when we will have two variants: core and vendor.
- // The suffix is not added for vendor-only module.
- ret.SubName += vendorSuffix
- } else if c.inRecovery() && !c.onlyInRecovery() {
- ret.SubName += recoverySuffix
- }
+ ret.SubName += c.Properties.SubName
return ret
}
@@ -207,7 +198,7 @@
library.androidMkWriteExportedFlags(w)
library.androidMkWriteAdditionalDependenciesForSourceAbiDiff(w)
- _, _, ext := splitFileExt(outputFile.Base())
+ _, _, ext := android.SplitFileExt(outputFile.Base())
fmt.Fprintln(w, "LOCAL_BUILT_MODULE_STEM := $(LOCAL_MODULE)"+ext)
@@ -312,6 +303,31 @@
androidMkWriteTestData(test.data, ctx, ret)
}
+func (fuzz *fuzzBinary) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+ ctx.subAndroidMk(ret, fuzz.binaryDecorator)
+
+ var fuzzFiles []string
+ for _, d := range fuzz.corpus {
+ fuzzFiles = append(fuzzFiles,
+ filepath.Dir(fuzz.corpusIntermediateDir.String())+":corpus/"+d.Base())
+ }
+
+ if fuzz.dictionary != nil {
+ fuzzFiles = append(fuzzFiles,
+ filepath.Dir(fuzz.dictionary.String())+":"+fuzz.dictionary.Base())
+ }
+
+ if len(fuzzFiles) > 0 {
+ ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
+ fmt.Fprintln(w, "LOCAL_TEST_DATA := "+strings.Join(fuzzFiles, " "))
+ })
+ }
+
+ ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
+ fmt.Fprintln(w, "LOCAL_IS_FUZZ_TARGET := true")
+ })
+}
+
func (test *testLibrary) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
ctx.subAndroidMk(ret, test.libraryDecorator)
}
@@ -319,7 +335,7 @@
func (library *toolchainLibraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
ret.Class = "STATIC_LIBRARIES"
ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
- _, suffix, _ := splitFileExt(outputFile.Base())
+ _, suffix, _ := android.SplitFileExt(outputFile.Base())
fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+suffix)
})
}
@@ -332,11 +348,10 @@
}
ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
- path := installer.path.RelPathString()
- dir, file := filepath.Split(path)
- stem, suffix, _ := splitFileExt(file)
+ path, file := filepath.Split(installer.path.ToMakePath().String())
+ stem, suffix, _ := android.SplitFileExt(file)
fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+suffix)
- fmt.Fprintln(w, "LOCAL_MODULE_PATH := $(OUT_DIR)/"+filepath.Clean(dir))
+ fmt.Fprintln(w, "LOCAL_MODULE_PATH := "+path)
fmt.Fprintln(w, "LOCAL_MODULE_STEM := "+stem)
})
}
@@ -347,7 +362,7 @@
ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
path, file := filepath.Split(c.installPath.String())
- stem, suffix, _ := splitFileExt(file)
+ stem, suffix, _ := android.SplitFileExt(file)
fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+suffix)
fmt.Fprintln(w, "LOCAL_MODULE_PATH := "+path)
fmt.Fprintln(w, "LOCAL_MODULE_STEM := "+stem)
@@ -357,11 +372,10 @@
func (c *llndkStubDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
ret.Class = "SHARED_LIBRARIES"
- ret.SubName = vendorSuffix
ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
c.libraryDecorator.androidMkWriteExportedFlags(w)
- _, _, ext := splitFileExt(outputFile.Base())
+ _, _, ext := android.SplitFileExt(outputFile.Base())
fmt.Fprintln(w, "LOCAL_BUILT_MODULE_STEM := $(LOCAL_MODULE)"+ext)
fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
@@ -378,12 +392,11 @@
ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
c.libraryDecorator.androidMkWriteExportedFlags(w)
- path := c.path.RelPathString()
- dir, file := filepath.Split(path)
- stem, suffix, ext := splitFileExt(file)
+ path, file := filepath.Split(c.path.ToMakePath().String())
+ stem, suffix, ext := android.SplitFileExt(file)
fmt.Fprintln(w, "LOCAL_BUILT_MODULE_STEM := $(LOCAL_MODULE)"+ext)
fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+suffix)
- fmt.Fprintln(w, "LOCAL_MODULE_PATH := $(OUT_DIR)/"+filepath.Clean(dir))
+ fmt.Fprintln(w, "LOCAL_MODULE_PATH := "+path)
fmt.Fprintln(w, "LOCAL_MODULE_STEM := "+stem)
})
}
@@ -398,7 +411,7 @@
ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
c.libraryDecorator.androidMkWriteExportedFlags(w)
- _, _, ext := splitFileExt(outputFile.Base())
+ _, _, ext := android.SplitFileExt(outputFile.Base())
fmt.Fprintln(w, "LOCAL_BUILT_MODULE_STEM := $(LOCAL_MODULE)"+ext)
fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
diff --git a/cc/binary.go b/cc/binary.go
index fd00060..9f18d6c 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -50,6 +50,9 @@
// binaries would be installed by default (in PRODUCT_PACKAGES) the other binary will be removed
// from PRODUCT_PACKAGES.
Overrides []string
+
+ // Inject boringssl hash into the shared library. This is only intended for use by external/boringssl.
+ Inject_bssl_hash *bool `android:"arch_variant"`
}
func init() {
@@ -342,6 +345,8 @@
flagsToBuilderFlags(flags), afterPrefixSymbols)
}
+ outputFile = maybeInjectBoringSSLHash(ctx, outputFile, binary.Properties.Inject_bssl_hash, fileName)
+
if Bool(binary.baseLinker.Properties.Use_version_lib) {
if ctx.Host() {
versionedOutputFile := outputFile
@@ -448,8 +453,8 @@
// Bionic binaries (e.g. linker) is installed to the bootstrap subdirectory.
// The original path becomes a symlink to the corresponding file in the
// runtime APEX.
- translatedArch := ctx.Target().NativeBridge == android.NativeBridgeEnabled || !ctx.Arch().Native
- if installToBootstrap(ctx.baseModuleName(), ctx.Config()) && !translatedArch && ctx.apexName() == "" && !ctx.inRecovery() {
+ translatedArch := ctx.Target().NativeBridge == android.NativeBridgeEnabled
+ if InstallToBootstrap(ctx.baseModuleName(), ctx.Config()) && !translatedArch && ctx.apexName() == "" && !ctx.inRecovery() {
if ctx.Device() && isBionic(ctx.baseModuleName()) {
binary.installSymlinkToRuntimeApex(ctx, file)
}
diff --git a/cc/builder.go b/cc/builder.go
index 00dc742..0760dd4 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -195,7 +195,7 @@
_ = pctx.SourcePathVariable("sAbiDiffer", "prebuilts/clang-tools/${config.HostPrebuiltTag}/bin/header-abi-diff")
- sAbiDiff = pctx.AndroidRuleFunc("sAbiDiff",
+ sAbiDiff = pctx.RuleFunc("sAbiDiff",
func(ctx android.PackageRuleContext) blueprint.RuleParams {
// TODO(b/78139997): Add -check-all-apis back
commandStr := "($sAbiDiffer ${allowFlags} -lib ${libName} -arch ${arch} -o ${out} -new ${in} -old ${referenceDump})"
@@ -224,12 +224,13 @@
_ = pctx.SourcePathVariable("cxxExtractor",
"prebuilts/clang-tools/${config.HostPrebuiltTag}/bin/cxx_extractor")
+ _ = pctx.SourcePathVariable("kytheVnames", "build/soong/vnames.json")
_ = pctx.VariableFunc("kytheCorpus",
func(ctx android.PackageVarContext) string { return ctx.Config().XrefCorpusName() })
kytheExtract = pctx.StaticRule("kythe",
blueprint.RuleParams{
- Command: "rm -f $out && KYTHE_CORPUS=${kytheCorpus} KYTHE_OUTPUT_FILE=$out $cxxExtractor $cFlags $in ",
- CommandDeps: []string{"$cxxExtractor"},
+ Command: "rm -f $out && KYTHE_CORPUS=${kytheCorpus} KYTHE_OUTPUT_FILE=$out KYTHE_VNAMES=$kytheVnames $cxxExtractor $cFlags $in ",
+ CommandDeps: []string{"$cxxExtractor", "$kytheVnames"},
},
"cFlags")
)
@@ -271,6 +272,8 @@
sAbiDump bool
emitXrefs bool
+ assemblerWithCpp bool
+
systemIncludeFlags string
groupStaticLibs bool
@@ -428,7 +431,9 @@
switch srcFile.Ext() {
case ".s":
- rule = ccNoDeps
+ if !flags.assemblerWithCpp {
+ rule = ccNoDeps
+ }
fallthrough
case ".S":
ccCmd = "clang"
@@ -547,7 +552,7 @@
flags builderFlags, outputFile android.ModuleOutPath, deps android.Paths) {
arCmd := "${config.ClangBin}/llvm-ar"
- arFlags := "crsD"
+ arFlags := "crsPD"
if !ctx.Darwin() {
arFlags += " -format=gnu"
}
@@ -760,7 +765,7 @@
// Generate a rule for compiling multiple .o files to a .o using ld partial linking
func TransformObjsToObj(ctx android.ModuleContext, objFiles android.Paths,
- flags builderFlags, outputFile android.WritablePath) {
+ flags builderFlags, outputFile android.WritablePath, deps android.Paths) {
ldCmd := "${config.ClangBin}/clang++"
@@ -769,6 +774,7 @@
Description: "link " + outputFile.Base(),
Output: outputFile,
Inputs: objFiles,
+ Implicits: deps,
Args: map[string]string{
"ldCmd": ldCmd,
"ldFlags": flags.ldFlags,
diff --git a/cc/cc.go b/cc/cc.go
index 0245c6a..806a6ed 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -36,9 +36,9 @@
android.RegisterModuleType("cc_defaults", defaultsFactory)
android.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.BottomUp("vndk", VndkMutator).Parallel()
ctx.BottomUp("image", ImageMutator).Parallel()
ctx.BottomUp("link", LinkageMutator).Parallel()
- ctx.BottomUp("vndk", VndkMutator).Parallel()
ctx.BottomUp("ndk_api", ndkApiMutator).Parallel()
ctx.BottomUp("test_per_src", TestPerSrcMutator).Parallel()
ctx.BottomUp("version", VersionMutator).Parallel()
@@ -174,7 +174,8 @@
CFlagsDeps android.Paths // Files depended on by compiler flags
LdFlagsDeps android.Paths // Files depended on by linker flags
- GroupStaticLibs bool
+ AssemblerWithCpp bool
+ GroupStaticLibs bool
proto android.ProtoFlags
protoC bool // Whether to use C instead of C++
@@ -199,7 +200,8 @@
PreventInstall bool `blueprint:"mutated"`
ApexesProvidingSharedLibs []string `blueprint:"mutated"`
- UseVndk bool `blueprint:"mutated"`
+ VndkVersion string `blueprint:"mutated"`
+ SubName string `blueprint:"mutated"`
// *.logtags files, to combine together in order to generate the /system/etc/event-log-tags
// file
@@ -391,6 +393,22 @@
return ok && ccDepTag == testPerSrcDepTag
}
+func SharedDepTag() dependencyTag {
+ return sharedDepTag
+}
+
+func StaticDepTag() dependencyTag {
+ return staticDepTag
+}
+
+func CrtBeginDepTag() dependencyTag {
+ return crtBeginDepTag
+}
+
+func CrtEndDepTag() dependencyTag {
+ return crtEndDepTag
+}
+
// Module contains the properties and members used by all C/C++ module types, and implements
// the blueprint.Module interface. It delegates to compiler, linker, and installer interfaces
// to construct the output file. Behavior can be customized with a Customizer interface
@@ -398,6 +416,7 @@
android.ModuleBase
android.DefaultableModuleBase
android.ApexModuleBase
+ android.SdkBase
Properties BaseProperties
VendorProperties VendorProperties
@@ -469,6 +488,19 @@
return ""
}
+// IsVndkOnSystem returns true if a module is supposed to be a vndk library provided by system to vendor
+func (c *Module) IsVndkOnSystem() bool {
+ if linker, ok := c.linker.(libraryInterface); ok {
+ return linker.shared() && c.isVndk() && c.useVndk() && !c.isVndkExt()
+ }
+
+ return false
+}
+
+func (c *Module) VndkVersion() string {
+ return c.vndkVersion()
+}
+
func (c *Module) Init() android.Module {
c.AddProperties(&c.Properties, &c.VendorProperties)
if c.compiler != nil {
@@ -524,6 +556,7 @@
android.InitDefaultableModule(c)
android.InitApexModule(c)
+ android.InitSdkAwareModule(c)
return c
}
@@ -540,7 +573,7 @@
}
func (c *Module) useVndk() bool {
- return c.Properties.UseVndk
+ return c.Properties.VndkVersion != ""
}
func (c *Module) isCoverageVariant() bool {
@@ -574,10 +607,7 @@
}
func (c *Module) vndkVersion() string {
- if vndkdep := c.vndkdep; vndkdep != nil {
- return vndkdep.Properties.Vndk.Version
- }
- return ""
+ return c.Properties.VndkVersion
}
func (c *Module) isPgoCompile() bool {
@@ -657,6 +687,10 @@
}
func (c *Module) nativeCoverage() bool {
+ // Bug: http://b/137883967 - native-bridge modules do not currently work with coverage
+ if c.Target().NativeBridge == android.NativeBridgeEnabled {
+ return false
+ }
return c.linker != nil && c.linker.nativeCoverage()
}
@@ -668,7 +702,7 @@
return false
}
-func installToBootstrap(name string, config android.Config) bool {
+func InstallToBootstrap(name string, config android.Config) bool {
if name == "libclang_rt.hwasan-aarch64-android" {
return inList("hwaddress", config.SanitizeDevice())
}
@@ -983,6 +1017,31 @@
c.makeLinkType = c.getMakeLinkType(actx)
+ c.Properties.SubName = ""
+
+ if c.Target().NativeBridge == android.NativeBridgeEnabled {
+ c.Properties.SubName += nativeBridgeSuffix
+ }
+
+ if _, ok := c.linker.(*vndkPrebuiltLibraryDecorator); ok {
+ // .vendor suffix is added for backward compatibility with VNDK snapshot whose names with
+ // such suffixes are already hard-coded in prebuilts/vndk/.../Android.bp.
+ c.Properties.SubName += vendorSuffix
+ } else if _, ok := c.linker.(*llndkStubDecorator); ok || (c.useVndk() && c.hasVendorVariant()) {
+ // .vendor.{version} suffix is added only when we will have two variants: core and vendor.
+ // The suffix is not added for vendor-only module.
+ c.Properties.SubName += vendorSuffix
+ vendorVersion := actx.DeviceConfig().VndkVersion()
+ if vendorVersion == "current" {
+ vendorVersion = actx.DeviceConfig().PlatformVndkVersion()
+ }
+ if c.Properties.VndkVersion != vendorVersion {
+ c.Properties.SubName += "." + c.Properties.VndkVersion
+ }
+ } else if c.inRecovery() && !c.onlyInRecovery() {
+ c.Properties.SubName += recoverySuffix
+ }
+
ctx := &moduleContext{
ModuleContext: actx,
moduleContextImpl: moduleContextImpl{
@@ -1053,6 +1112,9 @@
if c.sabi != nil {
flags = c.sabi.flags(ctx, flags)
}
+
+ flags.AssemblerWithCpp = inList("-xassembler-with-cpp", flags.AsFlags)
+
// Optimization to reduce size of build.ninja
// Replace the long list of flags for each file with a module-local variable
ctx.Variable(pctx, "cflags", strings.Join(flags.CFlags, " "))
@@ -1327,10 +1389,9 @@
depTag = headerExportDepTag
}
if buildStubs {
- actx.AddFarVariationDependencies([]blueprint.Variation{
- {Mutator: "arch", Variation: ctx.Target().String()},
- {Mutator: "image", Variation: c.imageVariation()},
- }, depTag, lib)
+ actx.AddFarVariationDependencies(append(ctx.Target().Variations(),
+ blueprint.Variation{Mutator: "image", Variation: c.imageVariation()}),
+ depTag, lib)
} else {
actx.AddVariationDependencies(nil, depTag, lib)
}
@@ -1467,9 +1528,11 @@
if vndkdep := c.vndkdep; vndkdep != nil {
if vndkdep.isVndkExt() {
- baseModuleMode := vendorMode
+ var baseModuleMode string
if actx.DeviceConfig().VndkVersion() == "" {
baseModuleMode = coreMode
+ } else {
+ baseModuleMode = c.imageVariation()
}
actx.AddVariationDependencies([]blueprint.Variation{
{Mutator: "image", Variation: baseModuleMode},
@@ -1492,7 +1555,7 @@
// Host code is not restricted
return
}
- if from.Properties.UseVndk {
+ if from.useVndk() {
// Though vendor code is limited by the vendor mutator,
// each vendor-available module needs to check
// link-type for VNDK.
@@ -1870,7 +1933,11 @@
if ptr != nil {
if !linkFile.Valid() {
- ctx.ModuleErrorf("module %q missing output file", depName)
+ if !ctx.Config().AllowMissingDependencies() {
+ ctx.ModuleErrorf("module %q missing output file", depName)
+ } else {
+ ctx.AddMissingDependencies([]string{depName})
+ }
return
}
*ptr = append(*ptr, linkFile.Path())
@@ -1899,7 +1966,15 @@
} else if c.useVndk() && bothVendorAndCoreVariantsExist {
// The vendor module in Make will have been renamed to not conflict with the core
// module, so update the dependency name here accordingly.
- return libName + vendorSuffix
+ ret := libName + vendorSuffix
+ vendorVersion := ctx.DeviceConfig().VndkVersion()
+ if vendorVersion == "current" {
+ vendorVersion = ctx.DeviceConfig().PlatformVndkVersion()
+ }
+ if c.Properties.VndkVersion != vendorVersion {
+ ret += "." + c.Properties.VndkVersion
+ }
+ return ret
} else if (ctx.Platform() || ctx.ProductSpecific()) && isVendorPublicLib {
return libName + vendorPublicLibrarySuffix
} else if ccDep.inRecovery() && !ccDep.onlyInRecovery() {
@@ -2080,18 +2155,27 @@
return false
}
+func (c *Module) AvailableFor(what string) bool {
+ if linker, ok := c.linker.(interface {
+ availableFor(string) bool
+ }); ok {
+ return c.ApexModuleBase.AvailableFor(what) || linker.availableFor(what)
+ } else {
+ return c.ApexModuleBase.AvailableFor(what)
+ }
+}
+
func (c *Module) installable() bool {
return c.installer != nil && !c.Properties.PreventInstall && c.IsForPlatform() && c.outputFile.Valid()
}
func (c *Module) imageVariation() string {
- variation := "core"
if c.useVndk() {
- variation = "vendor"
+ return vendorMode + "." + c.Properties.VndkVersion
} else if c.inRecovery() {
- variation = "recovery"
+ return recoveryMode
}
- return variation
+ return coreMode
}
func (c *Module) IDEInfo(dpInfo *android.IdeInfo) {
@@ -2110,6 +2194,16 @@
}
}
+func (c *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
+ if depTag, ok := ctx.OtherModuleDependencyTag(dep).(dependencyTag); ok {
+ if cc, ok := dep.(*Module); ok && cc.IsStubs() && depTag.shared {
+ // dynamic dep to a stubs lib crosses APEX boundary
+ return false
+ }
+ }
+ return true
+}
+
//
// Defaults
//
@@ -2139,10 +2233,13 @@
&BaseLinkerProperties{},
&ObjectLinkerProperties{},
&LibraryProperties{},
+ &StaticProperties{},
+ &SharedProperties{},
&FlagExporterProperties{},
&BinaryLinkerProperties{},
&TestProperties{},
&TestBinaryProperties{},
+ &FuzzProperties{},
&StlProperties{},
&SanitizeProperties{},
&StripProperties{},
@@ -2168,7 +2265,7 @@
// SDK libraries. (which framework-private libraries can use)
coreMode = "core"
- // vendorMode is the variant used for /vendor code that compiles
+ // vendorMode is the variant prefix used for /vendor code that compiles
// against the VNDK.
vendorMode = "vendor"
@@ -2232,7 +2329,10 @@
variants = append(variants, coreMode)
}
if vendorVariantNeeded {
- variants = append(variants, vendorMode)
+ variants = append(variants, vendorMode+"."+mctx.DeviceConfig().PlatformVndkVersion())
+ if vndkVersion := mctx.DeviceConfig().VndkVersion(); vndkVersion != "current" {
+ variants = append(variants, vendorMode+"."+vndkVersion)
+ }
}
if recoveryVariantNeeded {
variants = append(variants, recoveryMode)
@@ -2304,32 +2404,51 @@
}
var coreVariantNeeded bool = false
- var vendorVariantNeeded bool = false
var recoveryVariantNeeded bool = false
+ var vendorVariants []string
+
+ platformVndkVersion := mctx.DeviceConfig().PlatformVndkVersion()
+ deviceVndkVersion := mctx.DeviceConfig().VndkVersion()
+ if deviceVndkVersion == "current" {
+ deviceVndkVersion = platformVndkVersion
+ }
+
if mctx.DeviceConfig().VndkVersion() == "" {
// If the device isn't compiling against the VNDK, we always
// use the core mode.
coreVariantNeeded = true
+ } else if m.Target().NativeBridge == android.NativeBridgeEnabled {
+ // Skip creating vendor variants for natvie bridge modules
+ coreVariantNeeded = true
} else if _, ok := m.linker.(*llndkStubDecorator); ok {
// LL-NDK stubs only exist in the vendor variant, since the
// real libraries will be used in the core variant.
- vendorVariantNeeded = true
+ vendorVariants = append(vendorVariants,
+ platformVndkVersion,
+ deviceVndkVersion,
+ )
} else if _, ok := m.linker.(*llndkHeadersDecorator); ok {
// ... and LL-NDK headers as well
- vendorVariantNeeded = true
- } else if _, ok := m.linker.(*vndkPrebuiltLibraryDecorator); ok {
+ vendorVariants = append(vendorVariants,
+ platformVndkVersion,
+ deviceVndkVersion,
+ )
+ } else if lib, ok := m.linker.(*vndkPrebuiltLibraryDecorator); ok {
// Make vendor variants only for the versions in BOARD_VNDK_VERSION and
// PRODUCT_EXTRA_VNDK_VERSIONS.
- vendorVariantNeeded = true
+ vendorVariants = append(vendorVariants, lib.version())
} else if m.hasVendorVariant() && !vendorSpecific {
// This will be available in both /system and /vendor
// or a /system directory that is available to vendor.
coreVariantNeeded = true
- vendorVariantNeeded = true
+ vendorVariants = append(vendorVariants, platformVndkVersion)
+ if m.isVndk() {
+ vendorVariants = append(vendorVariants, deviceVndkVersion)
+ }
} else if vendorSpecific && String(m.Properties.Sdk_version) == "" {
// This will be available in /vendor (or /odm) only
- vendorVariantNeeded = true
+ vendorVariants = append(vendorVariants, deviceVndkVersion)
} else {
// This is either in /system (or similar: /data), or is a
// modules built with the NDK. Modules built with the NDK
@@ -2358,17 +2477,17 @@
if coreVariantNeeded {
variants = append(variants, coreMode)
}
- if vendorVariantNeeded {
- variants = append(variants, vendorMode)
+ for _, variant := range android.FirstUniqueStrings(vendorVariants) {
+ variants = append(variants, vendorMode+"."+variant)
}
if recoveryVariantNeeded {
variants = append(variants, recoveryMode)
}
mod := mctx.CreateVariations(variants...)
for i, v := range variants {
- if v == vendorMode {
+ if strings.HasPrefix(v, vendorMode+".") {
m := mod[i].(*Module)
- m.Properties.UseVndk = true
+ m.Properties.VndkVersion = strings.TrimPrefix(v, vendorMode+".")
squashVendorSrcs(m)
} else if v == recoveryMode {
m := mod[i].(*Module)
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 52234a8..689aacd 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -15,8 +15,6 @@
package cc
import (
- "android/soong/android"
-
"fmt"
"io/ioutil"
"os"
@@ -25,6 +23,8 @@
"sort"
"strings"
"testing"
+
+ "android/soong/android"
)
var buildDir string
@@ -53,6 +53,7 @@
}
func testCcWithConfig(t *testing.T, bp string, config android.Config) *android.TestContext {
+ t.Helper()
return testCcWithConfigForOs(t, bp, config, android.Android)
}
@@ -112,7 +113,7 @@
const (
coreVariant = "android_arm64_armv8-a_core_shared"
- vendorVariant = "android_arm64_armv8-a_vendor_shared"
+ vendorVariant = "android_arm64_armv8-a_vendor.VER_shared"
recoveryVariant = "android_arm64_armv8-a_recovery_shared"
)
@@ -328,8 +329,8 @@
vndkCoreLib2ndPath := filepath.Join(vndkLib2ndPath, "shared", "vndk-core")
vndkSpLib2ndPath := filepath.Join(vndkLib2ndPath, "shared", "vndk-sp")
- variant := "android_arm64_armv8-a_vendor_shared"
- variant2nd := "android_arm_armv7-a-neon_vendor_shared"
+ variant := "android_arm64_armv8-a_vendor.VER_shared"
+ variant2nd := "android_arm_armv7-a-neon_vendor.VER_shared"
checkVndkSnapshot(t, ctx, "libvndk", vndkCoreLibPath, variant)
checkVndkSnapshot(t, ctx, "libvndk", vndkCoreLib2ndPath, variant2nd)
@@ -1343,6 +1344,8 @@
assertArrayString(t, *vndkPrivateLibraries(config),
[]string{"libllndkprivate", "libvndkprivate"})
+ vendorVariant27 := "android_arm64_armv8-a_vendor.27_shared"
+
tests := []struct {
variant string
name string
@@ -1353,8 +1356,8 @@
{vendorVariant, "libvndkprivate", "native:vndk_private"},
{vendorVariant, "libvendor", "native:vendor"},
{vendorVariant, "libvndkext", "native:vendor"},
- {vendorVariant, "prevndk.vndk.27.arm.binder32", "native:vndk"},
{vendorVariant, "libllndk.llndk", "native:vndk"},
+ {vendorVariant27, "prevndk.vndk.27.arm.binder32", "native:vndk"},
{coreVariant, "libvndk", "native:platform"},
{coreVariant, "libvndkprivate", "native:platform"},
{coreVariant, "libllndk", "native:platform"},
@@ -1792,7 +1795,7 @@
`)
// _static variant is used since _shared reuses *.o from the static variant
- cc := ctx.ModuleForTests("libvendor", "android_arm_armv7-a-neon_vendor_static").Rule("cc")
+ cc := ctx.ModuleForTests("libvendor", "android_arm_armv7-a-neon_vendor.VER_static").Rule("cc")
cflags := cc.Args["cFlags"]
if !strings.Contains(cflags, "-Imy_include") {
t.Errorf("cflags for libvendor must contain -Imy_include, but was %#v.", cflags)
@@ -1878,7 +1881,7 @@
// runtime_libs for vendor variants have '.vendor' suffixes if the modules have both core
// and vendor variants.
- variant = "android_arm64_armv8-a_vendor_shared"
+ variant = "android_arm64_armv8-a_vendor.VER_shared"
module = ctx.ModuleForTests("libvendor_available2", variant).Module().(*Module)
checkRuntimeLibs(t, []string{"libvendor_available1.vendor"}, module)
@@ -1894,7 +1897,7 @@
module := ctx.ModuleForTests("libvendor_available3", variant).Module().(*Module)
checkRuntimeLibs(t, []string{"libvendor_available1"}, module)
- variant = "android_arm64_armv8-a_vendor_shared"
+ variant = "android_arm64_armv8-a_vendor.VER_shared"
module = ctx.ModuleForTests("libvendor_available3", variant).Module().(*Module)
checkRuntimeLibs(t, nil, module)
}
@@ -2091,9 +2094,9 @@
}
// test if libvendor is linked to the real shared lib
- ld = ctx.ModuleForTests("libvendor", strings.Replace(variant, "_core", "_vendor", 1)).Rule("ld")
+ ld = ctx.ModuleForTests("libvendor", strings.Replace(variant, "_core", "_vendor.VER", 1)).Rule("ld")
libflags = ld.Args["libFlags"]
- stubPaths = getOutputPaths(ctx, strings.Replace(variant, "_core", "_vendor", 1), []string{"libvendorpublic"})
+ stubPaths = getOutputPaths(ctx, strings.Replace(variant, "_core", "_vendor.VER", 1), []string{"libvendorpublic"})
if !strings.Contains(libflags, stubPaths[0].String()) {
t.Errorf("libflags for libvendor must contain %#v, but was %#v", stubPaths[0], libflags)
}
@@ -2264,6 +2267,24 @@
}
}
+func TestErrorsIfAModuleDependsOnDisabled(t *testing.T) {
+ testCcError(t, `module "libA" .* depends on disabled module "libB"`, `
+ cc_library {
+ name: "libA",
+ srcs: ["foo.c"],
+ shared_libs: ["libB"],
+ stl: "none",
+ }
+
+ cc_library {
+ name: "libB",
+ srcs: ["foo.c"],
+ enabled: false,
+ stl: "none",
+ }
+ `)
+}
+
// Simple smoke test for the cc_fuzz target that ensures the rule compiles
// correctly.
func TestFuzzTarget(t *testing.T) {
@@ -2301,3 +2322,67 @@
}
}
}
+
+func TestDefaults(t *testing.T) {
+ ctx := testCc(t, `
+ cc_defaults {
+ name: "defaults",
+ srcs: ["foo.c"],
+ static: {
+ srcs: ["bar.c"],
+ },
+ shared: {
+ srcs: ["baz.c"],
+ },
+ }
+
+ cc_library_static {
+ name: "libstatic",
+ defaults: ["defaults"],
+ }
+
+ cc_library_shared {
+ name: "libshared",
+ defaults: ["defaults"],
+ }
+
+ cc_library {
+ name: "libboth",
+ defaults: ["defaults"],
+ }
+
+ cc_binary {
+ name: "binary",
+ defaults: ["defaults"],
+ }`)
+
+ pathsToBase := func(paths android.Paths) []string {
+ var ret []string
+ for _, p := range paths {
+ ret = append(ret, p.Base())
+ }
+ return ret
+ }
+
+ shared := ctx.ModuleForTests("libshared", "android_arm64_armv8-a_core_shared").Rule("ld")
+ if g, w := pathsToBase(shared.Inputs), []string{"foo.o", "baz.o"}; !reflect.DeepEqual(w, g) {
+ t.Errorf("libshared ld rule wanted %q, got %q", w, g)
+ }
+ bothShared := ctx.ModuleForTests("libboth", "android_arm64_armv8-a_core_shared").Rule("ld")
+ if g, w := pathsToBase(bothShared.Inputs), []string{"foo.o", "baz.o"}; !reflect.DeepEqual(w, g) {
+ t.Errorf("libboth ld rule wanted %q, got %q", w, g)
+ }
+ binary := ctx.ModuleForTests("binary", "android_arm64_armv8-a_core").Rule("ld")
+ if g, w := pathsToBase(binary.Inputs), []string{"foo.o"}; !reflect.DeepEqual(w, g) {
+ t.Errorf("binary ld rule wanted %q, got %q", w, g)
+ }
+
+ static := ctx.ModuleForTests("libstatic", "android_arm64_armv8-a_core_static").Rule("ar")
+ if g, w := pathsToBase(static.Inputs), []string{"foo.o", "bar.o"}; !reflect.DeepEqual(w, g) {
+ t.Errorf("libstatic ar rule wanted %q, got %q", w, g)
+ }
+ bothStatic := ctx.ModuleForTests("libboth", "android_arm64_armv8-a_core_static").Rule("ar")
+ if g, w := pathsToBase(bothStatic.Inputs), []string{"foo.o", "bar.o"}; !reflect.DeepEqual(w, g) {
+ t.Errorf("libboth ar rule wanted %q, got %q", w, g)
+ }
+}
diff --git a/cc/cflag_artifacts.go b/cc/cflag_artifacts.go
new file mode 100644
index 0000000..9ed3876
--- /dev/null
+++ b/cc/cflag_artifacts.go
@@ -0,0 +1,188 @@
+package cc
+
+import (
+ "fmt"
+ "sort"
+ "strings"
+
+ "github.com/google/blueprint/proptools"
+
+ "android/soong/android"
+)
+
+func init() {
+ android.RegisterSingletonType("cflag_artifacts_text", cflagArtifactsTextFactory)
+}
+
+var (
+ TrackedCFlags = []string{
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ "-Wthread-safety",
+ "-O3",
+ }
+
+ TrackedCFlagsDir = []string{
+ "device/google/",
+ "vendor/google/",
+ }
+)
+
+const FileBP = 50
+
+// Stores output files.
+type cflagArtifactsText struct {
+ interOutputs map[string]android.WritablePaths
+ outputs android.WritablePaths
+}
+
+// allowedDir verifies if the directory/project is part of the TrackedCFlagsDir
+// filter.
+func allowedDir(subdir string) bool {
+ subdir += "/"
+ for _, prefix := range TrackedCFlagsDir {
+ if strings.HasPrefix(subdir, prefix) {
+ return true
+ }
+ }
+ return false
+}
+
+func (s *cflagArtifactsText) genFlagFilename(flag string) string {
+ return fmt.Sprintf("module_cflags%s.txt", flag)
+}
+
+// incrementFile is used to generate an output path object with the passed in flag
+// and part number.
+// e.g. FLAG + part # -> out/soong/cflags/module_cflags-FLAG.txt.0
+func (s *cflagArtifactsText) incrementFile(ctx android.SingletonContext,
+ flag string, part int) (string, android.OutputPath) {
+
+ filename := fmt.Sprintf("%s.%d", s.genFlagFilename(flag), part)
+ filepath := android.PathForOutput(ctx, "cflags", filename)
+ s.interOutputs[flag] = append(s.interOutputs[flag], filepath)
+ return filename, filepath
+}
+
+// GenCFlagArtifactParts is used to generate the build rules which produce the
+// intermediary files for each desired C Flag artifact
+// e.g. module_cflags-FLAG.txt.0, module_cflags-FLAG.txt.1, ...
+func (s *cflagArtifactsText) GenCFlagArtifactParts(ctx android.SingletonContext,
+ flag string, using bool, modules []string, part int) int {
+
+ cleanedName := strings.Replace(flag, "=", "_", -1)
+ filename, filepath := s.incrementFile(ctx, cleanedName, part)
+ rule := android.NewRuleBuilder()
+ rule.Command().Textf("rm -f %s", filepath.String())
+
+ if using {
+ rule.Command().
+ Textf("echo '# Modules using %s'", flag).
+ FlagWithOutput(">> ", filepath)
+ } else {
+ rule.Command().
+ Textf("echo '# Modules not using %s'", flag).
+ FlagWithOutput(">> ", filepath)
+ }
+
+ length := len(modules)
+
+ if length == 0 {
+ rule.Build(pctx, ctx, filename, "gen "+filename)
+ part++
+ }
+
+ // Following loop splits the module list for each tracked C Flag into
+ // chunks of length FileBP (file breakpoint) and generates a partial artifact
+ // (intermediary file) build rule for each split.
+ moduleShards := android.ShardStrings(modules, FileBP)
+ for index, shard := range moduleShards {
+ rule.Command().
+ Textf("for m in %s; do echo $m",
+ strings.Join(proptools.ShellEscapeList(shard), " ")).
+ FlagWithOutput(">> ", filepath).
+ Text("; done")
+ rule.Build(pctx, ctx, filename, "gen "+filename)
+
+ if index+1 != len(moduleShards) {
+ filename, filepath = s.incrementFile(ctx, cleanedName, part+index+1)
+ rule = android.NewRuleBuilder()
+ rule.Command().Textf("rm -f %s", filepath.String())
+ }
+ }
+
+ return part + len(moduleShards)
+}
+
+// GenCFlagArtifacts is used to generate build rules which combine the
+// intermediary files of a specific tracked flag into a single C Flag artifact
+// for each tracked flag.
+// e.g. module_cflags-FLAG.txt.0 + module_cflags-FLAG.txt.1 = module_cflags-FLAG.txt
+func (s *cflagArtifactsText) GenCFlagArtifacts(ctx android.SingletonContext) {
+ // Scans through s.interOutputs and creates a build rule for each tracked C
+ // Flag that concatenates the associated intermediary file into a single
+ // artifact.
+ for _, flag := range TrackedCFlags {
+ // Generate build rule to combine related intermediary files into a
+ // C Flag artifact
+ rule := android.NewRuleBuilder()
+ filename := s.genFlagFilename(flag)
+ outputpath := android.PathForOutput(ctx, "cflags", filename)
+ rule.Command().
+ Text("cat").
+ Inputs(s.interOutputs[flag].Paths()).
+ FlagWithOutput("> ", outputpath)
+ rule.Build(pctx, ctx, filename, "gen "+filename)
+ s.outputs = append(s.outputs, outputpath)
+ }
+}
+
+func (s *cflagArtifactsText) GenerateBuildActions(ctx android.SingletonContext) {
+ modulesWithCFlag := make(map[string][]string)
+
+ // Scan through all modules, selecting the ones that are part of the filter,
+ // and then storing into a map which tracks whether or not tracked C flag is
+ // used or not.
+ ctx.VisitAllModules(func(module android.Module) {
+ if ccModule, ok := module.(*Module); ok {
+ if allowedDir(ctx.ModuleDir(ccModule)) {
+ cflags := ccModule.flags.CFlags
+ cppflags := ccModule.flags.CppFlags
+ module := fmt.Sprintf("%s:%s (%s)",
+ ctx.BlueprintFile(ccModule),
+ ctx.ModuleName(ccModule),
+ ctx.ModuleSubDir(ccModule))
+ for _, flag := range TrackedCFlags {
+ if inList(flag, cflags) || inList(flag, cppflags) {
+ modulesWithCFlag[flag] = append(modulesWithCFlag[flag], module)
+ } else {
+ modulesWithCFlag["!"+flag] = append(modulesWithCFlag["!"+flag], module)
+ }
+ }
+ }
+ }
+ })
+
+ // Traversing map and setting up rules to produce intermediary files which
+ // contain parts of each expected C Flag artifact.
+ for _, flag := range TrackedCFlags {
+ sort.Strings(modulesWithCFlag[flag])
+ part := s.GenCFlagArtifactParts(ctx, flag, true, modulesWithCFlag[flag], 0)
+ sort.Strings(modulesWithCFlag["!"+flag])
+ s.GenCFlagArtifactParts(ctx, flag, false, modulesWithCFlag["!"+flag], part)
+ }
+
+ // Combine intermediary files into a single C Flag artifact.
+ s.GenCFlagArtifacts(ctx)
+}
+
+func cflagArtifactsTextFactory() android.Singleton {
+ return &cflagArtifactsText{
+ interOutputs: make(map[string]android.WritablePaths),
+ }
+}
+
+func (s *cflagArtifactsText) MakeVars(ctx android.MakeVarsContext) {
+ ctx.Strict("SOONG_MODULES_CFLAG_ARTIFACTS", strings.Join(s.outputs.Strings(), " "))
+}
diff --git a/cc/compiler.go b/cc/compiler.go
index 85ff400..ffb6ad2 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -309,7 +309,6 @@
flags.SystemIncludeFlags = append(flags.SystemIncludeFlags,
"-isystem "+getCurrentIncludePath(ctx).String(),
"-isystem "+getCurrentIncludePath(ctx).Join(ctx, config.NDKTriple(tc)).String())
- flags.GlobalFlags = append(flags.GlobalFlags, "-D__ANDROID_NDK__")
}
if ctx.useVndk() {
diff --git a/cc/config/arm_device.go b/cc/config/arm_device.go
index cd7c410..d37e486 100644
--- a/cc/config/arm_device.go
+++ b/cc/config/arm_device.go
@@ -236,6 +236,7 @@
"cortex-a72": "${config.ArmClangCortexA53Cflags}",
"cortex-a73": "${config.ArmClangCortexA53Cflags}",
"cortex-a75": "${config.ArmClangCortexA55Cflags}",
+ "cortex-a76": "${config.ArmClangCortexA55Cflags}",
"krait": "${config.ArmClangKraitCflags}",
"kryo": "${config.ArmClangKryoCflags}",
"kryo385": "${config.ArmClangCortexA53Cflags}",
diff --git a/cc/config/clang.go b/cc/config/clang.go
index 47b60e7..71bea42 100644
--- a/cc/config/clang.go
+++ b/cc/config/clang.go
@@ -101,9 +101,8 @@
// not emit the table by default on Android since NDK still uses GNU binutils.
"-faddrsig",
- // Make implicit fallthrough an error in the future.
+ // -Wimplicit-fallthrough is not enabled by -Wall.
"-Wimplicit-fallthrough",
- "-Wno-error=implicit-fallthrough",
// Help catch common 32/64-bit errors.
"-Werror=int-conversion",
@@ -116,10 +115,6 @@
// TODO: can we remove this now?
"-Wno-reserved-id-macro",
- // Disable overly aggressive warning for format strings.
- // Bug: 20148343
- "-Wno-format-pedantic",
-
// Workaround for ccache with clang.
// See http://petereisentraut.blogspot.com/2011/05/ccache-and-clang.html.
"-Wno-unused-command-line-argument",
@@ -168,25 +163,13 @@
// new warnings are fixed.
"-Wno-tautological-constant-compare",
"-Wno-tautological-type-limit-compare",
- "-Wno-tautological-unsigned-enum-zero-compare",
- "-Wno-tautological-unsigned-zero-compare",
-
- // http://b/72330874 Disable -Wenum-compare until the instances detected by this new
- // warning are fixed.
- "-Wno-enum-compare",
- "-Wno-enum-compare-switch",
-
- // Disable c++98-specific warning since Android is not concerned with C++98
- // compatibility.
- "-Wno-c++98-compat-extra-semi",
-
- // Disable this warning because we don't care about behavior with older compilers.
- "-Wno-return-std-move-in-c++11",
}, " "))
- // Extra cflags for projects under external/ directory
+ // Extra cflags for projects under external/ directory to disable warnings that are infeasible
+ // to fix in all the external projects and their upstream repos.
pctx.StaticVariable("ClangExtraExternalCflags", strings.Join([]string{
- // TODO(yikong): Move -Wno flags here
+ "-Wno-enum-compare",
+ "-Wno-enum-compare-switch",
// http://b/72331524 Allow null pointer arithmetic until the instances detected by
// this new warning are fixed.
diff --git a/cc/config/global.go b/cc/config/global.go
index 2150abf..0943126 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -46,6 +46,8 @@
"-g",
"-fno-strict-aliasing",
+
+ "-Werror=date-time",
}
commonGlobalConlyflags = []string{}
@@ -67,7 +69,6 @@
"-Werror=non-virtual-dtor",
"-Werror=address",
"-Werror=sequence-point",
- "-Werror=date-time",
"-Werror=format-security",
}
@@ -107,6 +108,7 @@
noOverrideGlobalCflags = []string{
"-Werror=int-to-pointer-cast",
"-Werror=pointer-to-int-cast",
+ "-Werror=fortify-source",
}
IllegalFlags = []string{
@@ -122,8 +124,8 @@
// prebuilts/clang default settings.
ClangDefaultBase = "prebuilts/clang/host"
- ClangDefaultVersion = "clang-r365631"
- ClangDefaultShortVersion = "9.0.6"
+ ClangDefaultVersion = "clang-r365631b"
+ ClangDefaultShortVersion = "9.0.7"
// Directories with warnings from Android.bp files.
WarningAllowedProjects = []string{
diff --git a/cc/config/vndk.go b/cc/config/vndk.go
index e754ad5..3e8abac 100644
--- a/cc/config/vndk.go
+++ b/cc/config/vndk.go
@@ -65,6 +65,7 @@
"android.hardware.neuralnetworks@1.0",
"android.hardware.neuralnetworks@1.1",
"android.hardware.neuralnetworks@1.2",
+ "android.hardware.neuralnetworks@1.3",
"android.hardware.nfc@1.0",
"android.hardware.nfc@1.1",
"android.hardware.nfc@1.2",
@@ -120,6 +121,8 @@
"libmedia_omx",
"libmemtrack",
"libnetutils",
+ "libprotobuf-cpp-full",
+ "libprotobuf-cpp-lite",
"libpuresoftkeymasterdevice",
"libradio_metadata",
"libselinux",
diff --git a/cc/config/x86_windows_host.go b/cc/config/x86_windows_host.go
index 0f500b6..43e8c85 100644
--- a/cc/config/x86_windows_host.go
+++ b/cc/config/x86_windows_host.go
@@ -73,6 +73,7 @@
"-m32",
"-Wl,--large-address-aware",
"-L${WindowsGccRoot}/${WindowsGccTriple}/lib32",
+ "-static-libgcc",
}
windowsX86ClangLdflags = append(ClangFilterUnknownCflags(windowsX86Ldflags), []string{
"-B${WindowsGccRoot}/${WindowsGccTriple}/bin",
@@ -86,6 +87,7 @@
"-m64",
"-L${WindowsGccRoot}/${WindowsGccTriple}/lib64",
"-Wl,--high-entropy-va",
+ "-static-libgcc",
}
windowsX8664ClangLdflags = append(ClangFilterUnknownCflags(windowsX8664Ldflags), []string{
"-B${WindowsGccRoot}/${WindowsGccTriple}/bin",
diff --git a/cc/fuzz.go b/cc/fuzz.go
index d44c02d..a99b0bb 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -15,13 +15,26 @@
package cc
import (
+ "path/filepath"
+ "strings"
+
+ "github.com/google/blueprint/proptools"
+
"android/soong/android"
"android/soong/cc/config"
- "github.com/google/blueprint/proptools"
)
+type FuzzProperties struct {
+ // Optional list of seed files to be installed to the fuzz target's output
+ // directory.
+ Corpus []string `android:"path"`
+ // Optional dictionary to be installed to the fuzz target's output directory.
+ Dictionary *string `android:"path"`
+}
+
func init() {
android.RegisterModuleType("cc_fuzz", FuzzFactory)
+ android.RegisterSingletonType("cc_fuzz_packaging", fuzzPackagingFactory)
}
// cc_fuzz creates a host/device fuzzer binary. Host binaries can be found at
@@ -39,10 +52,16 @@
type fuzzBinary struct {
*binaryDecorator
*baseCompiler
+
+ Properties FuzzProperties
+ dictionary android.Path
+ corpus android.Paths
+ corpusIntermediateDir android.Path
}
func (fuzz *fuzzBinary) linkerProps() []interface{} {
props := fuzz.binaryDecorator.linkerProps()
+ props = append(props, &fuzz.Properties)
return props
}
@@ -78,21 +97,36 @@
}
func (fuzz *fuzzBinary) install(ctx ModuleContext, file android.Path) {
- fuzz.binaryDecorator.baseInstaller.dir = "fuzz"
- fuzz.binaryDecorator.baseInstaller.dir64 = "fuzz"
+ fuzz.binaryDecorator.baseInstaller.dir = filepath.Join(
+ "fuzz", ctx.Target().Arch.ArchType.String(), ctx.ModuleName())
+ fuzz.binaryDecorator.baseInstaller.dir64 = filepath.Join(
+ "fuzz", ctx.Target().Arch.ArchType.String(), ctx.ModuleName())
fuzz.binaryDecorator.baseInstaller.install(ctx, file)
+
+ fuzz.corpus = android.PathsForModuleSrc(ctx, fuzz.Properties.Corpus)
+ builder := android.NewRuleBuilder()
+ intermediateDir := android.PathForModuleOut(ctx, "corpus")
+ for _, entry := range fuzz.corpus {
+ builder.Command().Text("cp").
+ Input(entry).
+ Output(intermediateDir.Join(ctx, entry.Base()))
+ }
+ builder.Build(pctx, ctx, "copy_corpus", "copy corpus")
+ fuzz.corpusIntermediateDir = intermediateDir
+
+ if fuzz.Properties.Dictionary != nil {
+ fuzz.dictionary = android.PathForModuleSrc(ctx, *fuzz.Properties.Dictionary)
+ if fuzz.dictionary.Ext() != ".dict" {
+ ctx.PropertyErrorf("dictionary",
+ "Fuzzer dictionary %q does not have '.dict' extension",
+ fuzz.dictionary.String())
+ }
+ }
}
func NewFuzz(hod android.HostOrDeviceSupported) *Module {
module, binary := NewBinary(hod)
- // TODO(mitchp): The toolchain does not currently export the x86 (32-bit)
- // variant of libFuzzer for host. There is no way to only disable the host
- // 32-bit variant, so we specify cc_fuzz targets as 64-bit only. This doesn't
- // hurt anyone, as cc_fuzz is mostly for experimental targets as of this
- // moment.
- module.multilib = "64"
-
binary.baseInstaller = NewFuzzInstaller()
module.sanitize.SetSanitizer(fuzzer, true)
@@ -125,12 +159,108 @@
// include the STL.
android.AddLoadHook(module, func(ctx android.LoadHookContext) {
staticStlLinkage := struct {
- Stl *string
+ Target struct {
+ Linux_glibc struct {
+ Stl *string
+ }
+ }
}{}
- staticStlLinkage.Stl = proptools.StringPtr("libc++_static")
+ staticStlLinkage.Target.Linux_glibc.Stl = proptools.StringPtr("libc++_static")
ctx.AppendProperties(&staticStlLinkage)
})
return module
}
+
+// Responsible for generating GNU Make rules that package fuzz targets into
+// their architecture & target/host specific zip file.
+type fuzzPackager struct {
+ packages android.Paths
+}
+
+func fuzzPackagingFactory() android.Singleton {
+ return &fuzzPackager{}
+}
+
+type fileToZip struct {
+ SourceFilePath android.Path
+ DestinationPathPrefix string
+}
+
+func (s *fuzzPackager) GenerateBuildActions(ctx android.SingletonContext) {
+ // Map between each architecture + host/device combination, and the files that
+ // need to be packaged (in the tuple of {source file, destination folder in
+ // archive}).
+ archDirs := make(map[android.OutputPath][]fileToZip)
+
+ ctx.VisitAllModules(func(module android.Module) {
+ // Discard non-fuzz targets.
+ ccModule, ok := module.(*Module)
+ if !ok {
+ return
+ }
+ fuzzModule, ok := ccModule.compiler.(*fuzzBinary)
+ if !ok {
+ return
+ }
+
+ // Discard vendor-NDK-linked modules, they're duplicates of fuzz targets
+ // we're going to package anyway.
+ if ccModule.useVndk() || !ccModule.Enabled() {
+ return
+ }
+
+ hostOrTargetString := "target"
+ if ccModule.Host() {
+ hostOrTargetString = "host"
+ }
+
+ archString := ccModule.Arch().ArchType.String()
+ archDir := android.PathForIntermediates(ctx, "fuzz", hostOrTargetString, archString)
+
+ // The executable.
+ archDirs[archDir] = append(archDirs[archDir],
+ fileToZip{ccModule.outputFile.Path(), ccModule.Name()})
+
+ // The corpora.
+ for _, corpusEntry := range fuzzModule.corpus {
+ archDirs[archDir] = append(archDirs[archDir],
+ fileToZip{corpusEntry, ccModule.Name() + "/corpus"})
+ }
+
+ // The dictionary.
+ if fuzzModule.dictionary != nil {
+ archDirs[archDir] = append(archDirs[archDir],
+ fileToZip{fuzzModule.dictionary, ccModule.Name()})
+ }
+ })
+
+ for archDir, filesToZip := range archDirs {
+ arch := archDir.Base()
+ hostOrTarget := filepath.Base(filepath.Dir(archDir.String()))
+ builder := android.NewRuleBuilder()
+ outputFile := android.PathForOutput(ctx, "fuzz-"+hostOrTarget+"-"+arch+".zip")
+ s.packages = append(s.packages, outputFile)
+
+ command := builder.Command().BuiltTool(ctx, "soong_zip").
+ Flag("-j").
+ FlagWithOutput("-o ", outputFile)
+
+ for _, fileToZip := range filesToZip {
+ command.FlagWithArg("-P ", fileToZip.DestinationPathPrefix).
+ FlagWithInput("-f ", fileToZip.SourceFilePath)
+ }
+
+ builder.Build(pctx, ctx, "create-fuzz-package-"+arch+"-"+hostOrTarget,
+ "Create fuzz target packages for "+arch+"-"+hostOrTarget)
+ }
+}
+
+func (s *fuzzPackager) MakeVars(ctx android.MakeVarsContext) {
+ // TODO(mitchp): Migrate this to use MakeVarsContext::DistForGoal() when it's
+ // ready to handle phony targets created in Soong. In the meantime, this
+ // exports the phony 'fuzz' target and dependencies on packages to
+ // core/main.mk so that we can use dist-for-goals.
+ ctx.Strict("SOONG_FUZZ_PACKAGING_ARCH_MODULES", strings.Join(s.packages.Strings(), " "))
+}
diff --git a/cc/gen.go b/cc/gen.go
index 42b0cbe..17ab45f 100644
--- a/cc/gen.go
+++ b/cc/gen.go
@@ -113,7 +113,14 @@
aidlPackage := strings.TrimSuffix(aidlFile.Rel(), aidlFile.Base())
baseName := strings.TrimSuffix(aidlFile.Base(), aidlFile.Ext())
- shortName := strings.TrimPrefix(baseName, "I")
+ shortName := baseName
+ // TODO(b/111362593): aidl_to_cpp_common.cpp uses heuristics to figure out if
+ // an interface name has a leading I. Those same heuristics have been
+ // moved here.
+ if len(baseName) >= 2 && baseName[0] == 'I' &&
+ strings.ToUpper(baseName)[1] == baseName[1] {
+ shortName = strings.TrimPrefix(baseName, "I")
+ }
outDir := android.PathForModuleGen(ctx, "aidl")
headerI := outDir.Join(ctx, aidlPackage, baseName+".h")
diff --git a/cc/installer.go b/cc/installer.go
index a52ccf1..9fdc88a 100644
--- a/cc/installer.go
+++ b/cc/installer.go
@@ -52,7 +52,7 @@
relative string
location installLocation
- path android.OutputPath
+ path android.InstallPath
}
var _ installer = (*baseInstaller)(nil)
@@ -61,16 +61,15 @@
return []interface{}{&installer.Properties}
}
-func (installer *baseInstaller) installDir(ctx ModuleContext) android.OutputPath {
+func (installer *baseInstaller) installDir(ctx ModuleContext) android.InstallPath {
dir := installer.dir
if ctx.toolchain().Is64Bit() && installer.dir64 != "" {
dir = installer.dir64
}
- if !ctx.Host() && !ctx.Arch().Native {
- dir = filepath.Join(dir, ctx.Arch().ArchType.String())
- }
if ctx.Target().NativeBridge == android.NativeBridgeEnabled {
dir = filepath.Join(dir, ctx.Target().NativeBridgeRelativePath)
+ } else if !ctx.Host() && ctx.Config().HasMultilibConflict(ctx.Arch().ArchType) {
+ dir = filepath.Join(dir, ctx.Arch().ArchType.String())
}
if installer.location == InstallInData && ctx.useVndk() {
dir = filepath.Join(dir, "vendor")
diff --git a/cc/library.go b/cc/library.go
index 6564fa1..80dc76c 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -31,24 +31,7 @@
"android/soong/genrule"
)
-type StaticSharedLibraryProperties struct {
- Srcs []string `android:"path,arch_variant"`
- Cflags []string `android:"arch_variant"`
-
- Enabled *bool `android:"arch_variant"`
- Whole_static_libs []string `android:"arch_variant"`
- Static_libs []string `android:"arch_variant"`
- Shared_libs []string `android:"arch_variant"`
- System_shared_libs []string `android:"arch_variant"`
-
- Export_shared_lib_headers []string `android:"arch_variant"`
- Export_static_lib_headers []string `android:"arch_variant"`
-}
-
type LibraryProperties struct {
- Static StaticSharedLibraryProperties `android:"arch_variant"`
- Shared StaticSharedLibraryProperties `android:"arch_variant"`
-
// local file name to pass to the linker as -unexported_symbols_list
Unexported_symbols_list *string `android:"path,arch_variant"`
// local file name to pass to the linker as -force_symbols_not_weak_list
@@ -88,6 +71,16 @@
// set the name of the output
Stem *string `android:"arch_variant"`
+ // set suffix of the name of the output
+ Suffix *string `android:"arch_variant"`
+
+ Target struct {
+ Vendor struct {
+ // set suffix of the name of the output
+ Suffix *string `android:"arch_variant"`
+ }
+ }
+
// Names of modules to be overridden. Listed modules can only be other shared libraries
// (in Make or Soong).
// This does not completely prevent installation of the overridden libraries, but if both
@@ -118,6 +111,30 @@
Inject_bssl_hash *bool `android:"arch_variant"`
}
+type StaticProperties struct {
+ Static StaticOrSharedProperties `android:"arch_variant"`
+}
+
+type SharedProperties struct {
+ Shared StaticOrSharedProperties `android:"arch_variant"`
+}
+
+type StaticOrSharedProperties struct {
+ Srcs []string `android:"path,arch_variant"`
+ Cflags []string `android:"arch_variant"`
+
+ Enabled *bool `android:"arch_variant"`
+ Whole_static_libs []string `android:"arch_variant"`
+ Static_libs []string `android:"arch_variant"`
+ Shared_libs []string `android:"arch_variant"`
+ System_shared_libs []string `android:"arch_variant"`
+
+ Export_shared_lib_headers []string `android:"arch_variant"`
+ Export_static_lib_headers []string `android:"arch_variant"`
+
+ Apex_available []string `android:"arch_variant"`
+}
+
type LibraryMutatedProperties struct {
// Build a static variant
BuildStatic bool `blueprint:"mutated"`
@@ -285,6 +302,8 @@
// functionality: static vs. shared linkage, reusing object files for shared libraries
type libraryDecorator struct {
Properties LibraryProperties
+ StaticProperties StaticProperties
+ SharedProperties SharedProperties
MutatedProperties LibraryMutatedProperties
// For reusing static library objects for shared library
@@ -345,11 +364,20 @@
func (library *libraryDecorator) linkerProps() []interface{} {
var props []interface{}
props = append(props, library.baseLinker.linkerProps()...)
- return append(props,
+ props = append(props,
&library.Properties,
&library.MutatedProperties,
&library.flagExporter.Properties,
&library.stripper.StripProperties)
+
+ if library.MutatedProperties.BuildShared {
+ props = append(props, &library.SharedProperties)
+ }
+ if library.MutatedProperties.BuildStatic {
+ props = append(props, &library.StaticProperties)
+ }
+
+ return props
}
func (library *libraryDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags {
@@ -363,9 +391,9 @@
}
if library.static() {
- flags.CFlags = append(flags.CFlags, library.Properties.Static.Cflags...)
+ flags.CFlags = append(flags.CFlags, library.StaticProperties.Static.Cflags...)
} else if library.shared() {
- flags.CFlags = append(flags.CFlags, library.Properties.Shared.Cflags...)
+ flags.CFlags = append(flags.CFlags, library.SharedProperties.Shared.Cflags...)
}
if library.shared() {
@@ -464,7 +492,7 @@
}
}
}
- if enabled != nil && Bool(enabled) {
+ if Bool(enabled) || ctx.hasStubsVariants() {
return "PLATFORM"
}
return ""
@@ -488,10 +516,10 @@
if len(library.baseCompiler.Properties.Srcs) > 0 {
ctx.PropertyErrorf("srcs", "cc_library_headers must not have any srcs")
}
- if len(library.Properties.Static.Srcs) > 0 {
+ if len(library.StaticProperties.Static.Srcs) > 0 {
ctx.PropertyErrorf("static.srcs", "cc_library_headers must not have any srcs")
}
- if len(library.Properties.Shared.Srcs) > 0 {
+ if len(library.SharedProperties.Shared.Srcs) > 0 {
ctx.PropertyErrorf("shared.srcs", "cc_library_headers must not have any srcs")
}
return Objects{}
@@ -506,8 +534,8 @@
SourceAbiFlags = append(SourceAbiFlags, "-I"+reexportedInclude)
}
flags.SAbiFlags = SourceAbiFlags
- total_length := len(library.baseCompiler.Properties.Srcs) + len(deps.GeneratedSources) + len(library.Properties.Shared.Srcs) +
- len(library.Properties.Static.Srcs)
+ total_length := len(library.baseCompiler.Properties.Srcs) + len(deps.GeneratedSources) +
+ len(library.SharedProperties.Shared.Srcs) + len(library.StaticProperties.Static.Srcs)
if total_length > 0 {
flags.SAbiDump = true
}
@@ -517,11 +545,11 @@
buildFlags := flagsToBuilderFlags(flags)
if library.static() {
- srcs := android.PathsForModuleSrc(ctx, library.Properties.Static.Srcs)
+ srcs := android.PathsForModuleSrc(ctx, library.StaticProperties.Static.Srcs)
objs = objs.Append(compileObjs(ctx, buildFlags, android.DeviceStaticLibrary,
srcs, library.baseCompiler.pathDeps, library.baseCompiler.cFlagsDeps))
} else if library.shared() {
- srcs := android.PathsForModuleSrc(ctx, library.Properties.Shared.Srcs)
+ srcs := android.PathsForModuleSrc(ctx, library.SharedProperties.Shared.Srcs)
objs = objs.Append(compileObjs(ctx, buildFlags, android.DeviceSharedLibrary,
srcs, library.baseCompiler.pathDeps, library.baseCompiler.cFlagsDeps))
}
@@ -547,9 +575,11 @@
// Write LOCAL_ADDITIONAL_DEPENDENCIES for ABI diff
androidMkWriteAdditionalDependenciesForSourceAbiDiff(w io.Writer)
+
+ availableFor(string) bool
}
-func (library *libraryDecorator) getLibName(ctx ModuleContext) string {
+func (library *libraryDecorator) getLibName(ctx BaseModuleContext) string {
name := library.libName
if name == "" {
name = String(library.Properties.Stem)
@@ -558,6 +588,16 @@
}
}
+ suffix := ""
+ if ctx.useVndk() {
+ suffix = String(library.Properties.Target.Vendor.Suffix)
+ }
+ if suffix == "" {
+ suffix = String(library.Properties.Suffix)
+ }
+
+ name += suffix
+
if ctx.isVndkExt() {
name = ctx.getVndkExtendsModuleName()
}
@@ -605,12 +645,12 @@
func (library *libraryDecorator) linkerDeps(ctx DepsContext, deps Deps) Deps {
if library.static() {
- if library.Properties.Static.System_shared_libs != nil {
- library.baseLinker.Properties.System_shared_libs = library.Properties.Static.System_shared_libs
+ if library.StaticProperties.Static.System_shared_libs != nil {
+ library.baseLinker.Properties.System_shared_libs = library.StaticProperties.Static.System_shared_libs
}
} else if library.shared() {
- if library.Properties.Shared.System_shared_libs != nil {
- library.baseLinker.Properties.System_shared_libs = library.Properties.Shared.System_shared_libs
+ if library.SharedProperties.Shared.System_shared_libs != nil {
+ library.baseLinker.Properties.System_shared_libs = library.SharedProperties.Shared.System_shared_libs
}
}
@@ -618,12 +658,12 @@
if library.static() {
deps.WholeStaticLibs = append(deps.WholeStaticLibs,
- library.Properties.Static.Whole_static_libs...)
- deps.StaticLibs = append(deps.StaticLibs, library.Properties.Static.Static_libs...)
- deps.SharedLibs = append(deps.SharedLibs, library.Properties.Static.Shared_libs...)
+ library.StaticProperties.Static.Whole_static_libs...)
+ deps.StaticLibs = append(deps.StaticLibs, library.StaticProperties.Static.Static_libs...)
+ deps.SharedLibs = append(deps.SharedLibs, library.StaticProperties.Static.Shared_libs...)
- deps.ReexportSharedLibHeaders = append(deps.ReexportSharedLibHeaders, library.Properties.Static.Export_shared_lib_headers...)
- deps.ReexportStaticLibHeaders = append(deps.ReexportStaticLibHeaders, library.Properties.Static.Export_static_lib_headers...)
+ deps.ReexportSharedLibHeaders = append(deps.ReexportSharedLibHeaders, library.StaticProperties.Static.Export_shared_lib_headers...)
+ deps.ReexportStaticLibHeaders = append(deps.ReexportStaticLibHeaders, library.StaticProperties.Static.Export_static_lib_headers...)
} else if library.shared() {
if ctx.toolchain().Bionic() && !Bool(library.baseLinker.Properties.Nocrt) {
if !ctx.useSdk() {
@@ -642,12 +682,12 @@
deps.CrtEnd = "ndk_crtend_so." + version
}
}
- deps.WholeStaticLibs = append(deps.WholeStaticLibs, library.Properties.Shared.Whole_static_libs...)
- deps.StaticLibs = append(deps.StaticLibs, library.Properties.Shared.Static_libs...)
- deps.SharedLibs = append(deps.SharedLibs, library.Properties.Shared.Shared_libs...)
+ deps.WholeStaticLibs = append(deps.WholeStaticLibs, library.SharedProperties.Shared.Whole_static_libs...)
+ deps.StaticLibs = append(deps.StaticLibs, library.SharedProperties.Shared.Static_libs...)
+ deps.SharedLibs = append(deps.SharedLibs, library.SharedProperties.Shared.Shared_libs...)
- deps.ReexportSharedLibHeaders = append(deps.ReexportSharedLibHeaders, library.Properties.Shared.Export_shared_lib_headers...)
- deps.ReexportStaticLibHeaders = append(deps.ReexportStaticLibHeaders, library.Properties.Shared.Export_static_lib_headers...)
+ deps.ReexportSharedLibHeaders = append(deps.ReexportSharedLibHeaders, library.SharedProperties.Shared.Export_shared_lib_headers...)
+ deps.ReexportStaticLibHeaders = append(deps.ReexportStaticLibHeaders, library.SharedProperties.Shared.Export_static_lib_headers...)
}
if ctx.useVndk() {
deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, library.baseLinker.Properties.Target.Vendor.Exclude_static_libs)
@@ -755,9 +795,7 @@
// Optimize out relinking against shared libraries whose interface hasn't changed by
// depending on a table of contents file instead of the library itself.
- tocPath := outputFile.RelPathString()
- tocPath = pathtools.ReplaceExtension(tocPath, flags.Toolchain.ShlibSuffix()[1:]+".toc")
- tocFile := android.PathForOutput(ctx, tocPath)
+ tocFile := outputFile.ReplaceExtension(ctx, flags.Toolchain.ShlibSuffix()[1:]+".toc")
library.tocFile = android.OptionalPathForPath(tocFile)
TransformSharedObjectToToc(ctx, outputFile, tocFile, builderFlags)
@@ -771,18 +809,7 @@
}
library.unstrippedOutputFile = outputFile
- // TODO(b/137267623): Remove this in favor of a cc_genrule when they support operating on shared libraries.
- if Bool(library.Properties.Inject_bssl_hash) {
- hashedOutputfile := outputFile
- outputFile = android.PathForModuleOut(ctx, "unhashed", fileName)
-
- rule := android.NewRuleBuilder()
- rule.Command().
- BuiltTool(ctx, "bssl_inject_hash").
- FlagWithInput("-in-object ", outputFile).
- FlagWithOutput("-o ", hashedOutputfile)
- rule.Build(pctx, ctx, "injectCryptoHash", "inject crypto hash")
- }
+ outputFile = maybeInjectBoringSSLHash(ctx, outputFile, library.Properties.Inject_bssl_hash, fileName)
if Bool(library.baseLinker.Properties.Use_version_lib) {
if ctx.Host() {
@@ -894,7 +921,7 @@
}
exportedHeaderFlags := strings.Join(SourceAbiFlags, " ")
library.sAbiOutputFile = TransformDumpToLinkedDump(ctx, objs.sAbiDumpFiles, soFile, fileName, exportedHeaderFlags,
- android.OptionalPathForModuleSrc(ctx, library.Properties.Header_abi_checker.Symbol_file),
+ android.OptionalPathForModuleSrc(ctx, library.symbolFileForAbiCheck(ctx)),
library.Properties.Header_abi_checker.Exclude_symbol_versions,
library.Properties.Header_abi_checker.Exclude_symbol_tags)
@@ -969,11 +996,13 @@
}
func (library *libraryDecorator) buildStatic() bool {
- return library.MutatedProperties.BuildStatic && BoolDefault(library.Properties.Static.Enabled, true)
+ return library.MutatedProperties.BuildStatic &&
+ BoolDefault(library.StaticProperties.Static.Enabled, true)
}
func (library *libraryDecorator) buildShared() bool {
- return library.MutatedProperties.BuildShared && BoolDefault(library.Properties.Shared.Enabled, true)
+ return library.MutatedProperties.BuildShared &&
+ BoolDefault(library.SharedProperties.Shared.Enabled, true)
}
func (library *libraryDecorator) getWholeStaticMissingDeps() []string {
@@ -1023,9 +1052,9 @@
// Bionic libraries (e.g. libc.so) is installed to the bootstrap subdirectory.
// The original path becomes a symlink to the corresponding file in the
// runtime APEX.
- translatedArch := ctx.Target().NativeBridge == android.NativeBridgeEnabled || !ctx.Arch().Native
- if installToBootstrap(ctx.baseModuleName(), ctx.Config()) && !library.buildStubs() && !translatedArch && !ctx.inRecovery() {
- if ctx.Device() && isBionic(ctx.baseModuleName()) {
+ translatedArch := ctx.Target().NativeBridge == android.NativeBridgeEnabled
+ if InstallToBootstrap(ctx.baseModuleName(), ctx.Config()) && !library.buildStubs() && !translatedArch && !ctx.inRecovery() {
+ if ctx.Device() {
library.installSymlinkToRuntimeApex(ctx, file)
}
library.baseInstaller.subDir = "bootstrap"
@@ -1095,10 +1124,33 @@
return library.MutatedProperties.BuildStubs
}
+func (library *libraryDecorator) symbolFileForAbiCheck(ctx ModuleContext) *string {
+ if library.Properties.Header_abi_checker.Symbol_file != nil {
+ return library.Properties.Header_abi_checker.Symbol_file
+ }
+ if ctx.hasStubsVariants() && library.Properties.Stubs.Symbol_file != nil {
+ return library.Properties.Stubs.Symbol_file
+ }
+ return nil
+}
+
func (library *libraryDecorator) stubsVersion() string {
return library.MutatedProperties.StubsVersion
}
+func (library *libraryDecorator) availableFor(what string) bool {
+ var list []string
+ if library.static() {
+ list = library.StaticProperties.Static.Apex_available
+ } else if library.shared() {
+ list = library.SharedProperties.Shared.Apex_available
+ }
+ if len(list) == 0 {
+ return false
+ }
+ return android.CheckAvailableForApex(what, list)
+}
+
var versioningMacroNamesListKey = android.NewOnceKey("versioningMacroNamesList")
func versioningMacroNamesList(config android.Config) *map[string]string {
@@ -1147,16 +1199,16 @@
// Check libraries in addition to cflags, since libraries may be exporting different
// include directories.
- if len(staticCompiler.Properties.Static.Cflags) == 0 &&
- len(sharedCompiler.Properties.Shared.Cflags) == 0 &&
- len(staticCompiler.Properties.Static.Whole_static_libs) == 0 &&
- len(sharedCompiler.Properties.Shared.Whole_static_libs) == 0 &&
- len(staticCompiler.Properties.Static.Static_libs) == 0 &&
- len(sharedCompiler.Properties.Shared.Static_libs) == 0 &&
- len(staticCompiler.Properties.Static.Shared_libs) == 0 &&
- len(sharedCompiler.Properties.Shared.Shared_libs) == 0 &&
- staticCompiler.Properties.Static.System_shared_libs == nil &&
- sharedCompiler.Properties.Shared.System_shared_libs == nil {
+ if len(staticCompiler.StaticProperties.Static.Cflags) == 0 &&
+ len(sharedCompiler.SharedProperties.Shared.Cflags) == 0 &&
+ len(staticCompiler.StaticProperties.Static.Whole_static_libs) == 0 &&
+ len(sharedCompiler.SharedProperties.Shared.Whole_static_libs) == 0 &&
+ len(staticCompiler.StaticProperties.Static.Static_libs) == 0 &&
+ len(sharedCompiler.SharedProperties.Shared.Static_libs) == 0 &&
+ len(staticCompiler.StaticProperties.Static.Shared_libs) == 0 &&
+ len(sharedCompiler.SharedProperties.Shared.Shared_libs) == 0 &&
+ staticCompiler.StaticProperties.Static.System_shared_libs == nil &&
+ sharedCompiler.SharedProperties.Shared.System_shared_libs == nil {
mctx.AddInterVariantDependency(reuseObjTag, shared, static)
sharedCompiler.baseCompiler.Properties.OriginalSrcs =
@@ -1286,3 +1338,39 @@
}
}
}
+
+// maybeInjectBoringSSLHash adds a rule to run bssl_inject_hash on the output file if the module has the
+// inject_bssl_hash or if any static library dependencies have inject_bssl_hash set. It returns the output path
+// that the linked output file should be written to.
+// TODO(b/137267623): Remove this in favor of a cc_genrule when they support operating on shared libraries.
+func maybeInjectBoringSSLHash(ctx android.ModuleContext, outputFile android.ModuleOutPath,
+ inject *bool, fileName string) android.ModuleOutPath {
+ // TODO(b/137267623): Remove this in favor of a cc_genrule when they support operating on shared libraries.
+ injectBoringSSLHash := Bool(inject)
+ ctx.VisitDirectDeps(func(dep android.Module) {
+ tag := ctx.OtherModuleDependencyTag(dep)
+ if tag == staticDepTag || tag == staticExportDepTag || tag == wholeStaticDepTag || tag == lateStaticDepTag {
+ if cc, ok := dep.(*Module); ok {
+ if library, ok := cc.linker.(*libraryDecorator); ok {
+ if Bool(library.Properties.Inject_bssl_hash) {
+ injectBoringSSLHash = true
+ }
+ }
+ }
+ }
+ })
+ if injectBoringSSLHash {
+ hashedOutputfile := outputFile
+ outputFile = android.PathForModuleOut(ctx, "unhashed", fileName)
+
+ rule := android.NewRuleBuilder()
+ rule.Command().
+ BuiltTool(ctx, "bssl_inject_hash").
+ Flag("-sha256").
+ FlagWithInput("-in-object ", outputFile).
+ FlagWithOutput("-o ", hashedOutputfile)
+ rule.Build(pctx, ctx, "injectCryptoHash", "inject crypto hash")
+ }
+
+ return outputFile
+}
diff --git a/cc/linker.go b/cc/linker.go
index 563ad04..e5e1486 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -491,7 +491,7 @@
gen_sorted_bss_symbols = pctx.AndroidStaticRule("gen_sorted_bss_symbols",
blueprint.RuleParams{
Command: "CROSS_COMPILE=$crossCompile $genSortedBssSymbolsPath ${in} ${out}",
- CommandDeps: []string{"$genSortedBssSymbolsPath"},
+ CommandDeps: []string{"$genSortedBssSymbolsPath", "${crossCompile}nm"},
},
"crossCompile")
)
diff --git a/cc/llndk_library.go b/cc/llndk_library.go
index 4d59975..9cbe800 100644
--- a/cc/llndk_library.go
+++ b/cc/llndk_library.go
@@ -76,7 +76,7 @@
}
func (stub *llndkStubDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
- vndk_ver := ctx.DeviceConfig().VndkVersion()
+ vndk_ver := ctx.Module().(*Module).Properties.VndkVersion
if vndk_ver == "current" {
platform_vndk_ver := ctx.DeviceConfig().PlatformVndkVersion()
if !inList(platform_vndk_ver, ctx.Config().PlatformVersionCombinedCodenames()) {
@@ -177,7 +177,6 @@
libraryDecorator: library,
}
stub.Properties.Vendor_available = BoolPtr(true)
- module.Properties.UseVndk = true
module.compiler = stub
module.linker = stub
module.installer = nil
diff --git a/cc/ndk_headers.go b/cc/ndk_headers.go
index 4065128..b8423be 100644
--- a/cc/ndk_headers.go
+++ b/cc/ndk_headers.go
@@ -48,7 +48,7 @@
}
// Returns the NDK base include path for use with sdk_version current. Usable with -I.
-func getCurrentIncludePath(ctx android.ModuleContext) android.OutputPath {
+func getCurrentIncludePath(ctx android.ModuleContext) android.InstallPath {
return getNdkSysrootBase(ctx).Join(ctx, "usr/include")
}
@@ -94,7 +94,7 @@
}
func getHeaderInstallDir(ctx android.ModuleContext, header android.Path, from string,
- to string) android.OutputPath {
+ to string) android.InstallPath {
// Output path is the sysroot base + "usr/include" + to directory + directory component
// of the file without the leading from directory stripped.
//
diff --git a/cc/ndk_sysroot.go b/cc/ndk_sysroot.go
index e39bae5..f6de4ef 100644
--- a/cc/ndk_sysroot.go
+++ b/cc/ndk_sysroot.go
@@ -66,12 +66,12 @@
pctx.Import("android/soong/android")
}
-func getNdkInstallBase(ctx android.PathContext) android.OutputPath {
- return android.PathForOutput(ctx, "ndk")
+func getNdkInstallBase(ctx android.PathContext) android.InstallPath {
+ return android.PathForNdkInstall(ctx)
}
// Returns the main install directory for the NDK sysroot. Usable with --sysroot.
-func getNdkSysrootBase(ctx android.PathContext) android.OutputPath {
+func getNdkSysrootBase(ctx android.PathContext) android.InstallPath {
return getNdkInstallBase(ctx).Join(ctx, "sysroot")
}
diff --git a/cc/object.go b/cc/object.go
index 1a2711d..31729a5 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -52,8 +52,9 @@
// input to a cc_genrule module.
func ObjectFactory() android.Module {
module := newBaseModule(android.HostAndDeviceSupported, android.MultilibBoth)
+ module.sanitize = &sanitize{}
module.linker = &objectLinker{
- baseLinker: NewBaseLinker(nil),
+ baseLinker: NewBaseLinker(module.sanitize),
}
module.compiler = NewBaseCompiler()
@@ -103,7 +104,7 @@
var outputFile android.Path
builderFlags := flagsToBuilderFlags(flags)
- if len(objs.objFiles) == 1 {
+ if len(objs.objFiles) == 1 && String(object.Properties.Linker_script) == "" {
outputFile = objs.objFiles[0]
if String(object.Properties.Prefix_symbols) != "" {
@@ -123,7 +124,7 @@
output = input
}
- TransformObjsToObj(ctx, objs.objFiles, builderFlags, output)
+ TransformObjsToObj(ctx, objs.objFiles, builderFlags, output, flags.LdFlagsDeps)
}
ctx.CheckbuildFile(outputFile)
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index dc6c43a..4e6cdd7 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -19,8 +19,8 @@
)
func init() {
- android.RegisterModuleType("cc_prebuilt_library_shared", prebuiltSharedLibraryFactory)
- android.RegisterModuleType("cc_prebuilt_library_static", prebuiltStaticLibraryFactory)
+ android.RegisterModuleType("cc_prebuilt_library_shared", PrebuiltSharedLibraryFactory)
+ android.RegisterModuleType("cc_prebuilt_library_static", PrebuiltStaticLibraryFactory)
android.RegisterModuleType("cc_prebuilt_binary", prebuiltBinaryFactory)
}
@@ -97,7 +97,7 @@
if p.shared() {
p.unstrippedOutputFile = in
- libName := ctx.baseModuleName() + flags.Toolchain.ShlibSuffix()
+ libName := p.libraryDecorator.getLibName(ctx) + flags.Toolchain.ShlibSuffix()
if p.needsStrip(ctx) {
stripped := android.PathForModuleOut(ctx, "stripped", libName)
p.stripExecutableOrSharedLib(ctx, in, stripped, builderFlags)
@@ -131,7 +131,7 @@
// cc_prebuilt_library_shared installs a precompiled shared library that are
// listed in the srcs property in the device's directory.
-func prebuiltSharedLibraryFactory() android.Module {
+func PrebuiltSharedLibraryFactory() android.Module {
module, _ := NewPrebuiltSharedLibrary(android.HostAndDeviceSupported)
return module.Init()
}
@@ -152,13 +152,14 @@
// Prebuilt libraries can be included in APEXes
android.InitApexModule(module)
+ android.InitSdkAwareModule(module)
return module, library
}
// cc_prebuilt_library_static installs a precompiled static library that are
// listed in the srcs property in the device's directory.
-func prebuiltStaticLibraryFactory() android.Module {
+func PrebuiltStaticLibraryFactory() android.Module {
module, _ := NewPrebuiltStaticLibrary(android.HostAndDeviceSupported)
return module.Init()
}
@@ -176,6 +177,7 @@
module.AddProperties(&prebuilt.properties)
android.InitPrebuiltModule(module, &prebuilt.properties.Srcs)
+ android.InitSdkAwareModule(module)
return module, library
}
diff --git a/cc/prebuilt_test.go b/cc/prebuilt_test.go
index 98d78e8..edcd26e 100644
--- a/cc/prebuilt_test.go
+++ b/cc/prebuilt_test.go
@@ -72,8 +72,8 @@
ctx := CreateTestContext(bp, fs, android.Android)
- ctx.RegisterModuleType("cc_prebuilt_library_shared", android.ModuleFactoryAdaptor(prebuiltSharedLibraryFactory))
- ctx.RegisterModuleType("cc_prebuilt_library_static", android.ModuleFactoryAdaptor(prebuiltStaticLibraryFactory))
+ ctx.RegisterModuleType("cc_prebuilt_library_shared", android.ModuleFactoryAdaptor(PrebuiltSharedLibraryFactory))
+ ctx.RegisterModuleType("cc_prebuilt_library_static", android.ModuleFactoryAdaptor(PrebuiltStaticLibraryFactory))
ctx.RegisterModuleType("cc_prebuilt_binary", android.ModuleFactoryAdaptor(prebuiltBinaryFactory))
ctx.PreArchMutators(android.RegisterPrebuiltsPreArchMutators)
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 192b8d9..5172fc8 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -56,7 +56,8 @@
minimalRuntimeFlags = []string{"-fsanitize-minimal-runtime", "-fno-sanitize-trap=integer,undefined",
"-fno-sanitize-recover=integer,undefined"}
- hwasanGlobalOptions = []string{"heap_history_size=1023,stack_history_size=512"}
+ hwasanGlobalOptions = []string{"heap_history_size=1023", "stack_history_size=512",
+ "export_memory_stats=0", "max_malloc_fill_size=0"}
)
type sanitizerType int
@@ -464,7 +465,6 @@
if Bool(sanitize.Properties.Sanitize.Fuzzer) {
flags.CFlags = append(flags.CFlags, "-fsanitize=fuzzer-no-link")
- flags.LdFlags = append(flags.LdFlags, "-fsanitize=fuzzer-no-link")
// TODO(b/131771163): LTO and Fuzzer support is mutually incompatible.
_, flags.LdFlags = removeFromList("-flto", flags.LdFlags)
@@ -472,9 +472,21 @@
flags.LdFlags = append(flags.LdFlags, "-fno-lto")
flags.CFlags = append(flags.CFlags, "-fno-lto")
+ // TODO(b/142430592): Upstream linker scripts for sanitizer runtime libraries
+ // discard the sancov_lowest_stack symbol, because it's emulated TLS (and thus
+ // doesn't match the linker script due to the "__emutls_v." prefix).
+ flags.LdFlags = append(flags.LdFlags, "-fno-sanitize-coverage=stack-depth")
+ flags.CFlags = append(flags.CFlags, "-fno-sanitize-coverage=stack-depth")
+
// TODO(b/133876586): Experimental PM breaks sanitizer coverage.
_, flags.CFlags = removeFromList("-fexperimental-new-pass-manager", flags.CFlags)
flags.CFlags = append(flags.CFlags, "-fno-experimental-new-pass-manager")
+
+ // Disable fortify for fuzzing builds. Generally, we'll be building with
+ // UBSan or ASan here and the fortify checks pollute the stack traces.
+ _, flags.CFlags = removeFromList("-D_FORTIFY_SOURCE=1", flags.CFlags)
+ _, flags.CFlags = removeFromList("-D_FORTIFY_SOURCE=2", flags.CFlags)
+ flags.CFlags = append(flags.CFlags, "-U_FORTIFY_SOURCE")
}
if Bool(sanitize.Properties.Sanitize.Cfi) {
@@ -667,7 +679,7 @@
func isSanitizableDependencyTag(tag blueprint.DependencyTag) bool {
t, ok := tag.(dependencyTag)
- return ok && t.library || t == reuseObjTag
+ return ok && t.library || t == reuseObjTag || t == objDepTag
}
// Propagate sanitizer requirements down from binaries
@@ -853,7 +865,8 @@
} else {
runtimeLibrary = config.ScudoRuntimeLibrary(toolchain)
}
- } else if len(diagSanitizers) > 0 || c.sanitize.Properties.UbsanRuntimeDep {
+ } else if len(diagSanitizers) > 0 || c.sanitize.Properties.UbsanRuntimeDep ||
+ Bool(c.sanitize.Properties.Sanitize.Fuzzer) {
runtimeLibrary = config.UndefinedBehaviorSanitizerRuntimeLibrary(toolchain)
}
@@ -871,18 +884,16 @@
// added to libFlags and LOCAL_SHARED_LIBRARIES by cc.Module
if c.staticBinary() {
// static executable gets static runtime libs
- mctx.AddFarVariationDependencies([]blueprint.Variation{
+ mctx.AddFarVariationDependencies(append(mctx.Target().Variations(), []blueprint.Variation{
{Mutator: "link", Variation: "static"},
{Mutator: "image", Variation: c.imageVariation()},
- {Mutator: "arch", Variation: mctx.Target().String()},
- }, staticDepTag, runtimeLibrary)
+ }...), staticDepTag, runtimeLibrary)
} else if !c.static() && !c.header() {
// dynamic executable and shared libs get shared runtime libs
- mctx.AddFarVariationDependencies([]blueprint.Variation{
+ mctx.AddFarVariationDependencies(append(mctx.Target().Variations(), []blueprint.Variation{
{Mutator: "link", Variation: "shared"},
{Mutator: "image", Variation: c.imageVariation()},
- {Mutator: "arch", Variation: mctx.Target().String()},
- }, earlySharedDepTag, runtimeLibrary)
+ }...), earlySharedDepTag, runtimeLibrary)
}
// static lib does not have dependency to the runtime library. The
// dependency will be added to the executables or shared libs using
diff --git a/cc/stl.go b/cc/stl.go
index 458129c..aa34240 100644
--- a/cc/stl.go
+++ b/cc/stl.go
@@ -221,13 +221,13 @@
if !ctx.toolchain().Bionic() {
flags.CppFlags = append(flags.CppFlags, "-nostdinc++")
- flags.extraLibFlags = append(flags.extraLibFlags, "-nodefaultlibs")
- if ctx.staticBinary() {
- flags.extraLibFlags = append(flags.extraLibFlags, hostStaticGccLibs[ctx.Os()]...)
- } else {
- flags.extraLibFlags = append(flags.extraLibFlags, hostDynamicGccLibs[ctx.Os()]...)
- }
+ flags.extraLibFlags = append(flags.extraLibFlags, "-nostdlib++")
if ctx.Windows() {
+ if stl.Properties.SelectedStl == "libc++_static" {
+ // These are transitively needed by libc++_static.
+ flags.extraLibFlags = append(flags.extraLibFlags,
+ "-lmsvcrt", "-lucrt")
+ }
// Use SjLj exceptions for 32-bit. libgcc_eh implements SjLj
// exception model for 32-bit.
if ctx.Arch().ArchType == android.X86 {
@@ -260,12 +260,7 @@
// None or error.
if !ctx.toolchain().Bionic() {
flags.CppFlags = append(flags.CppFlags, "-nostdinc++")
- flags.extraLibFlags = append(flags.extraLibFlags, "-nodefaultlibs")
- if ctx.staticBinary() {
- flags.extraLibFlags = append(flags.extraLibFlags, hostStaticGccLibs[ctx.Os()]...)
- } else {
- flags.extraLibFlags = append(flags.extraLibFlags, hostDynamicGccLibs[ctx.Os()]...)
- }
+ flags.extraLibFlags = append(flags.extraLibFlags, "-nostdlib++")
}
default:
panic(fmt.Errorf("Unknown stl: %q", stl.Properties.SelectedStl))
@@ -273,22 +268,3 @@
return flags
}
-
-var hostDynamicGccLibs, hostStaticGccLibs map[android.OsType][]string
-
-func init() {
- hostDynamicGccLibs = map[android.OsType][]string{
- android.Fuchsia: []string{"-lc", "-lunwind"},
- android.Linux: []string{"-lgcc_s", "-lgcc", "-lc", "-lgcc_s", "-lgcc"},
- android.Darwin: []string{"-lc", "-lSystem"},
- android.Windows: []string{"-Wl,--start-group", "-lmingw32", "-lgcc", "-lgcc_eh",
- "-lmoldname", "-lmingwex", "-lmsvcrt", "-lucrt", "-lpthread",
- "-ladvapi32", "-lshell32", "-luser32", "-lkernel32", "-lpsapi",
- "-Wl,--end-group"},
- }
- hostStaticGccLibs = map[android.OsType][]string{
- android.Linux: []string{"-Wl,--start-group", "-lgcc", "-lgcc_eh", "-lc", "-Wl,--end-group"},
- android.Darwin: []string{"NO_STATIC_HOST_BINARIES_ON_DARWIN"},
- android.Windows: []string{"NO_STATIC_HOST_BINARIES_ON_WINDOWS"},
- }
-}
diff --git a/cc/strip.go b/cc/strip.go
index f3e3374..7e560ec 100644
--- a/cc/strip.go
+++ b/cc/strip.go
@@ -27,7 +27,6 @@
Keep_symbols *bool `android:"arch_variant"`
Keep_symbols_list []string `android:"arch_variant"`
Keep_symbols_and_debug_frame *bool `android:"arch_variant"`
- Use_gnu_strip *bool `android:"arch_variant"`
} `android:"arch_variant"`
}
@@ -54,9 +53,6 @@
} else if !Bool(stripper.StripProperties.Strip.All) {
flags.stripKeepMiniDebugInfo = true
}
- if Bool(stripper.StripProperties.Strip.Use_gnu_strip) {
- flags.stripUseGnuStrip = true
- }
if ctx.Config().Debuggable() && !flags.stripKeepMiniDebugInfo && !isStaticLib {
flags.stripAddGnuDebuglink = true
}
diff --git a/cc/test.go b/cc/test.go
index aff8ba5..0e66e28 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -16,6 +16,7 @@
import (
"path/filepath"
+ "strconv"
"strings"
"android/soong/android"
@@ -68,6 +69,22 @@
// Add RootTargetPreparer to auto generated test config. This guarantees the test to run
// with root permission.
Require_root *bool
+
+ // Add RunCommandTargetPreparer to stop framework before the test and start it after the test.
+ Disable_framework *bool
+
+ // Add MinApiLevelModuleController to auto generated test config. If the device property of
+ // "ro.product.first_api_level" < Test_min_api_level, then skip this module.
+ Test_min_api_level *int64
+
+ // Add MinApiLevelModuleController to auto generated test config. If the device property of
+ // "ro.build.version.sdk" < Test_min_sdk_version, then skip this module.
+ Test_min_sdk_version *int64
+
+ // Flag to indicate whether or not to create test config automatically. If AndroidTest.xml
+ // doesn't exist next to the Android.bp, this attribute doesn't need to be set to true
+ // explicitly.
+ Auto_gen_config *bool
}
func init() {
@@ -311,9 +328,21 @@
func (test *testBinary) install(ctx ModuleContext, file android.Path) {
test.data = android.PathsForModuleSrc(ctx, test.Properties.Data)
+ var api_level_prop string
var configs []tradefed.Config
+ var min_level string
if Bool(test.Properties.Require_root) {
- configs = append(configs, tradefed.Preparer{"com.android.tradefed.targetprep.RootTargetPreparer"})
+ configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RootTargetPreparer", nil})
+ } else {
+ var options []tradefed.Option
+ options = append(options, tradefed.Option{"force-root", "false"})
+ configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RootTargetPreparer", options})
+ }
+ if Bool(test.Properties.Disable_framework) {
+ var options []tradefed.Option
+ options = append(options, tradefed.Option{"run-command", "stop"})
+ options = append(options, tradefed.Option{"teardown-command", "start"})
+ configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RunCommandTargetPreparer", options})
}
if Bool(test.testDecorator.Properties.Isolated) {
configs = append(configs, tradefed.Option{"not-shardable", "true"})
@@ -321,9 +350,24 @@
if test.Properties.Test_options.Run_test_as != nil {
configs = append(configs, tradefed.Option{"run-test-as", String(test.Properties.Test_options.Run_test_as)})
}
+ if test.Properties.Test_min_api_level != nil && test.Properties.Test_min_sdk_version != nil {
+ ctx.PropertyErrorf("test_min_api_level", "'test_min_api_level' and 'test_min_sdk_version' should not be set at the same time.")
+ } else if test.Properties.Test_min_api_level != nil {
+ api_level_prop = "ro.product.first_api_level"
+ min_level = strconv.FormatInt(int64(*test.Properties.Test_min_api_level), 10)
+ } else if test.Properties.Test_min_sdk_version != nil {
+ api_level_prop = "ro.build.version.sdk"
+ min_level = strconv.FormatInt(int64(*test.Properties.Test_min_sdk_version), 10)
+ }
+ if api_level_prop != "" {
+ var options []tradefed.Option
+ options = append(options, tradefed.Option{"min-api-level", min_level})
+ options = append(options, tradefed.Option{"api-level-prop", api_level_prop})
+ configs = append(configs, tradefed.Object{"module_controller", "com.android.tradefed.testtype.suite.module.MinApiLevelModuleController", options})
+ }
test.testConfig = tradefed.AutoGenNativeTestConfig(ctx, test.Properties.Test_config,
- test.Properties.Test_config_template, test.Properties.Test_suites, configs)
+ test.Properties.Test_config_template, test.Properties.Test_suites, configs, test.Properties.Auto_gen_config)
test.binaryDecorator.baseInstaller.dir = "nativetest"
test.binaryDecorator.baseInstaller.dir64 = "nativetest64"
@@ -414,6 +458,11 @@
// Add RootTargetPreparer to auto generated test config. This guarantees the test to run
// with root permission.
Require_root *bool
+
+ // Flag to indicate whether or not to create test config automatically. If AndroidTest.xml
+ // doesn't exist next to the Android.bp, this attribute doesn't need to be set to true
+ // explicitly.
+ Auto_gen_config *bool
}
type benchmarkDecorator struct {
@@ -448,10 +497,10 @@
benchmark.data = android.PathsForModuleSrc(ctx, benchmark.Properties.Data)
var configs []tradefed.Config
if Bool(benchmark.Properties.Require_root) {
- configs = append(configs, tradefed.Preparer{"com.android.tradefed.targetprep.RootTargetPreparer"})
+ configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RootTargetPreparer", nil})
}
benchmark.testConfig = tradefed.AutoGenNativeBenchmarkTestConfig(ctx, benchmark.Properties.Test_config,
- benchmark.Properties.Test_config_template, benchmark.Properties.Test_suites, configs)
+ benchmark.Properties.Test_config_template, benchmark.Properties.Test_suites, configs, benchmark.Properties.Auto_gen_config)
benchmark.binaryDecorator.baseInstaller.dir = filepath.Join("benchmarktest", ctx.ModuleName())
benchmark.binaryDecorator.baseInstaller.dir64 = filepath.Join("benchmarktest64", ctx.ModuleName())
diff --git a/cc/testing.go b/cc/testing.go
index 5a3993c..6fa6ea7 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -190,6 +190,7 @@
name: "crtbegin_so",
recovery_available: true,
vendor_available: true,
+ stl: "none",
}
cc_object {
@@ -208,6 +209,7 @@
name: "crtend_so",
recovery_available: true,
vendor_available: true,
+ stl: "none",
}
cc_object {
@@ -239,6 +241,7 @@
os android.OsType) *android.TestContext {
ctx := android.NewTestArchContext()
+ ctx.RegisterModuleType("cc_defaults", android.ModuleFactoryAdaptor(defaultsFactory))
ctx.RegisterModuleType("cc_binary", android.ModuleFactoryAdaptor(BinaryFactory))
ctx.RegisterModuleType("cc_binary_host", android.ModuleFactoryAdaptor(binaryHostFactory))
ctx.RegisterModuleType("cc_fuzz", android.ModuleFactoryAdaptor(FuzzFactory))
@@ -253,7 +256,7 @@
ctx.RegisterModuleType("vendor_public_library", android.ModuleFactoryAdaptor(vendorPublicLibraryFactory))
ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(ObjectFactory))
ctx.RegisterModuleType("filegroup", android.ModuleFactoryAdaptor(android.FileGroupFactory))
- ctx.RegisterModuleType("vndk_prebuilt_shared", android.ModuleFactoryAdaptor(vndkPrebuiltSharedFactory))
+ ctx.RegisterModuleType("vndk_prebuilt_shared", android.ModuleFactoryAdaptor(VndkPrebuiltSharedFactory))
ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
ctx.BottomUp("image", ImageMutator).Parallel()
ctx.BottomUp("link", LinkageMutator).Parallel()
@@ -264,6 +267,7 @@
ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
ctx.TopDown("double_loadable", checkDoubleLoadableLibraries).Parallel()
})
+ ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
ctx.RegisterSingletonType("vndk-snapshot", android.SingletonFactoryAdaptor(VndkSnapshotSingleton))
// add some modules that are required by the compiler and/or linker
@@ -274,6 +278,7 @@
"foo.c": nil,
"foo.lds": nil,
"bar.c": nil,
+ "baz.c": nil,
"baz.o": nil,
"a.proto": nil,
"b.aidl": nil,
diff --git a/cc/util.go b/cc/util.go
index fb6338a..2f7bec2 100644
--- a/cc/util.go
+++ b/cc/util.go
@@ -79,7 +79,8 @@
systemIncludeFlags: strings.Join(in.SystemIncludeFlags, " "),
- groupStaticLibs: in.GroupStaticLibs,
+ assemblerWithCpp: in.AssemblerWithCpp,
+ groupStaticLibs: in.GroupStaticLibs,
proto: in.proto,
protoC: in.protoC,
@@ -103,32 +104,6 @@
return list
}
-var shlibVersionPattern = regexp.MustCompile("(?:\\.\\d+(?:svn)?)+")
-
-// splitFileExt splits a file name into root, suffix and ext. root stands for the file name without
-// the file extension and the version number (e.g. "libexample"). suffix stands for the
-// concatenation of the file extension and the version number (e.g. ".so.1.0"). ext stands for the
-// file extension after the version numbers are trimmed (e.g. ".so").
-func splitFileExt(name string) (string, string, string) {
- // Extract and trim the shared lib version number if the file name ends with dot digits.
- suffix := ""
- matches := shlibVersionPattern.FindAllStringIndex(name, -1)
- if len(matches) > 0 {
- lastMatch := matches[len(matches)-1]
- if lastMatch[1] == len(name) {
- suffix = name[lastMatch[0]:lastMatch[1]]
- name = name[0:lastMatch[0]]
- }
- }
-
- // Extract the file name root and the file extension.
- ext := filepath.Ext(name)
- root := strings.TrimSuffix(name, ext)
- suffix = ext + suffix
-
- return root, suffix, ext
-}
-
// linkDirOnDevice/linkName -> target
func makeSymlinkCmd(linkDirOnDevice string, linkName string, target string) string {
dir := filepath.Join("$(PRODUCT_OUT)", linkDirOnDevice)
diff --git a/cc/util_test.go b/cc/util_test.go
deleted file mode 100644
index 7c718ea..0000000
--- a/cc/util_test.go
+++ /dev/null
@@ -1,84 +0,0 @@
-// 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 cc
-
-import (
- "testing"
-)
-
-func TestSplitFileExt(t *testing.T) {
- t.Run("soname with version", func(t *testing.T) {
- root, suffix, ext := splitFileExt("libtest.so.1.0.30")
- expected := "libtest"
- if root != expected {
- t.Errorf("root should be %q but got %q", expected, root)
- }
- expected = ".so.1.0.30"
- if suffix != expected {
- t.Errorf("suffix should be %q but got %q", expected, suffix)
- }
- expected = ".so"
- if ext != expected {
- t.Errorf("ext should be %q but got %q", expected, ext)
- }
- })
-
- t.Run("soname with svn version", func(t *testing.T) {
- root, suffix, ext := splitFileExt("libtest.so.1svn")
- expected := "libtest"
- if root != expected {
- t.Errorf("root should be %q but got %q", expected, root)
- }
- expected = ".so.1svn"
- if suffix != expected {
- t.Errorf("suffix should be %q but got %q", expected, suffix)
- }
- expected = ".so"
- if ext != expected {
- t.Errorf("ext should be %q but got %q", expected, ext)
- }
- })
-
- t.Run("version numbers in the middle should be ignored", func(t *testing.T) {
- root, suffix, ext := splitFileExt("libtest.1.0.30.so")
- expected := "libtest.1.0.30"
- if root != expected {
- t.Errorf("root should be %q but got %q", expected, root)
- }
- expected = ".so"
- if suffix != expected {
- t.Errorf("suffix should be %q but got %q", expected, suffix)
- }
- expected = ".so"
- if ext != expected {
- t.Errorf("ext should be %q but got %q", expected, ext)
- }
- })
-
- t.Run("no known file extension", func(t *testing.T) {
- root, suffix, ext := splitFileExt("test.exe")
- expected := "test"
- if root != expected {
- t.Errorf("root should be %q but got %q", expected, root)
- }
- expected = ".exe"
- if suffix != expected {
- t.Errorf("suffix should be %q but got %q", expected, suffix)
- }
- if ext != expected {
- t.Errorf("ext should be %q but got %q", expected, ext)
- }
- })
-}
diff --git a/cc/vndk.go b/cc/vndk.go
index 2a86f5b..14bbf11 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -49,10 +49,6 @@
// Extending another module
Extends *string
-
- // for vndk_prebuilt_shared, this is set by "version" property.
- // Otherwise, this is set as PLATFORM_VNDK_VERSION.
- Version string `blueprint:"mutated"`
}
}
@@ -129,7 +125,7 @@
// Other (static and LL-NDK) libraries are allowed to link.
return
}
- if !to.Properties.UseVndk {
+ if !to.useVndk() {
ctx.ModuleErrorf("(%s) should not link to %q which is not a vendor-available library",
vndk.typeName(), to.Name())
return
@@ -317,17 +313,12 @@
if !ok {
return
}
-
if !m.Enabled() {
return
}
-
- if m.isVndk() {
- if lib, ok := m.linker.(*vndkPrebuiltLibraryDecorator); ok {
- m.vndkdep.Properties.Vndk.Version = lib.version()
- } else {
- m.vndkdep.Properties.Vndk.Version = mctx.DeviceConfig().PlatformVndkVersion()
- }
+ if m.Target().NativeBridge == android.NativeBridgeEnabled {
+ // Skip native_bridge modules
+ return
}
if _, ok := m.linker.(*llndkStubDecorator); ok {
@@ -338,8 +329,8 @@
lib, is_lib := m.linker.(*libraryDecorator)
prebuilt_lib, is_prebuilt_lib := m.linker.(*prebuiltLibraryLinker)
- if (is_lib && lib.shared()) || (is_prebuilt_lib && prebuilt_lib.shared()) {
- if m.vndkdep.isVndk() && !m.vndkdep.isVndkExt() {
+ if (is_lib && lib.buildShared()) || (is_prebuilt_lib && prebuilt_lib.buildShared()) {
+ if m.vndkdep != nil && m.vndkdep.isVndk() && !m.vndkdep.isVndkExt() {
processVndkLibrary(mctx, m)
return
}
diff --git a/cc/vndk_prebuilt.go b/cc/vndk_prebuilt.go
index c8ff87f..2cebb6d 100644
--- a/cc/vndk_prebuilt.go
+++ b/cc/vndk_prebuilt.go
@@ -129,6 +129,18 @@
func (p *vndkPrebuiltLibraryDecorator) link(ctx ModuleContext,
flags Flags, deps PathDeps, objs Objects) android.Path {
+
+ arches := ctx.DeviceConfig().Arches()
+ if len(arches) == 0 || arches[0].ArchType.String() != p.arch() {
+ ctx.Module().SkipInstall()
+ return nil
+ }
+
+ if ctx.DeviceConfig().BinderBitness() != p.binderBit() {
+ ctx.Module().SkipInstall()
+ return nil
+ }
+
if len(p.properties.Srcs) > 0 && p.shared() {
p.libraryDecorator.exportIncludes(ctx)
p.libraryDecorator.reexportSystemDirs(p.properties.Export_system_include_dirs...)
@@ -136,9 +148,15 @@
// current VNDK prebuilts are only shared libs.
return p.singleSourcePath(ctx)
}
+
+ ctx.Module().SkipInstall()
return nil
}
+func (p *vndkPrebuiltLibraryDecorator) nativeCoverage() bool {
+ return false
+}
+
func (p *vndkPrebuiltLibraryDecorator) install(ctx ModuleContext, file android.Path) {
arches := ctx.DeviceConfig().Arches()
if len(arches) == 0 || arches[0].ArchType.String() != p.arch() {
@@ -163,13 +181,19 @@
module.stl = nil
module.sanitize = nil
library.StripProperties.Strip.None = BoolPtr(true)
- module.Properties.UseVndk = true
prebuilt := &vndkPrebuiltLibraryDecorator{
libraryDecorator: library,
}
prebuilt.properties.Check_elf_files = BoolPtr(false)
+ prebuilt.baseLinker.Properties.No_libcrt = BoolPtr(true)
+ prebuilt.baseLinker.Properties.Nocrt = BoolPtr(true)
+
+ // Prevent default system libs (libc, libm, and libdl) from being linked
+ if prebuilt.baseLinker.Properties.System_shared_libs == nil {
+ prebuilt.baseLinker.Properties.System_shared_libs = []string{}
+ }
module.compiler = nil
module.linker = prebuilt
@@ -202,11 +226,11 @@
// },
// },
// }
-func vndkPrebuiltSharedFactory() android.Module {
+func VndkPrebuiltSharedFactory() android.Module {
module := vndkPrebuiltSharedLibrary()
return module.Init()
}
func init() {
- android.RegisterModuleType("vndk_prebuilt_shared", vndkPrebuiltSharedFactory)
+ android.RegisterModuleType("vndk_prebuilt_shared", VndkPrebuiltSharedFactory)
}
diff --git a/cmd/dep_fixer/Android.bp b/cmd/dep_fixer/Android.bp
index d2d1113..97364d5 100644
--- a/cmd/dep_fixer/Android.bp
+++ b/cmd/dep_fixer/Android.bp
@@ -14,10 +14,6 @@
blueprint_go_binary {
name: "dep_fixer",
- deps: ["androidmk-parser"],
- srcs: [
- "main.go",
- "deps.go",
- ],
- testSrcs: ["deps_test.go"],
+ deps: ["soong-makedeps"],
+ srcs: ["main.go"],
}
diff --git a/cmd/dep_fixer/main.go b/cmd/dep_fixer/main.go
index f94cf2f..d1bd139 100644
--- a/cmd/dep_fixer/main.go
+++ b/cmd/dep_fixer/main.go
@@ -25,6 +25,8 @@
"io/ioutil"
"log"
"os"
+
+ "android/soong/makedeps"
)
func main() {
@@ -39,7 +41,7 @@
log.Fatal("Expected at least one input file as an argument")
}
- var mergedDeps *Deps
+ var mergedDeps *makedeps.Deps
var firstInput []byte
for i, arg := range flag.Args() {
@@ -48,7 +50,7 @@
log.Fatalf("Error opening %q: %v", arg, err)
}
- deps, err := Parse(arg, bytes.NewBuffer(append([]byte(nil), input...)))
+ deps, err := makedeps.Parse(arg, bytes.NewBuffer(append([]byte(nil), input...)))
if err != nil {
log.Fatalf("Failed to parse: %v", err)
}
diff --git a/cmd/merge_zips/merge_zips.go b/cmd/merge_zips/merge_zips.go
index 27179cb..a9be612 100644
--- a/cmd/merge_zips/merge_zips.go
+++ b/cmd/merge_zips/merge_zips.go
@@ -417,7 +417,7 @@
}
oldOlderMiz := miz.older
if oldOlderMiz.newer != miz {
- panic(fmt.Errorf("broken list between %p:%#v and %p:%#v", miz, oldOlderMiz))
+ panic(fmt.Errorf("broken list between %p:%#v and %p:%#v", miz, miz, oldOlderMiz, oldOlderMiz))
}
miz.older = olderMiz
olderMiz.older = oldOlderMiz
diff --git a/cmd/multiproduct_kati/main.go b/cmd/multiproduct_kati/main.go
index 1171a65..2800ade 100644
--- a/cmd/multiproduct_kati/main.go
+++ b/cmd/multiproduct_kati/main.go
@@ -158,7 +158,7 @@
func main() {
stdio := terminal.StdioImpl{}
- output := terminal.NewStatusOutput(stdio.Stdout(), "",
+ output := terminal.NewStatusOutput(stdio.Stdout(), "", false,
build.OsEnvironment().IsEnvTrue("ANDROID_QUIET_BUILD"))
log := logger.New(output)
@@ -391,7 +391,7 @@
Thread: mpctx.Tracer.NewThread(product),
Status: &status.Status{},
}}
- ctx.Status.AddOutput(terminal.NewStatusOutput(ctx.Writer, "",
+ ctx.Status.AddOutput(terminal.NewStatusOutput(ctx.Writer, "", false,
build.OsEnvironment().IsEnvTrue("ANDROID_QUIET_BUILD")))
config := build.NewConfig(ctx, flag.Args()...)
diff --git a/cmd/sbox/Android.bp b/cmd/sbox/Android.bp
index fe4c7bb..a706810d 100644
--- a/cmd/sbox/Android.bp
+++ b/cmd/sbox/Android.bp
@@ -14,6 +14,7 @@
blueprint_go_binary {
name: "sbox",
+ deps: ["soong-makedeps"],
srcs: [
"sbox.go",
],
diff --git a/cmd/sbox/sbox.go b/cmd/sbox/sbox.go
index 4ac9295..7057b33 100644
--- a/cmd/sbox/sbox.go
+++ b/cmd/sbox/sbox.go
@@ -15,6 +15,7 @@
package main
import (
+ "bytes"
"errors"
"flag"
"fmt"
@@ -25,6 +26,8 @@
"path/filepath"
"strings"
"time"
+
+ "android/soong/makedeps"
)
var (
@@ -152,9 +155,6 @@
return err
}
allOutputs = append(allOutputs, sandboxedDepfile)
- if !strings.Contains(rawCommand, "__SBOX_DEPFILE__") {
- return fmt.Errorf("the --depfile-out argument only makes sense if the command contains the text __SBOX_DEPFILE__")
- }
rawCommand = strings.Replace(rawCommand, "__SBOX_DEPFILE__", filepath.Join(tempDir, sandboxedDepfile), -1)
}
@@ -281,6 +281,26 @@
}
}
+ // Rewrite the depfile so that it doesn't include the (randomized) sandbox directory
+ if depfileOut != "" {
+ in, err := ioutil.ReadFile(depfileOut)
+ if err != nil {
+ return err
+ }
+
+ deps, err := makedeps.Parse(depfileOut, bytes.NewBuffer(in))
+ if err != nil {
+ return err
+ }
+
+ deps.Output = "outputfile"
+
+ err = ioutil.WriteFile(depfileOut, deps.Print(), 0666)
+ if err != nil {
+ return err
+ }
+ }
+
// TODO(jeffrygaston) if a process creates more output files than it declares, should there be a warning?
return nil
}
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index 39303bf..974c644 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -41,6 +41,12 @@
// description for the flag (to display when running help)
description string
+ // Forces the status output into dumb terminal mode.
+ forceDumbOutput bool
+
+ // Sets a prefix string to use for filenames of log files.
+ logsPrefix string
+
// Creates the build configuration based on the args and build context.
config func(ctx build.Context, args ...string) build.Config
@@ -64,17 +70,21 @@
stdio: stdio,
run: make,
}, {
- flag: "--dumpvar-mode",
- description: "print the value of the legacy make variable VAR to stdout",
- config: dumpVarConfig,
- stdio: customStdio,
- run: dumpVar,
+ flag: "--dumpvar-mode",
+ description: "print the value of the legacy make variable VAR to stdout",
+ forceDumbOutput: true,
+ logsPrefix: "dumpvars-",
+ config: dumpVarConfig,
+ stdio: customStdio,
+ run: dumpVar,
}, {
- flag: "--dumpvars-mode",
- description: "dump the values of one or more legacy make variables, in shell syntax",
- config: dumpVarConfig,
- stdio: customStdio,
- run: dumpVars,
+ flag: "--dumpvars-mode",
+ description: "dump the values of one or more legacy make variables, in shell syntax",
+ forceDumbOutput: true,
+ logsPrefix: "dumpvars-",
+ config: dumpVarConfig,
+ stdio: customStdio,
+ run: dumpVars,
}, {
flag: "--build-mode",
description: "build modules based on the specified build action",
@@ -113,7 +123,7 @@
os.Exit(1)
}
- output := terminal.NewStatusOutput(c.stdio().Stdout(), os.Getenv("NINJA_STATUS"),
+ output := terminal.NewStatusOutput(c.stdio().Stdout(), os.Getenv("NINJA_STATUS"), c.forceDumbOutput,
build.OsEnvironment().IsEnvTrue("ANDROID_QUIET_BUILD"))
log := logger.New(output)
@@ -157,14 +167,14 @@
}
os.MkdirAll(logsDir, 0777)
- log.SetOutput(filepath.Join(logsDir, "soong.log"))
- trace.SetOutput(filepath.Join(logsDir, "build.trace"))
- stat.AddOutput(status.NewVerboseLog(log, filepath.Join(logsDir, "verbose.log")))
- stat.AddOutput(status.NewErrorLog(log, filepath.Join(logsDir, "error.log")))
- stat.AddOutput(status.NewProtoErrorLog(log, filepath.Join(logsDir, "build_error")))
+ log.SetOutput(filepath.Join(logsDir, c.logsPrefix+"soong.log"))
+ trace.SetOutput(filepath.Join(logsDir, c.logsPrefix+"build.trace"))
+ stat.AddOutput(status.NewVerboseLog(log, filepath.Join(logsDir, c.logsPrefix+"verbose.log")))
+ stat.AddOutput(status.NewErrorLog(log, filepath.Join(logsDir, c.logsPrefix+"error.log")))
+ stat.AddOutput(status.NewProtoErrorLog(log, filepath.Join(logsDir, c.logsPrefix+"build_error")))
stat.AddOutput(status.NewCriticalPath(log))
- defer met.Dump(filepath.Join(logsDir, "soong_metrics"))
+ defer met.Dump(filepath.Join(logsDir, c.logsPrefix+"soong_metrics"))
if start, ok := os.LookupEnv("TRACE_BEGIN_SOONG"); ok {
if !strings.HasSuffix(start, "N") {
@@ -180,6 +190,11 @@
}
}
+ // Fix up the source tree due to a repo bug where it doesn't remove
+ // linkfiles that have been removed
+ fixBadDanglingLink(buildCtx, "hardware/qcom/sdm710/Android.bp")
+ fixBadDanglingLink(buildCtx, "hardware/qcom/sdm710/Android.mk")
+
f := build.NewSourceFinder(buildCtx, config)
defer f.Shutdown()
build.FindSources(buildCtx, config, f)
@@ -187,6 +202,20 @@
c.run(buildCtx, config, args, logsDir)
}
+func fixBadDanglingLink(ctx build.Context, name string) {
+ _, err := os.Lstat(name)
+ if err != nil {
+ return
+ }
+ _, err = os.Stat(name)
+ if os.IsNotExist(err) {
+ err = os.Remove(name)
+ if err != nil {
+ ctx.Fatalf("Failed to remove dangling link %q: %v", name, err)
+ }
+ }
+}
+
func dumpVar(ctx build.Context, config build.Config, args []string, _ string) {
flags := flag.NewFlagSet("dumpvar", flag.ExitOnError)
flags.Usage = func() {
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index 51f5519..9215eff 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -24,8 +24,6 @@
// GlobalConfig stores the configuration for dex preopting set by the product
type GlobalConfig struct {
- DefaultNoStripping bool // don't strip dex files by default
-
DisablePreopt bool // disable preopt for all modules
DisablePreoptModules []string // modules with preopt disabled by product-specific config
@@ -42,7 +40,7 @@
BootJars []string // modules for jars that form the boot class path
- RuntimeApexJars []string // modules for jars that are in the runtime apex
+ ArtApexJars []string // modules for jars that are in the ART APEX
ProductUpdatableBootModules []string
ProductUpdatableBootLocations []string
@@ -55,8 +53,7 @@
DefaultCompilerFilter string // default compiler filter to pass to dex2oat, overridden by --compiler-filter= in module-specific dex2oat flags
SystemServerCompilerFilter string // default compiler filter to pass to dex2oat for system server jars
- GenerateDMFiles bool // generate Dex Metadata files
- NeverAllowStripping bool // whether stripping should not be done - used as build time check to make sure dex files are always available
+ GenerateDMFiles bool // generate Dex Metadata files
NoDebugInfo bool // don't generate debug info by default
DontResolveStartupStrings bool // don't resolve string literals loaded during application startup.
@@ -133,10 +130,6 @@
ForceCreateAppImage bool
PresignedPrebuilt bool
-
- NoStripping bool
- StripInputPath android.Path
- StripOutputPath android.WritablePath
}
func constructPath(ctx android.PathContext, path string) android.Path {
@@ -233,8 +226,6 @@
LibraryPaths map[string]string
DexPreoptImages []string
PreoptBootClassPathDexFiles []string
- StripInputPath string
- StripOutputPath string
}
config := ModuleJSONConfig{}
@@ -252,8 +243,6 @@
config.ModuleConfig.LibraryPaths = constructPathMap(ctx, config.LibraryPaths)
config.ModuleConfig.DexPreoptImages = constructPaths(ctx, config.DexPreoptImages)
config.ModuleConfig.PreoptBootClassPathDexFiles = constructPaths(ctx, config.PreoptBootClassPathDexFiles)
- config.ModuleConfig.StripInputPath = constructPath(ctx, config.StripInputPath)
- config.ModuleConfig.StripOutputPath = constructWritablePath(ctx, config.StripOutputPath)
// This needs to exist, but dependencies are already handled in Make, so we don't need to pass them through JSON.
config.ModuleConfig.DexPreoptImagesDeps = make([]android.Paths, len(config.ModuleConfig.DexPreoptImages))
@@ -283,7 +272,6 @@
func GlobalConfigForTests(ctx android.PathContext) GlobalConfig {
return GlobalConfig{
- DefaultNoStripping: false,
DisablePreopt: false,
DisablePreoptModules: nil,
OnlyPreoptBootImageAndSystemServer: false,
@@ -292,7 +280,7 @@
DisableGenerateProfile: false,
ProfileDir: "",
BootJars: nil,
- RuntimeApexJars: nil,
+ ArtApexJars: nil,
ProductUpdatableBootModules: nil,
ProductUpdatableBootLocations: nil,
SystemServerJars: nil,
@@ -302,7 +290,6 @@
DefaultCompilerFilter: "",
SystemServerCompilerFilter: "",
GenerateDMFiles: false,
- NeverAllowStripping: false,
NoDebugInfo: false,
DontResolveStartupStrings: false,
AlwaysSystemServerDebugInfo: false,
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index c378f09..46e0f0a 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -13,7 +13,7 @@
// limitations under the License.
// The dexpreopt package converts a global dexpreopt config and a module dexpreopt config into rules to perform
-// dexpreopting and to strip the dex files from the APK or JAR.
+// dexpreopting.
//
// It is used in two places; in the dexpeopt_gen binary for modules defined in Make, and directly linked into Soong.
//
@@ -22,8 +22,7 @@
// changed. One script takes an APK or JAR as an input and produces a zip file containing any outputs of preopting,
// in the location they should be on the device. The Make build rules will unzip the zip file into $(PRODUCT_OUT) when
// installing the APK, which will install the preopt outputs into $(PRODUCT_OUT)/system or $(PRODUCT_OUT)/system_other
-// as necessary. The zip file may be empty if preopting was disabled for any reason. The second script takes an APK or
-// JAR as an input and strips the dex files in it as necessary.
+// as necessary. The zip file may be empty if preopting was disabled for any reason.
//
// The intermediate shell scripts allow changes to this package or to the global config to regenerate the shell scripts
// but only require re-executing preopting if the script has changed.
@@ -48,45 +47,6 @@
const SystemPartition = "/system/"
const SystemOtherPartition = "/system_other/"
-// GenerateStripRule generates a set of commands that will take an APK or JAR as an input and strip the dex files if
-// they are no longer necessary after preopting.
-func GenerateStripRule(global GlobalConfig, module ModuleConfig) (rule *android.RuleBuilder, err error) {
- defer func() {
- if r := recover(); r != nil {
- if _, ok := r.(runtime.Error); ok {
- panic(r)
- } else if e, ok := r.(error); ok {
- err = e
- rule = nil
- } else {
- panic(r)
- }
- }
- }()
-
- tools := global.Tools
-
- rule = android.NewRuleBuilder()
-
- strip := shouldStripDex(module, global)
-
- if strip {
- if global.NeverAllowStripping {
- panic(fmt.Errorf("Stripping requested on %q, though the product does not allow it", module.DexLocation))
- }
- // Only strips if the dex files are not already uncompressed
- rule.Command().
- Textf(`if (zipinfo %s '*.dex' 2>/dev/null | grep -v ' stor ' >/dev/null) ; then`, module.StripInputPath).
- Tool(tools.Zip2zip).FlagWithInput("-i ", module.StripInputPath).FlagWithOutput("-o ", module.StripOutputPath).
- FlagWithArg("-x ", `"classes*.dex"`).
- Textf(`; else cp -f %s %s; fi`, module.StripInputPath, module.StripOutputPath)
- } else {
- rule.Command().Text("cp -f").Input(module.StripInputPath).Output(module.StripOutputPath)
- }
-
- return rule, nil
-}
-
// GenerateDexpreoptRule generates a set of commands that will preopt a module based on a GlobalConfig and a
// ModuleConfig. The produced files and their install locations will be available through rule.Installs().
func GenerateDexpreoptRule(ctx android.PathContext,
@@ -120,7 +80,6 @@
if !dexpreoptDisabled(global, module) {
// Don't preopt individual boot jars, they will be preopted together.
- // This check is outside dexpreoptDisabled because they still need to be stripped.
if !contains(global.BootJars, module.Name) {
appImage := (generateProfile || module.ForceCreateAppImage || global.DefaultAppImages) &&
!module.NoCreateAppImage
@@ -248,7 +207,7 @@
odexPath := module.BuildPath.InSameDir(ctx, "oat", arch.String(), pathtools.ReplaceExtension(base, "odex"))
odexInstallPath := toOdexPath(module.DexLocation)
if odexOnSystemOther(module, global) {
- odexInstallPath = strings.Replace(odexInstallPath, SystemPartition, SystemOtherPartition, 1)
+ odexInstallPath = filepath.Join(SystemOtherPartition, odexInstallPath)
}
vdexPath := odexPath.ReplaceExtension(ctx, "vdex")
@@ -515,51 +474,6 @@
rule.Install(vdexPath, vdexInstallPath)
}
-// Return if the dex file in the APK should be stripped. If an APK is found to contain uncompressed dex files at
-// dex2oat time it will not be stripped even if strip=true.
-func shouldStripDex(module ModuleConfig, global GlobalConfig) bool {
- strip := !global.DefaultNoStripping
-
- if dexpreoptDisabled(global, module) {
- strip = false
- }
-
- if module.NoStripping {
- strip = false
- }
-
- // Don't strip modules that are not on the system partition in case the oat/vdex version in system ROM
- // doesn't match the one in other partitions. It needs to be able to fall back to the APK for that case.
- if !strings.HasPrefix(module.DexLocation, SystemPartition) {
- strip = false
- }
-
- // system_other isn't there for an OTA, so don't strip if module is on system, and odex is on system_other.
- if odexOnSystemOther(module, global) {
- strip = false
- }
-
- if module.HasApkLibraries {
- strip = false
- }
-
- // Don't strip with dex files we explicitly uncompress (dexopt will not store the dex code).
- if module.UncompressedDex {
- strip = false
- }
-
- if shouldGenerateDM(module, global) {
- strip = false
- }
-
- if module.PresignedPrebuilt {
- // Only strip out files if we can re-sign the package.
- strip = false
- }
-
- return strip
-}
-
func shouldGenerateDM(module ModuleConfig, global GlobalConfig) bool {
// Generating DM files only makes sense for verify, avoid doing for non verify compiler filter APKs.
// No reason to use a dm file if the dex is already uncompressed.
@@ -581,7 +495,8 @@
}
for _, f := range global.PatternsOnSystemOther {
- if makefileMatch(filepath.Join(SystemPartition, f), dexLocation) {
+ // See comment of SYSTEM_OTHER_ODEX_FILTER for details on the matching.
+ if makefileMatch("/"+f, dexLocation) || makefileMatch(filepath.Join(SystemPartition, f), dexLocation) {
return true
}
}
diff --git a/dexpreopt/dexpreopt_gen/dexpreopt_gen.go b/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
index d54ddb1..009e906 100644
--- a/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
+++ b/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
@@ -31,7 +31,6 @@
var (
dexpreoptScriptPath = flag.String("dexpreopt_script", "", "path to output dexpreopt script")
- stripScriptPath = flag.String("strip_script", "", "path to output strip script")
globalConfigPath = flag.String("global", "", "path to global configuration file")
moduleConfigPath = flag.String("module", "", "path to module configuration file")
outDir = flag.String("out_dir", "", "path to output directory")
@@ -64,10 +63,6 @@
usage("path to output dexpreopt script is required")
}
- if *stripScriptPath == "" {
- usage("path to output strip script is required")
- }
-
if *globalConfigPath == "" {
usage("path to global configuration file is required")
}
@@ -90,10 +85,6 @@
os.Exit(2)
}
- // This shouldn't be using *PathForTesting, but it's outside of soong_build so its OK for now.
- moduleConfig.StripInputPath = android.PathForTesting("$1")
- moduleConfig.StripOutputPath = android.WritablePathForTesting("$2")
-
moduleConfig.DexPath = android.PathForTesting("$1")
defer func() {
@@ -110,11 +101,11 @@
}
}()
- writeScripts(ctx, globalConfig, moduleConfig, *dexpreoptScriptPath, *stripScriptPath)
+ writeScripts(ctx, globalConfig, moduleConfig, *dexpreoptScriptPath)
}
func writeScripts(ctx android.PathContext, global dexpreopt.GlobalConfig, module dexpreopt.ModuleConfig,
- dexpreoptScriptPath, stripScriptPath string) {
+ dexpreoptScriptPath string) {
dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(ctx, global, module)
if err != nil {
panic(err)
@@ -135,11 +126,6 @@
FlagWithArg("-C ", installDir.String()).
FlagWithArg("-D ", installDir.String())
- stripRule, err := dexpreopt.GenerateStripRule(global, module)
- if err != nil {
- panic(err)
- }
-
write := func(rule *android.RuleBuilder, file string) {
script := &bytes.Buffer{}
script.WriteString(scriptHeader)
@@ -180,15 +166,8 @@
if module.DexPath.String() != "$1" {
panic(fmt.Errorf("module.DexPath must be '$1', was %q", module.DexPath))
}
- if module.StripInputPath.String() != "$1" {
- panic(fmt.Errorf("module.StripInputPath must be '$1', was %q", module.StripInputPath))
- }
- if module.StripOutputPath.String() != "$2" {
- panic(fmt.Errorf("module.StripOutputPath must be '$2', was %q", module.StripOutputPath))
- }
write(dexpreoptRule, dexpreoptScriptPath)
- write(stripRule, stripScriptPath)
}
const scriptHeader = `#!/bin/bash
diff --git a/dexpreopt/dexpreopt_test.go b/dexpreopt/dexpreopt_test.go
index 7f1fe42..6f8120e 100644
--- a/dexpreopt/dexpreopt_test.go
+++ b/dexpreopt/dexpreopt_test.go
@@ -16,17 +16,28 @@
import (
"android/soong/android"
- "reflect"
- "strings"
+ "fmt"
"testing"
)
-func testModuleConfig(ctx android.PathContext) ModuleConfig {
+func testSystemModuleConfig(ctx android.PathContext, name string) ModuleConfig {
+ return testModuleConfig(ctx, name, "system")
+}
+
+func testSystemProductModuleConfig(ctx android.PathContext, name string) ModuleConfig {
+ return testModuleConfig(ctx, name, "system/product")
+}
+
+func testProductModuleConfig(ctx android.PathContext, name string) ModuleConfig {
+ return testModuleConfig(ctx, name, "product")
+}
+
+func testModuleConfig(ctx android.PathContext, name, partition string) ModuleConfig {
return ModuleConfig{
- Name: "test",
- DexLocation: "/system/app/test/test.apk",
- BuildPath: android.PathForOutput(ctx, "test/test.apk"),
- DexPath: android.PathForOutput(ctx, "test/dex/test.jar"),
+ Name: name,
+ DexLocation: fmt.Sprintf("/%s/app/test/%s.apk", partition, name),
+ BuildPath: android.PathForOutput(ctx, fmt.Sprintf("%s/%s.apk", name, name)),
+ DexPath: android.PathForOutput(ctx, fmt.Sprintf("%s/dex/%s.jar", name, name)),
UncompressedDex: false,
HasApkLibraries: false,
PreoptFlags: nil,
@@ -45,15 +56,12 @@
NoCreateAppImage: false,
ForceCreateAppImage: false,
PresignedPrebuilt: false,
- NoStripping: false,
- StripInputPath: android.PathForOutput(ctx, "unstripped/test.apk"),
- StripOutputPath: android.PathForOutput(ctx, "stripped/test.apk"),
}
}
func TestDexPreopt(t *testing.T) {
ctx := android.PathContextForTesting(android.TestConfig("out", nil), nil)
- global, module := GlobalConfigForTests(ctx), testModuleConfig(ctx)
+ global, module := GlobalConfigForTests(ctx), testSystemModuleConfig(ctx, "test")
rule, err := GenerateDexpreoptRule(ctx, global, module)
if err != nil {
@@ -70,45 +78,66 @@
}
}
-func TestDexPreoptStrip(t *testing.T) {
- // Test that we panic if we strip in a configuration where stripping is not allowed.
- ctx := android.PathContextForTesting(android.TestConfig("out", nil), nil)
- global, module := GlobalConfigForTests(ctx), testModuleConfig(ctx)
-
- global.NeverAllowStripping = true
- module.NoStripping = false
-
- _, err := GenerateStripRule(global, module)
- if err == nil {
- t.Errorf("Expected an error when calling GenerateStripRule on a stripped module")
- }
-}
-
func TestDexPreoptSystemOther(t *testing.T) {
ctx := android.PathContextForTesting(android.TestConfig("out", nil), nil)
- global, module := GlobalConfigForTests(ctx), testModuleConfig(ctx)
+ global := GlobalConfigForTests(ctx)
+ systemModule := testSystemModuleConfig(ctx, "Stest")
+ systemProductModule := testSystemProductModuleConfig(ctx, "SPtest")
+ productModule := testProductModuleConfig(ctx, "Ptest")
global.HasSystemOther = true
- global.PatternsOnSystemOther = []string{"app/%"}
- rule, err := GenerateDexpreoptRule(ctx, global, module)
- if err != nil {
- t.Fatal(err)
+ type moduleTest struct {
+ module ModuleConfig
+ expectedPartition string
+ }
+ tests := []struct {
+ patterns []string
+ moduleTests []moduleTest
+ }{
+ {
+ patterns: []string{"app/%"},
+ moduleTests: []moduleTest{
+ {module: systemModule, expectedPartition: "system_other/system"},
+ {module: systemProductModule, expectedPartition: "system/product"},
+ {module: productModule, expectedPartition: "product"},
+ },
+ },
+ {
+ patterns: []string{"app/%", "product/app/%"},
+ moduleTests: []moduleTest{
+ {module: systemModule, expectedPartition: "system_other/system"},
+ {module: systemProductModule, expectedPartition: "system_other/system/product"},
+ {module: productModule, expectedPartition: "system_other/product"},
+ },
+ },
}
- wantInstalls := android.RuleBuilderInstalls{
- {android.PathForOutput(ctx, "test/oat/arm/package.odex"), "/system_other/app/test/oat/arm/test.odex"},
- {android.PathForOutput(ctx, "test/oat/arm/package.vdex"), "/system_other/app/test/oat/arm/test.vdex"},
+ for _, test := range tests {
+ global.PatternsOnSystemOther = test.patterns
+ for _, mt := range test.moduleTests {
+ rule, err := GenerateDexpreoptRule(ctx, global, mt.module)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ name := mt.module.Name
+ wantInstalls := android.RuleBuilderInstalls{
+ {android.PathForOutput(ctx, name+"/oat/arm/package.odex"), fmt.Sprintf("/%s/app/test/oat/arm/%s.odex", mt.expectedPartition, name)},
+ {android.PathForOutput(ctx, name+"/oat/arm/package.vdex"), fmt.Sprintf("/%s/app/test/oat/arm/%s.vdex", mt.expectedPartition, name)},
+ }
+
+ if rule.Installs().String() != wantInstalls.String() {
+ t.Errorf("\npatterns: %v\nwant installs:\n %v\ngot:\n %v", test.patterns, wantInstalls, rule.Installs())
+ }
+ }
}
- if rule.Installs().String() != wantInstalls.String() {
- t.Errorf("\nwant installs:\n %v\ngot:\n %v", wantInstalls, rule.Installs())
- }
}
func TestDexPreoptProfile(t *testing.T) {
ctx := android.PathContextForTesting(android.TestConfig("out", nil), nil)
- global, module := GlobalConfigForTests(ctx), testModuleConfig(ctx)
+ global, module := GlobalConfigForTests(ctx), testSystemModuleConfig(ctx, "test")
module.ProfileClassListing = android.OptionalPathForPath(android.PathForTesting("profile"))
@@ -128,56 +157,3 @@
t.Errorf("\nwant installs:\n %v\ngot:\n %v", wantInstalls, rule.Installs())
}
}
-
-func TestStripDex(t *testing.T) {
- tests := []struct {
- name string
- setup func(global *GlobalConfig, module *ModuleConfig)
- strip bool
- }{
- {
- name: "default strip",
- setup: func(global *GlobalConfig, module *ModuleConfig) {},
- strip: true,
- },
- {
- name: "global no stripping",
- setup: func(global *GlobalConfig, module *ModuleConfig) { global.DefaultNoStripping = true },
- strip: false,
- },
- {
- name: "module no stripping",
- setup: func(global *GlobalConfig, module *ModuleConfig) { module.NoStripping = true },
- strip: false,
- },
- }
-
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
-
- ctx := android.PathContextForTesting(android.TestConfig("out", nil), nil)
- global, module := GlobalConfigForTests(ctx), testModuleConfig(ctx)
-
- test.setup(&global, &module)
-
- rule, err := GenerateStripRule(global, module)
- if err != nil {
- t.Fatal(err)
- }
-
- if test.strip {
- want := `zip2zip -i out/unstripped/test.apk -o out/stripped/test.apk -x "classes*.dex"`
- if len(rule.Commands()) < 1 || !strings.Contains(rule.Commands()[0], want) {
- t.Errorf("\nwant commands[0] to have:\n %v\ngot:\n %v", want, rule.Commands()[0])
- }
- } else {
- wantCommands := []string{
- "cp -f out/unstripped/test.apk out/stripped/test.apk",
- }
- if !reflect.DeepEqual(rule.Commands(), wantCommands) {
- t.Errorf("\nwant commands:\n %v\ngot:\n %v", wantCommands, rule.Commands())
- }
- }
- })
- }
-}
diff --git a/genrule/genrule.go b/genrule/genrule.go
index cf0b484..a7c5d65 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -17,6 +17,7 @@
import (
"fmt"
"io"
+ "strconv"
"strings"
"github.com/google/blueprint"
@@ -37,11 +38,21 @@
var (
pctx = android.NewPackageContext("android/soong/genrule")
+
+ gensrcsMerge = pctx.AndroidStaticRule("gensrcsMerge", blueprint.RuleParams{
+ Command: "${soongZip} -o ${tmpZip} @${tmpZip}.rsp && ${zipSync} -d ${genDir} ${tmpZip}",
+ CommandDeps: []string{"${soongZip}", "${zipSync}"},
+ Rspfile: "${tmpZip}.rsp",
+ RspfileContent: "${zipArgs}",
+ }, "tmpZip", "genDir", "zipArgs")
)
func init() {
pctx.Import("android/soong/android")
pctx.HostBinToolVariable("sboxCmd", "sbox")
+
+ pctx.HostBinToolVariable("soongZip", "soong_zip")
+ pctx.HostBinToolVariable("zipSync", "zipsync")
}
type SourceFileGenerator interface {
@@ -112,9 +123,9 @@
taskGenerator taskFunc
- deps android.Paths
- rule blueprint.Rule
- rawCommand string
+ deps android.Paths
+ rule blueprint.Rule
+ rawCommands []string
exportedIncludeDirs android.Paths
@@ -122,15 +133,20 @@
outputDeps android.Paths
subName string
+ subDir string
}
-type taskFunc func(ctx android.ModuleContext, rawCommand string, srcFiles android.Paths) generateTask
+type taskFunc func(ctx android.ModuleContext, rawCommand string, srcFiles android.Paths) []generateTask
type generateTask struct {
in android.Paths
out android.WritablePaths
+ copyTo android.WritablePaths
+ genDir android.WritablePath
sandboxOuts []string
cmd string
+ shard int
+ shards int
}
func (g *Module) GeneratedSourceFiles() android.Paths {
@@ -156,9 +172,7 @@
if m := android.SrcIsModule(tool); m != "" {
tool = m
}
- ctx.AddFarVariationDependencies([]blueprint.Variation{
- {Mutator: "arch", Variation: ctx.Config().BuildOsVariant},
- }, tag, tool)
+ ctx.AddFarVariationDependencies(ctx.Config().BuildOSTarget.Variations(), tag, tool)
}
}
}
@@ -169,10 +183,10 @@
if len(g.properties.Export_include_dirs) > 0 {
for _, dir := range g.properties.Export_include_dirs {
g.exportedIncludeDirs = append(g.exportedIncludeDirs,
- android.PathForModuleGen(ctx, ctx.ModuleDir(), dir))
+ android.PathForModuleGen(ctx, g.subDir, ctx.ModuleDir(), dir))
}
} else {
- g.exportedIncludeDirs = append(g.exportedIncludeDirs, android.PathForModuleGen(ctx, ""))
+ g.exportedIncludeDirs = append(g.exportedIncludeDirs, android.PathForModuleGen(ctx, g.subDir))
}
locationLabels := map[string][]string{}
@@ -277,120 +291,170 @@
}
}
- task := g.taskGenerator(ctx, String(g.properties.Cmd), srcFiles)
+ var copyFrom android.Paths
+ var outputFiles android.WritablePaths
+ var zipArgs strings.Builder
- for _, out := range task.out {
- addLocationLabel(out.Rel(), []string{filepath.Join("__SBOX_OUT_DIR__", out.Rel())})
- }
-
- referencedDepfile := false
-
- rawCommand, err := android.ExpandNinjaEscaped(task.cmd, func(name string) (string, bool, error) {
- // report the error directly without returning an error to android.Expand to catch multiple errors in a
- // single run
- reportError := func(fmt string, args ...interface{}) (string, bool, error) {
- ctx.PropertyErrorf("cmd", fmt, args...)
- return "SOONG_ERROR", false, nil
+ for _, task := range g.taskGenerator(ctx, String(g.properties.Cmd), srcFiles) {
+ for _, out := range task.out {
+ addLocationLabel(out.Rel(), []string{filepath.Join("__SBOX_OUT_DIR__", out.Rel())})
}
- switch name {
- case "location":
- if len(g.properties.Tools) == 0 && len(g.properties.Tool_files) == 0 {
- return reportError("at least one `tools` or `tool_files` is required if $(location) is used")
+ referencedDepfile := false
+
+ rawCommand, err := android.ExpandNinjaEscaped(task.cmd, func(name string) (string, bool, error) {
+ // report the error directly without returning an error to android.Expand to catch multiple errors in a
+ // single run
+ reportError := func(fmt string, args ...interface{}) (string, bool, error) {
+ ctx.PropertyErrorf("cmd", fmt, args...)
+ return "SOONG_ERROR", false, nil
}
- paths := locationLabels[firstLabel]
- if len(paths) == 0 {
- return reportError("default label %q has no files", firstLabel)
- } else if len(paths) > 1 {
- return reportError("default label %q has multiple files, use $(locations %s) to reference it",
- firstLabel, firstLabel)
- }
- return locationLabels[firstLabel][0], false, nil
- case "in":
- return "${in}", true, nil
- case "out":
- return "__SBOX_OUT_FILES__", false, nil
- case "depfile":
- referencedDepfile = true
- if !Bool(g.properties.Depfile) {
- return reportError("$(depfile) used without depfile property")
- }
- return "__SBOX_DEPFILE__", false, nil
- case "genDir":
- return "__SBOX_OUT_DIR__", false, nil
- default:
- if strings.HasPrefix(name, "location ") {
- label := strings.TrimSpace(strings.TrimPrefix(name, "location "))
- if paths, ok := locationLabels[label]; ok {
- if len(paths) == 0 {
- return reportError("label %q has no files", label)
- } else if len(paths) > 1 {
- return reportError("label %q has multiple files, use $(locations %s) to reference it",
- label, label)
- }
- return paths[0], false, nil
- } else {
- return reportError("unknown location label %q", label)
+
+ switch name {
+ case "location":
+ if len(g.properties.Tools) == 0 && len(g.properties.Tool_files) == 0 {
+ return reportError("at least one `tools` or `tool_files` is required if $(location) is used")
}
- } else if strings.HasPrefix(name, "locations ") {
- label := strings.TrimSpace(strings.TrimPrefix(name, "locations "))
- if paths, ok := locationLabels[label]; ok {
- if len(paths) == 0 {
- return reportError("label %q has no files", label)
- }
- return strings.Join(paths, " "), false, nil
- } else {
- return reportError("unknown locations label %q", label)
+ paths := locationLabels[firstLabel]
+ if len(paths) == 0 {
+ return reportError("default label %q has no files", firstLabel)
+ } else if len(paths) > 1 {
+ return reportError("default label %q has multiple files, use $(locations %s) to reference it",
+ firstLabel, firstLabel)
}
- } else {
- return reportError("unknown variable '$(%s)'", name)
+ return locationLabels[firstLabel][0], false, nil
+ case "in":
+ return "${in}", true, nil
+ case "out":
+ return "__SBOX_OUT_FILES__", false, nil
+ case "depfile":
+ referencedDepfile = true
+ if !Bool(g.properties.Depfile) {
+ return reportError("$(depfile) used without depfile property")
+ }
+ return "__SBOX_DEPFILE__", false, nil
+ case "genDir":
+ return "__SBOX_OUT_DIR__", false, nil
+ default:
+ if strings.HasPrefix(name, "location ") {
+ label := strings.TrimSpace(strings.TrimPrefix(name, "location "))
+ if paths, ok := locationLabels[label]; ok {
+ if len(paths) == 0 {
+ return reportError("label %q has no files", label)
+ } else if len(paths) > 1 {
+ return reportError("label %q has multiple files, use $(locations %s) to reference it",
+ label, label)
+ }
+ return paths[0], false, nil
+ } else {
+ return reportError("unknown location label %q", label)
+ }
+ } else if strings.HasPrefix(name, "locations ") {
+ label := strings.TrimSpace(strings.TrimPrefix(name, "locations "))
+ if paths, ok := locationLabels[label]; ok {
+ if len(paths) == 0 {
+ return reportError("label %q has no files", label)
+ }
+ return strings.Join(paths, " "), false, nil
+ } else {
+ return reportError("unknown locations label %q", label)
+ }
+ } else {
+ return reportError("unknown variable '$(%s)'", name)
+ }
}
+ })
+
+ if err != nil {
+ ctx.PropertyErrorf("cmd", "%s", err.Error())
+ return
}
- })
- if err != nil {
- ctx.PropertyErrorf("cmd", "%s", err.Error())
- return
+ if Bool(g.properties.Depfile) && !referencedDepfile {
+ ctx.PropertyErrorf("cmd", "specified depfile=true but did not include a reference to '${depfile}' in cmd")
+ return
+ }
+
+ // tell the sbox command which directory to use as its sandbox root
+ buildDir := android.PathForOutput(ctx).String()
+ sandboxPath := shared.TempDirForOutDir(buildDir)
+
+ // recall that Sprintf replaces percent sign expressions, whereas dollar signs expressions remain as written,
+ // to be replaced later by ninja_strings.go
+ depfilePlaceholder := ""
+ if Bool(g.properties.Depfile) {
+ depfilePlaceholder = "$depfileArgs"
+ }
+
+ // Escape the command for the shell
+ rawCommand = "'" + strings.Replace(rawCommand, "'", `'\''`, -1) + "'"
+ g.rawCommands = append(g.rawCommands, rawCommand)
+ sandboxCommand := fmt.Sprintf("rm -rf %s && $sboxCmd --sandbox-path %s --output-root %s -c %s %s $allouts",
+ task.genDir, sandboxPath, task.genDir, rawCommand, depfilePlaceholder)
+
+ ruleParams := blueprint.RuleParams{
+ Command: sandboxCommand,
+ CommandDeps: []string{"$sboxCmd"},
+ }
+ args := []string{"allouts"}
+ if Bool(g.properties.Depfile) {
+ ruleParams.Deps = blueprint.DepsGCC
+ args = append(args, "depfileArgs")
+ }
+ name := "generator"
+ if task.shards > 1 {
+ name += strconv.Itoa(task.shard)
+ }
+ rule := ctx.Rule(pctx, name, ruleParams, args...)
+
+ g.generateSourceFile(ctx, task, rule)
+
+ if len(task.copyTo) > 0 {
+ outputFiles = append(outputFiles, task.copyTo...)
+ copyFrom = append(copyFrom, task.out.Paths()...)
+ zipArgs.WriteString(" -C " + task.genDir.String())
+ zipArgs.WriteString(android.JoinWithPrefix(task.out.Strings(), " -f "))
+ } else {
+ outputFiles = append(outputFiles, task.out...)
+ }
}
- if Bool(g.properties.Depfile) && !referencedDepfile {
- ctx.PropertyErrorf("cmd", "specified depfile=true but did not include a reference to '${depfile}' in cmd")
+ if len(copyFrom) > 0 {
+ ctx.Build(pctx, android.BuildParams{
+ Rule: gensrcsMerge,
+ Implicits: copyFrom,
+ Outputs: outputFiles,
+ Args: map[string]string{
+ "zipArgs": zipArgs.String(),
+ "tmpZip": android.PathForModuleGen(ctx, g.subDir+".zip").String(),
+ "genDir": android.PathForModuleGen(ctx, g.subDir).String(),
+ },
+ })
}
- // tell the sbox command which directory to use as its sandbox root
- buildDir := android.PathForOutput(ctx).String()
- sandboxPath := shared.TempDirForOutDir(buildDir)
+ g.outputFiles = outputFiles.Paths()
- // recall that Sprintf replaces percent sign expressions, whereas dollar signs expressions remain as written,
- // to be replaced later by ninja_strings.go
- depfilePlaceholder := ""
- if Bool(g.properties.Depfile) {
- depfilePlaceholder = "$depfileArgs"
+ // For <= 6 outputs, just embed those directly in the users. Right now, that covers >90% of
+ // the genrules on AOSP. That will make things simpler to look at the graph in the common
+ // case. For larger sets of outputs, inject a phony target in between to limit ninja file
+ // growth.
+ if len(g.outputFiles) <= 6 {
+ g.outputDeps = g.outputFiles
+ } else {
+ phonyFile := android.PathForModuleGen(ctx, "genrule-phony")
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: blueprint.Phony,
+ Output: phonyFile,
+ Inputs: g.outputFiles,
+ })
+
+ g.outputDeps = android.Paths{phonyFile}
}
- genDir := android.PathForModuleGen(ctx)
- // Escape the command for the shell
- rawCommand = "'" + strings.Replace(rawCommand, "'", `'\''`, -1) + "'"
- g.rawCommand = rawCommand
- sandboxCommand := fmt.Sprintf("$sboxCmd --sandbox-path %s --output-root %s -c %s %s $allouts",
- sandboxPath, genDir, rawCommand, depfilePlaceholder)
-
- ruleParams := blueprint.RuleParams{
- Command: sandboxCommand,
- CommandDeps: []string{"$sboxCmd"},
- }
- args := []string{"allouts"}
- if Bool(g.properties.Depfile) {
- ruleParams.Deps = blueprint.DepsGCC
- args = append(args, "depfileArgs")
- }
- g.rule = ctx.Rule(pctx, "generator", ruleParams, args...)
-
- g.generateSourceFile(ctx, task)
-
}
-func (g *Module) generateSourceFile(ctx android.ModuleContext, task generateTask) {
+func (g *Module) generateSourceFile(ctx android.ModuleContext, task generateTask, rule blueprint.Rule) {
desc := "generate"
if len(task.out) == 0 {
ctx.ModuleErrorf("must have at least one output file")
@@ -405,9 +469,13 @@
depFile = android.PathForModuleGen(ctx, task.out[0].Rel()+".d")
}
+ if task.shards > 1 {
+ desc += " " + strconv.Itoa(task.shard)
+ }
+
params := android.BuildParams{
- Rule: g.rule,
- Description: "generate",
+ Rule: rule,
+ Description: desc,
Output: task.out[0],
ImplicitOutputs: task.out[1:],
Inputs: task.in,
@@ -422,28 +490,6 @@
}
ctx.Build(pctx, params)
-
- for _, outputFile := range task.out {
- g.outputFiles = append(g.outputFiles, outputFile)
- }
-
- // For <= 6 outputs, just embed those directly in the users. Right now, that covers >90% of
- // the genrules on AOSP. That will make things simpler to look at the graph in the common
- // case. For larger sets of outputs, inject a phony target in between to limit ninja file
- // growth.
- if len(task.out) <= 6 {
- g.outputDeps = g.outputFiles
- } else {
- phonyFile := android.PathForModuleGen(ctx, "genrule-phony")
-
- ctx.Build(pctx, android.BuildParams{
- Rule: android.Phony,
- Output: phonyFile,
- Inputs: g.outputFiles,
- })
-
- g.outputDeps = android.Paths{phonyFile}
- }
}
// Collect information for opening IDE project files in java/jdeps.go.
@@ -465,7 +511,7 @@
SubName: g.subName,
Extra: []android.AndroidMkExtraFunc{
func(w io.Writer, outputFile android.Path) {
- fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES :=", strings.Join(g.outputFiles.Strings(), " "))
+ fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES :=", strings.Join(g.outputDeps.Strings(), " "))
},
},
Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
@@ -502,47 +548,80 @@
func NewGenSrcs() *Module {
properties := &genSrcsProperties{}
- taskGenerator := func(ctx android.ModuleContext, rawCommand string, srcFiles android.Paths) generateTask {
- commands := []string{}
- outFiles := android.WritablePaths{}
- genDir := android.PathForModuleGen(ctx)
- sandboxOuts := []string{}
- for _, in := range srcFiles {
- outFile := android.GenPathWithExt(ctx, "", in, String(properties.Output_extension))
- outFiles = append(outFiles, outFile)
+ taskGenerator := func(ctx android.ModuleContext, rawCommand string, srcFiles android.Paths) []generateTask {
+ genDir := android.PathForModuleGen(ctx, "gensrcs")
+ shardSize := defaultShardSize
+ if s := properties.Shard_size; s != nil {
+ shardSize = int(*s)
+ }
- sandboxOutfile := pathToSandboxOut(outFile, genDir)
- sandboxOuts = append(sandboxOuts, sandboxOutfile)
+ shards := android.ShardPaths(srcFiles, shardSize)
+ var generateTasks []generateTask
- command, err := android.Expand(rawCommand, func(name string) (string, error) {
- switch name {
- case "in":
- return in.String(), nil
- case "out":
- return sandboxOutfile, nil
- default:
- return "$(" + name + ")", nil
- }
- })
- if err != nil {
- ctx.PropertyErrorf("cmd", err.Error())
+ for i, shard := range shards {
+ var commands []string
+ var outFiles android.WritablePaths
+ var copyTo android.WritablePaths
+ var shardDir android.WritablePath
+ var sandboxOuts []string
+
+ if len(shards) > 1 {
+ shardDir = android.PathForModuleGen(ctx, strconv.Itoa(i))
+ } else {
+ shardDir = genDir
}
- // escape the command in case for example it contains '#', an odd number of '"', etc
- command = fmt.Sprintf("bash -c %v", proptools.ShellEscape(command))
- commands = append(commands, command)
- }
- fullCommand := strings.Join(commands, " && ")
+ for _, in := range shard {
+ outFile := android.GenPathWithExt(ctx, "gensrcs", in, String(properties.Output_extension))
+ sandboxOutfile := pathToSandboxOut(outFile, genDir)
- return generateTask{
- in: srcFiles,
- out: outFiles,
- sandboxOuts: sandboxOuts,
- cmd: fullCommand,
+ if len(shards) > 1 {
+ shardFile := android.GenPathWithExt(ctx, strconv.Itoa(i), in, String(properties.Output_extension))
+ copyTo = append(copyTo, outFile)
+ outFile = shardFile
+ }
+
+ outFiles = append(outFiles, outFile)
+ sandboxOuts = append(sandboxOuts, sandboxOutfile)
+
+ command, err := android.Expand(rawCommand, func(name string) (string, error) {
+ switch name {
+ case "in":
+ return in.String(), nil
+ case "out":
+ return sandboxOutfile, nil
+ default:
+ return "$(" + name + ")", nil
+ }
+ })
+ if err != nil {
+ ctx.PropertyErrorf("cmd", err.Error())
+ }
+
+ // escape the command in case for example it contains '#', an odd number of '"', etc
+ command = fmt.Sprintf("bash -c %v", proptools.ShellEscape(command))
+ commands = append(commands, command)
+ }
+ fullCommand := strings.Join(commands, " && ")
+
+ generateTasks = append(generateTasks, generateTask{
+ in: shard,
+ out: outFiles,
+ copyTo: copyTo,
+ genDir: shardDir,
+ sandboxOuts: sandboxOuts,
+ cmd: fullCommand,
+ shard: i,
+ shards: len(shards),
+ })
}
+
+ return generateTasks
}
- return generatorFactory(taskGenerator, properties)
+ g := generatorFactory(taskGenerator, properties)
+ g.subDir = "gensrcs"
+ return g
}
func GenSrcsFactory() android.Module {
@@ -554,12 +633,17 @@
type genSrcsProperties struct {
// extension that will be substituted for each output file
Output_extension *string
+
+ // maximum number of files that will be passed on a single command line.
+ Shard_size *int64
}
+const defaultShardSize = 100
+
func NewGenRule() *Module {
properties := &genRuleProperties{}
- taskGenerator := func(ctx android.ModuleContext, rawCommand string, srcFiles android.Paths) generateTask {
+ taskGenerator := func(ctx android.ModuleContext, rawCommand string, srcFiles android.Paths) []generateTask {
outs := make(android.WritablePaths, len(properties.Out))
sandboxOuts := make([]string, len(properties.Out))
genDir := android.PathForModuleGen(ctx)
@@ -567,12 +651,13 @@
outs[i] = android.PathForModuleGen(ctx, out)
sandboxOuts[i] = pathToSandboxOut(outs[i], genDir)
}
- return generateTask{
+ return []generateTask{{
in: srcFiles,
out: outs,
+ genDir: android.PathForModuleGen(ctx),
sandboxOuts: sandboxOuts,
cmd: rawCommand,
- }
+ }}
}
return generatorFactory(taskGenerator, properties)
diff --git a/genrule/genrule_test.go b/genrule/genrule_test.go
index 0b6952f..5ac0e8c 100644
--- a/genrule/genrule_test.go
+++ b/genrule/genrule_test.go
@@ -57,6 +57,7 @@
ctx := android.NewTestArchContext()
ctx.RegisterModuleType("filegroup", android.ModuleFactoryAdaptor(android.FileGroupFactory))
ctx.RegisterModuleType("genrule", android.ModuleFactoryAdaptor(GenRuleFactory))
+ ctx.RegisterModuleType("gensrcs", android.ModuleFactoryAdaptor(GenSrcsFactory))
ctx.RegisterModuleType("genrule_defaults", android.ModuleFactoryAdaptor(defaultsFactory))
ctx.RegisterModuleType("tool", android.ModuleFactoryAdaptor(toolFactory))
ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
@@ -109,6 +110,9 @@
"tool_file2": nil,
"in1": nil,
"in2": nil,
+ "in1.txt": nil,
+ "in2.txt": nil,
+ "in3.txt": nil,
}
for k, v := range fs {
@@ -491,11 +495,102 @@
}
gen := ctx.ModuleForTests("gen", "").Module().(*Module)
- if g, w := gen.rawCommand, "'"+test.expect+"'"; w != g {
+ if g, w := gen.rawCommands[0], "'"+test.expect+"'"; w != g {
t.Errorf("want %q, got %q", w, g)
}
})
}
+}
+
+func TestGenSrcs(t *testing.T) {
+ testcases := []struct {
+ name string
+ prop string
+
+ allowMissingDependencies bool
+
+ err string
+ cmds []string
+ deps []string
+ files []string
+ }{
+ {
+ name: "gensrcs",
+ prop: `
+ tools: ["tool"],
+ srcs: ["in1.txt", "in2.txt"],
+ cmd: "$(location) $(in) > $(out)",
+ `,
+ cmds: []string{
+ "'bash -c '\\''out/tool in1.txt > __SBOX_OUT_DIR__/in1.h'\\'' && bash -c '\\''out/tool in2.txt > __SBOX_OUT_DIR__/in2.h'\\'''",
+ },
+ deps: []string{buildDir + "/.intermediates/gen/gen/gensrcs/in1.h", buildDir + "/.intermediates/gen/gen/gensrcs/in2.h"},
+ files: []string{buildDir + "/.intermediates/gen/gen/gensrcs/in1.h", buildDir + "/.intermediates/gen/gen/gensrcs/in2.h"},
+ },
+ {
+ name: "shards",
+ prop: `
+ tools: ["tool"],
+ srcs: ["in1.txt", "in2.txt", "in3.txt"],
+ cmd: "$(location) $(in) > $(out)",
+ shard_size: 2,
+ `,
+ cmds: []string{
+ "'bash -c '\\''out/tool in1.txt > __SBOX_OUT_DIR__/in1.h'\\'' && bash -c '\\''out/tool in2.txt > __SBOX_OUT_DIR__/in2.h'\\'''",
+ "'bash -c '\\''out/tool in3.txt > __SBOX_OUT_DIR__/in3.h'\\'''",
+ },
+ deps: []string{buildDir + "/.intermediates/gen/gen/gensrcs/in1.h", buildDir + "/.intermediates/gen/gen/gensrcs/in2.h", buildDir + "/.intermediates/gen/gen/gensrcs/in3.h"},
+ files: []string{buildDir + "/.intermediates/gen/gen/gensrcs/in1.h", buildDir + "/.intermediates/gen/gen/gensrcs/in2.h", buildDir + "/.intermediates/gen/gen/gensrcs/in3.h"},
+ },
+ }
+
+ for _, test := range testcases {
+ t.Run(test.name, func(t *testing.T) {
+ config := android.TestArchConfig(buildDir, nil)
+ bp := "gensrcs {\n"
+ bp += `name: "gen",` + "\n"
+ bp += `output_extension: "h",` + "\n"
+ bp += test.prop
+ bp += "}\n"
+
+ ctx := testContext(config, bp, nil)
+
+ _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+ if errs == nil {
+ _, errs = ctx.PrepareBuildActions(config)
+ }
+ if errs == nil && test.err != "" {
+ t.Fatalf("want error %q, got no error", test.err)
+ } else if errs != nil && test.err == "" {
+ android.FailIfErrored(t, errs)
+ } else if test.err != "" {
+ if len(errs) != 1 {
+ t.Errorf("want 1 error, got %d errors:", len(errs))
+ for _, err := range errs {
+ t.Errorf(" %s", err.Error())
+ }
+ t.FailNow()
+ }
+ if !strings.Contains(errs[0].Error(), test.err) {
+ t.Fatalf("want %q, got %q", test.err, errs[0].Error())
+ }
+ return
+ }
+
+ gen := ctx.ModuleForTests("gen", "").Module().(*Module)
+ if g, w := gen.rawCommands, test.cmds; !reflect.DeepEqual(w, g) {
+ t.Errorf("want %q, got %q", w, g)
+ }
+
+ if g, w := gen.outputDeps.Strings(), test.deps; !reflect.DeepEqual(w, g) {
+ t.Errorf("want deps %q, got %q", w, g)
+ }
+
+ if g, w := gen.outputFiles.Strings(), test.files; !reflect.DeepEqual(w, g) {
+ t.Errorf("want files %q, got %q", w, g)
+ }
+ })
+ }
}
@@ -529,8 +624,8 @@
gen := ctx.ModuleForTests("gen", "").Module().(*Module)
expectedCmd := "'cp ${in} __SBOX_OUT_FILES__'"
- if gen.rawCommand != expectedCmd {
- t.Errorf("Expected cmd: %q, actual: %q", expectedCmd, gen.rawCommand)
+ if gen.rawCommands[0] != expectedCmd {
+ t.Errorf("Expected cmd: %q, actual: %q", expectedCmd, gen.rawCommands[0])
}
expectedSrcs := []string{"in1"}
diff --git a/go.mod b/go.mod
index cc328e0..1483a31 100644
--- a/go.mod
+++ b/go.mod
@@ -7,3 +7,5 @@
replace github.com/golang/protobuf v0.0.0 => ../../external/golang-protobuf
replace github.com/google/blueprint v0.0.0 => ../blueprint
+
+go 1.13
diff --git a/java/aapt2.go b/java/aapt2.go
index f0eb99c..cfe0dea 100644
--- a/java/aapt2.go
+++ b/java/aapt2.go
@@ -63,7 +63,7 @@
func aapt2Compile(ctx android.ModuleContext, dir android.Path, paths android.Paths,
flags []string) android.WritablePaths {
- shards := shardPaths(paths, AAPT2_SHARD_SIZE)
+ shards := android.ShardPaths(paths, AAPT2_SHARD_SIZE)
ret := make(android.WritablePaths, 0, len(paths))
diff --git a/java/aar.go b/java/aar.go
index a4e6f91..6426ac3 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -220,14 +220,13 @@
manifestPath := manifestFixer(ctx, manifestSrcPath, sdkContext, sdkLibraries,
a.isLibrary, a.useEmbeddedNativeLibs, a.usesNonSdkApis, a.useEmbeddedDex, a.hasNoCode)
- a.transitiveManifestPaths = append(android.Paths{manifestPath}, transitiveStaticLibManifests...)
+ // Add additional manifest files to transitive manifests.
+ additionalManifests := android.PathsForModuleSrc(ctx, a.aaptProperties.Additional_manifests)
+ a.transitiveManifestPaths = append(android.Paths{manifestPath}, additionalManifests...)
+ a.transitiveManifestPaths = append(a.transitiveManifestPaths, transitiveStaticLibManifests...)
- if len(transitiveStaticLibManifests) > 0 {
- // Merge additional manifest files with app manifest.
- additionalManifests := android.PathsForModuleSrc(ctx, a.aaptProperties.Additional_manifests)
- additionalManifests = append(additionalManifests, transitiveStaticLibManifests...)
-
- a.mergedManifestFile = manifestMerger(ctx, manifestPath, additionalManifests, a.isLibrary)
+ if len(a.transitiveManifestPaths) > 1 {
+ a.mergedManifestFile = manifestMerger(ctx, a.transitiveManifestPaths[0], a.transitiveManifestPaths[1:], a.isLibrary)
if !a.isLibrary {
// Only use the merged manifest for applications. For libraries, the transitive closure of manifests
// will be propagated to the final application and merged there. The merged manifest for libraries is
@@ -249,7 +248,8 @@
}
packageRes := android.PathForModuleOut(ctx, "package-res.apk")
- srcJar := android.PathForModuleGen(ctx, "R.jar")
+ // the subdir "android" is required to be filtered by package names
+ srcJar := android.PathForModuleGen(ctx, "android", "R.srcjar")
proguardOptionsFile := android.PathForModuleGen(ctx, "proguard.options")
rTxt := android.PathForModuleOut(ctx, "R.txt")
// This file isn't used by Soong, but is generated for exporting
@@ -520,6 +520,10 @@
return proptools.StringDefault(a.properties.Sdk_version, defaultSdkVersion(a))
}
+func (a *AARImport) systemModules() string {
+ return ""
+}
+
func (a *AARImport) minSdkVersion() string {
if a.properties.Min_sdk_version != nil {
return *a.properties.Min_sdk_version
@@ -620,7 +624,8 @@
aapt2CompileZip(ctx, flata, aar, "res", compileFlags)
a.exportPackage = android.PathForModuleOut(ctx, "package-res.apk")
- srcJar := android.PathForModuleGen(ctx, "R.jar")
+ // the subdir "android" is required to be filtered by package names
+ srcJar := android.PathForModuleGen(ctx, "android", "R.srcjar")
proguardOptionsFile := android.PathForModuleGen(ctx, "proguard.options")
rTxt := android.PathForModuleOut(ctx, "R.txt")
a.extraAaptPackagesFile = android.PathForModuleOut(ctx, "extra_packages")
diff --git a/java/androidmk.go b/java/androidmk.go
index c00e070..9e9b277 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -22,7 +22,9 @@
"android/soong/android"
)
-func (library *Library) AndroidMkHostDex(w io.Writer, name string, data android.AndroidMkData) {
+// TODO(jungjw): We'll probably want AndroidMkEntriesProvider.AndroidMkEntries to return multiple
+// entries so that this can be more error-proof.
+func (library *Library) AndroidMkHostDex(w io.Writer, name string, entries *android.AndroidMkEntries) {
if Bool(library.deviceProperties.Hostdex) && !library.Host() {
fmt.Fprintln(w, "include $(CLEAR_VARS)")
fmt.Fprintln(w, "LOCAL_MODULE := "+name+"-hostdex")
@@ -38,14 +40,14 @@
}
fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", library.headerJarFile.String())
fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", library.implementationAndResourcesJar.String())
- if len(data.Required) > 0 {
- fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", strings.Join(data.Required, " "))
+ if len(entries.Required) > 0 {
+ fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", strings.Join(entries.Required, " "))
}
- if len(data.Host_required) > 0 {
- fmt.Fprintln(w, "LOCAL_HOST_REQUIRED_MODULES :=", strings.Join(data.Host_required, " "))
+ if len(entries.Host_required) > 0 {
+ fmt.Fprintln(w, "LOCAL_HOST_REQUIRED_MODULES :=", strings.Join(entries.Host_required, " "))
}
- if len(data.Target_required) > 0 {
- fmt.Fprintln(w, "LOCAL_TARGET_REQUIRED_MODULES :=", strings.Join(data.Target_required, " "))
+ if len(entries.Target_required) > 0 {
+ fmt.Fprintln(w, "LOCAL_TARGET_REQUIRED_MODULES :=", strings.Join(entries.Target_required, " "))
}
if r := library.deviceProperties.Target.Hostdex.Required; len(r) > 0 {
fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES +=", strings.Join(r, " "))
@@ -54,247 +56,241 @@
}
}
-func (library *Library) AndroidMk() android.AndroidMkData {
+func (library *Library) AndroidMkEntries() android.AndroidMkEntries {
if !library.IsForPlatform() {
- return android.AndroidMkData{
+ return android.AndroidMkEntries{
Disabled: true,
}
}
- return android.AndroidMkData{
+ return android.AndroidMkEntries{
Class: "JAVA_LIBRARIES",
OutputFile: android.OptionalPathForPath(library.outputFile),
Include: "$(BUILD_SYSTEM)/soong_java_prebuilt.mk",
- Extra: []android.AndroidMkExtraFunc{
- func(w io.Writer, outputFile android.Path) {
+ ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+ func(entries *android.AndroidMkEntries) {
if len(library.logtagsSrcs) > 0 {
var logtags []string
for _, l := range library.logtagsSrcs {
logtags = append(logtags, l.Rel())
}
- fmt.Fprintln(w, "LOCAL_LOGTAGS_FILES :=", strings.Join(logtags, " "))
+ entries.AddStrings("LOCAL_LOGTAGS_FILES", logtags...)
}
if library.installFile == nil {
- fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
+ entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", true)
}
if library.dexJarFile != nil {
- fmt.Fprintln(w, "LOCAL_SOONG_DEX_JAR :=", library.dexJarFile.String())
+ entries.SetPath("LOCAL_SOONG_DEX_JAR", library.dexJarFile)
}
if len(library.dexpreopter.builtInstalled) > 0 {
- fmt.Fprintln(w, "LOCAL_SOONG_BUILT_INSTALLED :=", library.dexpreopter.builtInstalled)
+ entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", library.dexpreopter.builtInstalled)
}
- fmt.Fprintln(w, "LOCAL_SDK_VERSION :=", library.sdkVersion())
- fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", library.implementationAndResourcesJar.String())
- fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", library.headerJarFile.String())
+ entries.SetString("LOCAL_SDK_VERSION", library.sdkVersion())
+ entries.SetPath("LOCAL_SOONG_CLASSES_JAR", library.implementationAndResourcesJar)
+ entries.SetPath("LOCAL_SOONG_HEADER_JAR", library.headerJarFile)
if library.jacocoReportClassesFile != nil {
- fmt.Fprintln(w, "LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR :=", library.jacocoReportClassesFile.String())
+ entries.SetPath("LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR", library.jacocoReportClassesFile)
}
- if len(library.exportedSdkLibs) != 0 {
- fmt.Fprintln(w, "LOCAL_EXPORT_SDK_LIBRARIES :=", strings.Join(library.exportedSdkLibs, " "))
- }
+ entries.AddStrings("LOCAL_EXPORT_SDK_LIBRARIES", library.exportedSdkLibs...)
if len(library.additionalCheckedModules) != 0 {
- fmt.Fprintln(w, "LOCAL_ADDITIONAL_CHECKED_MODULE +=", strings.Join(library.additionalCheckedModules.Strings(), " "))
+ entries.AddStrings("LOCAL_ADDITIONAL_CHECKED_MODULE", library.additionalCheckedModules.Strings()...)
}
if library.proguardDictionary != nil {
- fmt.Fprintln(w, "LOCAL_SOONG_PROGUARD_DICT :=", library.proguardDictionary.String())
+ entries.SetPath("LOCAL_SOONG_PROGUARD_DICT", library.proguardDictionary)
}
},
},
- Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
- android.WriteAndroidMkData(w, data)
- library.AndroidMkHostDex(w, name, data)
+ ExtraFooters: []android.AndroidMkExtraFootersFunc{
+ func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
+ library.AndroidMkHostDex(w, name, entries)
+ },
},
}
}
// Called for modules that are a component of a test suite.
-func testSuiteComponent(w io.Writer, test_suites []string) {
- fmt.Fprintln(w, "LOCAL_MODULE_TAGS := tests")
+func testSuiteComponent(entries *android.AndroidMkEntries, test_suites []string) {
+ entries.SetString("LOCAL_MODULE_TAGS", "tests")
if len(test_suites) > 0 {
- fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE :=",
- strings.Join(test_suites, " "))
+ entries.AddStrings("LOCAL_COMPATIBILITY_SUITE", test_suites...)
} else {
- fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE := null-suite")
+ entries.SetString("LOCAL_COMPATIBILITY_SUITE", "null-suite")
}
}
-func (j *Test) AndroidMk() android.AndroidMkData {
- data := j.Library.AndroidMk()
- data.Extra = append(data.Extra, func(w io.Writer, outputFile android.Path) {
- testSuiteComponent(w, j.testProperties.Test_suites)
+func (j *Test) AndroidMkEntries() android.AndroidMkEntries {
+ entries := j.Library.AndroidMkEntries()
+ entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+ testSuiteComponent(entries, j.testProperties.Test_suites)
if j.testConfig != nil {
- fmt.Fprintln(w, "LOCAL_FULL_TEST_CONFIG :=", j.testConfig.String())
+ entries.SetPath("LOCAL_FULL_TEST_CONFIG", j.testConfig)
}
+ androidMkWriteTestData(j.data, entries)
})
- androidMkWriteTestData(j.data, &data)
-
- return data
+ return entries
}
-func (j *TestHelperLibrary) AndroidMk() android.AndroidMkData {
- data := j.Library.AndroidMk()
- data.Extra = append(data.Extra, func(w io.Writer, outputFile android.Path) {
- testSuiteComponent(w, j.testHelperLibraryProperties.Test_suites)
+func (j *TestHelperLibrary) AndroidMkEntries() android.AndroidMkEntries {
+ entries := j.Library.AndroidMkEntries()
+ entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+ testSuiteComponent(entries, j.testHelperLibraryProperties.Test_suites)
})
- return data
+ return entries
}
-func (prebuilt *Import) AndroidMk() android.AndroidMkData {
- if !prebuilt.IsForPlatform() {
- return android.AndroidMkData{
+func (prebuilt *Import) AndroidMkEntries() android.AndroidMkEntries {
+ if !prebuilt.IsForPlatform() || !prebuilt.ContainingSdk().Unversioned() {
+ return android.AndroidMkEntries{
Disabled: true,
}
}
- return android.AndroidMkData{
+ return android.AndroidMkEntries{
Class: "JAVA_LIBRARIES",
OutputFile: android.OptionalPathForPath(prebuilt.combinedClasspathFile),
Include: "$(BUILD_SYSTEM)/soong_java_prebuilt.mk",
- Extra: []android.AndroidMkExtraFunc{
- func(w io.Writer, outputFile android.Path) {
- fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := ", !Bool(prebuilt.properties.Installable))
- fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", prebuilt.combinedClasspathFile.String())
- fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", prebuilt.combinedClasspathFile.String())
- fmt.Fprintln(w, "LOCAL_SDK_VERSION :=", prebuilt.sdkVersion())
+ ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+ func(entries *android.AndroidMkEntries) {
+ entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", !Bool(prebuilt.properties.Installable))
+ entries.SetPath("LOCAL_SOONG_HEADER_JAR", prebuilt.combinedClasspathFile)
+ entries.SetPath("LOCAL_SOONG_CLASSES_JAR", prebuilt.combinedClasspathFile)
+ entries.SetString("LOCAL_SDK_VERSION", prebuilt.sdkVersion())
},
},
}
}
-func (prebuilt *DexImport) AndroidMk() android.AndroidMkData {
+func (prebuilt *DexImport) AndroidMkEntries() android.AndroidMkEntries {
if !prebuilt.IsForPlatform() {
- return android.AndroidMkData{
+ return android.AndroidMkEntries{
Disabled: true,
}
}
- return android.AndroidMkData{
+ return android.AndroidMkEntries{
Class: "JAVA_LIBRARIES",
OutputFile: android.OptionalPathForPath(prebuilt.maybeStrippedDexJarFile),
Include: "$(BUILD_SYSTEM)/soong_java_prebuilt.mk",
- Extra: []android.AndroidMkExtraFunc{
- func(w io.Writer, outputFile android.Path) {
+ ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+ func(entries *android.AndroidMkEntries) {
if prebuilt.dexJarFile != nil {
- fmt.Fprintln(w, "LOCAL_SOONG_DEX_JAR :=", prebuilt.dexJarFile.String())
+ entries.SetPath("LOCAL_SOONG_DEX_JAR", prebuilt.dexJarFile)
// TODO(b/125517186): export the dex jar as a classes jar to match some mis-uses in Make until
// boot_jars_package_check.mk can check dex jars.
- fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", prebuilt.dexJarFile.String())
- fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", prebuilt.dexJarFile.String())
+ entries.SetPath("LOCAL_SOONG_HEADER_JAR", prebuilt.dexJarFile)
+ entries.SetPath("LOCAL_SOONG_CLASSES_JAR", prebuilt.dexJarFile)
}
if len(prebuilt.dexpreopter.builtInstalled) > 0 {
- fmt.Fprintln(w, "LOCAL_SOONG_BUILT_INSTALLED :=", prebuilt.dexpreopter.builtInstalled)
+ entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", prebuilt.dexpreopter.builtInstalled)
}
},
},
}
}
-func (prebuilt *AARImport) AndroidMk() android.AndroidMkData {
- return android.AndroidMkData{
+func (prebuilt *AARImport) AndroidMkEntries() android.AndroidMkEntries {
+ return android.AndroidMkEntries{
Class: "JAVA_LIBRARIES",
OutputFile: android.OptionalPathForPath(prebuilt.classpathFile),
Include: "$(BUILD_SYSTEM)/soong_java_prebuilt.mk",
- Extra: []android.AndroidMkExtraFunc{
- func(w io.Writer, outputFile android.Path) {
- fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
- fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", prebuilt.classpathFile.String())
- fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", prebuilt.classpathFile.String())
- fmt.Fprintln(w, "LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE :=", prebuilt.exportPackage.String())
- fmt.Fprintln(w, "LOCAL_SOONG_EXPORT_PROGUARD_FLAGS :=", prebuilt.proguardFlags.String())
- fmt.Fprintln(w, "LOCAL_SOONG_STATIC_LIBRARY_EXTRA_PACKAGES :=", prebuilt.extraAaptPackagesFile.String())
- fmt.Fprintln(w, "LOCAL_FULL_MANIFEST_FILE :=", prebuilt.manifest.String())
- fmt.Fprintln(w, "LOCAL_SDK_VERSION :=", prebuilt.sdkVersion())
+ ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+ func(entries *android.AndroidMkEntries) {
+ entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
+ entries.SetPath("LOCAL_SOONG_HEADER_JAR", prebuilt.classpathFile)
+ entries.SetPath("LOCAL_SOONG_CLASSES_JAR", prebuilt.classpathFile)
+ entries.SetPath("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE", prebuilt.exportPackage)
+ entries.SetPath("LOCAL_SOONG_EXPORT_PROGUARD_FLAGS", prebuilt.proguardFlags)
+ entries.SetPath("LOCAL_SOONG_STATIC_LIBRARY_EXTRA_PACKAGES", prebuilt.extraAaptPackagesFile)
+ entries.SetPath("LOCAL_FULL_MANIFEST_FILE", prebuilt.manifest)
+ entries.SetString("LOCAL_SDK_VERSION", prebuilt.sdkVersion())
},
},
}
}
-func (binary *Binary) AndroidMk() android.AndroidMkData {
+func (binary *Binary) AndroidMkEntries() android.AndroidMkEntries {
if !binary.isWrapperVariant {
- return android.AndroidMkData{
+ return android.AndroidMkEntries{
Class: "JAVA_LIBRARIES",
OutputFile: android.OptionalPathForPath(binary.outputFile),
Include: "$(BUILD_SYSTEM)/soong_java_prebuilt.mk",
- Extra: []android.AndroidMkExtraFunc{
- func(w io.Writer, outputFile android.Path) {
- fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", binary.headerJarFile.String())
- fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", binary.implementationAndResourcesJar.String())
+ ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+ func(entries *android.AndroidMkEntries) {
+ entries.SetPath("LOCAL_SOONG_HEADER_JAR", binary.headerJarFile)
+ entries.SetPath("LOCAL_SOONG_CLASSES_JAR", binary.implementationAndResourcesJar)
if binary.dexJarFile != nil {
- fmt.Fprintln(w, "LOCAL_SOONG_DEX_JAR :=", binary.dexJarFile.String())
+ entries.SetPath("LOCAL_SOONG_DEX_JAR", binary.dexJarFile)
}
if len(binary.dexpreopter.builtInstalled) > 0 {
- fmt.Fprintln(w, "LOCAL_SOONG_BUILT_INSTALLED :=", binary.dexpreopter.builtInstalled)
+ entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", binary.dexpreopter.builtInstalled)
}
},
},
- Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
- android.WriteAndroidMkData(w, data)
-
- fmt.Fprintln(w, "jar_installed_module := $(LOCAL_INSTALLED_MODULE)")
+ ExtraFooters: []android.AndroidMkExtraFootersFunc{
+ func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
+ fmt.Fprintln(w, "jar_installed_module := $(LOCAL_INSTALLED_MODULE)")
+ },
},
}
} else {
- return android.AndroidMkData{
+ return android.AndroidMkEntries{
Class: "EXECUTABLES",
OutputFile: android.OptionalPathForPath(binary.wrapperFile),
- Extra: []android.AndroidMkExtraFunc{
- func(w io.Writer, outputFile android.Path) {
- fmt.Fprintln(w, "LOCAL_STRIP_MODULE := false")
+ ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+ func(entries *android.AndroidMkEntries) {
+ entries.SetBool("LOCAL_STRIP_MODULE", false)
},
},
- Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
- android.WriteAndroidMkData(w, data)
-
- // Ensure that the wrapper script timestamp is always updated when the jar is updated
- fmt.Fprintln(w, "$(LOCAL_INSTALLED_MODULE): $(jar_installed_module)")
- fmt.Fprintln(w, "jar_installed_module :=")
+ ExtraFooters: []android.AndroidMkExtraFootersFunc{
+ func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
+ // Ensure that the wrapper script timestamp is always updated when the jar is updated
+ fmt.Fprintln(w, "$(LOCAL_INSTALLED_MODULE): $(jar_installed_module)")
+ fmt.Fprintln(w, "jar_installed_module :=")
+ },
},
}
}
}
-func (app *AndroidApp) AndroidMk() android.AndroidMkData {
- return android.AndroidMkData{
+func (app *AndroidApp) AndroidMkEntries() android.AndroidMkEntries {
+ return android.AndroidMkEntries{
Class: "APPS",
OutputFile: android.OptionalPathForPath(app.outputFile),
Include: "$(BUILD_SYSTEM)/soong_app_prebuilt.mk",
- Extra: []android.AndroidMkExtraFunc{
- func(w io.Writer, outputFile android.Path) {
- // TODO(jungjw): This, outputting two LOCAL_MODULE lines, works, but is not ideal. Find a better solution.
- if app.Name() != app.installApkName {
- fmt.Fprintln(w, "# Overridden by PRODUCT_PACKAGE_NAME_OVERRIDES")
- fmt.Fprintln(w, "LOCAL_MODULE :=", app.installApkName)
- }
- fmt.Fprintln(w, "LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE :=", app.exportPackage.String())
+ ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+ func(entries *android.AndroidMkEntries) {
+ // App module names can be overridden.
+ entries.SetString("LOCAL_MODULE", app.installApkName)
+ entries.SetPath("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE", app.exportPackage)
if app.dexJarFile != nil {
- fmt.Fprintln(w, "LOCAL_SOONG_DEX_JAR :=", app.dexJarFile.String())
+ entries.SetPath("LOCAL_SOONG_DEX_JAR", app.dexJarFile)
}
if app.implementationAndResourcesJar != nil {
- fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", app.implementationAndResourcesJar.String())
+ entries.SetPath("LOCAL_SOONG_CLASSES_JAR", app.implementationAndResourcesJar)
}
if app.headerJarFile != nil {
- fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", app.headerJarFile.String())
+ entries.SetPath("LOCAL_SOONG_HEADER_JAR", app.headerJarFile)
}
if app.bundleFile != nil {
- fmt.Fprintln(w, "LOCAL_SOONG_BUNDLE :=", app.bundleFile.String())
+ entries.SetPath("LOCAL_SOONG_BUNDLE", app.bundleFile)
}
if app.jacocoReportClassesFile != nil {
- fmt.Fprintln(w, "LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR :=", app.jacocoReportClassesFile.String())
+ entries.SetPath("LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR", app.jacocoReportClassesFile)
}
if app.proguardDictionary != nil {
- fmt.Fprintln(w, "LOCAL_SOONG_PROGUARD_DICT :=", app.proguardDictionary.String())
+ entries.SetPath("LOCAL_SOONG_PROGUARD_DICT", app.proguardDictionary)
}
if app.Name() == "framework-res" {
- fmt.Fprintln(w, "LOCAL_MODULE_PATH := $(TARGET_OUT_JAVA_LIBRARIES)")
+ entries.SetString("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")
+ entries.SetBoolIfTrue("LOCAL_NO_STANDARD_LIBRARIES", true)
}
filterRRO := func(filter overlayType) android.Paths {
@@ -310,38 +306,37 @@
}
deviceRRODirs := filterRRO(device)
if len(deviceRRODirs) > 0 {
- fmt.Fprintln(w, "LOCAL_SOONG_DEVICE_RRO_DIRS :=", strings.Join(deviceRRODirs.Strings(), " "))
+ entries.AddStrings("LOCAL_SOONG_DEVICE_RRO_DIRS", deviceRRODirs.Strings()...)
}
productRRODirs := filterRRO(product)
if len(productRRODirs) > 0 {
- fmt.Fprintln(w, "LOCAL_SOONG_PRODUCT_RRO_DIRS :=", strings.Join(productRRODirs.Strings(), " "))
+ entries.AddStrings("LOCAL_SOONG_PRODUCT_RRO_DIRS", productRRODirs.Strings()...)
}
- if Bool(app.appProperties.Export_package_resources) {
- fmt.Fprintln(w, "LOCAL_EXPORT_PACKAGE_RESOURCES := true")
- }
+ entries.SetBoolIfTrue("LOCAL_EXPORT_PACKAGE_RESOURCES", Bool(app.appProperties.Export_package_resources))
- fmt.Fprintln(w, "LOCAL_FULL_MANIFEST_FILE :=", app.manifestPath.String())
+ entries.SetPath("LOCAL_FULL_MANIFEST_FILE", app.manifestPath)
- if Bool(app.appProperties.Privileged) {
- fmt.Fprintln(w, "LOCAL_PRIVILEGED_MODULE := true")
- }
+ entries.SetBoolIfTrue("LOCAL_PRIVILEGED_MODULE", app.Privileged())
- fmt.Fprintln(w, "LOCAL_CERTIFICATE :=", app.certificate.Pem.String())
- if overriddenPkgs := app.getOverriddenPackages(); len(overriddenPkgs) > 0 {
- fmt.Fprintln(w, "LOCAL_OVERRIDES_PACKAGES :=", strings.Join(overriddenPkgs, " "))
- }
+ entries.SetPath("LOCAL_CERTIFICATE", app.certificate.Pem)
+ entries.AddStrings("LOCAL_OVERRIDES_PACKAGES", app.getOverriddenPackages()...)
for _, jniLib := range app.installJniLibs {
- fmt.Fprintln(w, "LOCAL_SOONG_JNI_LIBS_"+jniLib.target.Arch.ArchType.String(), "+=", jniLib.name)
+ entries.AddStrings("LOCAL_SOONG_JNI_LIBS_"+jniLib.target.Arch.ArchType.String(), jniLib.name)
}
if len(app.dexpreopter.builtInstalled) > 0 {
- fmt.Fprintln(w, "LOCAL_SOONG_BUILT_INSTALLED :=", app.dexpreopter.builtInstalled)
+ entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", app.dexpreopter.builtInstalled)
}
for _, split := range app.aapt.splits {
- install := "$(LOCAL_MODULE_PATH)/" + strings.TrimSuffix(app.installApkName, ".apk") + split.suffix + ".apk"
- fmt.Fprintln(w, "LOCAL_SOONG_BUILT_INSTALLED +=", split.path.String()+":"+install)
+ install := app.onDeviceDir + "/" +
+ strings.TrimSuffix(app.installApkName, ".apk") + "_" + split.suffix + ".apk"
+ entries.AddStrings("LOCAL_SOONG_BUILT_INSTALLED", split.path.String()+":"+install)
}
+ },
+ },
+ ExtraFooters: []android.AndroidMkExtraFootersFunc{
+ func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
if app.noticeOutputs.Merged.Valid() {
fmt.Fprintf(w, "$(call dist-for-goals,%s,%s:%s)\n",
app.installApkName, app.noticeOutputs.Merged.String(), app.installApkName+"_NOTICE")
@@ -370,85 +365,116 @@
return overridden
}
-func (a *AndroidTest) AndroidMk() android.AndroidMkData {
- data := a.AndroidApp.AndroidMk()
- data.Extra = append(data.Extra, func(w io.Writer, outputFile android.Path) {
- testSuiteComponent(w, a.testProperties.Test_suites)
+func (a *AndroidTest) AndroidMkEntries() android.AndroidMkEntries {
+ entries := a.AndroidApp.AndroidMkEntries()
+ entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+ testSuiteComponent(entries, a.testProperties.Test_suites)
if a.testConfig != nil {
- fmt.Fprintln(w, "LOCAL_FULL_TEST_CONFIG :=", a.testConfig.String())
+ entries.SetPath("LOCAL_FULL_TEST_CONFIG", a.testConfig)
}
- })
- androidMkWriteTestData(a.data, &data)
-
- return data
-}
-
-func (a *AndroidTestHelperApp) AndroidMk() android.AndroidMkData {
- data := a.AndroidApp.AndroidMk()
- data.Extra = append(data.Extra, func(w io.Writer, outputFile android.Path) {
- testSuiteComponent(w, a.appTestHelperAppProperties.Test_suites)
+ androidMkWriteTestData(a.data, entries)
})
- return data
+ return entries
}
-func (a *AndroidLibrary) AndroidMk() android.AndroidMkData {
- data := a.Library.AndroidMk()
+func (a *AndroidTestHelperApp) AndroidMkEntries() android.AndroidMkEntries {
+ entries := a.AndroidApp.AndroidMkEntries()
+ entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+ testSuiteComponent(entries, a.appTestHelperAppProperties.Test_suites)
+ })
- data.Extra = append(data.Extra, func(w io.Writer, outputFile android.Path) {
+ return entries
+}
+
+func (a *AndroidLibrary) AndroidMkEntries() android.AndroidMkEntries {
+ entries := a.Library.AndroidMkEntries()
+
+ entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
if a.aarFile != nil {
- fmt.Fprintln(w, "LOCAL_SOONG_AAR :=", a.aarFile.String())
+ entries.SetPath("LOCAL_SOONG_AAR", a.aarFile)
}
if a.Name() == "framework-res" {
- fmt.Fprintln(w, "LOCAL_MODULE_PATH := $(TARGET_OUT_JAVA_LIBRARIES)")
+ entries.SetString("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")
+ entries.SetBoolIfTrue("LOCAL_NO_STANDARD_LIBRARIES", true)
}
- fmt.Fprintln(w, "LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE :=", a.exportPackage.String())
- fmt.Fprintln(w, "LOCAL_SOONG_STATIC_LIBRARY_EXTRA_PACKAGES :=", a.extraAaptPackagesFile.String())
- fmt.Fprintln(w, "LOCAL_FULL_MANIFEST_FILE :=", a.mergedManifestFile.String())
- fmt.Fprintln(w, "LOCAL_SOONG_EXPORT_PROGUARD_FLAGS :=",
- strings.Join(a.exportedProguardFlagFiles.Strings(), " "))
- fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
+ entries.SetPath("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE", a.exportPackage)
+ entries.SetPath("LOCAL_SOONG_STATIC_LIBRARY_EXTRA_PACKAGES", a.extraAaptPackagesFile)
+ entries.SetPath("LOCAL_FULL_MANIFEST_FILE", a.mergedManifestFile)
+ entries.AddStrings("LOCAL_SOONG_EXPORT_PROGUARD_FLAGS", a.exportedProguardFlagFiles.Strings()...)
+ entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", true)
})
- return data
+ return entries
}
-func (jd *Javadoc) AndroidMk() android.AndroidMkData {
- return android.AndroidMkData{
+func (jd *Javadoc) AndroidMkEntries() android.AndroidMkEntries {
+ return android.AndroidMkEntries{
Class: "JAVA_LIBRARIES",
OutputFile: android.OptionalPathForPath(jd.stubsSrcJar),
Include: "$(BUILD_SYSTEM)/soong_droiddoc_prebuilt.mk",
- Extra: []android.AndroidMkExtraFunc{
- func(w io.Writer, outputFile android.Path) {
+ ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+ func(entries *android.AndroidMkEntries) {
if BoolDefault(jd.properties.Installable, true) {
- fmt.Fprintln(w, "LOCAL_DROIDDOC_DOC_ZIP := ", jd.docZip.String())
+ entries.SetPath("LOCAL_DROIDDOC_DOC_ZIP", jd.docZip)
}
if jd.stubsSrcJar != nil {
- fmt.Fprintln(w, "LOCAL_DROIDDOC_STUBS_SRCJAR := ", jd.stubsSrcJar.String())
+ entries.SetPath("LOCAL_DROIDDOC_STUBS_SRCJAR", jd.stubsSrcJar)
}
},
},
}
}
-func (ddoc *Droiddoc) AndroidMk() android.AndroidMkData {
- return android.AndroidMkData{
+func (ddoc *Droiddoc) AndroidMkEntries() android.AndroidMkEntries {
+ return android.AndroidMkEntries{
Class: "JAVA_LIBRARIES",
OutputFile: android.OptionalPathForPath(ddoc.stubsSrcJar),
Include: "$(BUILD_SYSTEM)/soong_droiddoc_prebuilt.mk",
- Extra: []android.AndroidMkExtraFunc{
- func(w io.Writer, outputFile android.Path) {
+ ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+ func(entries *android.AndroidMkEntries) {
if BoolDefault(ddoc.Javadoc.properties.Installable, true) && ddoc.Javadoc.docZip != nil {
- fmt.Fprintln(w, "LOCAL_DROIDDOC_DOC_ZIP := ", ddoc.Javadoc.docZip.String())
+ entries.SetPath("LOCAL_DROIDDOC_DOC_ZIP", ddoc.Javadoc.docZip)
}
if ddoc.Javadoc.stubsSrcJar != nil {
- fmt.Fprintln(w, "LOCAL_DROIDDOC_STUBS_SRCJAR := ", ddoc.Javadoc.stubsSrcJar.String())
+ entries.SetPath("LOCAL_DROIDDOC_STUBS_SRCJAR", ddoc.Javadoc.stubsSrcJar)
}
+ apiFilePrefix := "INTERNAL_PLATFORM_"
+ if String(ddoc.properties.Api_tag_name) != "" {
+ apiFilePrefix += String(ddoc.properties.Api_tag_name) + "_"
+ }
+ if ddoc.apiFile != nil {
+ entries.SetPath(apiFilePrefix+"API_FILE", ddoc.apiFile)
+ }
+ if ddoc.dexApiFile != nil {
+ entries.SetPath(apiFilePrefix+"DEX_API_FILE", ddoc.dexApiFile)
+ }
+ if ddoc.privateApiFile != nil {
+ entries.SetPath(apiFilePrefix+"PRIVATE_API_FILE", ddoc.privateApiFile)
+ }
+ if ddoc.privateDexApiFile != nil {
+ entries.SetPath(apiFilePrefix+"PRIVATE_DEX_API_FILE", ddoc.privateDexApiFile)
+ }
+ if ddoc.removedApiFile != nil {
+ entries.SetPath(apiFilePrefix+"REMOVED_API_FILE", ddoc.removedApiFile)
+ }
+ if ddoc.removedDexApiFile != nil {
+ entries.SetPath(apiFilePrefix+"REMOVED_DEX_API_FILE", ddoc.removedDexApiFile)
+ }
+ if ddoc.exactApiFile != nil {
+ entries.SetPath(apiFilePrefix+"EXACT_API_FILE", ddoc.exactApiFile)
+ }
+ if ddoc.proguardFile != nil {
+ entries.SetPath(apiFilePrefix+"PROGUARD_FILE", ddoc.proguardFile)
+ }
+ },
+ },
+ ExtraFooters: []android.AndroidMkExtraFootersFunc{
+ func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
if ddoc.checkCurrentApiTimestamp != nil {
fmt.Fprintln(w, ".PHONY:", ddoc.Name()+"-check-current-api")
fmt.Fprintln(w, ddoc.Name()+"-check-current-api:",
@@ -484,58 +510,62 @@
fmt.Fprintln(w, "droidcore: checkapi")
}
}
- apiFilePrefix := "INTERNAL_PLATFORM_"
- if String(ddoc.properties.Api_tag_name) != "" {
- apiFilePrefix += String(ddoc.properties.Api_tag_name) + "_"
- }
- if ddoc.apiFile != nil {
- fmt.Fprintln(w, apiFilePrefix+"API_FILE := ", ddoc.apiFile.String())
- }
- if ddoc.dexApiFile != nil {
- fmt.Fprintln(w, apiFilePrefix+"DEX_API_FILE := ", ddoc.dexApiFile.String())
- }
- if ddoc.privateApiFile != nil {
- fmt.Fprintln(w, apiFilePrefix+"PRIVATE_API_FILE := ", ddoc.privateApiFile.String())
- }
- if ddoc.privateDexApiFile != nil {
- fmt.Fprintln(w, apiFilePrefix+"PRIVATE_DEX_API_FILE := ", ddoc.privateDexApiFile.String())
- }
- if ddoc.removedApiFile != nil {
- fmt.Fprintln(w, apiFilePrefix+"REMOVED_API_FILE := ", ddoc.removedApiFile.String())
- }
- if ddoc.removedDexApiFile != nil {
- fmt.Fprintln(w, apiFilePrefix+"REMOVED_DEX_API_FILE := ", ddoc.removedDexApiFile.String())
- }
- if ddoc.exactApiFile != nil {
- fmt.Fprintln(w, apiFilePrefix+"EXACT_API_FILE := ", ddoc.exactApiFile.String())
- }
- if ddoc.proguardFile != nil {
- fmt.Fprintln(w, apiFilePrefix+"PROGUARD_FILE := ", ddoc.proguardFile.String())
- }
},
},
}
}
-func (dstubs *Droidstubs) AndroidMk() android.AndroidMkData {
- return android.AndroidMkData{
+func (dstubs *Droidstubs) AndroidMkEntries() android.AndroidMkEntries {
+ return android.AndroidMkEntries{
Class: "JAVA_LIBRARIES",
OutputFile: android.OptionalPathForPath(dstubs.stubsSrcJar),
Include: "$(BUILD_SYSTEM)/soong_droiddoc_prebuilt.mk",
- Extra: []android.AndroidMkExtraFunc{
- func(w io.Writer, outputFile android.Path) {
+ ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+ func(entries *android.AndroidMkEntries) {
if dstubs.Javadoc.stubsSrcJar != nil {
- fmt.Fprintln(w, "LOCAL_DROIDDOC_STUBS_SRCJAR := ", dstubs.Javadoc.stubsSrcJar.String())
+ entries.SetPath("LOCAL_DROIDDOC_STUBS_SRCJAR", dstubs.Javadoc.stubsSrcJar)
}
if dstubs.apiVersionsXml != nil {
- fmt.Fprintln(w, "LOCAL_DROIDDOC_API_VERSIONS_XML := ", dstubs.apiVersionsXml.String())
+ entries.SetPath("LOCAL_DROIDDOC_API_VERSIONS_XML", dstubs.apiVersionsXml)
}
if dstubs.annotationsZip != nil {
- fmt.Fprintln(w, "LOCAL_DROIDDOC_ANNOTATIONS_ZIP := ", dstubs.annotationsZip.String())
+ entries.SetPath("LOCAL_DROIDDOC_ANNOTATIONS_ZIP", dstubs.annotationsZip)
}
if dstubs.jdiffDocZip != nil {
- fmt.Fprintln(w, "LOCAL_DROIDDOC_JDIFF_DOC_ZIP := ", dstubs.jdiffDocZip.String())
+ entries.SetPath("LOCAL_DROIDDOC_JDIFF_DOC_ZIP", dstubs.jdiffDocZip)
}
+ if dstubs.metadataZip != nil {
+ entries.SetPath("LOCAL_DROIDDOC_METADATA_ZIP", dstubs.metadataZip)
+ }
+ apiFilePrefix := "INTERNAL_PLATFORM_"
+ if String(dstubs.properties.Api_tag_name) != "" {
+ apiFilePrefix += String(dstubs.properties.Api_tag_name) + "_"
+ }
+ if dstubs.apiFile != nil {
+ entries.SetPath(apiFilePrefix+"API_FILE", dstubs.apiFile)
+ }
+ if dstubs.dexApiFile != nil {
+ entries.SetPath(apiFilePrefix+"DEX_API_FILE", dstubs.dexApiFile)
+ }
+ if dstubs.privateApiFile != nil {
+ entries.SetPath(apiFilePrefix+"PRIVATE_API_FILE", dstubs.privateApiFile)
+ }
+ if dstubs.privateDexApiFile != nil {
+ entries.SetPath(apiFilePrefix+"PRIVATE_DEX_API_FILE", dstubs.privateDexApiFile)
+ }
+ if dstubs.removedApiFile != nil {
+ entries.SetPath(apiFilePrefix+"REMOVED_API_FILE", dstubs.removedApiFile)
+ }
+ if dstubs.removedDexApiFile != nil {
+ entries.SetPath(apiFilePrefix+"REMOVED_DEX_API_FILE", dstubs.removedDexApiFile)
+ }
+ if dstubs.exactApiFile != nil {
+ entries.SetPath(apiFilePrefix+"EXACT_API_FILE", dstubs.exactApiFile)
+ }
+ },
+ },
+ ExtraFooters: []android.AndroidMkExtraFootersFunc{
+ func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
if dstubs.checkCurrentApiTimestamp != nil {
fmt.Fprintln(w, ".PHONY:", dstubs.Name()+"-check-current-api")
fmt.Fprintln(w, dstubs.Name()+"-check-current-api:",
@@ -571,6 +601,18 @@
fmt.Fprintln(w, "droidcore: checkapi")
}
}
+ if dstubs.apiLintTimestamp != nil {
+ fmt.Fprintln(w, ".PHONY:", dstubs.Name()+"-api-lint")
+ fmt.Fprintln(w, dstubs.Name()+"-api-lint:",
+ dstubs.apiLintTimestamp.String())
+
+ fmt.Fprintln(w, ".PHONY: checkapi")
+ fmt.Fprintln(w, "checkapi:",
+ dstubs.apiLintTimestamp.String())
+
+ fmt.Fprintln(w, ".PHONY: droidcore")
+ fmt.Fprintln(w, "droidcore: checkapi")
+ }
if dstubs.checkNullabilityWarningsTimestamp != nil {
fmt.Fprintln(w, ".PHONY:", dstubs.Name()+"-check-nullability-warnings")
fmt.Fprintln(w, dstubs.Name()+"-check-nullability-warnings:",
@@ -579,31 +621,6 @@
fmt.Fprintln(w, ".PHONY:", "droidcore")
fmt.Fprintln(w, "droidcore: ", dstubs.Name()+"-check-nullability-warnings")
}
- apiFilePrefix := "INTERNAL_PLATFORM_"
- if String(dstubs.properties.Api_tag_name) != "" {
- apiFilePrefix += String(dstubs.properties.Api_tag_name) + "_"
- }
- if dstubs.apiFile != nil {
- fmt.Fprintln(w, apiFilePrefix+"API_FILE := ", dstubs.apiFile.String())
- }
- if dstubs.dexApiFile != nil {
- fmt.Fprintln(w, apiFilePrefix+"DEX_API_FILE := ", dstubs.dexApiFile.String())
- }
- if dstubs.privateApiFile != nil {
- fmt.Fprintln(w, apiFilePrefix+"PRIVATE_API_FILE := ", dstubs.privateApiFile.String())
- }
- if dstubs.privateDexApiFile != nil {
- fmt.Fprintln(w, apiFilePrefix+"PRIVATE_DEX_API_FILE := ", dstubs.privateDexApiFile.String())
- }
- if dstubs.removedApiFile != nil {
- fmt.Fprintln(w, apiFilePrefix+"REMOVED_API_FILE := ", dstubs.removedApiFile.String())
- }
- if dstubs.removedDexApiFile != nil {
- fmt.Fprintln(w, apiFilePrefix+"REMOVED_DEX_API_FILE := ", dstubs.removedDexApiFile.String())
- }
- if dstubs.exactApiFile != nil {
- fmt.Fprintln(w, apiFilePrefix+"EXACT_API_FILE := ", dstubs.exactApiFile.String())
- }
},
},
}
@@ -614,30 +631,37 @@
Class: "APPS",
OutputFile: android.OptionalPathForPath(a.outputFile),
Include: "$(BUILD_SYSTEM)/soong_app_prebuilt.mk",
- AddCustomEntries: func(name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
- entries.SetBoolIfTrue("LOCAL_PRIVILEGED_MODULE", Bool(a.properties.Privileged))
- if a.certificate != nil {
- entries.SetString("LOCAL_CERTIFICATE", a.certificate.Pem.String())
- } else {
- entries.SetString("LOCAL_CERTIFICATE", "PRESIGNED")
- }
- entries.AddStrings("LOCAL_OVERRIDES_PACKAGES", a.properties.Overrides...)
- if len(a.dexpreopter.builtInstalled) > 0 {
- entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", a.dexpreopter.builtInstalled)
- }
- entries.AddStrings("LOCAL_INSTALLED_MODULE_STEM", a.installPath.Rel())
+ ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+ func(entries *android.AndroidMkEntries) {
+ entries.SetBoolIfTrue("LOCAL_PRIVILEGED_MODULE", a.Privileged())
+ if a.certificate != nil {
+ entries.SetPath("LOCAL_CERTIFICATE", a.certificate.Pem)
+ } else {
+ entries.SetString("LOCAL_CERTIFICATE", "PRESIGNED")
+ }
+ entries.AddStrings("LOCAL_OVERRIDES_PACKAGES", a.properties.Overrides...)
+ if len(a.dexpreopter.builtInstalled) > 0 {
+ entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", a.dexpreopter.builtInstalled)
+ }
+ entries.AddStrings("LOCAL_INSTALLED_MODULE_STEM", a.installPath.Rel())
+ },
},
}
}
-func androidMkWriteTestData(data android.Paths, ret *android.AndroidMkData) {
+func (a *AndroidTestImport) AndroidMkEntries() android.AndroidMkEntries {
+ entries := a.AndroidAppImport.AndroidMkEntries()
+ entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+ testSuiteComponent(entries, a.testProperties.Test_suites)
+ androidMkWriteTestData(a.data, entries)
+ })
+ return entries
+}
+
+func androidMkWriteTestData(data android.Paths, entries *android.AndroidMkEntries) {
var testFiles []string
for _, d := range data {
testFiles = append(testFiles, d.String()+":"+d.Rel())
}
- if len(testFiles) > 0 {
- ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
- fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUPPORT_FILES := "+strings.Join(testFiles, " "))
- })
- }
+ entries.AddStrings("LOCAL_COMPATIBILITY_SUPPORT_FILES", testFiles...)
}
diff --git a/java/androidmk_test.go b/java/androidmk_test.go
index fbf2baa..438b66a 100644
--- a/java/androidmk_test.go
+++ b/java/androidmk_test.go
@@ -15,107 +15,12 @@
package java
import (
- "bytes"
- "io"
- "io/ioutil"
- "strings"
+ "reflect"
"testing"
"android/soong/android"
)
-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) {
ctx, config := testJava(t, `
java_library {
@@ -125,8 +30,14 @@
}
`)
- mk := getAndroidMk(t, ctx, config, "foo")
- mk.moduleFor("foo").hasRequired("libfoo")
+ mod := ctx.ModuleForTests("foo", "android_common").Module()
+ entries := android.AndroidMkEntriesForTest(t, config, "", mod)
+
+ expected := []string{"libfoo"}
+ actual := entries.EntryMap["LOCAL_REQUIRED_MODULES"]
+ if !reflect.DeepEqual(expected, actual) {
+ t.Errorf("Unexpected required modules - expected: %q, actual: %q", expected, actual)
+ }
}
func TestHostdex(t *testing.T) {
@@ -138,9 +49,19 @@
}
`)
- mk := getAndroidMk(t, ctx, config, "foo")
- mk.moduleFor("foo")
- mk.moduleFor("foo-hostdex")
+ mod := ctx.ModuleForTests("foo", "android_common").Module()
+ entries := android.AndroidMkEntriesForTest(t, config, "", mod)
+
+ expected := []string{"foo"}
+ actual := entries.EntryMap["LOCAL_MODULE"]
+ if !reflect.DeepEqual(expected, actual) {
+ t.Errorf("Unexpected module name - expected: %q, actual: %q", expected, actual)
+ }
+
+ footerLines := entries.FooterLinesForTests()
+ if !android.InList("LOCAL_MODULE := foo-hostdex", footerLines) {
+ t.Errorf("foo-hostdex is not found in the footers: %q", footerLines)
+ }
}
func TestHostdexRequired(t *testing.T) {
@@ -153,9 +74,19 @@
}
`)
- mk := getAndroidMk(t, ctx, config, "foo")
- mk.moduleFor("foo").hasRequired("libfoo")
- mk.moduleFor("foo-hostdex").hasRequired("libfoo")
+ mod := ctx.ModuleForTests("foo", "android_common").Module()
+ entries := android.AndroidMkEntriesForTest(t, config, "", mod)
+
+ expected := []string{"libfoo"}
+ actual := entries.EntryMap["LOCAL_REQUIRED_MODULES"]
+ if !reflect.DeepEqual(expected, actual) {
+ t.Errorf("Unexpected required modules - expected: %q, actual: %q", expected, actual)
+ }
+
+ footerLines := entries.FooterLinesForTests()
+ if !android.InList("LOCAL_REQUIRED_MODULES := libfoo", footerLines) {
+ t.Errorf("Wrong or missing required line for foo-hostdex in the footers: %q", footerLines)
+ }
}
func TestHostdexSpecificRequired(t *testing.T) {
@@ -172,7 +103,15 @@
}
`)
- mk := getAndroidMk(t, ctx, config, "foo")
- mk.moduleFor("foo").hasNoRequired("libfoo")
- mk.moduleFor("foo-hostdex").hasRequired("libfoo")
+ mod := ctx.ModuleForTests("foo", "android_common").Module()
+ entries := android.AndroidMkEntriesForTest(t, config, "", mod)
+
+ if r, ok := entries.EntryMap["LOCAL_REQUIRED_MODULES"]; ok {
+ t.Errorf("Unexpected required modules: %q", r)
+ }
+
+ footerLines := entries.FooterLinesForTests()
+ if !android.InList("LOCAL_REQUIRED_MODULES += libfoo", footerLines) {
+ t.Errorf("Wrong or missing required line for foo-hostdex in the footers: %q", footerLines)
+ }
}
diff --git a/java/app.go b/java/app.go
index f5a5da0..3dbcbf4 100644
--- a/java/app.go
+++ b/java/app.go
@@ -39,6 +39,7 @@
android.RegisterModuleType("android_app_certificate", AndroidAppCertificateFactory)
android.RegisterModuleType("override_android_app", OverrideAndroidAppModuleFactory)
android.RegisterModuleType("android_app_import", AndroidAppImportFactory)
+ android.RegisterModuleType("android_test_import", AndroidTestImportFactory)
initAndroidAppImportVariantGroupTypes()
}
@@ -125,6 +126,10 @@
// the install APK name is normally the same as the module name, but can be overridden with PRODUCT_PACKAGE_NAME_OVERRIDES.
installApkName string
+ installDir android.InstallPath
+
+ onDeviceDir string
+
additionalAaptFlags []string
noticeOutputs android.NoticeOutputs
@@ -138,6 +143,10 @@
return nil
}
+func (a *AndroidApp) OutputFile() android.Path {
+ return a.outputFile
+}
+
var _ AndroidLibraryDependency = (*AndroidApp)(nil)
type Certificate struct {
@@ -158,10 +167,8 @@
embedJni := a.shouldEmbedJnis(ctx)
for _, jniTarget := range ctx.MultiTargets() {
- variation := []blueprint.Variation{
- {Mutator: "arch", Variation: jniTarget.String()},
- {Mutator: "link", Variation: "shared"},
- }
+ variation := append(jniTarget.Variations(),
+ blueprint.Variation{Mutator: "link", Variation: "shared"})
tag := &jniDependencyTag{
target: jniTarget,
}
@@ -221,7 +228,7 @@
// Uncompress dex in APKs of privileged apps (even for unbundled builds, they may
// be preinstalled as prebuilts).
- if ctx.Config().UncompressPrivAppDex() && Bool(a.appProperties.Privileged) {
+ if ctx.Config().UncompressPrivAppDex() && a.Privileged() {
return true
}
@@ -309,12 +316,11 @@
if ctx.ModuleName() == "framework-res" {
// framework-res.apk is installed as system/framework/framework-res.apk
installDir = "framework"
- } else if Bool(a.appProperties.Privileged) {
+ } else if a.Privileged() {
installDir = filepath.Join("priv-app", a.installApkName)
} else {
installDir = filepath.Join("app", a.installApkName)
}
-
a.dexpreopter.installPath = android.PathForModuleInstall(ctx, installDir, a.installApkName+".apk")
a.dexpreopter.isInstallable = Bool(a.properties.Installable)
a.dexpreopter.uncompressedDex = a.shouldUncompressDex(ctx)
@@ -347,7 +353,7 @@
return jniJarFile
}
-func (a *AndroidApp) noticeBuildActions(ctx android.ModuleContext, installDir android.OutputPath) {
+func (a *AndroidApp) noticeBuildActions(ctx android.ModuleContext) {
// Collect NOTICE files from all dependencies.
seenModules := make(map[android.Module]bool)
noticePathSet := make(map[android.Path]bool)
@@ -387,7 +393,7 @@
return noticePaths[i].String() < noticePaths[j].String()
})
- a.noticeOutputs = android.BuildNoticeOutput(ctx, installDir, a.installApkName+".apk", noticePaths)
+ a.noticeOutputs = android.BuildNoticeOutput(ctx, a.installDir, a.installApkName+".apk", noticePaths)
}
// Reads and prepends a main cert from the default cert dir if it hasn't been set already, i.e. it
@@ -433,17 +439,19 @@
// Check if the install APK name needs to be overridden.
a.installApkName = ctx.DeviceConfig().OverridePackageNameFor(a.Name())
- var installDir android.OutputPath
if ctx.ModuleName() == "framework-res" {
// framework-res.apk is installed as system/framework/framework-res.apk
- installDir = android.PathForModuleInstall(ctx, "framework")
- } else if Bool(a.appProperties.Privileged) {
- installDir = android.PathForModuleInstall(ctx, "priv-app", a.installApkName)
+ a.installDir = android.PathForModuleInstall(ctx, "framework")
+ } else if a.Privileged() {
+ a.installDir = android.PathForModuleInstall(ctx, "priv-app", a.installApkName)
+ } else if ctx.InstallInTestcases() {
+ a.installDir = android.PathForModuleInstall(ctx, a.installApkName)
} else {
- installDir = android.PathForModuleInstall(ctx, "app", a.installApkName)
+ a.installDir = android.PathForModuleInstall(ctx, "app", a.installApkName)
}
+ a.onDeviceDir = android.InstallPathToOnDevicePath(ctx, a.installDir)
- a.noticeBuildActions(ctx, installDir)
+ a.noticeBuildActions(ctx)
if Bool(a.appProperties.Embed_notices) || ctx.Config().IsEnvTrue("ALWAYS_EMBED_NOTICES") {
a.aapt.noticeFile = a.noticeOutputs.HtmlGzOutput
}
@@ -489,9 +497,9 @@
a.bundleFile = bundleFile
// Install the app package.
- ctx.InstallFile(installDir, a.installApkName+".apk", a.outputFile)
+ ctx.InstallFile(a.installDir, a.installApkName+".apk", a.outputFile)
for _, split := range a.aapt.splits {
- ctx.InstallFile(installDir, a.installApkName+"_"+split.suffix+".apk", split.path)
+ ctx.InstallFile(a.installDir, a.installApkName+"_"+split.suffix+".apk", split.path)
}
}
@@ -538,6 +546,19 @@
return String(a.overridableAppProperties.Certificate)
}
+// For OutputFileProducer interface
+func (a *AndroidApp) OutputFiles(tag string) (android.Paths, error) {
+ switch tag {
+ case ".aapt.srcjar":
+ return []android.Path{a.aaptSrcJar}, nil
+ }
+ return a.Library.OutputFiles(tag)
+}
+
+func (a *AndroidApp) Privileged() bool {
+ return Bool(a.appProperties.Privileged)
+}
+
// android_app compiles sources and Android resources into an Android application package `.apk` file.
func AndroidAppFactory() android.Module {
module := &AndroidApp{}
@@ -584,6 +605,10 @@
data android.Paths
}
+func (a *AndroidTest) InstallInTestcases() bool {
+ return true
+}
+
func (a *AndroidTest) GenerateAndroidBuildActions(ctx android.ModuleContext) {
// Check if the instrumentation target package is overridden before generating build actions.
if a.appTestProperties.Instrumentation_for != nil {
@@ -594,7 +619,8 @@
}
a.generateAndroidBuildActions(ctx)
- a.testConfig = tradefed.AutoGenInstrumentationTestConfig(ctx, a.testProperties.Test_config, a.testProperties.Test_config_template, a.manifestPath, a.testProperties.Test_suites)
+ a.testConfig = tradefed.AutoGenInstrumentationTestConfig(ctx, a.testProperties.Test_config,
+ a.testProperties.Test_config_template, a.manifestPath, a.testProperties.Test_suites, a.testProperties.Auto_gen_config)
a.data = android.PathsForModuleSrc(ctx, a.testProperties.Data)
}
@@ -642,6 +668,11 @@
// list of compatibility suites (for example "cts", "vts") that the module should be
// installed into.
Test_suites []string `android:"arch_variant"`
+
+ // Flag to indicate whether or not to create test config automatically. If AndroidTest.xml
+ // doesn't exist next to the Android.bp, this attribute doesn't need to be set to true
+ // explicitly.
+ Auto_gen_config *bool
}
type AndroidTestHelperApp struct {
@@ -744,7 +775,7 @@
usesLibrary usesLibrary
- installPath android.OutputPath
+ installPath android.InstallPath
}
type AndroidAppImportProperties struct {
@@ -845,7 +876,7 @@
}
// Uncompress dex in APKs of privileged apps
- if ctx.Config().UncompressPrivAppDex() && Bool(a.properties.Privileged) {
+ if ctx.Config().UncompressPrivAppDex() && a.Privileged() {
return true
}
@@ -866,6 +897,10 @@
}
func (a *AndroidAppImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ a.generateAndroidBuildActions(ctx)
+}
+
+func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext) {
numCertPropsSet := 0
if String(a.properties.Certificate) != "" {
numCertPropsSet++
@@ -972,6 +1007,10 @@
a.AddProperties(a.archVariants)
}
+func (a *AndroidAppImport) Privileged() bool {
+ return Bool(a.properties.Privileged)
+}
+
func createVariantGroupType(variants []string, variantGroupName string) reflect.Type {
props := reflect.TypeOf((*AndroidAppImportProperties)(nil))
@@ -1024,6 +1063,39 @@
return module
}
+type AndroidTestImport struct {
+ AndroidAppImport
+
+ testProperties testProperties
+
+ data android.Paths
+}
+
+func (a *AndroidTestImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ a.generateAndroidBuildActions(ctx)
+
+ a.data = android.PathsForModuleSrc(ctx, a.testProperties.Data)
+}
+
+// android_test_import imports a prebuilt test apk with additional processing specified in the
+// module. DPI or arch variant configurations can be made as with android_app_import.
+func AndroidTestImportFactory() android.Module {
+ module := &AndroidTestImport{}
+ module.AddProperties(&module.properties)
+ module.AddProperties(&module.dexpreoptProperties)
+ module.AddProperties(&module.usesLibrary.usesLibraryProperties)
+ module.AddProperties(&module.testProperties)
+ module.populateAllVariantStructs()
+ android.AddLoadHook(module, func(ctx android.LoadHookContext) {
+ module.processVariants(ctx)
+ })
+
+ InitJavaModule(module, android.DeviceSupported)
+ android.InitSingleSourcePrebuiltModule(module, &module.properties, "Apk")
+
+ return module
+}
+
type UsesLibraryProperties struct {
// A list of shared library modules that will be listed in uses-library tags in the AndroidManifest.xml file.
Uses_libs []string
diff --git a/java/app_builder.go b/java/app_builder.go
index 348c8b4..ec2f6da 100644
--- a/java/app_builder.go
+++ b/java/app_builder.go
@@ -31,31 +31,13 @@
var (
Signapk = pctx.AndroidStaticRule("signapk",
blueprint.RuleParams{
- Command: `${config.JavaCmd} ${config.JavaVmFlags} -Djava.library.path=$$(dirname $signapkJniLibrary) ` +
- `-jar $signapkCmd $flags $certificates $in $out`,
- CommandDeps: []string{"$signapkCmd", "$signapkJniLibrary"},
+ Command: `${config.JavaCmd} ${config.JavaVmFlags} -Djava.library.path=$$(dirname ${config.SignapkJniLibrary}) ` +
+ `-jar ${config.SignapkCmd} $flags $certificates $in $out`,
+ CommandDeps: []string{"${config.SignapkCmd}", "${config.SignapkJniLibrary}"},
},
"flags", "certificates")
-
- androidManifestMerger = pctx.AndroidStaticRule("androidManifestMerger",
- blueprint.RuleParams{
- Command: "java -classpath $androidManifestMergerCmd com.android.manifmerger.Main merge " +
- "--main $in --libs $libsManifests --out $out",
- CommandDeps: []string{"$androidManifestMergerCmd"},
- Description: "merge manifest files",
- },
- "libsManifests")
)
-func init() {
- pctx.SourcePathVariable("androidManifestMergerCmd", "prebuilts/devtools/tools/lib/manifest-merger.jar")
- pctx.HostBinToolVariable("aaptCmd", "aapt")
- pctx.HostJavaToolVariable("signapkCmd", "signapk.jar")
- // TODO(ccross): this should come from the signapk dependencies, but we don't have any way
- // to express host JNI dependencies yet.
- pctx.HostJNIToolVariable("signapkJniLibrary", "libconscrypt_openjdk_jni")
-}
-
var combineApk = pctx.AndroidStaticRule("combineApk",
blueprint.RuleParams{
Command: `${config.MergeZipsCmd} $out $in`,
diff --git a/java/app_test.go b/java/app_test.go
index be1ff29..05ab856 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -1149,13 +1149,7 @@
variant.MaybeOutput("dexpreopt/oat/arm64/package.odex").Rule == nil {
t.Errorf("can't find dexpreopt outputs")
}
- // Make sure stripping wasn't done.
- stripRule := variant.Output("dexpreopt/foo.apk")
- if !strings.HasPrefix(stripRule.RuleParams.Command, "cp -f") {
- t.Errorf("unexpected, non-skipping strip command: %q", stripRule.RuleParams.Command)
- }
-
- // Make sure signing was skipped and aligning was done instead.
+ // Make sure signing was skipped and aligning was done.
if variant.MaybeOutput("signed/foo.apk").Rule != nil {
t.Errorf("signing rule shouldn't be included.")
}
@@ -1381,6 +1375,34 @@
}
}
+func TestAndroidTestImport(t *testing.T) {
+ ctx, config := testJava(t, `
+ android_test_import {
+ name: "foo",
+ apk: "prebuilts/apk/app.apk",
+ presigned: true,
+ data: [
+ "testdata/data",
+ ],
+ }
+ `)
+
+ test := ctx.ModuleForTests("foo", "android_common").Module().(*AndroidTestImport)
+
+ // Check android mks.
+ entries := android.AndroidMkEntriesForTest(t, config, "", test)
+ expected := []string{"tests"}
+ actual := entries.EntryMap["LOCAL_MODULE_TAGS"]
+ if !reflect.DeepEqual(expected, actual) {
+ t.Errorf("Unexpected module tags - expected: %q, actual: %q", expected, actual)
+ }
+ expected = []string{"testdata/data:testdata/data"}
+ actual = entries.EntryMap["LOCAL_COMPATIBILITY_SUPPORT_FILES"]
+ if !reflect.DeepEqual(expected, actual) {
+ t.Errorf("Unexpected test data - expected: %q, actual: %q", expected, actual)
+ }
+}
+
func TestStl(t *testing.T) {
ctx, _ := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
cc_library {
diff --git a/java/builder.go b/java/builder.go
index f174cf0..0a5c79b 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -64,6 +64,7 @@
_ = pctx.VariableFunc("kytheCorpus",
func(ctx android.PackageVarContext) string { return ctx.Config().XrefCorpusName() })
+ _ = pctx.SourcePathVariable("kytheVnames", "build/soong/vnames.json")
// Run it with -add-opens=java.base/java.nio=ALL-UNNAMED to avoid JDK9's warning about
// "Illegal reflective access by com.google.protobuf.Utf8$UnsafeProcessor ...
// to field java.nio.Buffer.address"
@@ -74,6 +75,7 @@
`( [ ! -s $srcJarDir/list -a ! -s $out.rsp ] || ` +
`KYTHE_ROOT_DIRECTORY=. KYTHE_OUTPUT_FILE=$out ` +
`KYTHE_CORPUS=${kytheCorpus} ` +
+ `KYTHE_VNAMES=${kytheVnames} ` +
`${config.SoongJavacWrapper} ${config.JavaCmd} ` +
`--add-opens=java.base/java.nio=ALL-UNNAMED ` +
`-jar ${config.JavaKytheExtractorJar} ` +
@@ -84,6 +86,7 @@
CommandDeps: []string{
"${config.JavaCmd}",
"${config.JavaKytheExtractorJar}",
+ "${kytheVnames}",
"${config.ZipSyncCmd}",
},
CommandOrderOnly: []string{"${config.SoongJavacWrapper}"},
@@ -229,10 +232,9 @@
// Emits the rule to generate Xref input file (.kzip file) for the given set of source files and source jars
// to compile with given set of builder flags, etc.
-func emitXrefRule(ctx android.ModuleContext, xrefFile android.WritablePath,
+func emitXrefRule(ctx android.ModuleContext, xrefFile android.WritablePath, idx int,
srcFiles, srcJars android.Paths,
- flags javaBuilderFlags, deps android.Paths,
- intermediatesDir string) {
+ flags javaBuilderFlags, deps android.Paths) {
deps = append(deps, srcJars...)
@@ -260,6 +262,11 @@
processor = "-processor " + flags.processor
}
+ intermediatesDir := "xref"
+ if idx >= 0 {
+ intermediatesDir += strconv.Itoa(idx)
+ }
+
ctx.Build(pctx,
android.BuildParams{
Rule: kytheExtract,
diff --git a/java/config/config.go b/java/config/config.go
index b371cbf..f418ee7 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -29,7 +29,7 @@
DefaultBootclasspathLibraries = []string{"core.platform.api.stubs", "core-lambda-stubs"}
DefaultSystemModules = "core-platform-api-stubs-system-modules"
- DefaultLibraries = []string{"ext", "framework"}
+ DefaultLibraries = []string{"ext", "framework", "updatable_media_stubs"}
DefaultLambdaStubsLibrary = "core-lambda-stubs"
SdkLambdaStubsPath = "prebuilts/sdk/tools/core-lambda-stubs.jar"
@@ -45,6 +45,7 @@
"core-icu4j",
"core-oj",
"core-libart",
+ "updatable-media",
}
)
@@ -85,6 +86,14 @@
// This is set up and guaranteed by soong_ui
return ctx.Config().Getenv("ANDROID_JAVA_HOME")
})
+ pctx.VariableFunc("JlinkVersion", func(ctx android.PackageVarContext) string {
+ switch ctx.Config().Getenv("EXPERIMENTAL_USE_OPENJDK11_TOOLCHAIN") {
+ case "true":
+ return "11"
+ default:
+ return "9"
+ }
+ })
pctx.SourcePathVariable("JavaToolchain", "${JavaHome}/bin")
pctx.SourcePathVariableWithEnvOverride("JavacCmd",
@@ -140,27 +149,66 @@
pctx.HostJavaToolVariable("JacocoCLIJar", "jacoco-cli.jar")
- hostBinToolVariableWithPrebuilt := func(name, prebuiltDir, tool string) {
- pctx.VariableFunc(name, func(ctx android.PackageVarContext) string {
- if ctx.Config().UnbundledBuild() || ctx.Config().IsPdkBuild() {
- return filepath.Join(prebuiltDir, runtime.GOOS, "bin", tool)
- } else {
- return pctx.HostBinToolPath(ctx, tool).String()
- }
- })
- }
-
- hostBinToolVariableWithPrebuilt("Aapt2Cmd", "prebuilts/sdk/tools", "aapt2")
-
pctx.HostBinToolVariable("ManifestCheckCmd", "manifest_check")
pctx.HostBinToolVariable("ManifestFixerCmd", "manifest_fixer")
pctx.HostBinToolVariable("ManifestMergerCmd", "manifest-merger")
- pctx.HostBinToolVariable("ZipAlign", "zipalign")
-
pctx.HostBinToolVariable("Class2Greylist", "class2greylist")
pctx.HostBinToolVariable("HiddenAPI", "hiddenapi")
+
+ hostBinToolVariableWithSdkToolsPrebuilt("Aapt2Cmd", "aapt2")
+ hostBinToolVariableWithBuildToolsPrebuilt("AidlCmd", "aidl")
+ hostBinToolVariableWithBuildToolsPrebuilt("ZipAlign", "zipalign")
+
+ hostJavaToolVariableWithSdkToolsPrebuilt("SignapkCmd", "signapk")
+ // TODO(ccross): this should come from the signapk dependencies, but we don't have any way
+ // to express host JNI dependencies yet.
+ hostJNIToolVariableWithSdkToolsPrebuilt("SignapkJniLibrary", "libconscrypt_openjdk_jni")
+}
+
+func hostBinToolVariableWithSdkToolsPrebuilt(name, tool string) {
+ pctx.VariableFunc(name, func(ctx android.PackageVarContext) string {
+ if ctx.Config().UnbundledBuild() || ctx.Config().IsPdkBuild() {
+ return filepath.Join("prebuilts/sdk/tools", runtime.GOOS, "bin", tool)
+ } else {
+ return pctx.HostBinToolPath(ctx, tool).String()
+ }
+ })
+}
+
+func hostJavaToolVariableWithSdkToolsPrebuilt(name, tool string) {
+ pctx.VariableFunc(name, func(ctx android.PackageVarContext) string {
+ if ctx.Config().UnbundledBuild() || ctx.Config().IsPdkBuild() {
+ return filepath.Join("prebuilts/sdk/tools/lib", tool+".jar")
+ } else {
+ return pctx.HostJavaToolPath(ctx, tool+".jar").String()
+ }
+ })
+}
+
+func hostJNIToolVariableWithSdkToolsPrebuilt(name, tool string) {
+ pctx.VariableFunc(name, func(ctx android.PackageVarContext) string {
+ if ctx.Config().UnbundledBuild() || ctx.Config().IsPdkBuild() {
+ ext := ".so"
+ if runtime.GOOS == "darwin" {
+ ext = ".dylib"
+ }
+ return filepath.Join("prebuilts/sdk/tools", runtime.GOOS, "lib64", tool+ext)
+ } else {
+ return pctx.HostJNIToolPath(ctx, tool).String()
+ }
+ })
+}
+
+func hostBinToolVariableWithBuildToolsPrebuilt(name, tool string) {
+ pctx.VariableFunc(name, func(ctx android.PackageVarContext) string {
+ if ctx.Config().UnbundledBuild() || ctx.Config().IsPdkBuild() {
+ return filepath.Join("prebuilts/build-tools", ctx.Config().PrebuiltOS(), "bin", tool)
+ } else {
+ return pctx.HostBinToolPath(ctx, tool).String()
+ }
+ })
}
// JavaCmd returns a SourcePath object with the path to the java command.
diff --git a/java/config/makevars.go b/java/config/makevars.go
index ead298a..2fa6f89 100644
--- a/java/config/makevars.go
+++ b/java/config/makevars.go
@@ -38,6 +38,7 @@
ctx.Strict("ANDROID_JAVA_HOME", "${JavaHome}")
ctx.Strict("ANDROID_JAVA8_HOME", "prebuilts/jdk/jdk8/${hostPrebuiltTag}")
ctx.Strict("ANDROID_JAVA9_HOME", "prebuilts/jdk/jdk9/${hostPrebuiltTag}")
+ ctx.Strict("ANDROID_JAVA11_HOME", "prebuilts/jdk/jdk11/${hostPrebuiltTag}")
ctx.Strict("ANDROID_JAVA_TOOLCHAIN", "${JavaToolchain}")
ctx.Strict("JAVA", "${JavaCmd} ${JavaVmFlags}")
ctx.Strict("JAVAC", "${JavacCmd} ${JavacVmFlags}")
@@ -82,4 +83,17 @@
ctx.Strict("HIDDENAPI", "${HiddenAPI}")
ctx.Strict("DEX_FLAGS", "${DexFlags}")
+
+ ctx.Strict("AIDL", "${AidlCmd}")
+ ctx.Strict("AAPT2", "${Aapt2Cmd}")
+ ctx.Strict("ZIPALIGN", "${ZipAlign}")
+ ctx.Strict("SIGNAPK_JAR", "${SignapkCmd}")
+ ctx.Strict("SIGNAPK_JNI_LIBRARY_PATH", "${SignapkJniLibrary}")
+
+ ctx.Strict("SOONG_ZIP", "${SoongZipCmd}")
+ ctx.Strict("MERGE_ZIPS", "${MergeZipsCmd}")
+ ctx.Strict("ZIP2ZIP", "${Zip2ZipCmd}")
+
+ ctx.Strict("ZIPTIME", "${Ziptime}")
+
}
diff --git a/java/device_host_converter.go b/java/device_host_converter.go
index 030b010..14db521 100644
--- a/java/device_host_converter.go
+++ b/java/device_host_converter.go
@@ -18,8 +18,6 @@
"fmt"
"io"
- "github.com/google/blueprint"
-
"android/soong/android"
)
@@ -83,13 +81,13 @@
var deviceHostConverterDepTag = dependencyTag{name: "device_host_converter"}
func (d *DeviceForHost) DepsMutator(ctx android.BottomUpMutatorContext) {
- variation := []blueprint.Variation{{Mutator: "arch", Variation: "android_common"}}
- ctx.AddFarVariationDependencies(variation, deviceHostConverterDepTag, d.properties.Libs...)
+ ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(),
+ deviceHostConverterDepTag, d.properties.Libs...)
}
func (d *HostForDevice) DepsMutator(ctx android.BottomUpMutatorContext) {
- variation := []blueprint.Variation{{Mutator: "arch", Variation: ctx.Config().BuildOsCommonVariant}}
- ctx.AddFarVariationDependencies(variation, deviceHostConverterDepTag, d.properties.Libs...)
+ ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(),
+ deviceHostConverterDepTag, d.properties.Libs...)
}
func (d *DeviceHostConverter) GenerateAndroidBuildActions(ctx android.ModuleContext) {
diff --git a/java/device_host_converter_test.go b/java/device_host_converter_test.go
index 44aae9b..3c9a0f3 100644
--- a/java/device_host_converter_test.go
+++ b/java/device_host_converter_test.go
@@ -60,7 +60,7 @@
deviceImportModule := ctx.ModuleForTests("device_import_module", "android_common")
deviceImportCombined := deviceImportModule.Output("combined/device_import_module.jar")
- hostModule := ctx.ModuleForTests("host_module", config.BuildOsCommonVariant)
+ hostModule := ctx.ModuleForTests("host_module", config.BuildOSCommonTarget.String())
hostJavac := hostModule.Output("javac/host_module.jar")
hostRes := hostModule.Output("res/host_module.jar")
combined := hostModule.Output("combined/host_module.jar")
@@ -133,11 +133,11 @@
ctx, config := testJava(t, bp)
- hostModule := ctx.ModuleForTests("host_module", config.BuildOsCommonVariant)
+ hostModule := ctx.ModuleForTests("host_module", config.BuildOSCommonTarget.String())
hostJavac := hostModule.Output("javac/host_module.jar")
hostRes := hostModule.Output("res/host_module.jar")
- hostImportModule := ctx.ModuleForTests("host_import_module", config.BuildOsCommonVariant)
+ hostImportModule := ctx.ModuleForTests("host_import_module", config.BuildOSCommonTarget.String())
hostImportCombined := hostImportModule.Output("combined/host_import_module.jar")
deviceModule := ctx.ModuleForTests("device_module", "android_common")
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index 6214dac..2b1c994 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -22,7 +22,7 @@
type dexpreopter struct {
dexpreoptProperties DexpreoptProperties
- installPath android.OutputPath
+ installPath android.InstallPath
uncompressedDex bool
isSDKLibrary bool
isTest bool
@@ -40,13 +40,9 @@
type DexpreoptProperties struct {
Dex_preopt struct {
- // If false, prevent dexpreopting and stripping the dex file from the final jar. Defaults to
- // true.
+ // If false, prevent dexpreopting. Defaults to true.
Enabled *bool
- // If true, never strip the dex files from the final jar when dexpreopting. Defaults to false.
- No_stripping *bool
-
// If true, generate an app image (.art file) for this module.
App_image *bool
@@ -94,7 +90,7 @@
return false
}
-func odexOnSystemOther(ctx android.ModuleContext, installPath android.OutputPath) bool {
+func odexOnSystemOther(ctx android.ModuleContext, installPath android.InstallPath) bool {
return dexpreopt.OdexOnSystemOtherByName(ctx.ModuleName(), android.InstallPathToOnDevicePath(ctx, installPath), dexpreoptGlobalConfig(ctx))
}
@@ -126,10 +122,6 @@
archs = archs[:1]
}
}
- if ctx.Config().SecondArchIsTranslated() {
- // Only preopt primary arch for translated arch since there is only an image there.
- archs = archs[:1]
- }
var images android.Paths
var imagesDeps []android.Paths
@@ -140,8 +132,6 @@
dexLocation := android.InstallPathToOnDevicePath(ctx, d.installPath)
- strippedDexJarFile := android.PathForModuleOut(ctx, "dexpreopt", dexJarFile.Base())
-
var profileClassListing android.OptionalPath
var profileBootListing android.OptionalPath
profileIsTextListing := false
@@ -195,10 +185,6 @@
ForceCreateAppImage: BoolDefault(d.dexpreoptProperties.Dex_preopt.App_image, false),
PresignedPrebuilt: d.isPresignedPrebuilt,
-
- NoStripping: Bool(d.dexpreoptProperties.Dex_preopt.No_stripping),
- StripInputPath: dexJarFile,
- StripOutputPath: strippedDexJarFile.OutputPath,
}
dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(ctx, global, dexpreoptConfig)
@@ -211,13 +197,5 @@
d.builtInstalled = dexpreoptRule.Installs().String()
- stripRule, err := dexpreopt.GenerateStripRule(global, dexpreoptConfig)
- if err != nil {
- ctx.ModuleErrorf("error generating dexpreopt strip rule: %s", err.Error())
- return dexJarFile
- }
-
- stripRule.Build(pctx, ctx, "dexpreopt_strip", "dexpreopt strip")
-
- return strippedDexJarFile
+ return dexJarFile
}
diff --git a/java/dexpreopt_bootjars_test.go b/java/dexpreopt_bootjars_test.go
index 4c38399..244bd52 100644
--- a/java/dexpreopt_bootjars_test.go
+++ b/java/dexpreopt_bootjars_test.go
@@ -48,7 +48,7 @@
pathCtx := android.PathContextForTesting(config, nil)
dexpreoptConfig := dexpreopt.GlobalConfigForTests(pathCtx)
- dexpreoptConfig.RuntimeApexJars = []string{"foo", "bar", "baz"}
+ dexpreoptConfig.ArtApexJars = []string{"foo", "bar", "baz"}
setDexpreoptTestGlobalConfig(config, dexpreoptConfig)
ctx := testContext(bp, nil)
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index 4a4d6d5..043f9da 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -87,11 +87,7 @@
// supported through native bridge.
func dexpreoptTargets(ctx android.PathContext) []android.Target {
var targets []android.Target
- for i, target := range ctx.Config().Targets[android.Android] {
- if ctx.Config().SecondArchIsTranslated() && i > 0 {
- break
- }
-
+ for _, target := range ctx.Config().Targets[android.Android] {
if target.NativeBridge == android.NativeBridgeDisabled {
targets = append(targets, target)
}
@@ -107,17 +103,17 @@
return ctx.Config().Once(defaultBootImageConfigKey, func() interface{} {
global := dexpreoptGlobalConfig(ctx)
- runtimeModules := global.RuntimeApexJars
- nonFrameworkModules := concat(runtimeModules, global.ProductUpdatableBootModules)
+ artModules := global.ArtApexJars
+ nonFrameworkModules := concat(artModules, global.ProductUpdatableBootModules)
frameworkModules := android.RemoveListFromList(global.BootJars, nonFrameworkModules)
var nonUpdatableBootModules []string
var nonUpdatableBootLocations []string
- for _, m := range runtimeModules {
+ for _, m := range artModules {
nonUpdatableBootModules = append(nonUpdatableBootModules, m)
nonUpdatableBootLocations = append(nonUpdatableBootLocations,
- filepath.Join("/apex/com.android.runtime/javalib", m+".jar"))
+ filepath.Join("/apex/com.android.art/javalib", m+".jar"))
}
for _, m := range frameworkModules {
@@ -176,16 +172,16 @@
return ctx.Config().Once(apexBootImageConfigKey, func() interface{} {
global := dexpreoptGlobalConfig(ctx)
- runtimeModules := global.RuntimeApexJars
- nonFrameworkModules := concat(runtimeModules, global.ProductUpdatableBootModules)
+ artModules := global.ArtApexJars
+ nonFrameworkModules := concat(artModules, global.ProductUpdatableBootModules)
frameworkModules := android.RemoveListFromList(global.BootJars, nonFrameworkModules)
- imageModules := concat(runtimeModules, frameworkModules)
+ imageModules := concat(artModules, frameworkModules)
var bootLocations []string
- for _, m := range runtimeModules {
+ for _, m := range artModules {
bootLocations = append(bootLocations,
- filepath.Join("/apex/com.android.runtime/javalib", m+".jar"))
+ filepath.Join("/apex/com.android.art/javalib", m+".jar"))
}
for _, m := range frameworkModules {
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 8b15e0f..12335ff 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -17,7 +17,6 @@
import (
"fmt"
"path/filepath"
- "runtime"
"strings"
"github.com/google/blueprint/proptools"
@@ -58,21 +57,25 @@
// filegroup or genrule can be included within this property.
Exclude_srcs []string `android:"path,arch_variant"`
+ // list of package names that should actually be used. If this property is left unspecified,
+ // all the sources from the srcs property is used.
+ Filter_packages []string
+
// list of java libraries that will be in the classpath.
Libs []string `android:"arch_variant"`
- // the java library (in classpath) for documentation that provides java srcs and srcjars.
- Srcs_lib *string
-
- // List of packages to document from srcs_lib
- Srcs_lib_whitelist_pkgs []string
-
// If set to false, don't allow this module(-docs.zip) to be exported. Defaults to true.
Installable *bool
- // if not blank, set to the version of the sdk to compile against
+ // if not blank, set to the version of the sdk to compile against.
+ // Defaults to compiling against the current platform.
Sdk_version *string `android:"arch_variant"`
+ // When targeting 1.9 and above, override the modules to use with --system,
+ // otherwise provides defaults libraries to add to the bootclasspath.
+ // Defaults to "none"
+ System_modules *string
+
Aidl struct {
// Top level directories to pass to aidl tool
Include_dirs []string
@@ -241,6 +244,16 @@
// do not perform API check against Last_released, in the case that both two specified API
// files by Last_released are modules which don't exist.
Ignore_missing_latest_api *bool `blueprint:"mutated"`
+
+ Api_lint struct {
+ Enabled *bool
+
+ // If set, performs api_lint on any new APIs not found in the given signature file
+ New_since *string `android:"path"`
+
+ // If not blank, path to the baseline txt file for approved API lint violations.
+ Baseline_file *string `android:"path"`
+ }
}
// user can specify the version of previous released API file in order to do compatibility check.
@@ -300,8 +313,10 @@
android.InitDefaultableModule(module)
}
-func apiCheckEnabled(apiToCheck ApiToCheck, apiVersionTag string) bool {
- if String(apiToCheck.Api_file) != "" && String(apiToCheck.Removed_api_file) != "" {
+func apiCheckEnabled(ctx android.ModuleContext, apiToCheck ApiToCheck, apiVersionTag string) bool {
+ if ctx.Config().IsEnvTrue("WITHOUT_CHECK_API") {
+ return false
+ } else if String(apiToCheck.Api_file) != "" && String(apiToCheck.Removed_api_file) != "" {
return true
} else if String(apiToCheck.Api_file) != "" {
panic("for " + apiVersionTag + " removed_api_file has to be non-empty!")
@@ -392,6 +407,10 @@
return proptools.StringDefault(j.properties.Sdk_version, defaultSdkVersion(j))
}
+func (j *Javadoc) systemModules() string {
+ return proptools.String(j.properties.System_modules)
+}
+
func (j *Javadoc) minSdkVersion() string {
return j.sdkVersion()
}
@@ -418,13 +437,14 @@
}
ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.modules...)
}
+ } else if sdkDep.systemModules != "" {
+ // Add the system modules to both the system modules and bootclasspath.
+ ctx.AddVariationDependencies(nil, systemModulesTag, sdkDep.systemModules)
+ ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.systemModules)
}
}
ctx.AddVariationDependencies(nil, libTag, j.properties.Libs...)
- if j.properties.Srcs_lib != nil {
- ctx.AddVariationDependencies(nil, srcsLibTag, *j.properties.Srcs_lib)
- }
}
func (j *Javadoc) collectAidlFlags(ctx android.ModuleContext, deps deps) droiddocBuilderFlags {
@@ -465,14 +485,14 @@
flags droiddocBuilderFlags) android.Paths {
outSrcFiles := make(android.Paths, 0, len(srcFiles))
+ var aidlSrcs android.Paths
aidlIncludeFlags := genAidlIncludeFlags(srcFiles)
for _, srcFile := range srcFiles {
switch srcFile.Ext() {
case ".aidl":
- javaFile := genAidl(ctx, srcFile, flags.aidlFlags+aidlIncludeFlags, flags.aidlDeps)
- outSrcFiles = append(outSrcFiles, javaFile)
+ aidlSrcs = append(aidlSrcs, srcFile)
case ".logtags":
javaFile := genLogtags(ctx, srcFile)
outSrcFiles = append(outSrcFiles, javaFile)
@@ -481,6 +501,12 @@
}
}
+ // Process all aidl files together to support sharding them into one or more rules that produce srcjars.
+ if len(aidlSrcs) > 0 {
+ srcJarFiles := genAidl(ctx, aidlSrcs, flags.aidlFlags+aidlIncludeFlags, flags.aidlDeps)
+ outSrcFiles = append(outSrcFiles, srcJarFiles...)
+ }
+
return outSrcFiles
}
@@ -502,6 +528,10 @@
case bootClasspathTag:
if dep, ok := module.(Dependency); ok {
deps.bootClasspath = append(deps.bootClasspath, dep.ImplementationJars()...)
+ } else if sm, ok := module.(*SystemModules); ok {
+ // A system modules dependency has been added to the bootclasspath
+ // so add its libs to the bootclasspath.
+ deps.bootClasspath = append(deps.bootClasspath, sm.headerJars...)
} else {
panic(fmt.Errorf("unknown dependency %q for %q", otherName, ctx.ModuleName()))
}
@@ -518,27 +548,6 @@
default:
ctx.ModuleErrorf("depends on non-java module %q", otherName)
}
- case srcsLibTag:
- switch dep := module.(type) {
- case Dependency:
- srcs := dep.(SrcDependency).CompiledSrcs()
- for _, src := range srcs {
- if _, ok := src.(android.WritablePath); ok { // generated sources
- deps.srcs = append(deps.srcs, src)
- } else { // select source path for documentation based on whitelist path prefixs.
- for _, pkg := range j.properties.Srcs_lib_whitelist_pkgs {
- pkgAsPath := filepath.Join(strings.Split(pkg, ".")...)
- if strings.HasPrefix(src.Rel(), pkgAsPath) {
- deps.srcs = append(deps.srcs, src)
- break
- }
- }
- }
- }
- deps.srcJars = append(deps.srcJars, dep.(SrcDependency).CompiledSrcJars()...)
- default:
- ctx.ModuleErrorf("depends on non-java module %q", otherName)
- }
case systemModulesTag:
if deps.systemModules != nil {
panic("Found two system module dependencies")
@@ -553,6 +562,34 @@
// do not pass exclude_srcs directly when expanding srcFiles since exclude_srcs
// may contain filegroup or genrule.
srcFiles := android.PathsForModuleSrcExcludes(ctx, j.properties.Srcs, j.properties.Exclude_srcs)
+
+ filterByPackage := func(srcs []android.Path, filterPackages []string) []android.Path {
+ if filterPackages == nil {
+ return srcs
+ }
+ filtered := []android.Path{}
+ for _, src := range srcs {
+ if src.Ext() != ".java" {
+ // Don't filter-out non-Java (=generated sources) by package names. This is not ideal,
+ // but otherwise metalava emits stub sources having references to the generated AIDL classes
+ // in filtered-out pacages (e.g. com.android.internal.*).
+ // TODO(b/141149570) We need to fix this by introducing default private constructors or
+ // fixing metalava to not emit constructors having references to unknown classes.
+ filtered = append(filtered, src)
+ continue
+ }
+ packageName := strings.ReplaceAll(filepath.Dir(src.Rel()), "/", ".")
+ for _, pkg := range filterPackages {
+ if strings.HasPrefix(packageName, pkg) {
+ filtered = append(filtered, src)
+ break
+ }
+ }
+ }
+ return filtered
+ }
+ srcFiles = filterByPackage(srcFiles, j.properties.Filter_packages)
+
flags := j.collectAidlFlags(ctx, deps)
srcFiles = j.genSources(ctx, srcFiles, flags)
@@ -715,13 +752,6 @@
}
func (d *Droiddoc) doclavaDocsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, docletPath classpath) {
- var date string
- if runtime.GOOS == "darwin" {
- date = `date -r`
- } else {
- date = `date -d @`
- }
-
// Droiddoc always gets "-source 1.8" because it doesn't support 1.9 sources. For modules with 1.9
// sources, droiddoc will get sources produced by metalava which will have already stripped out the
// 1.9 language features.
@@ -732,7 +762,7 @@
FlagWithArg("-doclet ", "com.google.doclava.Doclava").
FlagWithInputList("-docletpath ", docletPath.Paths(), ":").
FlagWithArg("-hdf page.build ", ctx.Config().BuildId()+"-"+ctx.Config().BuildNumberFromFile()).
- FlagWithArg("-hdf page.now ", `"$(`+date+`$(cat `+ctx.Config().Getenv("BUILD_DATETIME_FILE")+`) "+%d %b %Y %k:%M")" `)
+ FlagWithArg("-hdf page.now ", `"$(date -d @$(cat `+ctx.Config().Getenv("BUILD_DATETIME_FILE")+`) "+%d %b %Y %k:%M")" `)
if String(d.properties.Custom_template) == "" {
// TODO: This is almost always droiddoc-templates-sdk
@@ -795,8 +825,8 @@
}
func (d *Droiddoc) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsDir android.WritablePath) {
- if apiCheckEnabled(d.properties.Check_api.Current, "current") ||
- apiCheckEnabled(d.properties.Check_api.Last_released, "last_released") ||
+ if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
+ apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") ||
String(d.properties.Api_filename) != "" {
d.apiFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_api.txt")
@@ -804,8 +834,8 @@
d.apiFilePath = d.apiFile
}
- if apiCheckEnabled(d.properties.Check_api.Current, "current") ||
- apiCheckEnabled(d.properties.Check_api.Last_released, "last_released") ||
+ if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
+ apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") ||
String(d.properties.Removed_api_filename) != "" {
d.removedApiFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_removed.txt")
cmd.FlagWithOutput("-removedApi ", d.removedApiFile)
@@ -1023,7 +1053,7 @@
rule.Build(pctx, ctx, "javadoc", desc)
- if apiCheckEnabled(d.properties.Check_api.Current, "current") &&
+ if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") &&
!ctx.Config().IsPdkBuild() {
apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Api_file))
@@ -1092,7 +1122,7 @@
rule.Build(pctx, ctx, "doclavaCurrentApiUpdate", "update current API")
}
- if apiCheckEnabled(d.properties.Check_api.Last_released, "last_released") &&
+ if apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") &&
!ctx.Config().IsPdkBuild() {
apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Api_file))
@@ -1152,6 +1182,7 @@
checkCurrentApiTimestamp android.WritablePath
updateCurrentApiTimestamp android.WritablePath
checkLastReleasedApiTimestamp android.WritablePath
+ apiLintTimestamp android.WritablePath
checkNullabilityWarningsTimestamp android.WritablePath
@@ -1162,6 +1193,9 @@
jdiffDocZip android.WritablePath
jdiffStubsSrcJar android.WritablePath
+
+ metadataZip android.WritablePath
+ metadataDir android.WritablePath
}
// droidstubs passes sources files through Metalava to generate stub .java files that only contain the API to be
@@ -1222,16 +1256,16 @@
}
func (d *Droidstubs) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsDir android.WritablePath) {
- if apiCheckEnabled(d.properties.Check_api.Current, "current") ||
- apiCheckEnabled(d.properties.Check_api.Last_released, "last_released") ||
+ if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
+ apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") ||
String(d.properties.Api_filename) != "" {
d.apiFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_api.txt")
cmd.FlagWithOutput("--api ", d.apiFile)
d.apiFilePath = d.apiFile
}
- if apiCheckEnabled(d.properties.Check_api.Current, "current") ||
- apiCheckEnabled(d.properties.Check_api.Last_released, "last_released") ||
+ if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
+ apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") ||
String(d.properties.Removed_api_filename) != "" {
d.removedApiFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_removed.txt")
cmd.FlagWithOutput("--removed-api ", d.removedApiFile)
@@ -1273,7 +1307,8 @@
}
if Bool(d.properties.Write_sdk_values) {
- cmd.FlagWithArg("--sdk-values ", android.PathForModuleOut(ctx, "out").String())
+ d.metadataDir = android.PathForModuleOut(ctx, "metadata")
+ cmd.FlagWithArg("--sdk-values ", d.metadataDir.String())
}
if Bool(d.properties.Create_doc_stubs) {
@@ -1480,6 +1515,18 @@
FlagWithOutput("-o ", d.Javadoc.stubsSrcJar).
FlagWithArg("-C ", stubsDir.String()).
FlagWithArg("-D ", stubsDir.String())
+
+ if Bool(d.properties.Write_sdk_values) {
+ d.metadataZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"-metadata.zip")
+ rule.Command().
+ BuiltTool(ctx, "soong_zip").
+ Flag("-write_if_changed").
+ Flag("-d").
+ FlagWithOutput("-o ", d.metadataZip).
+ FlagWithArg("-C ", d.metadataDir.String()).
+ FlagWithArg("-D ", d.metadataDir.String())
+ }
+
rule.Restat()
zipSyncCleanupCmd(rule, srcJarDir)
@@ -1488,7 +1535,58 @@
// Create rule for apicheck
- if apiCheckEnabled(d.properties.Check_api.Current, "current") &&
+ if BoolDefault(d.properties.Check_api.Api_lint.Enabled, false) && !ctx.Config().IsPdkBuild() {
+ rule := android.NewRuleBuilder()
+ rule.Command().Text("( true")
+
+ srcJarDir := android.PathForModuleOut(ctx, "api_lint", "srcjars")
+ srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars)
+
+ cmd := metalavaCmd(ctx, rule, javaVersion, d.Javadoc.srcFiles, srcJarList,
+ deps.bootClasspath, deps.classpath, d.Javadoc.sourcepaths)
+
+ cmd.Flag(d.Javadoc.args).Implicits(d.Javadoc.argFiles)
+
+ newSince := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Api_lint.New_since)
+ if newSince.Valid() {
+ cmd.FlagWithInput("--api-lint ", newSince.Path())
+ } else {
+ cmd.Flag("--api-lint")
+ }
+
+ d.inclusionAnnotationsFlags(ctx, cmd)
+ d.mergeAnnoDirFlags(ctx, cmd)
+
+ baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Api_lint.Baseline_file)
+ updatedBaselineOutput := android.PathForModuleOut(ctx, "api_lint_baseline.txt")
+ d.apiLintTimestamp = android.PathForModuleOut(ctx, "api_lint.timestamp")
+
+ if baselineFile.Valid() {
+ cmd.FlagWithInput("--baseline ", baselineFile.Path())
+ cmd.FlagWithOutput("--update-baseline ", updatedBaselineOutput)
+ }
+
+ zipSyncCleanupCmd(rule, srcJarDir)
+
+ msg := fmt.Sprintf(`\n******************************\n`+
+ `Your API changes are triggering API Lint warnings or errors.\n\n`+
+ `To make these errors go away, you have two choices:\n`+
+ ` 1. You can suppress the errors with @SuppressLint(\"<id>\").\n\n`+
+ ` 2. You can update the baseline by executing the following command:\n`+
+ ` cp \"$PWD/%s\" \"$PWD/%s\"\n\n`+
+ `******************************\n`, updatedBaselineOutput, baselineFile.Path())
+ rule.Command().
+ Text("touch").Output(d.apiLintTimestamp).
+ Text(") || (").
+ Text("echo").Flag("-e").Flag(`"` + msg + `"`).
+ Text("; exit 38").
+ Text(")")
+
+ rule.Build(pctx, ctx, "metalavaApiLint", "metalava API lint")
+
+ }
+
+ if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") &&
!ctx.Config().IsPdkBuild() {
if len(d.Javadoc.properties.Out) > 0 {
@@ -1573,7 +1671,7 @@
rule.Build(pctx, ctx, "metalavaCurrentApiUpdate", "update current API")
}
- if apiCheckEnabled(d.properties.Check_api.Last_released, "last_released") &&
+ if apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") &&
!ctx.Config().IsPdkBuild() {
if len(d.Javadoc.properties.Out) > 0 {
diff --git a/java/gen.go b/java/gen.go
index 532a22c..d50a665 100644
--- a/java/gen.go
+++ b/java/gen.go
@@ -15,29 +15,22 @@
package java
import (
+ "strconv"
"strings"
"github.com/google/blueprint"
+ "github.com/google/blueprint/pathtools"
"android/soong/android"
)
func init() {
- pctx.HostBinToolVariable("aidlCmd", "aidl")
- pctx.HostBinToolVariable("syspropCmd", "sysprop_java")
pctx.SourcePathVariable("logtagsCmd", "build/make/tools/java-event-log-tags.py")
pctx.SourcePathVariable("mergeLogtagsCmd", "build/make/tools/merge-event-log-tags.py")
pctx.SourcePathVariable("logtagsLib", "build/make/tools/event_log_tags.py")
}
var (
- aidl = pctx.AndroidStaticRule("aidl",
- blueprint.RuleParams{
- Command: "$aidlCmd -d$depFile $aidlFlags $in $out",
- CommandDeps: []string{"$aidlCmd"},
- },
- "depFile", "aidlFlags")
-
logtags = pctx.AndroidStaticRule("logtags",
blueprint.RuleParams{
Command: "$logtagsCmd -o $out $in",
@@ -49,36 +42,66 @@
Command: "$mergeLogtagsCmd -o $out $in",
CommandDeps: []string{"$mergeLogtagsCmd", "$logtagsLib"},
})
-
- sysprop = pctx.AndroidStaticRule("sysprop",
- blueprint.RuleParams{
- Command: `rm -rf $out.tmp && mkdir -p $out.tmp && ` +
- `$syspropCmd --scope $scope --java-output-dir $out.tmp $in && ` +
- `${config.SoongZipCmd} -jar -o $out -C $out.tmp -D $out.tmp && rm -rf $out.tmp`,
- CommandDeps: []string{
- "$syspropCmd",
- "${config.SoongZipCmd}",
- },
- }, "scope")
)
-func genAidl(ctx android.ModuleContext, aidlFile android.Path, aidlFlags string, deps android.Paths) android.Path {
- javaFile := android.GenPathWithExt(ctx, "aidl", aidlFile, "java")
- depFile := javaFile.String() + ".d"
+func genAidl(ctx android.ModuleContext, aidlFiles android.Paths, aidlFlags string, deps android.Paths) android.Paths {
+ // Shard aidl files into groups of 50 to avoid having to recompile all of them if one changes and to avoid
+ // hitting command line length limits.
+ shards := android.ShardPaths(aidlFiles, 50)
- ctx.Build(pctx, android.BuildParams{
- Rule: aidl,
- Description: "aidl " + aidlFile.Rel(),
- Output: javaFile,
- Input: aidlFile,
- Implicits: deps,
- Args: map[string]string{
- "depFile": depFile,
- "aidlFlags": aidlFlags,
- },
- })
+ srcJarFiles := make(android.Paths, 0, len(shards))
- return javaFile
+ for i, shard := range shards {
+ srcJarFile := android.PathForModuleGen(ctx, "aidl", "aidl"+strconv.Itoa(i)+".srcjar")
+ srcJarFiles = append(srcJarFiles, srcJarFile)
+
+ outDir := srcJarFile.ReplaceExtension(ctx, "tmp")
+
+ rule := android.NewRuleBuilder()
+
+ rule.Command().Text("rm -rf").Flag(outDir.String())
+ rule.Command().Text("mkdir -p").Flag(outDir.String())
+ rule.Command().Text("FLAGS=' " + aidlFlags + "'")
+
+ for _, aidlFile := range shard {
+ depFile := srcJarFile.InSameDir(ctx, aidlFile.String()+".d")
+ javaFile := outDir.Join(ctx, pathtools.ReplaceExtension(aidlFile.String(), "java"))
+ rule.Command().
+ Tool(ctx.Config().HostToolPath(ctx, "aidl")).
+ FlagWithDepFile("-d", depFile).
+ Flag("$FLAGS").
+ Input(aidlFile).
+ Output(javaFile).
+ Implicits(deps)
+ rule.Temporary(javaFile)
+ }
+
+ rule.Command().
+ Tool(ctx.Config().HostToolPath(ctx, "soong_zip")).
+ // TODO(b/124333557): this can't use -srcjar for now, aidl on parcelables generates java files
+ // without a package statement, which causes -srcjar to put them in the top level of the zip file.
+ // Once aidl skips parcelables we can use -srcjar.
+ //Flag("-srcjar").
+ Flag("-write_if_changed").
+ FlagWithOutput("-o ", srcJarFile).
+ FlagWithArg("-C ", outDir.String()).
+ FlagWithArg("-D ", outDir.String())
+
+ rule.Command().Text("rm -rf").Flag(outDir.String())
+
+ rule.Restat()
+
+ ruleName := "aidl"
+ ruleDesc := "aidl"
+ if len(shards) > 1 {
+ ruleName += "_" + strconv.Itoa(i)
+ ruleDesc += " " + strconv.Itoa(i)
+ }
+
+ rule.Build(pctx, ctx, ruleName, ruleDesc)
+ }
+
+ return srcJarFiles
}
func genLogtags(ctx android.ModuleContext, logtagsFile android.Path) android.Path {
@@ -94,22 +117,6 @@
return javaFile
}
-func genSysprop(ctx android.ModuleContext, syspropFile android.Path, scope string) android.Path {
- srcJarFile := android.GenPathWithExt(ctx, "sysprop", syspropFile, "srcjar")
-
- ctx.Build(pctx, android.BuildParams{
- Rule: sysprop,
- Description: "sysprop_java " + syspropFile.Rel(),
- Output: srcJarFile,
- Input: syspropFile,
- Args: map[string]string{
- "scope": scope,
- },
- })
-
- return srcJarFile
-}
-
func genAidlIncludeFlags(srcFiles android.Paths) string {
var baseDirs []string
for _, srcFile := range srcFiles {
@@ -127,49 +134,38 @@
flags javaBuilderFlags) android.Paths {
outSrcFiles := make(android.Paths, 0, len(srcFiles))
+ var protoSrcs android.Paths
+ var aidlSrcs android.Paths
aidlIncludeFlags := genAidlIncludeFlags(srcFiles)
for _, srcFile := range srcFiles {
switch srcFile.Ext() {
case ".aidl":
- javaFile := genAidl(ctx, srcFile, flags.aidlFlags+aidlIncludeFlags, flags.aidlDeps)
- outSrcFiles = append(outSrcFiles, javaFile)
+ aidlSrcs = append(aidlSrcs, srcFile)
case ".logtags":
j.logtagsSrcs = append(j.logtagsSrcs, srcFile)
javaFile := genLogtags(ctx, srcFile)
outSrcFiles = append(outSrcFiles, javaFile)
case ".proto":
- srcJarFile := genProto(ctx, srcFile, flags.proto)
- outSrcFiles = append(outSrcFiles, srcJarFile)
- case ".sysprop":
- // internal scope contains all properties
- // public scope only contains public properties
- // use public if the owner is different from client
- scope := "internal"
- if j.properties.Sysprop.Platform != nil {
- isProduct := ctx.ProductSpecific()
- isVendor := ctx.SocSpecific()
- isOwnerPlatform := Bool(j.properties.Sysprop.Platform)
-
- if isProduct {
- // product can't own any sysprop_library now, so product must use public scope
- scope = "public"
- } else if isVendor && !isOwnerPlatform {
- // vendor and odm can't use system's internal property.
- scope = "public"
- }
-
- // We don't care about clients under system.
- // They can't use sysprop_library owned by other partitions.
- }
- srcJarFile := genSysprop(ctx, srcFile, scope)
- outSrcFiles = append(outSrcFiles, srcJarFile)
+ protoSrcs = append(protoSrcs, srcFile)
default:
outSrcFiles = append(outSrcFiles, srcFile)
}
}
+ // Process all proto files together to support sharding them into one or more rules that produce srcjars.
+ if len(protoSrcs) > 0 {
+ srcJarFiles := genProto(ctx, protoSrcs, flags.proto)
+ outSrcFiles = append(outSrcFiles, srcJarFiles...)
+ }
+
+ // Process all aidl files together to support sharding them into one or more rules that produce srcjars.
+ if len(aidlSrcs) > 0 {
+ srcJarFiles := genAidl(ctx, aidlSrcs, flags.aidlFlags+aidlIncludeFlags, flags.aidlDeps)
+ outSrcFiles = append(outSrcFiles, srcJarFiles...)
+ }
+
return outSrcFiles
}
diff --git a/java/java.go b/java/java.go
index 2193a2b..be48256 100644
--- a/java/java.go
+++ b/java/java.go
@@ -25,6 +25,7 @@
"strings"
"github.com/google/blueprint"
+ "github.com/google/blueprint/pathtools"
"github.com/google/blueprint/proptools"
"android/soong/android"
@@ -183,10 +184,6 @@
Output_params []string
}
- Sysprop struct {
- Platform *bool
- } `blueprint:"mutated"`
-
Instrument bool `blueprint:"mutated"`
// List of files to include in the META-INF/services folder of the resulting jar.
@@ -273,7 +270,8 @@
Proguard_flags_files []string `android:"path"`
}
- // When targeting 1.9, override the modules to use with --system
+ // When targeting 1.9 and above, override the modules to use with --system,
+ // otherwise provides defaults libraries to add to the bootclasspath.
System_modules *string
UncompressDex bool `blueprint:"mutated"`
@@ -289,6 +287,7 @@
android.ModuleBase
android.DefaultableModuleBase
android.ApexModuleBase
+ android.SdkBase
properties CompilerProperties
protoProperties android.ProtoProperties
@@ -349,8 +348,8 @@
// list of SDK lib names that this java moudule is exporting
exportedSdkLibs []string
- // list of source files, collected from compiledJavaSrcs and compiledSrcJars
- // filter out Exclude_srcs, will be used by android.IDEInfo struct
+ // list of source files, collected from srcFiles with uniqie java and all kt files,
+ // will be used by android.IDEInfo struct
expandIDEInfoCompiledSrcs []string
// expanded Jarjar_rules
@@ -397,6 +396,7 @@
AidlIncludeDirs() android.Paths
ExportedSdkLibs() []string
SrcJarArgs() ([]string, android.Paths)
+ BaseModuleName() string
}
type SdkLibraryDependency interface {
@@ -404,29 +404,14 @@
SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion string) android.Paths
}
-type SrcDependency interface {
- CompiledSrcs() android.Paths
- CompiledSrcJars() android.Paths
-}
-
type xref interface {
XrefJavaFiles() android.Paths
}
-func (j *Module) CompiledSrcs() android.Paths {
- return j.compiledJavaSrcs
-}
-
-func (j *Module) CompiledSrcJars() android.Paths {
- return j.compiledSrcJars
-}
-
func (j *Module) XrefJavaFiles() android.Paths {
return j.kytheFiles
}
-var _ SrcDependency = (*Module)(nil)
-
func InitJavaModule(module android.DefaultableModule, hod android.HostOrDeviceSupported) {
android.InitAndroidArchModule(module, hod, android.MultilibCommon)
android.InitDefaultableModule(module)
@@ -473,7 +458,10 @@
type sdkDep struct {
useModule, useFiles, useDefaultLibs, invalidVersion bool
- modules []string
+ modules []string
+
+ // The default system modules to use. Will be an empty string if no system
+ // modules are to be used.
systemModules string
frameworkResModule string
@@ -512,6 +500,10 @@
return proptools.StringDefault(j.deviceProperties.Sdk_version, defaultSdkVersion(j))
}
+func (j *Module) systemModules() string {
+ return proptools.String(j.deviceProperties.System_modules)
+}
+
func (j *Module) minSdkVersion() string {
if j.deviceProperties.Min_sdk_version != nil {
return *j.deviceProperties.Min_sdk_version
@@ -544,14 +536,10 @@
ctx.AddVariationDependencies(nil, proguardRaiseTag, config.DefaultLibraries...)
}
}
- } else if j.deviceProperties.System_modules == nil {
- ctx.PropertyErrorf("sdk_version",
- `system_modules is required to be set when sdk_version is "none", did you mean "core_platform"`)
- } else if *j.deviceProperties.System_modules != "none" {
- ctx.AddVariationDependencies(nil, systemModulesTag, *j.deviceProperties.System_modules)
- }
- if (ctx.ModuleName() == "framework") || (ctx.ModuleName() == "framework-annotation-proc") {
- ctx.AddVariationDependencies(nil, frameworkResTag, "framework-res")
+ } else if sdkDep.systemModules != "" {
+ // Add the system modules to both the system modules and bootclasspath.
+ ctx.AddVariationDependencies(nil, systemModulesTag, sdkDep.systemModules)
+ ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.systemModules)
}
if ctx.ModuleName() == "android_stubs_current" ||
ctx.ModuleName() == "android_system_stubs_current" ||
@@ -563,9 +551,7 @@
ctx.AddVariationDependencies(nil, libTag, j.properties.Libs...)
ctx.AddVariationDependencies(nil, staticLibTag, j.properties.Static_libs...)
- ctx.AddFarVariationDependencies([]blueprint.Variation{
- {Mutator: "arch", Variation: ctx.Config().BuildOsCommonVariant},
- }, pluginTag, j.properties.Plugins...)
+ ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), pluginTag, j.properties.Plugins...)
android.ProtoDeps(ctx, &j.protoProperties)
if j.hasSrcExt(".proto") {
@@ -597,18 +583,6 @@
return false
}
-func shardPaths(paths android.Paths, shardSize int) []android.Paths {
- ret := make([]android.Paths, 0, (len(paths)+shardSize-1)/shardSize)
- for len(paths) > shardSize {
- ret = append(ret, paths[0:shardSize])
- paths = paths[shardSize:]
- }
- if len(paths) > 0 {
- ret = append(ret, paths)
- }
- return ret
-}
-
func (j *Module) hasSrcExt(ext string) bool {
return hasSrcExt(j.properties.Srcs, ext)
}
@@ -833,12 +807,6 @@
} else {
ctx.PropertyErrorf("plugins", "%q is not a java_plugin module", otherName)
}
- case frameworkResTag:
- if (ctx.ModuleName() == "framework") || (ctx.ModuleName() == "framework-annotation-proc") {
- // framework.jar has a one-off dependency on the R.java and Manifest.java files
- // generated by framework-res.apk
- deps.srcJars = append(deps.srcJars, dep.(*AndroidApp).aaptSrcJar)
- }
case frameworkApkTag:
if ctx.ModuleName() == "android_stubs_current" ||
ctx.ModuleName() == "android_system_stubs_current" ||
@@ -870,6 +838,12 @@
}
default:
switch tag {
+ case bootClasspathTag:
+ // If a system modules dependency has been added to the bootclasspath
+ // then add its libs to the bootclasspath.
+ sm := module.(*SystemModules)
+ deps.bootClasspath = append(deps.bootClasspath, sm.headerJars...)
+
case systemModulesTag:
if deps.systemModules != nil {
panic("Found two system module dependencies")
@@ -907,7 +881,7 @@
ctx.PropertyErrorf("sdk_version", "%s", err)
}
if javaVersion != "" {
- ret = javaVersion
+ ret = normalizeJavaVersion(ctx, javaVersion)
} else if ctx.Device() && sdk <= 23 {
ret = "1.7"
} else if ctx.Device() && sdk <= 29 || !ctx.Config().TargetOpenJDK9() {
@@ -926,6 +900,25 @@
return ret
}
+func normalizeJavaVersion(ctx android.ModuleContext, javaVersion string) string {
+ switch javaVersion {
+ case "1.6", "6":
+ return "1.6"
+ case "1.7", "7":
+ return "1.7"
+ case "1.8", "8":
+ return "1.8"
+ case "1.9", "9":
+ return "1.9"
+ case "10", "11":
+ ctx.PropertyErrorf("java_version", "Java language levels above 9 are not supported")
+ return "unsupported"
+ default:
+ ctx.PropertyErrorf("java_version", "Unrecognized Java language level")
+ return "unrecognized"
+ }
+}
+
func (j *Module) collectBuilderFlags(ctx android.ModuleContext, deps deps) javaBuilderFlags {
var flags javaBuilderFlags
@@ -1042,10 +1035,6 @@
srcJars = append(srcJars, aaptSrcJar)
}
- // Collect source files from compiledJavaSrcs, compiledSrcJars and filter out Exclude_srcs
- // that IDEInfo struct will use
- j.expandIDEInfoCompiledSrcs = append(j.expandIDEInfoCompiledSrcs, srcFiles.Strings()...)
-
if j.properties.Jarjar_rules != nil {
j.expandJarjarRules = android.PathForModuleSrc(ctx, *j.properties.Jarjar_rules)
}
@@ -1062,6 +1051,9 @@
}
}
+ // Collect .java files for AIDEGen
+ j.expandIDEInfoCompiledSrcs = append(j.expandIDEInfoCompiledSrcs, uniqueSrcFiles.Strings()...)
+
var kotlinJars android.Paths
if srcFiles.HasExt(".kt") {
@@ -1086,6 +1078,9 @@
kotlinSrcFiles = append(kotlinSrcFiles, uniqueSrcFiles...)
kotlinSrcFiles = append(kotlinSrcFiles, srcFiles.FilterByExt(".kt")...)
+ // Collect .kt files for AIDEGen
+ j.expandIDEInfoCompiledSrcs = append(j.expandIDEInfoCompiledSrcs, srcFiles.FilterByExt(".kt").Strings()...)
+
flags.classpath = append(flags.classpath, deps.kotlinStdlib...)
flags.classpath = append(flags.classpath, deps.kotlinAnnotations...)
@@ -1155,29 +1150,22 @@
shardSize := int(*(j.properties.Javac_shard_size))
var shardSrcs []android.Paths
if len(uniqueSrcFiles) > 0 {
- shardSrcs = shardPaths(uniqueSrcFiles, shardSize)
+ shardSrcs = android.ShardPaths(uniqueSrcFiles, shardSize)
for idx, shardSrc := range shardSrcs {
- classes := android.PathForModuleOut(ctx, "javac", jarName+strconv.Itoa(idx))
- TransformJavaToClasses(ctx, classes, idx, shardSrc, nil, flags, extraJarDeps)
+ classes := j.compileJavaClasses(ctx, jarName, idx, shardSrc,
+ nil, flags, extraJarDeps)
jars = append(jars, classes)
}
}
if len(srcJars) > 0 {
- classes := android.PathForModuleOut(ctx, "javac", jarName+strconv.Itoa(len(shardSrcs)))
- TransformJavaToClasses(ctx, classes, len(shardSrcs), nil, srcJars, flags, extraJarDeps)
+ classes := j.compileJavaClasses(ctx, jarName, len(shardSrcs),
+ nil, srcJars, flags, extraJarDeps)
jars = append(jars, classes)
}
} else {
- classes := android.PathForModuleOut(ctx, "javac", jarName)
- TransformJavaToClasses(ctx, classes, -1, uniqueSrcFiles, srcJars, flags, extraJarDeps)
+ classes := j.compileJavaClasses(ctx, jarName, -1, uniqueSrcFiles, srcJars, flags, extraJarDeps)
jars = append(jars, classes)
}
- if ctx.Config().EmitXrefRules() {
- extractionFile := android.PathForModuleOut(ctx, ctx.ModuleName()+".kzip")
- emitXrefRule(ctx, extractionFile, uniqueSrcFiles, srcJars, flags, extraJarDeps, "xref")
- j.kytheFiles = append(j.kytheFiles, extractionFile)
-
- }
if ctx.Failed() {
return
}
@@ -1398,6 +1386,27 @@
j.outputFile = outputFile.WithoutRel()
}
+func (j *Module) compileJavaClasses(ctx android.ModuleContext, jarName string, idx int,
+ srcFiles, srcJars android.Paths, flags javaBuilderFlags, extraJarDeps android.Paths) android.WritablePath {
+
+ kzipName := pathtools.ReplaceExtension(jarName, "kzip")
+ if idx >= 0 {
+ kzipName = strings.TrimSuffix(jarName, filepath.Ext(jarName)) + strconv.Itoa(idx) + ".kzip"
+ jarName += strconv.Itoa(idx)
+ }
+
+ classes := android.PathForModuleOut(ctx, "javac", jarName)
+ TransformJavaToClasses(ctx, classes, idx, srcFiles, srcJars, flags, extraJarDeps)
+
+ if ctx.Config().EmitXrefRules() {
+ extractionFile := android.PathForModuleOut(ctx, kzipName)
+ emitXrefRule(ctx, extractionFile, idx, srcFiles, srcJars, flags, extraJarDeps)
+ j.kytheFiles = append(j.kytheFiles, extractionFile)
+ }
+
+ return classes
+}
+
// Check for invalid kotlinc flags. Only use this for flags explicitly passed by the user,
// since some of these flags may be used internally.
func CheckKotlincFlags(ctx android.ModuleContext, flags []string) {
@@ -1556,12 +1565,20 @@
return len(srcFiles) > 0 || len(ctx.GetDirectDepsWithTag(staticLibTag)) > 0
}
+func (j *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
+ depTag := ctx.OtherModuleDependencyTag(dep)
+ // dependencies other than the static linkage are all considered crossing APEX boundary
+ return depTag == staticLibTag
+}
+
//
// Java libraries (.jar file)
//
type Library struct {
Module
+
+ InstallMixin func(ctx android.ModuleContext, installPath android.Path) (extraInstallDeps android.Paths)
}
func shouldUncompressDex(ctx android.ModuleContext, dexpreopter *dexpreopter) bool {
@@ -1592,8 +1609,12 @@
exclusivelyForApex := android.InAnyApex(ctx.ModuleName()) && !j.IsForPlatform()
if (Bool(j.properties.Installable) || ctx.Host()) && !exclusivelyForApex {
+ var extraInstallDeps android.Paths
+ if j.InstallMixin != nil {
+ extraInstallDeps = j.InstallMixin(ctx, j.outputFile)
+ }
j.installFile = ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"),
- ctx.ModuleName()+".jar", j.outputFile)
+ ctx.ModuleName()+".jar", j.outputFile, extraInstallDeps...)
}
}
@@ -1623,6 +1644,7 @@
InitJavaModule(module, android.HostAndDeviceSupported)
android.InitApexModule(module)
+ android.InitSdkAwareModule(module)
return module
}
@@ -1669,6 +1691,11 @@
// list of files or filegroup modules that provide data that should be installed alongside
// the test
Data []string `android:"path"`
+
+ // Flag to indicate whether or not to create test config automatically. If AndroidTest.xml
+ // doesn't exist next to the Android.bp, this attribute doesn't need to be set to true
+ // explicitly.
+ Auto_gen_config *bool
}
type testHelperLibraryProperties struct {
@@ -1693,7 +1720,8 @@
}
func (j *Test) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- j.testConfig = tradefed.AutoGenJavaTestConfig(ctx, j.testProperties.Test_config, j.testProperties.Test_config_template, j.testProperties.Test_suites)
+ j.testConfig = tradefed.AutoGenJavaTestConfig(ctx, j.testProperties.Test_config, j.testProperties.Test_config_template,
+ j.testProperties.Test_suites, j.testProperties.Auto_gen_config)
j.data = android.PathsForModuleSrc(ctx, j.testProperties.Data)
j.Library.GenerateAndroidBuildActions(ctx)
@@ -1785,7 +1813,7 @@
isWrapperVariant bool
wrapperFile android.Path
- binaryFile android.OutputPath
+ binaryFile android.InstallPath
}
func (j *Binary) HostToolPath() android.OptionalPath {
@@ -1903,6 +1931,7 @@
android.DefaultableModuleBase
android.ApexModuleBase
prebuilt android.Prebuilt
+ android.SdkBase
properties ImportProperties
@@ -2059,6 +2088,7 @@
android.InitPrebuiltModule(module, &module.properties.Jars)
InitJavaModule(module, android.HostAndDeviceSupported)
android.InitApexModule(module)
+ android.InitSdkAwareModule(module)
return module
}
diff --git a/java/java_test.go b/java/java_test.go
index 5fcdf96..3767d1b 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -18,6 +18,7 @@
"io/ioutil"
"os"
"path/filepath"
+ "reflect"
"strconv"
"strings"
"testing"
@@ -66,6 +67,7 @@
ctx.RegisterModuleType("android_library", android.ModuleFactoryAdaptor(AndroidLibraryFactory))
ctx.RegisterModuleType("android_test", android.ModuleFactoryAdaptor(AndroidTestFactory))
ctx.RegisterModuleType("android_test_helper_app", android.ModuleFactoryAdaptor(AndroidTestHelperAppFactory))
+ ctx.RegisterModuleType("android_test_import", android.ModuleFactoryAdaptor(AndroidTestImportFactory))
ctx.RegisterModuleType("java_binary", android.ModuleFactoryAdaptor(BinaryFactory))
ctx.RegisterModuleType("java_binary_host", android.ModuleFactoryAdaptor(BinaryHostFactory))
ctx.RegisterModuleType("java_device_for_host", android.ModuleFactoryAdaptor(DeviceForHostFactory))
@@ -200,6 +202,8 @@
"cert/new_cert.x509.pem": nil,
"cert/new_cert.pk8": nil,
+
+ "testdata/data": nil,
}
for k, v := range fs {
@@ -808,19 +812,22 @@
}
`)
- inputs := ctx.ModuleForTests("bar-doc", "android_common").Rule("javadoc").Inputs
+ barDoc := ctx.ModuleForTests("bar-doc", "android_common").Rule("javadoc")
var javaSrcs []string
- for _, i := range inputs {
+ for _, i := range barDoc.Inputs {
javaSrcs = append(javaSrcs, i.Base())
}
- if len(javaSrcs) != 3 || javaSrcs[0] != "a.java" || javaSrcs[1] != "IFoo.java" || javaSrcs[2] != "IBar.java" {
- t.Errorf("inputs of bar-doc must be []string{\"a.java\", \"IFoo.java\", \"IBar.java\", but was %#v.", javaSrcs)
+ if len(javaSrcs) != 1 || javaSrcs[0] != "a.java" {
+ t.Errorf("inputs of bar-doc must be []string{\"a.java\"}, but was %#v.", javaSrcs)
}
- aidlRule := ctx.ModuleForTests("bar-doc", "android_common").Output(inputs[2].String())
- aidlFlags := aidlRule.Args["aidlFlags"]
- if !strings.Contains(aidlFlags, "-Ibar-doc") {
- t.Errorf("aidl flags for IBar.aidl should contain \"-Ibar-doc\", but was %q", aidlFlags)
+ aidl := ctx.ModuleForTests("bar-doc", "android_common").Rule("aidl")
+ if g, w := barDoc.Implicits.Strings(), aidl.Output.String(); !inList(w, g) {
+ t.Errorf("implicits of bar-doc must contain %q, but was %q.", w, g)
+ }
+
+ if g, w := aidl.Implicits.Strings(), []string{"bar-doc/IBar.aidl", "bar-doc/IFoo.aidl"}; !reflect.DeepEqual(w, g) {
+ t.Errorf("aidl inputs must be %q, but was %q", w, g)
}
}
@@ -1066,29 +1073,31 @@
}
func TestPatchModule(t *testing.T) {
- bp := `
- java_library {
- name: "foo",
- srcs: ["a.java"],
- }
-
- java_library {
- name: "bar",
- srcs: ["b.java"],
- sdk_version: "none",
- system_modules: "none",
- patch_module: "java.base",
- }
-
- java_library {
- name: "baz",
- srcs: ["c.java"],
- patch_module: "java.base",
- }
- `
-
t.Run("Java language level 8", func(t *testing.T) {
- // Test default javac -source 1.8 -target 1.8
+ // Test with legacy javac -source 1.8 -target 1.8
+ bp := `
+ java_library {
+ name: "foo",
+ srcs: ["a.java"],
+ java_version: "1.8",
+ }
+
+ java_library {
+ name: "bar",
+ srcs: ["b.java"],
+ sdk_version: "none",
+ system_modules: "none",
+ patch_module: "java.base",
+ java_version: "1.8",
+ }
+
+ java_library {
+ name: "baz",
+ srcs: ["c.java"],
+ patch_module: "java.base",
+ java_version: "1.8",
+ }
+ `
ctx, _ := testJava(t, bp)
checkPatchModuleFlag(t, ctx, "foo", "")
@@ -1097,15 +1106,33 @@
})
t.Run("Java language level 9", func(t *testing.T) {
- // Test again with javac -source 9 -target 9
- config := testConfig(map[string]string{"EXPERIMENTAL_JAVA_LANGUAGE_LEVEL_9": "true"})
- ctx := testContext(bp, nil)
- run(t, ctx, config)
+ // Test with default javac -source 9 -target 9
+ bp := `
+ java_library {
+ name: "foo",
+ srcs: ["a.java"],
+ }
+
+ java_library {
+ name: "bar",
+ srcs: ["b.java"],
+ sdk_version: "none",
+ system_modules: "none",
+ patch_module: "java.base",
+ }
+
+ java_library {
+ name: "baz",
+ srcs: ["c.java"],
+ patch_module: "java.base",
+ }
+ `
+ ctx, _ := testJava(t, bp)
checkPatchModuleFlag(t, ctx, "foo", "")
expected := "java.base=.:" + buildDir
checkPatchModuleFlag(t, ctx, "bar", expected)
- expected = "java.base=" + strings.Join([]string{".", buildDir, moduleToPath("ext"), moduleToPath("framework")}, ":")
+ expected = "java.base=" + strings.Join([]string{".", buildDir, moduleToPath("ext"), moduleToPath("framework"), moduleToPath("updatable_media_stubs")}, ":")
checkPatchModuleFlag(t, ctx, "baz", expected)
})
}
diff --git a/java/platform_compat_config.go b/java/platform_compat_config.go
index 792edf3..23ba2b0 100644
--- a/java/platform_compat_config.go
+++ b/java/platform_compat_config.go
@@ -23,28 +23,27 @@
}
type platformCompatConfigProperties struct {
- Src *string `android:"path"`
- Prefix *string
+ Src *string `android:"path"`
}
type platformCompatConfig struct {
android.ModuleBase
properties platformCompatConfigProperties
- installDirPath android.OutputPath
+ installDirPath android.InstallPath
configFile android.OutputPath
}
func (p *platformCompatConfig) GenerateAndroidBuildActions(ctx android.ModuleContext) {
rule := android.NewRuleBuilder()
- configFileName := String(p.properties.Prefix) + "_platform_compat_config.xml"
+ configFileName := p.Name() + ".xml"
p.configFile = android.PathForModuleOut(ctx, configFileName).OutputPath
path := android.PathForModuleSrc(ctx, String(p.properties.Src))
// Use the empty config if the compat config file idoesn't exist (can happen if @ChangeId
// annotation is not used).
- emptyConfig := `<?xml version="1.0" encoding="UTF-8" standalone="no"?><config/>`
+ emptyConfig := `'<?xml version="1.0" encoding="UTF-8" standalone="no"?><config/>'`
configPath := `compat/compat_config.xml`
rule.Command().
@@ -61,13 +60,13 @@
Text(configPath).
Text(`>`).
Output(p.configFile).
- Text(`; else echo '`).
+ Text(`; else echo `).
Text(emptyConfig).
- Text(`' >`).
+ Text(`>`).
Output(p.configFile).
Text(`; fi`)
- p.installDirPath = android.PathForModuleInstall(ctx, "etc", "sysconfig")
+ p.installDirPath = android.PathForModuleInstall(ctx, "etc", "compatconfig")
rule.Build(pctx, ctx, configFileName, "Extract compat/compat_config.xml and install it")
}
@@ -77,9 +76,11 @@
Class: "ETC",
OutputFile: android.OptionalPathForPath(p.configFile),
Include: "$(BUILD_PREBUILT)",
- AddCustomEntries: func(name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
- entries.SetString("LOCAL_MODULE_PATH", "$(OUT_DIR)/"+p.installDirPath.RelPathString())
- entries.SetString("LOCAL_INSTALLED_MODULE_STEM", p.configFile.Base())
+ ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+ func(entries *android.AndroidMkEntries) {
+ entries.SetString("LOCAL_MODULE_PATH", p.installDirPath.ToMakePath().String())
+ entries.SetString("LOCAL_INSTALLED_MODULE_STEM", p.configFile.Base())
+ },
},
}
}
diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go
index c370811..0d5e31f 100644
--- a/java/prebuilt_apis.go
+++ b/java/prebuilt_apis.go
@@ -82,7 +82,7 @@
props.Sdk_version = proptools.StringPtr("current")
props.Installable = proptools.BoolPtr(false)
- mctx.CreateModule(android.ModuleFactoryAdaptor(ImportFactory), &props)
+ mctx.CreateModule(ImportFactory, &props)
}
func createFilegroup(mctx android.TopDownMutatorContext, module string, scope string, apiver string, path string) {
@@ -93,7 +93,7 @@
}{}
filegroupProps.Name = proptools.StringPtr(fgName)
filegroupProps.Srcs = []string{path}
- mctx.CreateModule(android.ModuleFactoryAdaptor(android.FileGroupFactory), &filegroupProps)
+ mctx.CreateModule(android.FileGroupFactory, &filegroupProps)
}
func getPrebuiltFiles(mctx android.TopDownMutatorContext, name string) []string {
diff --git a/java/proto.go b/java/proto.go
index 22a3eed..e013bb4 100644
--- a/java/proto.go
+++ b/java/proto.go
@@ -15,36 +15,61 @@
package java
import (
+ "path/filepath"
+ "strconv"
+
"android/soong/android"
)
-func genProto(ctx android.ModuleContext, protoFile android.Path, flags android.ProtoFlags) android.Path {
- srcJarFile := android.GenPathWithExt(ctx, "proto", protoFile, "srcjar")
+func genProto(ctx android.ModuleContext, protoFiles android.Paths, flags android.ProtoFlags) android.Paths {
+ // Shard proto files into groups of 100 to avoid having to recompile all of them if one changes and to avoid
+ // hitting command line length limits.
+ shards := android.ShardPaths(protoFiles, 100)
- outDir := srcJarFile.ReplaceExtension(ctx, "tmp")
- depFile := srcJarFile.ReplaceExtension(ctx, "srcjar.d")
+ srcJarFiles := make(android.Paths, 0, len(shards))
- rule := android.NewRuleBuilder()
+ for i, shard := range shards {
+ srcJarFile := android.PathForModuleGen(ctx, "proto", "proto"+strconv.Itoa(i)+".srcjar")
+ srcJarFiles = append(srcJarFiles, srcJarFile)
- rule.Command().Text("rm -rf").Flag(outDir.String())
- rule.Command().Text("mkdir -p").Flag(outDir.String())
+ outDir := srcJarFile.ReplaceExtension(ctx, "tmp")
- android.ProtoRule(ctx, rule, protoFile, flags, flags.Deps, outDir, depFile, nil)
+ rule := android.NewRuleBuilder()
- // Proto generated java files have an unknown package name in the path, so package the entire output directory
- // into a srcjar.
- rule.Command().
- BuiltTool(ctx, "soong_zip").
- Flag("-jar").
- FlagWithOutput("-o ", srcJarFile).
- FlagWithArg("-C ", outDir.String()).
- FlagWithArg("-D ", outDir.String())
+ rule.Command().Text("rm -rf").Flag(outDir.String())
+ rule.Command().Text("mkdir -p").Flag(outDir.String())
- rule.Command().Text("rm -rf").Flag(outDir.String())
+ for _, protoFile := range shard {
+ depFile := srcJarFile.InSameDir(ctx, protoFile.String()+".d")
+ rule.Command().Text("mkdir -p").Flag(filepath.Dir(depFile.String()))
+ android.ProtoRule(ctx, rule, protoFile, flags, flags.Deps, outDir, depFile, nil)
+ }
- rule.Build(pctx, ctx, "protoc_"+protoFile.Rel(), "protoc "+protoFile.Rel())
+ // Proto generated java files have an unknown package name in the path, so package the entire output directory
+ // into a srcjar.
+ rule.Command().
+ BuiltTool(ctx, "soong_zip").
+ Flag("-jar").
+ Flag("-write_if_changed").
+ FlagWithOutput("-o ", srcJarFile).
+ FlagWithArg("-C ", outDir.String()).
+ FlagWithArg("-D ", outDir.String())
- return srcJarFile
+ rule.Command().Text("rm -rf").Flag(outDir.String())
+
+ rule.Restat()
+
+ ruleName := "protoc"
+ ruleDesc := "protoc"
+ if len(shards) > 1 {
+ ruleName += "_" + strconv.Itoa(i)
+ ruleDesc += " " + strconv.Itoa(i)
+ }
+
+ rule.Build(pctx, ctx, ruleName, ruleDesc)
+ }
+
+ return srcJarFiles
}
func protoDeps(ctx android.BottomUpMutatorContext, p *android.ProtoProperties) {
@@ -82,6 +107,7 @@
typeToPlugin = "javamicro"
case "nano":
flags.proto.OutTypeFlag = "--javanano_out"
+ typeToPlugin = "javanano"
case "lite":
flags.proto.OutTypeFlag = "--java_out"
flags.proto.OutParams = append(flags.proto.OutParams, "lite")
diff --git a/java/robolectric.go b/java/robolectric.go
index 1de56a5..b7646eb 100644
--- a/java/robolectric.go
+++ b/java/robolectric.go
@@ -34,10 +34,17 @@
"truth-prebuilt",
}
+var (
+ roboCoverageLibsTag = dependencyTag{name: "roboSrcs"}
+)
+
type robolectricProperties struct {
// The name of the android_app module that the tests will run against.
Instrumentation_for *string
+ // Additional libraries for which coverage data should be generated
+ Coverage_libs []string
+
Test_options struct {
// Timeout in seconds when running the tests.
Timeout *int64
@@ -54,6 +61,8 @@
libs []string
tests []string
+
+ roboSrcJar android.Path
}
func (r *robolectricTest) DepsMutator(ctx android.BottomUpMutatorContext) {
@@ -66,13 +75,37 @@
}
ctx.AddVariationDependencies(nil, libTag, robolectricDefaultLibs...)
+
+ ctx.AddVariationDependencies(nil, roboCoverageLibsTag, r.robolectricProperties.Coverage_libs...)
}
func (r *robolectricTest) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ roboTestConfig := android.PathForModuleGen(ctx, "robolectric").
+ Join(ctx, "com/android/tools/test_config.properties")
+
+ // TODO: this inserts paths to built files into the test, it should really be inserting the contents.
+ instrumented := ctx.GetDirectDepsWithTag(instrumentationForTag)
+
+ if len(instrumented) != 1 {
+ panic(fmt.Errorf("expected exactly 1 instrumented dependency, got %d", len(instrumented)))
+ }
+
+ instrumentedApp, ok := instrumented[0].(*AndroidApp)
+ if !ok {
+ ctx.PropertyErrorf("instrumentation_for", "dependency must be an android_app")
+ }
+
+ generateRoboTestConfig(ctx, roboTestConfig, instrumentedApp)
+ r.extraResources = android.Paths{roboTestConfig}
+
r.Library.GenerateAndroidBuildActions(ctx)
+ roboSrcJar := android.PathForModuleGen(ctx, "robolectric", ctx.ModuleName()+".srcjar")
+ r.generateRoboSrcJar(ctx, roboSrcJar, instrumentedApp)
+ r.roboSrcJar = roboSrcJar
+
for _, dep := range ctx.GetDirectDepsWithTag(libTag) {
- r.libs = append(r.libs, ctx.OtherModuleName(dep))
+ r.libs = append(r.libs, dep.(Dependency).BaseModuleName())
}
// TODO: this could all be removed if tradefed was used as the test runner, it will find everything
@@ -90,51 +123,69 @@
}
}
-func shardTests(paths []string, shards int) [][]string {
- if shards > len(paths) {
- shards = len(paths)
- }
- if shards == 0 {
- return nil
- }
- ret := make([][]string, 0, shards)
- shardSize := (len(paths) + shards - 1) / shards
- for len(paths) > shardSize {
- ret = append(ret, paths[0:shardSize])
- paths = paths[shardSize:]
- }
- if len(paths) > 0 {
- ret = append(ret, paths)
- }
- return ret
+func generateRoboTestConfig(ctx android.ModuleContext, outputFile android.WritablePath, instrumentedApp *AndroidApp) {
+ manifest := instrumentedApp.mergedManifestFile
+ resourceApk := instrumentedApp.outputFile
+
+ rule := android.NewRuleBuilder()
+
+ rule.Command().Text("rm -f").Output(outputFile)
+ rule.Command().
+ Textf(`echo "android_merged_manifest=%s" >>`, manifest.String()).Output(outputFile).Text("&&").
+ Textf(`echo "android_resource_apk=%s" >>`, resourceApk.String()).Output(outputFile).
+ // Make it depend on the files to which it points so the test file's timestamp is updated whenever the
+ // contents change
+ Implicit(manifest).
+ Implicit(resourceApk)
+
+ rule.Build(pctx, ctx, "generate_test_config", "generate test_config.properties")
}
-func (r *robolectricTest) AndroidMk() android.AndroidMkData {
- data := r.Library.AndroidMk()
+func (r *robolectricTest) generateRoboSrcJar(ctx android.ModuleContext, outputFile android.WritablePath,
+ instrumentedApp *AndroidApp) {
- data.Custom = func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
- android.WriteAndroidMkData(w, data)
+ srcJarArgs := copyOf(instrumentedApp.srcJarArgs)
+ srcJarDeps := append(android.Paths(nil), instrumentedApp.srcJarDeps...)
- if s := r.robolectricProperties.Test_options.Shards; s != nil && *s > 1 {
- shards := shardTests(r.tests, int(*s))
- for i, shard := range shards {
- r.writeTestRunner(w, name, "Run"+name+strconv.Itoa(i), shard)
- }
-
- // TODO: add rules to dist the outputs of the individual tests, or combine them together?
- fmt.Fprintln(w, "")
- fmt.Fprintln(w, ".PHONY:", "Run"+name)
- fmt.Fprintln(w, "Run"+name, ": \\")
- for i := range shards {
- fmt.Fprintln(w, " ", "Run"+name+strconv.Itoa(i), "\\")
- }
- fmt.Fprintln(w, "")
- } else {
- r.writeTestRunner(w, name, "Run"+name, r.tests)
+ for _, m := range ctx.GetDirectDepsWithTag(roboCoverageLibsTag) {
+ if dep, ok := m.(Dependency); ok {
+ depSrcJarArgs, depSrcJarDeps := dep.SrcJarArgs()
+ srcJarArgs = append(srcJarArgs, depSrcJarArgs...)
+ srcJarDeps = append(srcJarDeps, depSrcJarDeps...)
}
}
- return data
+ TransformResourcesToJar(ctx, outputFile, srcJarArgs, srcJarDeps)
+}
+
+func (r *robolectricTest) AndroidMkEntries() android.AndroidMkEntries {
+ entries := r.Library.AndroidMkEntries()
+
+ entries.ExtraFooters = []android.AndroidMkExtraFootersFunc{
+ func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
+ if s := r.robolectricProperties.Test_options.Shards; s != nil && *s > 1 {
+ numShards := int(*s)
+ shardSize := (len(r.tests) + numShards - 1) / numShards
+ shards := android.ShardStrings(r.tests, shardSize)
+ for i, shard := range shards {
+ r.writeTestRunner(w, name, "Run"+name+strconv.Itoa(i), shard)
+ }
+
+ // TODO: add rules to dist the outputs of the individual tests, or combine them together?
+ fmt.Fprintln(w, "")
+ fmt.Fprintln(w, ".PHONY:", "Run"+name)
+ fmt.Fprintln(w, "Run"+name, ": \\")
+ for i := range shards {
+ fmt.Fprintln(w, " ", "Run"+name+strconv.Itoa(i), "\\")
+ }
+ fmt.Fprintln(w, "")
+ } else {
+ r.writeTestRunner(w, name, "Run"+name, r.tests)
+ }
+ },
+ }
+
+ return entries
}
func (r *robolectricTest) writeTestRunner(w io.Writer, module, name string, tests []string) {
@@ -144,6 +195,7 @@
fmt.Fprintln(w, "LOCAL_JAVA_LIBRARIES :=", module)
fmt.Fprintln(w, "LOCAL_JAVA_LIBRARIES += ", strings.Join(r.libs, " "))
fmt.Fprintln(w, "LOCAL_TEST_PACKAGE :=", String(r.robolectricProperties.Instrumentation_for))
+ fmt.Fprintln(w, "LOCAL_INSTRUMENT_SRCJARS :=", r.roboSrcJar.String())
fmt.Fprintln(w, "LOCAL_ROBOTEST_FILES :=", strings.Join(tests, " "))
if t := r.robolectricProperties.Test_options.Timeout; t != nil {
fmt.Fprintln(w, "LOCAL_ROBOTEST_TIMEOUT :=", *t)
@@ -164,6 +216,7 @@
module.AddProperties(
&module.Module.properties,
+ &module.Module.deviceProperties,
&module.Module.protoProperties,
&module.robolectricProperties)
diff --git a/java/robolectric_test.go b/java/robolectric_test.go
deleted file mode 100644
index e89c6e7..0000000
--- a/java/robolectric_test.go
+++ /dev/null
@@ -1,88 +0,0 @@
-// 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 (
- "reflect"
- "testing"
-)
-
-func Test_shardTests(t *testing.T) {
- type args struct {
- paths []string
- shards int
- }
- tests := []struct {
- name string
- args args
- want [][]string
- }{
- {
- name: "empty",
- args: args{
- paths: nil,
- shards: 1,
- },
- want: [][]string(nil),
- },
- {
- name: "too many shards",
- args: args{
- paths: []string{"a", "b"},
- shards: 3,
- },
- want: [][]string{{"a"}, {"b"}},
- },
- {
- name: "single shard",
- args: args{
- paths: []string{"a", "b"},
- shards: 1,
- },
- want: [][]string{{"a", "b"}},
- },
- {
- name: "shard per input",
- args: args{
- paths: []string{"a", "b", "c"},
- shards: 3,
- },
- want: [][]string{{"a"}, {"b"}, {"c"}},
- },
- {
- name: "balanced shards",
- args: args{
- paths: []string{"a", "b", "c", "d"},
- shards: 2,
- },
- want: [][]string{{"a", "b"}, {"c", "d"}},
- },
- {
- name: "unbalanced shards",
- args: args{
- paths: []string{"a", "b", "c"},
- shards: 2,
- },
- want: [][]string{{"a", "b"}, {"c"}},
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- if got := shardTests(tt.args.paths, tt.args.shards); !reflect.DeepEqual(got, tt.want) {
- t.Errorf("shardTests() = %v, want %v", got, tt.want)
- }
- })
- }
-}
diff --git a/java/sdk.go b/java/sdk.go
index d1e2ae4..c6a9a73 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -19,7 +19,6 @@
"android/soong/java/config"
"fmt"
"path/filepath"
- "runtime"
"sort"
"strconv"
"strings"
@@ -40,6 +39,8 @@
type sdkContext interface {
// sdkVersion returns the sdk_version property of the current module, or an empty string if it is not set.
sdkVersion() string
+ // systemModules returns the system_modules property of the current module, or an empty string if it is not set.
+ systemModules() string
// minSdkVersion returns the min_sdk_version property of the current module, or sdkVersion() if it is not set.
minSdkVersion() string
// targetSdkVersion returns the target_sdk_version property of the current module, or sdkVersion() if it is not set.
@@ -186,8 +187,18 @@
frameworkResModule: "framework-res",
}
case "none":
+ systemModules := sdkContext.systemModules()
+ if systemModules == "" {
+ ctx.PropertyErrorf("sdk_version",
+ `system_modules is required to be set to a non-empty value when sdk_version is "none", did you mean sdk_version: "core_platform"?`)
+ } else if systemModules == "none" {
+ // Normalize no system modules to an empty string.
+ systemModules = ""
+ }
+
return sdkDep{
noStandardLibs: true,
+ systemModules: systemModules,
}
case "core_platform":
return sdkDep{
@@ -349,15 +360,7 @@
cmd.Text("cat").
Inputs(android.PathsForSource(ctx, in)).
- Text("|")
-
- if runtime.GOOS == "darwin" {
- cmd.Text("md5")
- } else {
- cmd.Text("md5sum")
- }
-
- cmd.Text("| cut -d' ' -f1 >").
+ Text("| md5sum | cut -d' ' -f1 >").
Output(out)
} else {
// Unbundled build
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 56b30b2..476e549 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -100,12 +100,6 @@
// $(location <label>): the path to the droiddoc_option_files with name <label>
Droiddoc_options []string
- // the java library (in classpath) for documentation that provides java srcs and srcjars.
- Srcs_lib *string
-
- // list of packages to document from srcs_lib. Defaults to "android.annotation".
- Srcs_lib_whitelist_pkgs []string
-
// a list of top-level directories containing files to merge qualifier annotations
// (i.e. those intended to be included in the stubs written) from.
Merge_annotations_dirs []string
@@ -203,65 +197,65 @@
})
}
-func (module *SdkLibrary) AndroidMk() android.AndroidMkData {
- data := module.Library.AndroidMk()
- data.Required = append(data.Required, module.xmlFileName())
+func (module *SdkLibrary) AndroidMkEntries() android.AndroidMkEntries {
+ entries := module.Library.AndroidMkEntries()
+ entries.Required = append(entries.Required, module.xmlFileName())
- data.Custom = func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
- android.WriteAndroidMkData(w, data)
-
- module.Library.AndroidMkHostDex(w, name, data)
- if !Bool(module.sdkLibraryProperties.No_dist) {
- // Create a phony module that installs the impl library, for the case when this lib is
- // in PRODUCT_PACKAGES.
- owner := module.ModuleBase.Owner()
- if owner == "" {
- if Bool(module.sdkLibraryProperties.Core_lib) {
- owner = "core"
- } else {
- owner = "android"
+ entries.ExtraFooters = []android.AndroidMkExtraFootersFunc{
+ func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
+ module.Library.AndroidMkHostDex(w, name, entries)
+ if !Bool(module.sdkLibraryProperties.No_dist) {
+ // Create a phony module that installs the impl library, for the case when this lib is
+ // in PRODUCT_PACKAGES.
+ owner := module.ModuleBase.Owner()
+ if owner == "" {
+ if Bool(module.sdkLibraryProperties.Core_lib) {
+ owner = "core"
+ } else {
+ owner = "android"
+ }
+ }
+ // Create dist rules to install the stubs libs to the dist dir
+ if len(module.publicApiStubsPath) == 1 {
+ fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
+ module.publicApiStubsImplPath.Strings()[0]+
+ ":"+path.Join("apistubs", owner, "public",
+ module.BaseModuleName()+".jar")+")")
+ }
+ if len(module.systemApiStubsPath) == 1 {
+ fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
+ module.systemApiStubsImplPath.Strings()[0]+
+ ":"+path.Join("apistubs", owner, "system",
+ module.BaseModuleName()+".jar")+")")
+ }
+ if len(module.testApiStubsPath) == 1 {
+ fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
+ module.testApiStubsImplPath.Strings()[0]+
+ ":"+path.Join("apistubs", owner, "test",
+ module.BaseModuleName()+".jar")+")")
+ }
+ if module.publicApiFilePath != nil {
+ fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
+ module.publicApiFilePath.String()+
+ ":"+path.Join("apistubs", owner, "public", "api",
+ module.BaseModuleName()+".txt")+")")
+ }
+ if module.systemApiFilePath != nil {
+ fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
+ module.systemApiFilePath.String()+
+ ":"+path.Join("apistubs", owner, "system", "api",
+ module.BaseModuleName()+".txt")+")")
+ }
+ if module.testApiFilePath != nil {
+ fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
+ module.testApiFilePath.String()+
+ ":"+path.Join("apistubs", owner, "test", "api",
+ module.BaseModuleName()+".txt")+")")
}
}
- // Create dist rules to install the stubs libs to the dist dir
- if len(module.publicApiStubsPath) == 1 {
- fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
- module.publicApiStubsImplPath.Strings()[0]+
- ":"+path.Join("apistubs", owner, "public",
- module.BaseModuleName()+".jar")+")")
- }
- if len(module.systemApiStubsPath) == 1 {
- fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
- module.systemApiStubsImplPath.Strings()[0]+
- ":"+path.Join("apistubs", owner, "system",
- module.BaseModuleName()+".jar")+")")
- }
- if len(module.testApiStubsPath) == 1 {
- fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
- module.testApiStubsImplPath.Strings()[0]+
- ":"+path.Join("apistubs", owner, "test",
- module.BaseModuleName()+".jar")+")")
- }
- if module.publicApiFilePath != nil {
- fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
- module.publicApiFilePath.String()+
- ":"+path.Join("apistubs", owner, "public", "api",
- module.BaseModuleName()+".txt")+")")
- }
- if module.systemApiFilePath != nil {
- fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
- module.systemApiFilePath.String()+
- ":"+path.Join("apistubs", owner, "system", "api",
- module.BaseModuleName()+".txt")+")")
- }
- if module.testApiFilePath != nil {
- fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
- module.testApiFilePath.String()+
- ":"+path.Join("apistubs", owner, "test", "api",
- module.BaseModuleName()+".txt")+")")
- }
- }
+ },
}
- return data
+ return entries
}
// Module name of the stubs library
@@ -428,7 +422,7 @@
props.Product_specific = proptools.BoolPtr(true)
}
- mctx.CreateModule(android.ModuleFactoryAdaptor(LibraryFactory), &props)
+ mctx.CreateModule(LibraryFactory, &props)
}
// Creates a droiddoc module that creates stubs source files from the given full source
@@ -438,8 +432,6 @@
Name *string
Srcs []string
Installable *bool
- Srcs_lib *string
- Srcs_lib_whitelist_pkgs []string
Sdk_version *string
Libs []string
Arg_files []string
@@ -529,10 +521,8 @@
props.Check_api.Last_released.Removed_api_file = proptools.StringPtr(
module.latestRemovedApiFilegroupName(apiScope))
props.Check_api.Ignore_missing_latest_api = proptools.BoolPtr(true)
- props.Srcs_lib = module.sdkLibraryProperties.Srcs_lib
- props.Srcs_lib_whitelist_pkgs = module.sdkLibraryProperties.Srcs_lib_whitelist_pkgs
- mctx.CreateModule(android.ModuleFactoryAdaptor(DroidstubsFactory), &props)
+ mctx.CreateModule(DroidstubsFactory, &props)
}
// Creates the xml file that publicizes the runtime library
@@ -570,7 +560,7 @@
genruleProps.Name = proptools.StringPtr(module.xmlFileName() + "-gen")
genruleProps.Cmd = proptools.StringPtr("echo '" + xmlContent + "' > $(out)")
genruleProps.Out = []string{module.xmlFileName()}
- mctx.CreateModule(android.ModuleFactoryAdaptor(genrule.GenRuleFactory), &genruleProps)
+ mctx.CreateModule(genrule.GenRuleFactory, &genruleProps)
// creates a prebuilt_etc module to actually place the xml file under
// <partition>/etc/permissions
@@ -592,7 +582,7 @@
} else if module.ProductSpecific() {
etcProps.Product_specific = proptools.BoolPtr(true)
}
- mctx.CreateModule(android.ModuleFactoryAdaptor(android.PrebuiltEtcFactory), &etcProps)
+ mctx.CreateModule(android.PrebuiltEtcFactory, &etcProps)
}
func (module *SdkLibrary) PrebuiltJars(ctx android.BaseModuleContext, sdkVersion string) android.Paths {
@@ -825,7 +815,7 @@
props.Product_specific = proptools.BoolPtr(true)
}
- mctx.CreateModule(android.ModuleFactoryAdaptor(ImportFactory), &props, &module.properties)
+ mctx.CreateModule(ImportFactory, &props, &module.properties)
javaSdkLibraries := javaSdkLibraries(mctx.Config())
javaSdkLibrariesLock.Lock()
diff --git a/java/sdk_test.go b/java/sdk_test.go
index 6be17eb..fd47d81 100644
--- a/java/sdk_test.go
+++ b/java/sdk_test.go
@@ -124,7 +124,7 @@
name: "nostdlib system_modules",
properties: `sdk_version: "none", system_modules: "core-platform-api-stubs-system-modules"`,
system: "core-platform-api-stubs-system-modules",
- bootclasspath: []string{`""`},
+ bootclasspath: []string{"core-platform-api-stubs-system-modules-lib"},
classpath: []string{},
},
{
@@ -206,7 +206,7 @@
moduleType = testcase.moduleType
}
- bp := moduleType + ` {
+ props := `
name: "foo",
srcs: ["a.java"],
target: {
@@ -214,6 +214,10 @@
srcs: ["bar-doc/IFoo.aidl"],
},
},
+ `
+ bp := moduleType + " {" + props + testcase.properties + `
+ }`
+ bpJava8 := moduleType + " {" + props + `java_version: "1.8",
` + testcase.properties + `
}`
@@ -233,39 +237,64 @@
bootclasspath := convertModulesToPaths(testcase.bootclasspath)
classpath := convertModulesToPaths(testcase.classpath)
- bc := strings.Join(bootclasspath, ":")
- if bc != "" {
- bc = "-bootclasspath " + bc
+ bc := ""
+ var bcDeps []string
+ if len(bootclasspath) > 0 {
+ bc = "-bootclasspath " + strings.Join(bootclasspath, ":")
+ if bootclasspath[0] != `""` {
+ bcDeps = bootclasspath
+ }
}
- c := strings.Join(classpath, ":")
- if c != "" {
- c = "-classpath " + c
+ c := ""
+ if len(classpath) > 0 {
+ c = "-classpath " + strings.Join(classpath, ":")
}
+
system := ""
+ var systemDeps []string
if testcase.system == "none" {
system = "--system=none"
+ } else if testcase.system == "bootclasspath" {
+ system = bc
+ systemDeps = bcDeps
} else if testcase.system != "" {
system = "--system=" + filepath.Join(buildDir, ".intermediates", testcase.system, "android_common", "system")
+ // The module-relative parts of these paths are hardcoded in system_modules.go:
+ systemDeps = []string{
+ filepath.Join(buildDir, ".intermediates", testcase.system, "android_common", "system", "lib", "modules"),
+ filepath.Join(buildDir, ".intermediates", testcase.system, "android_common", "system", "lib", "jrt-fs.jar"),
+ filepath.Join(buildDir, ".intermediates", testcase.system, "android_common", "system", "release"),
+ }
}
- checkClasspath := func(t *testing.T, ctx *android.TestContext) {
- javac := ctx.ModuleForTests("foo", variant).Rule("javac")
+ checkClasspath := func(t *testing.T, ctx *android.TestContext, isJava8 bool) {
+ foo := ctx.ModuleForTests("foo", variant)
+ javac := foo.Rule("javac")
+ var deps []string
+
+ aidl := foo.MaybeRule("aidl")
+ if aidl.Rule != nil {
+ deps = append(deps, aidl.Output.String())
+ }
got := javac.Args["bootClasspath"]
- if got != bc {
- t.Errorf("bootclasspath expected %q != got %q", bc, got)
+ expected := ""
+ if isJava8 {
+ expected = bc
+ deps = append(deps, bcDeps...)
+ } else {
+ expected = system
+ deps = append(deps, systemDeps...)
+ }
+ if got != expected {
+ t.Errorf("bootclasspath expected %q != got %q", expected, got)
}
got = javac.Args["classpath"]
if got != c {
t.Errorf("classpath expected %q != got %q", c, got)
}
-
- var deps []string
- if len(bootclasspath) > 0 && bootclasspath[0] != `""` {
- deps = append(deps, bootclasspath...)
- }
deps = append(deps, classpath...)
if !reflect.DeepEqual(javac.Implicits.Strings(), deps) {
@@ -273,8 +302,31 @@
}
}
+ // Test with legacy javac -source 1.8 -target 1.8
t.Run("Java language level 8", func(t *testing.T) {
- // Test default javac -source 1.8 -target 1.8
+ config := testConfig(nil)
+ if testcase.unbundled {
+ config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true)
+ }
+ if testcase.pdk {
+ config.TestProductVariables.Pdk = proptools.BoolPtr(true)
+ }
+ ctx := testContext(bpJava8, nil)
+ run(t, ctx, config)
+
+ checkClasspath(t, ctx, true /* isJava8 */)
+
+ if testcase.host != android.Host {
+ aidl := ctx.ModuleForTests("foo", variant).Rule("aidl")
+
+ if g, w := aidl.RuleParams.Command, testcase.aidl+" -I."; !strings.Contains(g, w) {
+ t.Errorf("want aidl command to contain %q, got %q", w, g)
+ }
+ }
+ })
+
+ // Test with default javac -source 9 -target 9
+ t.Run("Java language level 9", func(t *testing.T) {
config := testConfig(nil)
if testcase.unbundled {
config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true)
@@ -285,46 +337,19 @@
ctx := testContext(bp, nil)
run(t, ctx, config)
- checkClasspath(t, ctx)
+ checkClasspath(t, ctx, false /* isJava8 */)
if testcase.host != android.Host {
aidl := ctx.ModuleForTests("foo", variant).Rule("aidl")
- aidlFlags := aidl.Args["aidlFlags"]
- // Trim trailing "-I." to avoid having to specify it in every test
- aidlFlags = strings.TrimSpace(strings.TrimSuffix(aidlFlags, "-I."))
-
- if g, w := aidlFlags, testcase.aidl; g != w {
- t.Errorf("want aidl flags %q, got %q", w, g)
+ if g, w := aidl.RuleParams.Command, testcase.aidl+" -I."; !strings.Contains(g, w) {
+ t.Errorf("want aidl command to contain %q, got %q", w, g)
}
}
})
- // Test again with javac -source 9 -target 9
- t.Run("Java language level 9", func(t *testing.T) {
- config := testConfig(map[string]string{"EXPERIMENTAL_JAVA_LANGUAGE_LEVEL_9": "true"})
- if testcase.unbundled {
- config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true)
- }
- if testcase.pdk {
- config.TestProductVariables.Pdk = proptools.BoolPtr(true)
- }
- ctx := testContext(bp, nil)
- run(t, ctx, config)
-
- javac := ctx.ModuleForTests("foo", variant).Rule("javac")
- got := javac.Args["bootClasspath"]
- expected := system
- if testcase.system == "bootclasspath" {
- expected = bc
- }
- if got != expected {
- t.Errorf("bootclasspath expected %q != got %q", expected, got)
- }
- })
-
- // Test again with PLATFORM_VERSION_CODENAME=REL
- t.Run("REL", func(t *testing.T) {
+ // Test again with PLATFORM_VERSION_CODENAME=REL, javac -source 8 -target 8
+ t.Run("REL + Java language level 8", func(t *testing.T) {
config := testConfig(nil)
config.TestProductVariables.Platform_sdk_codename = proptools.StringPtr("REL")
config.TestProductVariables.Platform_sdk_final = proptools.BoolPtr(true)
@@ -335,11 +360,13 @@
if testcase.pdk {
config.TestProductVariables.Pdk = proptools.BoolPtr(true)
}
- ctx := testContext(bp, nil)
+ ctx := testContext(bpJava8, nil)
run(t, ctx, config)
- checkClasspath(t, ctx)
+ checkClasspath(t, ctx, true /* isJava8 */)
})
+
+ // TODO(b/142896162): Add a with PLATFORM_VERSION_CODENAME=REL, javac -source 9 -target 9, when that all works.
})
}
diff --git a/java/system_modules.go b/java/system_modules.go
index c616249..b56a401 100644
--- a/java/system_modules.go
+++ b/java/system_modules.go
@@ -36,13 +36,15 @@
var (
jarsTosystemModules = pctx.AndroidStaticRule("jarsTosystemModules", blueprint.RuleParams{
Command: `rm -rf ${outDir} ${workDir} && mkdir -p ${workDir}/jmod && ` +
- `${moduleInfoJavaPath} ${moduleName} $in > ${workDir}/module-info.java && ` +
+ `${moduleInfoJavaPath} java.base $in > ${workDir}/module-info.java && ` +
`${config.JavacCmd} --system=none --patch-module=java.base=${classpath} ${workDir}/module-info.java && ` +
`${config.SoongZipCmd} -jar -o ${workDir}/classes.jar -C ${workDir} -f ${workDir}/module-info.class && ` +
`${config.MergeZipsCmd} -j ${workDir}/module.jar ${workDir}/classes.jar $in && ` +
- `${config.JmodCmd} create --module-version 9 --target-platform android ` +
- ` --class-path ${workDir}/module.jar ${workDir}/jmod/${moduleName}.jmod && ` +
- `${config.JlinkCmd} --module-path ${workDir}/jmod --add-modules ${moduleName} --output ${outDir} ` +
+ // Note: The version of the java.base module created must match the version
+ // of the jlink tool which consumes it.
+ `${config.JmodCmd} create --module-version ${config.JlinkVersion} --target-platform android ` +
+ ` --class-path ${workDir}/module.jar ${workDir}/jmod/java.base.jmod && ` +
+ `${config.JlinkCmd} --module-path ${workDir}/jmod --add-modules java.base --output ${outDir} ` +
// Note: The system-modules jlink plugin is disabled because (a) it is not
// useful on Android, and (b) it causes errors with later versions of jlink
// when the jdk.internal.module is absent from java.base (as it is here).
@@ -58,10 +60,10 @@
"${config.JrtFsJar}",
},
},
- "moduleName", "classpath", "outDir", "workDir")
+ "classpath", "outDir", "workDir")
)
-func TransformJarsToSystemModules(ctx android.ModuleContext, moduleName string, jars android.Paths) (android.Path, android.Paths) {
+func TransformJarsToSystemModules(ctx android.ModuleContext, jars android.Paths) (android.Path, android.Paths) {
outDir := android.PathForModuleOut(ctx, "system")
workDir := android.PathForModuleOut(ctx, "modules")
outputFile := android.PathForModuleOut(ctx, "system/lib/modules")
@@ -77,10 +79,9 @@
Outputs: outputs,
Inputs: jars,
Args: map[string]string{
- "moduleName": moduleName,
- "classpath": strings.Join(jars.Strings(), ":"),
- "workDir": workDir.String(),
- "outDir": outDir.String(),
+ "classpath": strings.Join(jars.Strings(), ":"),
+ "workDir": workDir.String(),
+ "outDir": outDir.String(),
},
})
@@ -101,6 +102,9 @@
properties SystemModulesProperties
+ // The aggregated header jars from all jars specified in the libs property.
+ // Used when system module is added as a dependency to bootclasspath.
+ headerJars android.Paths
outputDir android.Path
outputDeps android.Paths
}
@@ -118,7 +122,9 @@
jars = append(jars, dep.HeaderJars()...)
})
- system.outputDir, system.outputDeps = TransformJarsToSystemModules(ctx, "java.base", jars)
+ system.headerJars = jars
+
+ system.outputDir, system.outputDeps = TransformJarsToSystemModules(ctx, jars)
}
func (system *SystemModules) DepsMutator(ctx android.BottomUpMutatorContext) {
diff --git a/java/testing.go b/java/testing.go
index 5d116a7..acbefb9 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -38,6 +38,7 @@
extraModules := []string{
"core-lambda-stubs",
"ext",
+ "updatable_media_stubs",
"android_stubs_current",
"android_system_stubs_current",
"android_test_stubs_current",
@@ -102,7 +103,6 @@
`
systemModules := []string{
- "core-system-modules",
"core-current-stubs-system-modules",
"core-platform-api-stubs-system-modules",
"android_stubs_current_system_modules",
@@ -113,7 +113,13 @@
for _, extra := range systemModules {
bp += fmt.Sprintf(`
java_system_modules {
- name: "%s",
+ name: "%[1]s",
+ libs: ["%[1]s-lib"],
+ }
+ java_library {
+ name: "%[1]s-lib",
+ sdk_version: "none",
+ system_modules: "none",
}
`, extra)
}
diff --git a/java/tradefed.go b/java/tradefed.go
new file mode 100644
index 0000000..ebbdec1
--- /dev/null
+++ b/java/tradefed.go
@@ -0,0 +1,37 @@
+// 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"
+)
+
+func init() {
+ android.RegisterModuleType("tradefed_java_library_host", tradefedJavaLibraryFactory)
+}
+
+// tradefed_java_library_factory wraps java_library and installs an additional
+// copy of the output jar to $HOST_OUT/tradefed.
+func tradefedJavaLibraryFactory() android.Module {
+ module := LibraryHostFactory().(*Library)
+ module.InstallMixin = tradefedJavaLibraryInstall
+ return module
+}
+
+func tradefedJavaLibraryInstall(ctx android.ModuleContext, path android.Path) android.Paths {
+ installedPath := ctx.InstallFile(android.PathForModuleInstall(ctx, "tradefed"),
+ ctx.ModuleName()+".jar", path)
+ return android.Paths{installedPath}
+}
diff --git a/makedeps/Android.bp b/makedeps/Android.bp
new file mode 100644
index 0000000..b77b08f
--- /dev/null
+++ b/makedeps/Android.bp
@@ -0,0 +1,21 @@
+// 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.
+
+bootstrap_go_package {
+ name: "soong-makedeps",
+ pkgPath: "android/soong/makedeps",
+ deps: ["androidmk-parser"],
+ srcs: ["deps.go"],
+ testSrcs: ["deps_test.go"],
+}
diff --git a/cmd/dep_fixer/deps.go b/makedeps/deps.go
similarity index 91%
rename from cmd/dep_fixer/deps.go
rename to makedeps/deps.go
index 64c97f5..db49532 100644
--- a/cmd/dep_fixer/deps.go
+++ b/makedeps/deps.go
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package main
+package makedeps
import (
"bytes"
@@ -57,10 +57,12 @@
return nil, fmt.Errorf("%sunsupported variable expansion: %v", pos(node), x.Target.Dump())
}
outputs := x.Target.Words()
- if len(outputs) == 0 {
- return nil, fmt.Errorf("%smissing output: %v", pos(node), x)
+ if len(outputs) > 0 {
+ ret.Output = outputs[0].Value(nil)
+ } else {
+ // TODO(b/141372861): put this back
+ //return nil, fmt.Errorf("%smissing output: %v", pos(node), x)
}
- ret.Output = outputs[0].Value(nil)
if !x.Prerequisites.Const() {
return nil, fmt.Errorf("%sunsupported variable expansion: %v", pos(node), x.Prerequisites.Dump())
diff --git a/cmd/dep_fixer/deps_test.go b/makedeps/deps_test.go
similarity index 96%
rename from cmd/dep_fixer/deps_test.go
rename to makedeps/deps_test.go
index 0a779b7..ac2f699 100644
--- a/cmd/dep_fixer/deps_test.go
+++ b/makedeps/deps_test.go
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package main
+package makedeps
import (
"bytes"
@@ -147,6 +147,20 @@
},
},
},
+ {
+ // TODO(b/141372861): remove this
+ // AIDL produces a dep file with no output file for a parcelable (b/
+ name: "AIDL parcelable",
+ input: ` : \
+ frameworks/base/tests/net/integration/src/com/android/server/net/integrationtests/HttpResponse.aidl
+`,
+ output: Deps{
+ Output: "",
+ Inputs: []string{
+ "frameworks/base/tests/net/integration/src/com/android/server/net/integrationtests/HttpResponse.aidl",
+ },
+ },
+ },
}
for _, tc := range testCases {
diff --git a/python/androidmk.go b/python/androidmk.go
index 1e51e7b..aae7ced 100644
--- a/python/androidmk.go
+++ b/python/androidmk.go
@@ -89,12 +89,11 @@
ret.Required = append(ret.Required, "libc++")
ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
- path := installer.path.RelPathString()
- dir, file := filepath.Split(path)
+ path, file := filepath.Split(installer.path.ToMakePath().String())
stem := strings.TrimSuffix(file, filepath.Ext(file))
fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+filepath.Ext(file))
- fmt.Fprintln(w, "LOCAL_MODULE_PATH := $(OUT_DIR)/"+filepath.Clean(dir))
+ fmt.Fprintln(w, "LOCAL_MODULE_PATH := "+path)
fmt.Fprintln(w, "LOCAL_MODULE_STEM := "+stem)
fmt.Fprintln(w, "LOCAL_SHARED_LIBRARIES := "+strings.Join(installer.androidMkSharedLibs, " "))
})
diff --git a/python/binary.go b/python/binary.go
index 140f07a..695fa12 100644
--- a/python/binary.go
+++ b/python/binary.go
@@ -47,6 +47,11 @@
// false it will act much like the normal `python` executable, but with the sources and
// libraries automatically included in the PYTHONPATH.
Autorun *bool `android:"arch_variant"`
+
+ // Flag to indicate whether or not to create test config automatically. If AndroidTest.xml
+ // doesn't exist next to the Android.bp, this attribute doesn't need to be set to true
+ // explicitly.
+ Auto_gen_config *bool
}
type binaryDecorator struct {
diff --git a/python/installer.go b/python/installer.go
index 62f36f4..396f036 100644
--- a/python/installer.go
+++ b/python/installer.go
@@ -33,7 +33,7 @@
dir64 string
relative string
- path android.OutputPath
+ path android.InstallPath
androidMkSharedLibs []string
}
@@ -47,12 +47,12 @@
var _ installer = (*pythonInstaller)(nil)
-func (installer *pythonInstaller) installDir(ctx android.ModuleContext) android.OutputPath {
+func (installer *pythonInstaller) installDir(ctx android.ModuleContext) android.InstallPath {
dir := installer.dir
if ctx.Arch().ArchType.Multilib == "lib64" && installer.dir64 != "" {
dir = installer.dir64
}
- if !ctx.Host() && !ctx.Arch().Native {
+ if !ctx.Host() && ctx.Config().HasMultilibConflict(ctx.Arch().ArchType) {
dir = filepath.Join(dir, ctx.Arch().ArchType.String())
}
return android.PathForModuleInstall(ctx, dir, installer.relative)
diff --git a/python/python.go b/python/python.go
index ad08909..1b606cb 100644
--- a/python/python.go
+++ b/python/python.go
@@ -306,22 +306,17 @@
if p.bootstrapper.autorun() {
launcherModule = "py2-launcher-autorun"
}
- ctx.AddFarVariationDependencies([]blueprint.Variation{
- {Mutator: "arch", Variation: ctx.Target().String()},
- }, launcherTag, launcherModule)
+ ctx.AddFarVariationDependencies(ctx.Target().Variations(), launcherTag, launcherModule)
// Add py2-launcher shared lib dependencies. Ideally, these should be
// derived from the `shared_libs` property of "py2-launcher". However, we
// cannot read the property at this stage and it will be too late to add
// dependencies later.
- ctx.AddFarVariationDependencies([]blueprint.Variation{
- {Mutator: "arch", Variation: ctx.Target().String()},
- }, launcherSharedLibTag, "libsqlite")
+ ctx.AddFarVariationDependencies(ctx.Target().Variations(), launcherSharedLibTag, "libsqlite")
if ctx.Target().Os.Bionic() {
- ctx.AddFarVariationDependencies([]blueprint.Variation{
- {Mutator: "arch", Variation: ctx.Target().String()},
- }, launcherSharedLibTag, "libc", "libdl", "libm")
+ ctx.AddFarVariationDependencies(ctx.Target().Variations(), launcherSharedLibTag,
+ "libc", "libdl", "libm")
}
}
diff --git a/python/test.go b/python/test.go
index 55b0ab5..f684fd5 100644
--- a/python/test.go
+++ b/python/test.go
@@ -50,7 +50,8 @@
func (test *testDecorator) install(ctx android.ModuleContext, file android.Path) {
test.testConfig = tradefed.AutoGenPythonBinaryHostTestConfig(ctx, test.testProperties.Test_config,
- test.testProperties.Test_config_template, test.binaryDecorator.binaryProperties.Test_suites)
+ test.testProperties.Test_config_template, test.binaryDecorator.binaryProperties.Test_suites,
+ test.binaryDecorator.binaryProperties.Auto_gen_config)
test.binaryDecorator.pythonInstaller.dir = "nativetest"
test.binaryDecorator.pythonInstaller.dir64 = "nativetest64"
diff --git a/rust/androidmk.go b/rust/androidmk.go
new file mode 100644
index 0000000..a6208db
--- /dev/null
+++ b/rust/androidmk.go
@@ -0,0 +1,125 @@
+// Copyright 2019 The Android Open Source Project
+//
+// 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 rust
+
+import (
+ "fmt"
+ "io"
+ "path/filepath"
+ "strings"
+
+ "android/soong/android"
+)
+
+type AndroidMkContext interface {
+ Name() string
+ Target() android.Target
+ subAndroidMk(*android.AndroidMkData, interface{})
+}
+
+type subAndroidMkProvider interface {
+ AndroidMk(AndroidMkContext, *android.AndroidMkData)
+}
+
+func (mod *Module) subAndroidMk(data *android.AndroidMkData, obj interface{}) {
+ if mod.subAndroidMkOnce == nil {
+ mod.subAndroidMkOnce = make(map[subAndroidMkProvider]bool)
+ }
+ if androidmk, ok := obj.(subAndroidMkProvider); ok {
+ if !mod.subAndroidMkOnce[androidmk] {
+ mod.subAndroidMkOnce[androidmk] = true
+ androidmk.AndroidMk(mod, data)
+ }
+ }
+}
+
+func (mod *Module) AndroidMk() android.AndroidMkData {
+ ret := android.AndroidMkData{
+ OutputFile: mod.outputFile,
+ Include: "$(BUILD_SYSTEM)/soong_rust_prebuilt.mk",
+ Extra: []android.AndroidMkExtraFunc{
+ func(w io.Writer, outputFile android.Path) {
+ if len(mod.Properties.AndroidMkRlibs) > 0 {
+ fmt.Fprintln(w, "LOCAL_RLIB_LIBRARIES := "+strings.Join(mod.Properties.AndroidMkRlibs, " "))
+ }
+ if len(mod.Properties.AndroidMkDylibs) > 0 {
+ fmt.Fprintln(w, "LOCAL_DYLIB_LIBRARIES := "+strings.Join(mod.Properties.AndroidMkDylibs, " "))
+ }
+ if len(mod.Properties.AndroidMkProcMacroLibs) > 0 {
+ fmt.Fprintln(w, "LOCAL_PROC_MACRO_LIBRARIES := "+strings.Join(mod.Properties.AndroidMkProcMacroLibs, " "))
+ }
+ if len(mod.Properties.AndroidMkSharedLibs) > 0 {
+ fmt.Fprintln(w, "LOCAL_SHARED_LIBRARIES := "+strings.Join(mod.Properties.AndroidMkSharedLibs, " "))
+ }
+ if len(mod.Properties.AndroidMkStaticLibs) > 0 {
+ fmt.Fprintln(w, "LOCAL_STATIC_LIBRARIES := "+strings.Join(mod.Properties.AndroidMkStaticLibs, " "))
+ }
+ },
+ },
+ }
+
+ mod.subAndroidMk(&ret, mod.compiler)
+
+ return ret
+}
+
+func (binary *binaryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+ ctx.subAndroidMk(ret, binary.baseCompiler)
+
+ ret.Class = "EXECUTABLES"
+ ret.DistFile = binary.distFile
+ ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
+ fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", binary.unstrippedOutputFile.String())
+ })
+}
+
+func (library *libraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+ ctx.subAndroidMk(ret, library.baseCompiler)
+
+ if library.rlib() {
+ ret.Class = "RLIB_LIBRARIES"
+ } else if library.dylib() {
+ ret.Class = "DYLIB_LIBRARIES"
+ }
+ ret.DistFile = library.distFile
+ ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
+ if !library.rlib() {
+ fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", library.unstrippedOutputFile.String())
+ }
+ })
+}
+
+func (procMacro *procMacroDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+ ctx.subAndroidMk(ret, procMacro.baseCompiler)
+
+ ret.Class = "PROC_MACRO_LIBRARIES"
+ ret.DistFile = procMacro.distFile
+
+}
+
+func (compiler *baseCompiler) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+ // Soong installation is only supported for host modules. Have Make
+ // installation trigger Soong installation.
+ if ctx.Target().Os.Class == android.Host {
+ ret.OutputFile = android.OptionalPathForPath(compiler.path)
+ }
+ ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
+ path, file := filepath.Split(compiler.path.ToMakePath().String())
+ stem, suffix, _ := android.SplitFileExt(file)
+ fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+suffix)
+ fmt.Fprintln(w, "LOCAL_MODULE_PATH := "+path)
+ fmt.Fprintln(w, "LOCAL_MODULE_STEM := "+stem)
+ })
+}
diff --git a/rust/binary.go b/rust/binary.go
new file mode 100644
index 0000000..52f840e
--- /dev/null
+++ b/rust/binary.go
@@ -0,0 +1,125 @@
+// Copyright 2019 The Android Open Source Project
+//
+// 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 rust
+
+import (
+ "android/soong/android"
+ "android/soong/rust/config"
+)
+
+func init() {
+ android.RegisterModuleType("rust_binary", RustBinaryFactory)
+ android.RegisterModuleType("rust_binary_host", RustBinaryHostFactory)
+}
+
+type BinaryCompilerProperties struct {
+ // path to the main source file that contains the program entry point (e.g. src/main.rs)
+ Srcs []string `android:"path,arch_variant"`
+
+ // passes -C prefer-dynamic to rustc, which tells it to dynamically link the stdlib (assuming it has no dylib dependencies already)
+ Prefer_dynamic *bool
+}
+
+type binaryDecorator struct {
+ *baseCompiler
+
+ Properties BinaryCompilerProperties
+ distFile android.OptionalPath
+ unstrippedOutputFile android.Path
+}
+
+var _ compiler = (*binaryDecorator)(nil)
+
+// rust_binary produces a binary that is runnable on a device.
+func RustBinaryFactory() android.Module {
+ module, _ := NewRustBinary(android.HostAndDeviceSupported)
+ return module.Init()
+}
+
+func RustBinaryHostFactory() android.Module {
+ module, _ := NewRustBinary(android.HostSupported)
+ return module.Init()
+}
+
+func NewRustBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecorator) {
+ module := newModule(hod, android.MultilibFirst)
+
+ binary := &binaryDecorator{
+ baseCompiler: NewBaseCompiler("bin", ""),
+ }
+
+ module.compiler = binary
+
+ return module, binary
+}
+
+func (binary *binaryDecorator) preferDynamic() bool {
+ return Bool(binary.Properties.Prefer_dynamic)
+}
+
+func (binary *binaryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags {
+ flags = binary.baseCompiler.compilerFlags(ctx, flags)
+
+ if ctx.toolchain().Bionic() {
+ // no-undefined-version breaks dylib compilation since __rust_*alloc* functions aren't defined, but we can apply this to binaries.
+ flags.LinkFlags = append(flags.LinkFlags,
+ "-Wl,--gc-sections",
+ "-Wl,-z,nocopyreloc",
+ "-Wl,--no-undefined-version")
+ }
+
+ if binary.preferDynamic() {
+ flags.RustFlags = append(flags.RustFlags, "-C prefer-dynamic")
+ }
+ return flags
+}
+
+func (binary *binaryDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps {
+ deps = binary.baseCompiler.compilerDeps(ctx, deps)
+
+ if binary.preferDynamic() || len(deps.Dylibs) > 0 {
+ for _, stdlib := range config.Stdlibs {
+ deps.Dylibs = append(deps.Dylibs, stdlib+"_"+ctx.toolchain().RustTriple())
+ }
+ }
+
+ if ctx.toolchain().Bionic() {
+ deps = binary.baseCompiler.bionicDeps(ctx, deps)
+ deps.CrtBegin = "crtbegin_dynamic"
+ deps.CrtEnd = "crtend_android"
+ }
+
+ return deps
+}
+
+func (binary *binaryDecorator) compilerProps() []interface{} {
+ return append(binary.baseCompiler.compilerProps(),
+ &binary.Properties)
+}
+
+func (binary *binaryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path {
+ fileName := binary.getStem(ctx) + ctx.toolchain().ExecutableSuffix()
+
+ srcPath := srcPathFromModuleSrcs(ctx, binary.Properties.Srcs)
+
+ outputFile := android.PathForModuleOut(ctx, fileName)
+ binary.unstrippedOutputFile = outputFile
+
+ flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
+
+ TransformSrcToBinary(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
+
+ return outputFile
+}
diff --git a/rust/binary_test.go b/rust/binary_test.go
new file mode 100644
index 0000000..cd41fcf
--- /dev/null
+++ b/rust/binary_test.go
@@ -0,0 +1,46 @@
+// Copyright 2019 The Android Open Source Project
+//
+// 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 rust
+
+import (
+ "strings"
+ "testing"
+)
+
+// Test that the prefer_dynamic property is handled correctly.
+func TestPreferDynamicBinary(t *testing.T) {
+ ctx := testRust(t, `
+ rust_binary_host {
+ name: "fizz-buzz-dynamic",
+ srcs: ["foo.rs"],
+ prefer_dynamic: true,
+ }
+
+ rust_binary_host {
+ name: "fizz-buzz",
+ srcs: ["foo.rs"],
+ }`)
+
+ fizzBuzz := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Output("fizz-buzz")
+ fizzBuzzDynamic := ctx.ModuleForTests("fizz-buzz-dynamic", "linux_glibc_x86_64").Output("fizz-buzz-dynamic")
+
+ if !strings.Contains(fizzBuzzDynamic.Args["rustcFlags"], "prefer-dynamic") {
+ t.Errorf("missing prefer-dynamic flag, rustcFlags: %#v", fizzBuzzDynamic.Args["rustcFlags"])
+ }
+
+ if strings.Contains(fizzBuzz.Args["rustcFlags"], "prefer-dynamic") {
+ t.Errorf("unexpected prefer-dynamic flag, rustcFlags: %#v", fizzBuzz.Args["rustcFlags"])
+ }
+}
diff --git a/rust/builder.go b/rust/builder.go
new file mode 100644
index 0000000..104313f
--- /dev/null
+++ b/rust/builder.go
@@ -0,0 +1,132 @@
+// Copyright 2019 The Android Open Source Project
+//
+// 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 rust
+
+import (
+ "strings"
+
+ "github.com/google/blueprint"
+
+ "android/soong/android"
+)
+
+var (
+ _ = pctx.SourcePathVariable("rustcCmd", "${config.RustBin}/rustc")
+ rustc = pctx.AndroidStaticRule("rustc",
+ blueprint.RuleParams{
+ Command: "$rustcCmd " +
+ "-C linker=${config.RustLinker} " +
+ "-C link-args=\"${crtBegin} ${config.RustLinkerArgs} ${linkFlags} ${crtEnd}\" " +
+ "--emit link -o $out --emit dep-info=$out.d $in ${libFlags} $rustcFlags",
+ CommandDeps: []string{"$rustcCmd"},
+ Depfile: "$out.d",
+ Deps: blueprint.DepsGCC, // Rustc deps-info writes out make compatible dep files: https://github.com/rust-lang/rust/issues/7633
+ },
+ "rustcFlags", "linkFlags", "libFlags", "crtBegin", "crtEnd")
+)
+
+func init() {
+
+}
+
+func TransformSrcToBinary(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags, outputFile android.WritablePath, includeDirs []string) {
+ transformSrctoCrate(ctx, mainSrc, deps.RLibs, deps.DyLibs, deps.ProcMacros, deps.StaticLibs, deps.SharedLibs, deps.CrtBegin, deps.CrtEnd, flags, outputFile, "bin", includeDirs)
+}
+
+func TransformSrctoRlib(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags, outputFile android.WritablePath, includeDirs []string) {
+ transformSrctoCrate(ctx, mainSrc, deps.RLibs, deps.DyLibs, deps.ProcMacros, deps.StaticLibs, deps.SharedLibs, deps.CrtBegin, deps.CrtEnd, flags, outputFile, "rlib", includeDirs)
+}
+
+func TransformSrctoDylib(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags, outputFile android.WritablePath, includeDirs []string) {
+ transformSrctoCrate(ctx, mainSrc, deps.RLibs, deps.DyLibs, deps.ProcMacros, deps.StaticLibs, deps.SharedLibs, deps.CrtBegin, deps.CrtEnd, flags, outputFile, "dylib", includeDirs)
+}
+
+func TransformSrctoProcMacro(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags, outputFile android.WritablePath, includeDirs []string) {
+ transformSrctoCrate(ctx, mainSrc, deps.RLibs, deps.DyLibs, deps.ProcMacros, deps.StaticLibs, deps.SharedLibs, deps.CrtBegin, deps.CrtEnd, flags, outputFile, "proc-macro", includeDirs)
+}
+
+func rustLibsToPaths(libs RustLibraries) android.Paths {
+ var paths android.Paths
+ for _, lib := range libs {
+ paths = append(paths, lib.Path)
+ }
+ return paths
+}
+
+func transformSrctoCrate(ctx android.ModuleContext, main android.Path,
+ rlibs, dylibs, proc_macros RustLibraries, static_libs, shared_libs android.Paths, crtBegin, crtEnd android.OptionalPath, flags Flags, outputFile android.WritablePath, crate_type string, includeDirs []string) {
+
+ var inputs android.Paths
+ var deps android.Paths
+ var libFlags, rustcFlags, linkFlags []string
+ crate_name := ctx.(ModuleContext).CrateName()
+ targetTriple := ctx.(ModuleContext).toolchain().RustTriple()
+
+ inputs = append(inputs, main)
+
+ // Collect rustc flags
+ rustcFlags = append(rustcFlags, flags.GlobalRustFlags...)
+ rustcFlags = append(rustcFlags, flags.RustFlags...)
+ rustcFlags = append(rustcFlags, "--crate-type="+crate_type)
+ rustcFlags = append(rustcFlags, "--crate-name="+crate_name)
+ if targetTriple != "" {
+ rustcFlags = append(rustcFlags, "--target="+targetTriple)
+ linkFlags = append(linkFlags, "-target "+targetTriple)
+ }
+ // Collect linker flags
+ linkFlags = append(linkFlags, flags.GlobalLinkFlags...)
+ linkFlags = append(linkFlags, flags.LinkFlags...)
+
+ // Collect library/crate flags
+ for _, lib := range rlibs {
+ libFlags = append(libFlags, "--extern "+lib.CrateName+"="+lib.Path.String())
+ }
+ for _, lib := range dylibs {
+ libFlags = append(libFlags, "--extern "+lib.CrateName+"="+lib.Path.String())
+ }
+ for _, proc_macro := range proc_macros {
+ libFlags = append(libFlags, "--extern "+proc_macro.CrateName+"="+proc_macro.Path.String())
+ }
+
+ for _, path := range includeDirs {
+ libFlags = append(libFlags, "-L "+path)
+ }
+
+ // Collect dependencies
+ deps = append(deps, rustLibsToPaths(rlibs)...)
+ deps = append(deps, rustLibsToPaths(dylibs)...)
+ deps = append(deps, rustLibsToPaths(proc_macros)...)
+ deps = append(deps, static_libs...)
+ deps = append(deps, shared_libs...)
+ if crtBegin.Valid() {
+ deps = append(deps, crtBegin.Path(), crtEnd.Path())
+ }
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: rustc,
+ Description: "rustc " + main.Rel(),
+ Output: outputFile,
+ Inputs: inputs,
+ Implicits: deps,
+ Args: map[string]string{
+ "rustcFlags": strings.Join(rustcFlags, " "),
+ "linkFlags": strings.Join(linkFlags, " "),
+ "libFlags": strings.Join(libFlags, " "),
+ "crtBegin": crtBegin.String(),
+ "crtEnd": crtEnd.String(),
+ },
+ })
+
+}
diff --git a/rust/compiler.go b/rust/compiler.go
new file mode 100644
index 0000000..3f02835
--- /dev/null
+++ b/rust/compiler.go
@@ -0,0 +1,220 @@
+// Copyright 2019 The Android Open Source Project
+//
+// 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 rust
+
+import (
+ "fmt"
+ "path/filepath"
+
+ "android/soong/android"
+ "android/soong/rust/config"
+ "github.com/google/blueprint/proptools"
+)
+
+func getEdition(compiler *baseCompiler) string {
+ return proptools.StringDefault(compiler.Properties.Edition, config.DefaultEdition)
+}
+
+func getDenyWarnings(compiler *baseCompiler) bool {
+ return BoolDefault(compiler.Properties.Deny_warnings, config.DefaultDenyWarnings)
+}
+
+func NewBaseCompiler(dir, dir64 string) *baseCompiler {
+ return &baseCompiler{
+ Properties: BaseCompilerProperties{},
+ dir: dir,
+ dir64: dir64,
+ }
+}
+
+type BaseCompilerProperties struct {
+ // whether to pass "-D warnings" to rustc. Defaults to true.
+ Deny_warnings *bool
+
+ // flags to pass to rustc
+ Flags []string `android:"path,arch_variant"`
+
+ // flags to pass to the linker
+ Ld_flags []string `android:"path,arch_variant"`
+
+ // list of rust rlib crate dependencies
+ Rlibs []string `android:"arch_variant"`
+
+ // list of rust dylib crate dependencies
+ Dylibs []string `android:"arch_variant"`
+
+ // list of rust proc_macro crate dependencies
+ Proc_macros []string `android:"arch_variant"`
+
+ // list of C shared library dependencies
+ Shared_libs []string `android:"arch_variant"`
+
+ // list of C static library dependencies
+ Static_libs []string `android:"arch_variant"`
+
+ // crate name (defaults to module name); if library, this must be the expected extern crate name
+ Crate_name string `android:"arch_variant"`
+
+ // list of features to enable for this crate
+ Features []string `android:"arch_variant"`
+
+ // specific rust edition that should be used if the default version is not desired
+ Edition *string `android:"arch_variant"`
+
+ // sets name of the output
+ Stem *string `android:"arch_variant"`
+
+ // append to name of output
+ Suffix *string `android:"arch_variant"`
+
+ // install to a subdirectory of the default install path for the module
+ Relative_install_path *string `android:"arch_variant"`
+}
+
+type baseCompiler struct {
+ Properties BaseCompilerProperties
+ pathDeps android.Paths
+ rustFlagsDeps android.Paths
+ linkFlagsDeps android.Paths
+ flags string
+ linkFlags string
+ depFlags []string
+ linkDirs []string
+ edition string
+ src android.Path //rustc takes a single src file
+
+ // Install related
+ dir string
+ dir64 string
+ subDir string
+ relative string
+ path android.InstallPath
+}
+
+var _ compiler = (*baseCompiler)(nil)
+
+func (compiler *baseCompiler) compilerProps() []interface{} {
+ return []interface{}{&compiler.Properties}
+}
+
+func (compiler *baseCompiler) featuresToFlags(features []string) []string {
+ flags := []string{}
+ for _, feature := range features {
+ flags = append(flags, "--cfg 'feature=\""+feature+"\"'")
+ }
+ return flags
+}
+
+func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags) Flags {
+
+ if getDenyWarnings(compiler) {
+ flags.RustFlags = append(flags.RustFlags, "-D warnings")
+ }
+ flags.RustFlags = append(flags.RustFlags, compiler.Properties.Flags...)
+ flags.RustFlags = append(flags.RustFlags, compiler.featuresToFlags(compiler.Properties.Features)...)
+ flags.RustFlags = append(flags.RustFlags, "--edition="+getEdition(compiler))
+ flags.LinkFlags = append(flags.LinkFlags, compiler.Properties.Ld_flags...)
+ flags.GlobalRustFlags = append(flags.GlobalRustFlags, config.GlobalRustFlags...)
+ flags.GlobalRustFlags = append(flags.GlobalRustFlags, ctx.toolchain().ToolchainRustFlags())
+ flags.GlobalLinkFlags = append(flags.GlobalLinkFlags, ctx.toolchain().ToolchainLinkFlags())
+
+ if ctx.Host() && !ctx.Windows() {
+ rpath_prefix := `\$$ORIGIN/`
+ if ctx.Darwin() {
+ rpath_prefix = "@loader_path/"
+ }
+
+ var rpath string
+ if ctx.toolchain().Is64Bit() {
+ rpath = "lib64"
+ } else {
+ rpath = "lib"
+ }
+ flags.LinkFlags = append(flags.LinkFlags, "-Wl,-rpath,"+rpath_prefix+rpath)
+ flags.LinkFlags = append(flags.LinkFlags, "-Wl,-rpath,"+rpath_prefix+"../"+rpath)
+ }
+
+ return flags
+}
+
+func (compiler *baseCompiler) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path {
+ panic(fmt.Errorf("baseCrater doesn't know how to crate things!"))
+}
+
+func (compiler *baseCompiler) compilerDeps(ctx DepsContext, deps Deps) Deps {
+ deps.Rlibs = append(deps.Rlibs, compiler.Properties.Rlibs...)
+ deps.Dylibs = append(deps.Dylibs, compiler.Properties.Dylibs...)
+ deps.ProcMacros = append(deps.ProcMacros, compiler.Properties.Proc_macros...)
+ deps.StaticLibs = append(deps.StaticLibs, compiler.Properties.Static_libs...)
+ deps.SharedLibs = append(deps.SharedLibs, compiler.Properties.Shared_libs...)
+
+ return deps
+}
+
+func (compiler *baseCompiler) bionicDeps(ctx DepsContext, deps Deps) Deps {
+ deps.SharedLibs = append(deps.SharedLibs, "liblog")
+ deps.SharedLibs = append(deps.SharedLibs, "libc")
+ deps.SharedLibs = append(deps.SharedLibs, "libm")
+ deps.SharedLibs = append(deps.SharedLibs, "libdl")
+
+ //TODO(b/141331117) libstd requires libgcc on Android
+ deps.StaticLibs = append(deps.StaticLibs, "libgcc")
+
+ return deps
+}
+
+func (compiler *baseCompiler) crateName() string {
+ return compiler.Properties.Crate_name
+}
+
+func (compiler *baseCompiler) installDir(ctx ModuleContext) android.InstallPath {
+ dir := compiler.dir
+ if ctx.toolchain().Is64Bit() && compiler.dir64 != "" {
+ dir = compiler.dir64
+ }
+ if !ctx.Host() || ctx.Target().NativeBridge == android.NativeBridgeEnabled {
+ dir = filepath.Join(dir, ctx.Arch().ArchType.String())
+ }
+ return android.PathForModuleInstall(ctx, dir, compiler.subDir,
+ compiler.relativeInstallPath(), compiler.relative)
+}
+
+func (compiler *baseCompiler) install(ctx ModuleContext, file android.Path) {
+ compiler.path = ctx.InstallFile(compiler.installDir(ctx), file.Base(), file)
+}
+
+func (compiler *baseCompiler) getStem(ctx ModuleContext) string {
+ return compiler.getStemWithoutSuffix(ctx) + String(compiler.Properties.Suffix)
+}
+
+func (compiler *baseCompiler) getStemWithoutSuffix(ctx BaseModuleContext) string {
+ stem := ctx.baseModuleName()
+ if String(compiler.Properties.Stem) != "" {
+ stem = String(compiler.Properties.Stem)
+ }
+
+ return stem
+}
+func (compiler *baseCompiler) relativeInstallPath() string {
+ return String(compiler.Properties.Relative_install_path)
+}
+
+func srcPathFromModuleSrcs(ctx ModuleContext, srcs []string) android.Path {
+ srcPaths := android.PathsForModuleSrc(ctx, srcs)
+ if len(srcPaths) != 1 {
+ ctx.PropertyErrorf("srcs", "srcs can only contain one path for rust modules")
+ }
+ return srcPaths[0]
+}
diff --git a/rust/compiler_test.go b/rust/compiler_test.go
new file mode 100644
index 0000000..bbf9f8d
--- /dev/null
+++ b/rust/compiler_test.go
@@ -0,0 +1,76 @@
+// Copyright 2019 The Android Open Source Project
+//
+// 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 rust
+
+import (
+ "strings"
+ "testing"
+)
+
+// Test that feature flags are being correctly generated.
+func TestFeaturesToFlags(t *testing.T) {
+ ctx := testRust(t, `
+ rust_library_host_dylib {
+ name: "libfoo",
+ srcs: ["foo.rs"],
+ crate_name: "foo",
+ features: [
+ "fizz",
+ "buzz"
+ ],
+ }`)
+
+ libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc")
+
+ if !strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'feature=\"fizz\"'") ||
+ !strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'feature=\"buzz\"'") {
+ t.Fatalf("missing fizz and buzz feature flags for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"])
+ }
+}
+
+// Test that we reject multiple source files.
+func TestEnforceSingleSourceFile(t *testing.T) {
+
+ singleSrcError := "srcs can only contain one path for rust modules"
+
+ // Test libraries
+ testRustError(t, singleSrcError, `
+ rust_library_host {
+ name: "foo-bar-library",
+ srcs: ["foo.rs", "src/bar.rs"],
+ }`)
+
+ // Test binaries
+ testRustError(t, singleSrcError, `
+ rust_binary_host {
+ name: "foo-bar-binary",
+ srcs: ["foo.rs", "src/bar.rs"],
+ }`)
+
+ // Test proc_macros
+ testRustError(t, singleSrcError, `
+ rust_proc_macro {
+ name: "foo-bar-proc-macro",
+ srcs: ["foo.rs", "src/bar.rs"],
+ }`)
+
+ // Test prebuilts
+ testRustError(t, singleSrcError, `
+ rust_prebuilt_dylib {
+ name: "foo-bar-prebuilt",
+ srcs: ["liby.so", "libz.so"],
+ host_supported: true,
+ }`)
+}
diff --git a/rust/config/arm64_device.go b/rust/config/arm64_device.go
new file mode 100644
index 0000000..0264052
--- /dev/null
+++ b/rust/config/arm64_device.go
@@ -0,0 +1,92 @@
+// Copyright 2019 The Android Open Source Project
+//
+// 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 config
+
+import (
+ "strings"
+
+ "android/soong/android"
+)
+
+var (
+ Arm64RustFlags = []string{}
+ Arm64ArchFeatureRustFlags = map[string][]string{}
+ Arm64LinkFlags = []string{
+ "-Wl,--icf=safe",
+ "-Wl,-z,max-page-size=4096",
+
+ "-Wl,-execute-only",
+ }
+
+ Arm64ArchVariantRustFlags = map[string][]string{
+ "armv8-a": []string{},
+ "armv8-2a": []string{},
+ }
+)
+
+func init() {
+ registerToolchainFactory(android.Android, android.Arm64, Arm64ToolchainFactory)
+
+ pctx.StaticVariable("Arm64ToolchainRustFlags", strings.Join(Arm64RustFlags, " "))
+ pctx.StaticVariable("Arm64ToolchainLinkFlags", strings.Join(Arm64LinkFlags, " "))
+
+ for variant, rustFlags := range Arm64ArchVariantRustFlags {
+ pctx.StaticVariable("Arm64"+variant+"VariantRustFlags",
+ strings.Join(rustFlags, " "))
+ }
+
+}
+
+type toolchainArm64 struct {
+ toolchain64Bit
+ toolchainRustFlags string
+}
+
+func (t *toolchainArm64) RustTriple() string {
+ return "aarch64-linux-android"
+}
+
+func (t *toolchainArm64) ToolchainLinkFlags() string {
+ return "${config.DeviceGlobalLinkFlags} ${config.Arm64ToolchainLinkFlags}"
+}
+
+func (t *toolchainArm64) ToolchainRustFlags() string {
+ return t.toolchainRustFlags
+}
+
+func (t *toolchainArm64) RustFlags() string {
+ return "${config.Arm64ToolchainRustFlags}"
+}
+
+func (t *toolchainArm64) Supported() bool {
+ return true
+}
+
+func Arm64ToolchainFactory(arch android.Arch) Toolchain {
+ toolchainRustFlags := []string{
+ "${config.Arm64ToolchainRustFlags}",
+ "${config.Arm64" + arch.ArchVariant + "VariantRustFlags}",
+ }
+
+ toolchainRustFlags = append(toolchainRustFlags, deviceGlobalRustFlags...)
+
+ for _, feature := range arch.ArchFeatures {
+ toolchainRustFlags = append(toolchainRustFlags, Arm64ArchFeatureRustFlags[feature]...)
+ }
+
+ return &toolchainArm64{
+ toolchainRustFlags: strings.Join(toolchainRustFlags, " "),
+ }
+}
diff --git a/rust/config/arm_device.go b/rust/config/arm_device.go
new file mode 100644
index 0000000..aedb42b
--- /dev/null
+++ b/rust/config/arm_device.go
@@ -0,0 +1,92 @@
+// Copyright 2019 The Android Open Source Project
+//
+// 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 config
+
+import (
+ "strings"
+
+ "android/soong/android"
+)
+
+var (
+ ArmRustFlags = []string{}
+ ArmArchFeatureRustFlags = map[string][]string{}
+ ArmLinkFlags = []string{
+ "-Wl,--icf=safe",
+ "-Wl,-m,armelf",
+ }
+
+ ArmArchVariantRustFlags = map[string][]string{
+ "armv7-a": []string{},
+ "armv7-a-neon": []string{},
+ "armv8-a": []string{},
+ "armv8-2a": []string{},
+ }
+)
+
+func init() {
+ registerToolchainFactory(android.Android, android.Arm, ArmToolchainFactory)
+
+ pctx.StaticVariable("ArmToolchainRustFlags", strings.Join(ArmRustFlags, " "))
+ pctx.StaticVariable("ArmToolchainLinkFlags", strings.Join(ArmLinkFlags, " "))
+
+ for variant, rustFlags := range ArmArchVariantRustFlags {
+ pctx.StaticVariable("Arm"+variant+"VariantRustFlags",
+ strings.Join(rustFlags, " "))
+ }
+
+}
+
+type toolchainArm struct {
+ toolchain64Bit
+ toolchainRustFlags string
+}
+
+func (t *toolchainArm) RustTriple() string {
+ return "arm-linux-androideabi"
+}
+
+func (t *toolchainArm) ToolchainLinkFlags() string {
+ return "${config.DeviceGlobalLinkFlags} ${config.ArmToolchainLinkFlags}"
+}
+
+func (t *toolchainArm) ToolchainRustFlags() string {
+ return t.toolchainRustFlags
+}
+
+func (t *toolchainArm) RustFlags() string {
+ return "${config.ArmToolchainRustFlags}"
+}
+
+func (t *toolchainArm) Supported() bool {
+ return true
+}
+
+func ArmToolchainFactory(arch android.Arch) Toolchain {
+ toolchainRustFlags := []string{
+ "${config.ArmToolchainRustFlags}",
+ "${config.Arm" + arch.ArchVariant + "VariantRustFlags}",
+ }
+
+ toolchainRustFlags = append(toolchainRustFlags, deviceGlobalRustFlags...)
+
+ for _, feature := range arch.ArchFeatures {
+ toolchainRustFlags = append(toolchainRustFlags, ArmArchFeatureRustFlags[feature]...)
+ }
+
+ return &toolchainArm{
+ toolchainRustFlags: strings.Join(toolchainRustFlags, " "),
+ }
+}
diff --git a/rust/config/global.go b/rust/config/global.go
new file mode 100644
index 0000000..7846d21
--- /dev/null
+++ b/rust/config/global.go
@@ -0,0 +1,88 @@
+// Copyright 2019 The Android Open Source Project
+//
+// 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 config
+
+import (
+ "strings"
+
+ "android/soong/android"
+ _ "android/soong/cc/config"
+)
+
+var pctx = android.NewPackageContext("android/soong/rust/config")
+
+var (
+ RustDefaultVersion = "1.37.0"
+ RustDefaultBase = "prebuilts/rust/"
+ DefaultEdition = "2018"
+ Stdlibs = []string{
+ "libstd",
+ "libterm",
+ "libtest",
+ }
+
+ DefaultDenyWarnings = true
+
+ GlobalRustFlags = []string{
+ "--remap-path-prefix $$(pwd)=",
+ }
+
+ deviceGlobalRustFlags = []string{}
+
+ deviceGlobalLinkFlags = []string{
+ "-Bdynamic",
+ "-nostdlib",
+ "-Wl,-z,noexecstack",
+ "-Wl,-z,relro",
+ "-Wl,-z,now",
+ "-Wl,--build-id=md5",
+ "-Wl,--warn-shared-textrel",
+ "-Wl,--fatal-warnings",
+
+ "-Wl,--pack-dyn-relocs=android+relr",
+ "-Wl,--use-android-relr-tags",
+ "-Wl,--no-undefined",
+ "-Wl,--hash-style=gnu",
+ }
+)
+
+func init() {
+ pctx.SourcePathVariable("RustDefaultBase", RustDefaultBase)
+ pctx.VariableConfigMethod("HostPrebuiltTag", android.Config.PrebuiltOS)
+
+ pctx.VariableFunc("RustBase", func(ctx android.PackageVarContext) string {
+ if override := ctx.Config().Getenv("RUST_PREBUILTS_BASE"); override != "" {
+ return override
+ }
+ return "${RustDefaultBase}"
+ })
+
+ pctx.VariableFunc("RustVersion", func(ctx android.PackageVarContext) string {
+ if override := ctx.Config().Getenv("RUST_PREBUILTS_VERSION"); override != "" {
+ return override
+ }
+ return RustDefaultVersion
+ })
+
+ pctx.StaticVariable("RustPath", "${RustBase}/${HostPrebuiltTag}/${RustVersion}")
+ pctx.StaticVariable("RustBin", "${RustPath}/bin")
+
+ pctx.ImportAs("ccConfig", "android/soong/cc/config")
+ pctx.StaticVariable("RustLinker", "${ccConfig.ClangBin}/clang++")
+ pctx.StaticVariable("RustLinkerArgs", "-B ${ccConfig.ClangBin} -fuse-ld=lld")
+
+ pctx.StaticVariable("DeviceGlobalLinkFlags", strings.Join(deviceGlobalLinkFlags, " "))
+
+}
diff --git a/rust/config/toolchain.go b/rust/config/toolchain.go
new file mode 100644
index 0000000..328bca3
--- /dev/null
+++ b/rust/config/toolchain.go
@@ -0,0 +1,130 @@
+// Copyright 2019 The Android Open Source Project
+//
+// 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 config
+
+import (
+ "android/soong/android"
+)
+
+type Toolchain interface {
+ RustTriple() string
+ ToolchainRustFlags() string
+ ToolchainLinkFlags() string
+
+ SharedLibSuffix() string
+ StaticLibSuffix() string
+ RlibSuffix() string
+ DylibSuffix() string
+ ProcMacroSuffix() string
+ ExecutableSuffix() string
+
+ Is64Bit() bool
+ Supported() bool
+
+ Bionic() bool
+}
+
+type toolchainBase struct {
+}
+
+func (toolchainBase) RustTriple() string {
+ panic("toolchainBase does not define a triple.")
+}
+
+func (toolchainBase) ToolchainRustFlags() string {
+ panic("toolchainBase does not provide rust flags.")
+}
+
+func (toolchainBase) ToolchainLinkFlags() string {
+ panic("toolchainBase does not provide link flags.")
+}
+
+func (toolchainBase) Is64Bit() bool {
+ panic("toolchainBase cannot determine datapath width.")
+}
+
+func (toolchainBase) Bionic() bool {
+ return true
+}
+
+type toolchain64Bit struct {
+ toolchainBase
+}
+
+func (toolchain64Bit) Is64Bit() bool {
+ return true
+}
+
+type toolchain32Bit struct {
+ toolchainBase
+}
+
+func (toolchain32Bit) Is64Bit() bool {
+ return false
+}
+
+func (toolchain32Bit) Bionic() bool {
+ return true
+}
+
+func (toolchainBase) ExecutableSuffix() string {
+ return ""
+}
+
+func (toolchainBase) SharedLibSuffix() string {
+ return ".so"
+}
+
+func (toolchainBase) StaticLibSuffix() string {
+ return ".a"
+}
+
+func (toolchainBase) RlibSuffix() string {
+ return ".rlib"
+}
+func (toolchainBase) DylibSuffix() string {
+ return ".so"
+}
+
+func (toolchainBase) ProcMacroSuffix() string {
+ return ".so"
+}
+
+func (toolchainBase) Supported() bool {
+ return false
+}
+
+func toolchainBaseFactory() Toolchain {
+ return &toolchainBase{}
+}
+
+type toolchainFactory func(arch android.Arch) Toolchain
+
+var toolchainFactories = make(map[android.OsType]map[android.ArchType]toolchainFactory)
+
+func registerToolchainFactory(os android.OsType, arch android.ArchType, factory toolchainFactory) {
+ if toolchainFactories[os] == nil {
+ toolchainFactories[os] = make(map[android.ArchType]toolchainFactory)
+ }
+ toolchainFactories[os][arch] = factory
+}
+
+func FindToolchain(os android.OsType, arch android.Arch) Toolchain {
+ factory := toolchainFactories[os][arch.ArchType]
+ if factory == nil {
+ return toolchainBaseFactory()
+ }
+ return factory(arch)
+}
diff --git a/rust/config/whitelist.go b/rust/config/whitelist.go
new file mode 100644
index 0000000..4646264
--- /dev/null
+++ b/rust/config/whitelist.go
@@ -0,0 +1,21 @@
+package config
+
+var (
+ RustAllowedPaths = []string{
+ "external/rust/crates",
+ "external/crosvm",
+ "external/adhd",
+ }
+
+ RustModuleTypes = []string{
+ "rust_binary",
+ "rust_binary_host",
+ "rust_library",
+ "rust_library_dylib",
+ "rust_library_rlib",
+ "rust_library_host",
+ "rust_library_host_dylib",
+ "rust_library_host_rlib",
+ "rust_proc_macro",
+ }
+)
diff --git a/rust/config/x86_64_device.go b/rust/config/x86_64_device.go
new file mode 100644
index 0000000..2aca56a
--- /dev/null
+++ b/rust/config/x86_64_device.go
@@ -0,0 +1,88 @@
+// Copyright 2019 The Android Open Source Project
+//
+// 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 config
+
+import (
+ "strings"
+
+ "android/soong/android"
+)
+
+var (
+ x86_64RustFlags = []string{}
+ x86_64ArchFeatureRustFlags = map[string][]string{}
+ x86_64LinkFlags = []string{}
+
+ x86_64ArchVariantRustFlags = map[string][]string{
+ "": []string{},
+ "broadwell": []string{"-C target-cpu=broadwell"},
+ "haswell": []string{"-C target-cpu=haswell"},
+ "ivybridge": []string{"-C target-cpu=ivybridge"},
+ "sandybridge": []string{"-C target-cpu=sandybridge"},
+ "silvermont": []string{"-C target-cpu=silvermont"},
+ "skylake": []string{"-C target-cpu=skylake"},
+ //TODO: Add target-cpu=stoneyridge when rustc supports it.
+ "stoneyridge": []string{""},
+ }
+)
+
+func init() {
+ registerToolchainFactory(android.Android, android.X86_64, x86_64ToolchainFactory)
+
+ pctx.StaticVariable("x86_64ToolchainRustFlags", strings.Join(x86_64RustFlags, " "))
+ pctx.StaticVariable("x86_64ToolchainLinkFlags", strings.Join(x86_64LinkFlags, " "))
+
+ for variant, rustFlags := range x86_64ArchVariantRustFlags {
+ pctx.StaticVariable("X86_64"+variant+"VariantRustFlags",
+ strings.Join(rustFlags, " "))
+ }
+
+}
+
+type toolchainX86_64 struct {
+ toolchain64Bit
+ toolchainRustFlags string
+}
+
+func (t *toolchainX86_64) RustTriple() string {
+ return "x86_64-unknown-linux-gnu"
+}
+
+func (t *toolchainX86_64) ToolchainLinkFlags() string {
+ return "${config.x86_64ToolchainLinkFlags}"
+}
+
+func (t *toolchainX86_64) ToolchainRustFlags() string {
+ return t.toolchainRustFlags
+}
+
+func (t *toolchainX86_64) RustFlags() string {
+ return "${config.x86_64ToolchainRustFlags}"
+}
+
+func x86_64ToolchainFactory(arch android.Arch) Toolchain {
+ toolchainRustFlags := []string{
+ "${config.x86_64ToolchainRustFlags}",
+ "${config.X86_64" + arch.ArchVariant + "VariantRustFlags}",
+ }
+
+ for _, feature := range arch.ArchFeatures {
+ toolchainRustFlags = append(toolchainRustFlags, x86_64ArchFeatureRustFlags[feature]...)
+ }
+
+ return &toolchainX86_64{
+ toolchainRustFlags: strings.Join(toolchainRustFlags, " "),
+ }
+}
diff --git a/rust/config/x86_darwin_host.go b/rust/config/x86_darwin_host.go
new file mode 100644
index 0000000..7cfc59c
--- /dev/null
+++ b/rust/config/x86_darwin_host.go
@@ -0,0 +1,81 @@
+// Copyright 2019 The Android Open Source Project
+//
+// 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 config
+
+import (
+ "strings"
+
+ "android/soong/android"
+)
+
+var (
+ DarwinRustFlags = []string{}
+ DarwinRustLinkFlags = []string{}
+ darwinX8664Rustflags = []string{}
+ darwinX8664Linkflags = []string{}
+)
+
+func init() {
+ registerToolchainFactory(android.Darwin, android.X86_64, darwinX8664ToolchainFactory)
+ pctx.StaticVariable("DarwinToolchainRustFlags", strings.Join(DarwinRustFlags, " "))
+ pctx.StaticVariable("DarwinToolchainLinkFlags", strings.Join(DarwinRustLinkFlags, " "))
+ pctx.StaticVariable("DarwinToolchainX8664RustFlags", strings.Join(darwinX8664Rustflags, " "))
+ pctx.StaticVariable("DarwinToolchainX8664LinkFlags", strings.Join(darwinX8664Linkflags, " "))
+
+}
+
+type toolchainDarwin struct {
+ toolchainRustFlags string
+ toolchainLinkFlags string
+}
+
+type toolchainDarwinX8664 struct {
+ toolchain64Bit
+ toolchainDarwin
+}
+
+func (toolchainDarwinX8664) Supported() bool {
+ return true
+}
+
+func (toolchainDarwinX8664) Bionic() bool {
+ return false
+}
+
+func (t *toolchainDarwinX8664) Name() string {
+ return "x86_64"
+}
+
+func (t *toolchainDarwinX8664) RustTriple() string {
+ return "x86_64-apple-darwin"
+}
+
+func (t *toolchainDarwin) ShlibSuffix() string {
+ return ".dylib"
+}
+
+func (t *toolchainDarwinX8664) ToolchainLinkFlags() string {
+ return "${config.DarwinToolchainLinkFlags} ${config.DarwinToolchainX8664LinkFlags}"
+}
+
+func (t *toolchainDarwinX8664) ToolchainRustFlags() string {
+ return "${config.DarwinToolchainRustFlags} ${config.DarwinToolchainX8664RustFlags}"
+}
+
+func darwinX8664ToolchainFactory(arch android.Arch) Toolchain {
+ return toolchainDarwinX8664Singleton
+}
+
+var toolchainDarwinX8664Singleton Toolchain = &toolchainDarwinX8664{}
diff --git a/rust/config/x86_linux_host.go b/rust/config/x86_linux_host.go
new file mode 100644
index 0000000..5376e5b
--- /dev/null
+++ b/rust/config/x86_linux_host.go
@@ -0,0 +1,117 @@
+// Copyright 2019 The Android Open Source Project
+//
+// 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 config
+
+import (
+ "strings"
+
+ "android/soong/android"
+)
+
+var (
+ LinuxRustFlags = []string{}
+ LinuxRustLinkFlags = []string{}
+ linuxX86Rustflags = []string{}
+ linuxX86Linkflags = []string{}
+ linuxX8664Rustflags = []string{}
+ linuxX8664Linkflags = []string{}
+)
+
+func init() {
+ registerToolchainFactory(android.Linux, android.X86_64, linuxX8664ToolchainFactory)
+ registerToolchainFactory(android.Linux, android.X86, linuxX86ToolchainFactory)
+
+ pctx.StaticVariable("LinuxToolchainRustFlags", strings.Join(LinuxRustFlags, " "))
+ pctx.StaticVariable("LinuxToolchainLinkFlags", strings.Join(LinuxRustLinkFlags, " "))
+ pctx.StaticVariable("LinuxToolchainX86RustFlags", strings.Join(linuxX86Rustflags, " "))
+ pctx.StaticVariable("LinuxToolchainX86LinkFlags", strings.Join(linuxX86Linkflags, " "))
+ pctx.StaticVariable("LinuxToolchainX8664RustFlags", strings.Join(linuxX8664Rustflags, " "))
+ pctx.StaticVariable("LinuxToolchainX8664LinkFlags", strings.Join(linuxX8664Linkflags, " "))
+
+}
+
+type toolchainLinux struct {
+ toolchainRustFlags string
+ toolchainLinkFlags string
+}
+
+type toolchainLinuxX86 struct {
+ toolchain32Bit
+ toolchainLinux
+}
+
+type toolchainLinuxX8664 struct {
+ toolchain64Bit
+ toolchainLinux
+}
+
+func (toolchainLinuxX8664) Supported() bool {
+ return true
+}
+
+func (toolchainLinuxX8664) Bionic() bool {
+ return false
+}
+
+func (t *toolchainLinuxX8664) Name() string {
+ return "x86_64"
+}
+
+func (t *toolchainLinuxX8664) RustTriple() string {
+ return "x86_64-unknown-linux-gnu"
+}
+
+func (t *toolchainLinuxX8664) ToolchainLinkFlags() string {
+ return "${config.LinuxToolchainLinkFlags} ${config.LinuxToolchainX8664LinkFlags}"
+}
+
+func (t *toolchainLinuxX8664) ToolchainRustFlags() string {
+ return "${config.LinuxToolchainRustFlags} ${config.LinuxToolchainX8664RustFlags}"
+}
+
+func linuxX8664ToolchainFactory(arch android.Arch) Toolchain {
+ return toolchainLinuxX8664Singleton
+}
+
+func (toolchainLinuxX86) Supported() bool {
+ return true
+}
+
+func (toolchainLinuxX86) Bionic() bool {
+ return false
+}
+
+func (t *toolchainLinuxX86) Name() string {
+ return "x86"
+}
+
+func (t *toolchainLinuxX86) RustTriple() string {
+ return "i686-unknown-linux-gnu"
+}
+
+func (t *toolchainLinuxX86) ToolchainLinkFlags() string {
+ return "${config.LinuxToolchainLinkFlags} ${config.LinuxToolchainX86LinkFlags}"
+}
+
+func (t *toolchainLinuxX86) ToolchainRustFlags() string {
+ return "${config.LinuxToolchainRustFlags} ${config.LinuxToolchainX86RustFlags}"
+}
+
+func linuxX86ToolchainFactory(arch android.Arch) Toolchain {
+ return toolchainLinuxX86Singleton
+}
+
+var toolchainLinuxX8664Singleton Toolchain = &toolchainLinuxX8664{}
+var toolchainLinuxX86Singleton Toolchain = &toolchainLinuxX86{}
diff --git a/rust/library.go b/rust/library.go
new file mode 100644
index 0000000..c831727
--- /dev/null
+++ b/rust/library.go
@@ -0,0 +1,255 @@
+// Copyright 2019 The Android Open Source Project
+//
+// 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 rust
+
+import (
+ "android/soong/android"
+)
+
+func init() {
+ android.RegisterModuleType("rust_library", RustLibraryFactory)
+ android.RegisterModuleType("rust_library_dylib", RustLibraryDylibFactory)
+ android.RegisterModuleType("rust_library_rlib", RustLibraryRlibFactory)
+ android.RegisterModuleType("rust_library_host", RustLibraryHostFactory)
+ android.RegisterModuleType("rust_library_host_dylib", RustLibraryDylibHostFactory)
+ android.RegisterModuleType("rust_library_host_rlib", RustLibraryRlibHostFactory)
+
+ //TODO: Add support for generating standard shared/static libraries.
+}
+
+type VariantLibraryProperties struct {
+ Enabled *bool `android:"arch_variant"`
+}
+
+type LibraryCompilerProperties struct {
+ Rlib VariantLibraryProperties `android:"arch_variant"`
+ Dylib VariantLibraryProperties `android:"arch_variant"`
+
+ // path to the source file that is the main entry point of the program (e.g. src/lib.rs)
+ Srcs []string `android:"path,arch_variant"`
+}
+
+type LibraryMutatedProperties struct {
+ VariantName string `blueprint:"mutated"`
+
+ // Build a dylib variant
+ BuildDylib bool `blueprint:"mutated"`
+ // Build an rlib variant
+ BuildRlib bool `blueprint:"mutated"`
+
+ // This variant is a dylib
+ VariantIsDylib bool `blueprint:"mutated"`
+ // This variant is an rlib
+ VariantIsRlib bool `blueprint:"mutated"`
+}
+
+type libraryDecorator struct {
+ *baseCompiler
+
+ Properties LibraryCompilerProperties
+ MutatedProperties LibraryMutatedProperties
+ distFile android.OptionalPath
+ unstrippedOutputFile android.Path
+}
+
+type libraryInterface interface {
+ rlib() bool
+ dylib() bool
+
+ // Returns true if the build options for the module have selected a particular build type
+ buildRlib() bool
+ buildDylib() bool
+
+ // Sets a particular variant type
+ setRlib()
+ setDylib()
+}
+
+func (library *libraryDecorator) exportedDirs() []string {
+ return library.linkDirs
+}
+
+func (library *libraryDecorator) exportedDepFlags() []string {
+ return library.depFlags
+}
+
+func (library *libraryDecorator) reexportDirs(dirs ...string) {
+ library.linkDirs = android.FirstUniqueStrings(append(library.linkDirs, dirs...))
+}
+
+func (library *libraryDecorator) reexportDepFlags(flags ...string) {
+ library.depFlags = android.FirstUniqueStrings(append(library.depFlags, flags...))
+}
+
+func (library *libraryDecorator) rlib() bool {
+ return library.MutatedProperties.VariantIsRlib
+}
+
+func (library *libraryDecorator) dylib() bool {
+ return library.MutatedProperties.VariantIsDylib
+}
+
+func (library *libraryDecorator) buildRlib() bool {
+ return library.MutatedProperties.BuildRlib && BoolDefault(library.Properties.Rlib.Enabled, true)
+}
+
+func (library *libraryDecorator) buildDylib() bool {
+ return library.MutatedProperties.BuildDylib && BoolDefault(library.Properties.Dylib.Enabled, true)
+}
+
+func (library *libraryDecorator) setRlib() {
+ library.MutatedProperties.VariantIsRlib = true
+ library.MutatedProperties.VariantIsDylib = false
+}
+
+func (library *libraryDecorator) setDylib() {
+ library.MutatedProperties.VariantIsRlib = false
+ library.MutatedProperties.VariantIsDylib = true
+}
+
+var _ compiler = (*libraryDecorator)(nil)
+
+// rust_library produces all variants.
+func RustLibraryFactory() android.Module {
+ module, _ := NewRustLibrary(android.HostAndDeviceSupported)
+ return module.Init()
+}
+
+// rust_library_dylib produces a dylib.
+func RustLibraryDylibFactory() android.Module {
+ module, library := NewRustLibrary(android.HostAndDeviceSupported)
+ library.BuildOnlyDylib()
+ return module.Init()
+}
+
+// rust_library_rlib produces an rlib.
+func RustLibraryRlibFactory() android.Module {
+ module, library := NewRustLibrary(android.HostAndDeviceSupported)
+ library.BuildOnlyRlib()
+ return module.Init()
+}
+
+// rust_library_host produces all variants.
+func RustLibraryHostFactory() android.Module {
+ module, _ := NewRustLibrary(android.HostSupported)
+ return module.Init()
+}
+
+// rust_library_dylib_host produces a dylib.
+func RustLibraryDylibHostFactory() android.Module {
+ module, library := NewRustLibrary(android.HostSupported)
+ library.BuildOnlyDylib()
+ return module.Init()
+}
+
+// rust_library_rlib_host produces an rlib.
+func RustLibraryRlibHostFactory() android.Module {
+ module, library := NewRustLibrary(android.HostSupported)
+ library.BuildOnlyRlib()
+ return module.Init()
+}
+
+func (library *libraryDecorator) BuildOnlyDylib() {
+ library.MutatedProperties.BuildRlib = false
+}
+
+func (library *libraryDecorator) BuildOnlyRlib() {
+ library.MutatedProperties.BuildDylib = false
+}
+
+func NewRustLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator) {
+ module := newModule(hod, android.MultilibFirst)
+
+ library := &libraryDecorator{
+ MutatedProperties: LibraryMutatedProperties{
+ BuildDylib: true,
+ BuildRlib: true,
+ },
+ baseCompiler: NewBaseCompiler("lib", "lib64"),
+ }
+
+ module.compiler = library
+
+ return module, library
+}
+
+func (library *libraryDecorator) compilerProps() []interface{} {
+ return append(library.baseCompiler.compilerProps(),
+ &library.Properties,
+ &library.MutatedProperties)
+}
+
+func (library *libraryDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps {
+ deps = library.baseCompiler.compilerDeps(ctx, deps)
+
+ if ctx.toolchain().Bionic() && library.dylib() {
+ deps = library.baseCompiler.bionicDeps(ctx, deps)
+ }
+
+ return deps
+}
+
+func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path {
+ var outputFile android.WritablePath
+
+ srcPath := srcPathFromModuleSrcs(ctx, library.Properties.Srcs)
+
+ flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
+
+ if library.rlib() {
+ fileName := library.getStem(ctx) + ctx.toolchain().RlibSuffix()
+ outputFile = android.PathForModuleOut(ctx, fileName)
+
+ TransformSrctoRlib(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
+ } else if library.dylib() {
+ fileName := library.getStem(ctx) + ctx.toolchain().DylibSuffix()
+ outputFile = android.PathForModuleOut(ctx, fileName)
+
+ // We need prefer-dynamic for now to avoid linking in the static stdlib. See:
+ // https://github.com/rust-lang/rust/issues/19680
+ // https://github.com/rust-lang/rust/issues/34909
+ flags.RustFlags = append(flags.RustFlags, "-C prefer-dynamic")
+
+ TransformSrctoDylib(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
+ }
+
+ library.reexportDirs(deps.linkDirs...)
+ library.reexportDepFlags(deps.depFlags...)
+ library.unstrippedOutputFile = outputFile
+
+ return outputFile
+}
+
+func LibraryMutator(mctx android.BottomUpMutatorContext) {
+ if m, ok := mctx.Module().(*Module); ok && m.compiler != nil {
+ switch library := m.compiler.(type) {
+ case libraryInterface:
+ if library.buildRlib() && library.buildDylib() {
+ modules := mctx.CreateLocalVariations("rlib", "dylib")
+ rlib := modules[0].(*Module)
+ dylib := modules[1].(*Module)
+
+ rlib.compiler.(libraryInterface).setRlib()
+ dylib.compiler.(libraryInterface).setDylib()
+ } else if library.buildRlib() {
+ modules := mctx.CreateLocalVariations("rlib")
+ modules[0].(*Module).compiler.(libraryInterface).setRlib()
+ } else if library.buildDylib() {
+ modules := mctx.CreateLocalVariations("dylib")
+ modules[0].(*Module).compiler.(libraryInterface).setDylib()
+ }
+ }
+ }
+}
diff --git a/rust/library_test.go b/rust/library_test.go
new file mode 100644
index 0000000..bf8643e
--- /dev/null
+++ b/rust/library_test.go
@@ -0,0 +1,61 @@
+// Copyright 2019 The Android Open Source Project
+//
+// 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 rust
+
+import (
+ "strings"
+ "testing"
+)
+
+// Test that variants are being generated correctly, and that crate-types are correct.
+func TestLibraryVariants(t *testing.T) {
+
+ ctx := testRust(t, `
+ rust_library_host {
+ name: "libfoo",
+ srcs: ["foo.rs"],
+ crate_name: "foo",
+ }`)
+
+ // Test both variants are being built.
+ libfooRlib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_rlib").Output("libfoo.rlib")
+ libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Output("libfoo.so")
+
+ // Test crate type for rlib is correct.
+ if !strings.Contains(libfooRlib.Args["rustcFlags"], "crate-type=rlib") {
+ t.Errorf("missing crate-type for libfoo rlib, rustcFlags: %#v", libfooRlib.Args["rustcFlags"])
+ }
+
+ // Test crate type for dylib is correct.
+ if !strings.Contains(libfooDylib.Args["rustcFlags"], "crate-type=dylib") {
+ t.Errorf("missing crate-type for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"])
+ }
+}
+
+// Test that dylibs are not statically linking the standard library.
+func TestDylibPreferDynamic(t *testing.T) {
+ ctx := testRust(t, `
+ rust_library_host_dylib {
+ name: "libfoo",
+ srcs: ["foo.rs"],
+ crate_name: "foo",
+ }`)
+
+ libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Output("libfoo.so")
+
+ if !strings.Contains(libfooDylib.Args["rustcFlags"], "prefer-dynamic") {
+ t.Errorf("missing prefer-dynamic flag for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"])
+ }
+}
diff --git a/rust/prebuilt.go b/rust/prebuilt.go
new file mode 100644
index 0000000..fa69fbb
--- /dev/null
+++ b/rust/prebuilt.go
@@ -0,0 +1,70 @@
+// Copyright 2019 The Android Open Source Project
+//
+// 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 rust
+
+import (
+ "android/soong/android"
+)
+
+func init() {
+ android.RegisterModuleType("rust_prebuilt_dylib", PrebuiltDylibFactory)
+}
+
+type PrebuiltProperties struct {
+ // path to the prebuilt file
+ Srcs []string `android:"path,arch_variant"`
+}
+
+type prebuiltLibraryDecorator struct {
+ *libraryDecorator
+ Properties PrebuiltProperties
+}
+
+var _ compiler = (*prebuiltLibraryDecorator)(nil)
+
+func PrebuiltDylibFactory() android.Module {
+ module, _ := NewPrebuiltDylib(android.HostAndDeviceSupported)
+ return module.Init()
+}
+
+func NewPrebuiltDylib(hod android.HostOrDeviceSupported) (*Module, *prebuiltLibraryDecorator) {
+ module, library := NewRustLibrary(hod)
+ library.BuildOnlyDylib()
+ library.setDylib()
+ prebuilt := &prebuiltLibraryDecorator{
+ libraryDecorator: library,
+ }
+ module.compiler = prebuilt
+ module.AddProperties(&library.Properties)
+ return module, prebuilt
+}
+
+func (prebuilt *prebuiltLibraryDecorator) compilerProps() []interface{} {
+ return append(prebuilt.baseCompiler.compilerProps(),
+ &prebuilt.Properties)
+}
+
+func (prebuilt *prebuiltLibraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path {
+ srcPath := srcPathFromModuleSrcs(ctx, prebuilt.Properties.Srcs)
+
+ prebuilt.unstrippedOutputFile = srcPath
+
+ return srcPath
+}
+
+func (prebuilt *prebuiltLibraryDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps {
+ deps = prebuilt.baseCompiler.compilerDeps(ctx, deps)
+ return deps
+}
diff --git a/rust/proc_macro.go b/rust/proc_macro.go
new file mode 100644
index 0000000..1a247d9
--- /dev/null
+++ b/rust/proc_macro.go
@@ -0,0 +1,79 @@
+// Copyright 2019 The Android Open Source Project
+//
+// 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 rust
+
+import (
+ "android/soong/android"
+)
+
+func init() {
+ android.RegisterModuleType("rust_proc_macro", ProcMacroFactory)
+}
+
+type ProcMacroCompilerProperties struct {
+ // path to the source file that is the main entry point of the program (e.g. src/lib.rs)
+ Srcs []string `android:"path,arch_variant"`
+
+ // set name of the procMacro
+ Stem *string `android:"arch_variant"`
+ Suffix *string `android:"arch_variant"`
+}
+
+type procMacroDecorator struct {
+ *baseCompiler
+
+ Properties ProcMacroCompilerProperties
+ distFile android.OptionalPath
+ unstrippedOutputFile android.Path
+}
+
+type procMacroInterface interface {
+}
+
+var _ compiler = (*procMacroDecorator)(nil)
+
+func ProcMacroFactory() android.Module {
+ module, _ := NewProcMacro(android.HostSupportedNoCross)
+ return module.Init()
+}
+
+func NewProcMacro(hod android.HostOrDeviceSupported) (*Module, *procMacroDecorator) {
+ module := newModule(hod, android.MultilibFirst)
+
+ procMacro := &procMacroDecorator{
+ baseCompiler: NewBaseCompiler("lib", "lib64"),
+ }
+
+ module.compiler = procMacro
+
+ return module, procMacro
+}
+
+func (procMacro *procMacroDecorator) compilerProps() []interface{} {
+ return append(procMacro.baseCompiler.compilerProps(),
+ &procMacro.Properties)
+}
+
+func (procMacro *procMacroDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path {
+ fileName := procMacro.getStem(ctx) + ctx.toolchain().ProcMacroSuffix()
+ outputFile := android.PathForModuleOut(ctx, fileName)
+
+ srcPath := srcPathFromModuleSrcs(ctx, procMacro.Properties.Srcs)
+
+ procMacro.unstrippedOutputFile = outputFile
+
+ TransformSrctoProcMacro(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
+ return outputFile
+}
diff --git a/rust/rust.go b/rust/rust.go
new file mode 100644
index 0000000..707de4b
--- /dev/null
+++ b/rust/rust.go
@@ -0,0 +1,511 @@
+// Copyright 2019 The Android Open Source Project
+//
+// 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 rust
+
+import (
+ "strings"
+
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
+
+ "android/soong/android"
+ "android/soong/cc"
+ "android/soong/rust/config"
+)
+
+var pctx = android.NewPackageContext("android/soong/rust")
+
+func init() {
+ // Only allow rust modules to be defined for certain projects
+
+ android.AddNeverAllowRules(
+ android.NeverAllow().
+ NotIn(config.RustAllowedPaths...).
+ ModuleType(config.RustModuleTypes...))
+
+ android.RegisterModuleType("rust_defaults", defaultsFactory)
+ android.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.BottomUp("rust_libraries", LibraryMutator).Parallel()
+ })
+ pctx.Import("android/soong/rust/config")
+}
+
+type Flags struct {
+ GlobalRustFlags []string // Flags that apply globally to rust
+ GlobalLinkFlags []string // Flags that apply globally to linker
+ RustFlags []string // Flags that apply to rust
+ LinkFlags []string // Flags that apply to linker
+ RustFlagsDeps android.Paths // Files depended on by compiler flags
+ Toolchain config.Toolchain
+}
+
+type BaseProperties struct {
+ AndroidMkRlibs []string
+ AndroidMkDylibs []string
+ AndroidMkProcMacroLibs []string
+ AndroidMkSharedLibs []string
+ AndroidMkStaticLibs []string
+}
+
+type Module struct {
+ android.ModuleBase
+ android.DefaultableModuleBase
+
+ Properties BaseProperties
+
+ hod android.HostOrDeviceSupported
+ multilib android.Multilib
+
+ compiler compiler
+ cachedToolchain config.Toolchain
+ subAndroidMkOnce map[subAndroidMkProvider]bool
+ outputFile android.OptionalPath
+}
+
+type Deps struct {
+ Dylibs []string
+ Rlibs []string
+ ProcMacros []string
+ SharedLibs []string
+ StaticLibs []string
+
+ CrtBegin, CrtEnd string
+}
+
+type PathDeps struct {
+ DyLibs RustLibraries
+ RLibs RustLibraries
+ SharedLibs android.Paths
+ StaticLibs android.Paths
+ ProcMacros RustLibraries
+ linkDirs []string
+ depFlags []string
+ //ReexportedDeps android.Paths
+
+ CrtBegin android.OptionalPath
+ CrtEnd android.OptionalPath
+}
+
+type RustLibraries []RustLibrary
+
+type RustLibrary struct {
+ Path android.Path
+ CrateName string
+}
+
+type compiler interface {
+ compilerFlags(ctx ModuleContext, flags Flags) Flags
+ compilerProps() []interface{}
+ compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path
+ compilerDeps(ctx DepsContext, deps Deps) Deps
+ crateName() string
+
+ install(ctx ModuleContext, path android.Path)
+ relativeInstallPath() string
+}
+
+func defaultsFactory() android.Module {
+ return DefaultsFactory()
+}
+
+type Defaults struct {
+ android.ModuleBase
+ android.DefaultsModuleBase
+}
+
+func DefaultsFactory(props ...interface{}) android.Module {
+ module := &Defaults{}
+
+ module.AddProperties(props...)
+ module.AddProperties(
+ &BaseProperties{},
+ &BaseCompilerProperties{},
+ &BinaryCompilerProperties{},
+ &LibraryCompilerProperties{},
+ &ProcMacroCompilerProperties{},
+ &PrebuiltProperties{},
+ )
+
+ android.InitDefaultsModule(module)
+ return module
+}
+
+func (mod *Module) CrateName() string {
+ if mod.compiler != nil && mod.compiler.crateName() != "" {
+ return mod.compiler.crateName()
+ }
+ // Default crate names replace '-' in the name to '_'
+ return strings.Replace(mod.BaseModuleName(), "-", "_", -1)
+}
+
+func (mod *Module) Init() android.Module {
+ mod.AddProperties(&mod.Properties)
+
+ if mod.compiler != nil {
+ mod.AddProperties(mod.compiler.compilerProps()...)
+ }
+ android.InitAndroidArchModule(mod, mod.hod, mod.multilib)
+
+ android.InitDefaultableModule(mod)
+
+ // Explicitly disable unsupported targets.
+ android.AddLoadHook(mod, func(ctx android.LoadHookContext) {
+ disableTargets := struct {
+ Target struct {
+ Linux_bionic struct {
+ Enabled *bool
+ }
+ }
+ }{}
+ disableTargets.Target.Linux_bionic.Enabled = proptools.BoolPtr(false)
+
+ ctx.AppendProperties(&disableTargets)
+ })
+
+ return mod
+}
+
+func newBaseModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Module {
+ return &Module{
+ hod: hod,
+ multilib: multilib,
+ }
+}
+func newModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Module {
+ module := newBaseModule(hod, multilib)
+ return module
+}
+
+type ModuleContext interface {
+ android.ModuleContext
+ ModuleContextIntf
+}
+
+type BaseModuleContext interface {
+ android.BaseModuleContext
+ ModuleContextIntf
+}
+
+type DepsContext interface {
+ android.BottomUpMutatorContext
+ ModuleContextIntf
+}
+
+type ModuleContextIntf interface {
+ toolchain() config.Toolchain
+ baseModuleName() string
+ CrateName() string
+}
+
+type depsContext struct {
+ android.BottomUpMutatorContext
+ moduleContextImpl
+}
+
+type moduleContext struct {
+ android.ModuleContext
+ moduleContextImpl
+}
+
+type moduleContextImpl struct {
+ mod *Module
+ ctx BaseModuleContext
+}
+
+func (ctx *moduleContextImpl) toolchain() config.Toolchain {
+ return ctx.mod.toolchain(ctx.ctx)
+}
+
+func (mod *Module) toolchain(ctx android.BaseModuleContext) config.Toolchain {
+ if mod.cachedToolchain == nil {
+ mod.cachedToolchain = config.FindToolchain(ctx.Os(), ctx.Arch())
+ }
+ return mod.cachedToolchain
+}
+
+func (d *Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+}
+
+func (mod *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
+ ctx := &moduleContext{
+ ModuleContext: actx,
+ moduleContextImpl: moduleContextImpl{
+ mod: mod,
+ },
+ }
+ ctx.ctx = ctx
+
+ toolchain := mod.toolchain(ctx)
+
+ if !toolchain.Supported() {
+ // This toolchain's unsupported, there's nothing to do for this mod.
+ return
+ }
+
+ deps := mod.depsToPaths(ctx)
+ flags := Flags{
+ Toolchain: toolchain,
+ }
+
+ if mod.compiler != nil {
+ flags = mod.compiler.compilerFlags(ctx, flags)
+ outputFile := mod.compiler.compile(ctx, flags, deps)
+ mod.outputFile = android.OptionalPathForPath(outputFile)
+ mod.compiler.install(ctx, mod.outputFile.Path())
+ }
+}
+
+func (mod *Module) deps(ctx DepsContext) Deps {
+ deps := Deps{}
+
+ if mod.compiler != nil {
+ deps = mod.compiler.compilerDeps(ctx, deps)
+ }
+
+ deps.Rlibs = android.LastUniqueStrings(deps.Rlibs)
+ deps.Dylibs = android.LastUniqueStrings(deps.Dylibs)
+ deps.ProcMacros = android.LastUniqueStrings(deps.ProcMacros)
+ deps.SharedLibs = android.LastUniqueStrings(deps.SharedLibs)
+ deps.StaticLibs = android.LastUniqueStrings(deps.StaticLibs)
+
+ return deps
+
+}
+
+func (ctx *moduleContextImpl) baseModuleName() string {
+ return ctx.mod.ModuleBase.BaseModuleName()
+}
+
+func (ctx *moduleContextImpl) CrateName() string {
+ return ctx.mod.CrateName()
+}
+
+type dependencyTag struct {
+ blueprint.BaseDependencyTag
+ name string
+ library bool
+ proc_macro bool
+}
+
+var (
+ rlibDepTag = dependencyTag{name: "rlibTag", library: true}
+ dylibDepTag = dependencyTag{name: "dylib", library: true}
+ procMacroDepTag = dependencyTag{name: "procMacro", proc_macro: true}
+)
+
+func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
+ var depPaths PathDeps
+
+ directRlibDeps := []*Module{}
+ directDylibDeps := []*Module{}
+ directProcMacroDeps := []*Module{}
+ directSharedLibDeps := []*(cc.Module){}
+ directStaticLibDeps := []*(cc.Module){}
+
+ ctx.VisitDirectDeps(func(dep android.Module) {
+ depName := ctx.OtherModuleName(dep)
+ depTag := ctx.OtherModuleDependencyTag(dep)
+
+ if rustDep, ok := dep.(*Module); ok {
+ //Handle Rust Modules
+
+ linkFile := rustDep.outputFile
+ if !linkFile.Valid() {
+ ctx.ModuleErrorf("Invalid output file when adding dep %q to %q", depName, ctx.ModuleName())
+ }
+
+ switch depTag {
+ case dylibDepTag:
+ dylib, ok := rustDep.compiler.(libraryInterface)
+ if !ok || !dylib.dylib() {
+ ctx.ModuleErrorf("mod %q not an dylib library", depName)
+ return
+ }
+ directDylibDeps = append(directDylibDeps, rustDep)
+ mod.Properties.AndroidMkDylibs = append(mod.Properties.AndroidMkDylibs, depName)
+ case rlibDepTag:
+ rlib, ok := rustDep.compiler.(libraryInterface)
+ if !ok || !rlib.rlib() {
+ ctx.ModuleErrorf("mod %q not an rlib library", depName)
+ return
+ }
+ directRlibDeps = append(directRlibDeps, rustDep)
+ mod.Properties.AndroidMkRlibs = append(mod.Properties.AndroidMkRlibs, depName)
+ case procMacroDepTag:
+ directProcMacroDeps = append(directProcMacroDeps, rustDep)
+ mod.Properties.AndroidMkProcMacroLibs = append(mod.Properties.AndroidMkProcMacroLibs, depName)
+ }
+
+ //Append the dependencies exportedDirs
+ if lib, ok := rustDep.compiler.(*libraryDecorator); ok {
+ depPaths.linkDirs = append(depPaths.linkDirs, lib.exportedDirs()...)
+ depPaths.depFlags = append(depPaths.depFlags, lib.exportedDepFlags()...)
+ }
+
+ // Append this dependencies output to this mod's linkDirs so they can be exported to dependencies
+ // This can be probably be refactored by defining a common exporter interface similar to cc's
+ if depTag == dylibDepTag || depTag == rlibDepTag || depTag == procMacroDepTag {
+ linkDir := linkPathFromFilePath(linkFile.Path())
+ if lib, ok := mod.compiler.(*libraryDecorator); ok {
+ lib.linkDirs = append(lib.linkDirs, linkDir)
+ } else if procMacro, ok := mod.compiler.(*procMacroDecorator); ok {
+ procMacro.linkDirs = append(procMacro.linkDirs, linkDir)
+ }
+ }
+
+ } else if ccDep, ok := dep.(*cc.Module); ok {
+ //Handle C dependencies
+
+ if ccDep.Target().Os != ctx.Os() {
+ ctx.ModuleErrorf("OS mismatch between %q and %q", ctx.ModuleName(), depName)
+ return
+ }
+ if ccDep.Target().Arch.ArchType != ctx.Arch().ArchType {
+ ctx.ModuleErrorf("Arch mismatch between %q and %q", ctx.ModuleName(), depName)
+ return
+ }
+
+ linkFile := ccDep.OutputFile()
+ linkPath := linkPathFromFilePath(linkFile.Path())
+ libName := libNameFromFilePath(linkFile.Path())
+ if !linkFile.Valid() {
+ ctx.ModuleErrorf("Invalid output file when adding dep %q to %q", depName, ctx.ModuleName())
+ }
+
+ exportDep := false
+
+ switch depTag {
+ case cc.StaticDepTag():
+ depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
+ depPaths.depFlags = append(depPaths.depFlags, "-l"+libName)
+ directStaticLibDeps = append(directStaticLibDeps, ccDep)
+ mod.Properties.AndroidMkStaticLibs = append(mod.Properties.AndroidMkStaticLibs, depName)
+ case cc.SharedDepTag():
+ depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
+ depPaths.depFlags = append(depPaths.depFlags, "-l"+libName)
+ directSharedLibDeps = append(directSharedLibDeps, ccDep)
+ mod.Properties.AndroidMkSharedLibs = append(mod.Properties.AndroidMkSharedLibs, depName)
+ exportDep = true
+ case cc.CrtBeginDepTag():
+ depPaths.CrtBegin = linkFile
+ case cc.CrtEndDepTag():
+ depPaths.CrtEnd = linkFile
+ }
+
+ // Make sure these dependencies are propagated
+ if lib, ok := mod.compiler.(*libraryDecorator); ok && (exportDep || lib.rlib()) {
+ lib.linkDirs = append(lib.linkDirs, linkPath)
+ lib.depFlags = append(lib.depFlags, "-l"+libName)
+ } else if procMacro, ok := mod.compiler.(*procMacroDecorator); ok && exportDep {
+ procMacro.linkDirs = append(procMacro.linkDirs, linkPath)
+ procMacro.depFlags = append(procMacro.depFlags, "-l"+libName)
+ }
+
+ }
+ })
+
+ var rlibDepFiles RustLibraries
+ for _, dep := range directRlibDeps {
+ rlibDepFiles = append(rlibDepFiles, RustLibrary{Path: dep.outputFile.Path(), CrateName: dep.CrateName()})
+ }
+ var dylibDepFiles RustLibraries
+ for _, dep := range directDylibDeps {
+ dylibDepFiles = append(dylibDepFiles, RustLibrary{Path: dep.outputFile.Path(), CrateName: dep.CrateName()})
+ }
+ var procMacroDepFiles RustLibraries
+ for _, dep := range directProcMacroDeps {
+ procMacroDepFiles = append(procMacroDepFiles, RustLibrary{Path: dep.outputFile.Path(), CrateName: dep.CrateName()})
+ }
+
+ var staticLibDepFiles android.Paths
+ for _, dep := range directStaticLibDeps {
+ staticLibDepFiles = append(staticLibDepFiles, dep.OutputFile().Path())
+ }
+
+ var sharedLibDepFiles android.Paths
+ for _, dep := range directSharedLibDeps {
+ sharedLibDepFiles = append(sharedLibDepFiles, dep.OutputFile().Path())
+ }
+
+ depPaths.RLibs = append(depPaths.RLibs, rlibDepFiles...)
+ depPaths.DyLibs = append(depPaths.DyLibs, dylibDepFiles...)
+ depPaths.SharedLibs = append(depPaths.SharedLibs, sharedLibDepFiles...)
+ depPaths.StaticLibs = append(depPaths.StaticLibs, staticLibDepFiles...)
+ depPaths.ProcMacros = append(depPaths.ProcMacros, procMacroDepFiles...)
+
+ // Dedup exported flags from dependencies
+ depPaths.linkDirs = android.FirstUniqueStrings(depPaths.linkDirs)
+ depPaths.depFlags = android.FirstUniqueStrings(depPaths.depFlags)
+
+ return depPaths
+}
+
+func linkPathFromFilePath(filepath android.Path) string {
+ return strings.Split(filepath.String(), filepath.Base())[0]
+}
+func libNameFromFilePath(filepath android.Path) string {
+ libName := strings.Split(filepath.Base(), filepath.Ext())[0]
+ if strings.Contains(libName, "lib") {
+ libName = strings.Split(libName, "lib")[1]
+ }
+ return libName
+}
+func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) {
+ ctx := &depsContext{
+ BottomUpMutatorContext: actx,
+ moduleContextImpl: moduleContextImpl{
+ mod: mod,
+ },
+ }
+ ctx.ctx = ctx
+
+ deps := mod.deps(ctx)
+
+ actx.AddVariationDependencies([]blueprint.Variation{{Mutator: "rust_libraries", Variation: "rlib"}}, rlibDepTag, deps.Rlibs...)
+ actx.AddVariationDependencies([]blueprint.Variation{{Mutator: "rust_libraries", Variation: "dylib"}}, dylibDepTag, deps.Dylibs...)
+
+ ccDepVariations := []blueprint.Variation{}
+ ccDepVariations = append(ccDepVariations, blueprint.Variation{Mutator: "version", Variation: ""})
+ if !mod.Host() {
+ ccDepVariations = append(ccDepVariations, blueprint.Variation{Mutator: "image", Variation: "core"})
+ }
+ actx.AddVariationDependencies(append(ccDepVariations, blueprint.Variation{Mutator: "link", Variation: "shared"}), cc.SharedDepTag(), deps.SharedLibs...)
+ actx.AddVariationDependencies(append(ccDepVariations, blueprint.Variation{Mutator: "link", Variation: "static"}), cc.StaticDepTag(), deps.StaticLibs...)
+
+ if deps.CrtBegin != "" {
+ actx.AddVariationDependencies(ccDepVariations, cc.CrtBeginDepTag(), deps.CrtBegin)
+ }
+ if deps.CrtEnd != "" {
+ actx.AddVariationDependencies(ccDepVariations, cc.CrtEndDepTag(), deps.CrtEnd)
+ }
+
+ // proc_macros are compiler plugins, and so we need the host arch variant as a dependendcy.
+ actx.AddFarVariationDependencies(ctx.Config().BuildOSTarget.Variations(), procMacroDepTag, deps.ProcMacros...)
+}
+
+func (mod *Module) Name() string {
+ name := mod.ModuleBase.Name()
+ if p, ok := mod.compiler.(interface {
+ Name(string) string
+ }); ok {
+ name = p.Name(name)
+ }
+ return name
+}
+
+var Bool = proptools.Bool
+var BoolDefault = proptools.BoolDefault
+var String = proptools.String
+var StringPtr = proptools.StringPtr
diff --git a/rust/rust_test.go b/rust/rust_test.go
new file mode 100644
index 0000000..0c8d355
--- /dev/null
+++ b/rust/rust_test.go
@@ -0,0 +1,203 @@
+// Copyright 2019 The Android Open Source Project
+//
+// 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 rust
+
+import (
+ "io/ioutil"
+ "os"
+ "runtime"
+ "strings"
+ "testing"
+
+ "android/soong/android"
+)
+
+var (
+ buildDir string
+)
+
+func setUp() {
+ var err error
+ buildDir, err = ioutil.TempDir("", "soong_rust_test")
+ if err != nil {
+ panic(err)
+ }
+}
+
+func tearDown() {
+ os.RemoveAll(buildDir)
+}
+
+func TestMain(m *testing.M) {
+ run := func() int {
+ setUp()
+ defer tearDown()
+
+ return m.Run()
+ }
+
+ os.Exit(run())
+}
+
+func testRust(t *testing.T, bp string) *android.TestContext {
+ // TODO (b/140435149)
+ if runtime.GOOS != "linux" {
+ t.Skip("Only the Linux toolchain is supported for Rust")
+ }
+
+ t.Helper()
+ config := android.TestArchConfig(buildDir, nil)
+
+ t.Helper()
+ ctx := CreateTestContext(bp)
+ ctx.Register()
+
+ _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+ android.FailIfErrored(t, errs)
+ _, errs = ctx.PrepareBuildActions(config)
+ android.FailIfErrored(t, errs)
+
+ return ctx
+}
+
+func testRustError(t *testing.T, pattern string, bp string) {
+ // TODO (b/140435149)
+ if runtime.GOOS != "linux" {
+ t.Skip("Only the Linux toolchain is supported for Rust")
+ }
+
+ t.Helper()
+ config := android.TestArchConfig(buildDir, nil)
+
+ ctx := CreateTestContext(bp)
+ ctx.Register()
+
+ _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+ if len(errs) > 0 {
+ android.FailIfNoMatchingErrors(t, pattern, errs)
+ return
+ }
+
+ _, errs = ctx.PrepareBuildActions(config)
+ if len(errs) > 0 {
+ android.FailIfNoMatchingErrors(t, pattern, errs)
+ return
+ }
+
+ t.Fatalf("missing expected error %q (0 errors are returned)", pattern)
+}
+
+// Test that we can extract the lib name from a lib path.
+func TestLibNameFromFilePath(t *testing.T) {
+ barPath := android.PathForTesting("out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/libbar.so")
+ libName := libNameFromFilePath(barPath)
+ expectedResult := "bar"
+
+ if libName != expectedResult {
+ t.Errorf("libNameFromFilePath returned the wrong name; expected '%#v', got '%#v'", expectedResult, libName)
+ }
+}
+
+// Test that we can extract the link path from a lib path.
+func TestLinkPathFromFilePath(t *testing.T) {
+ barPath := android.PathForTesting("out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/libbar.so")
+ libName := linkPathFromFilePath(barPath)
+ expectedResult := "out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/"
+
+ if libName != expectedResult {
+ t.Errorf("libNameFromFilePath returned the wrong name; expected '%#v', got '%#v'", expectedResult, libName)
+ }
+}
+
+// Test default crate names from module names are generated correctly.
+func TestDefaultCrateName(t *testing.T) {
+ ctx := testRust(t, `
+ rust_library_host_dylib {
+ name: "fizz-buzz",
+ srcs: ["foo.rs"],
+ }`)
+ module := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64_dylib").Module().(*Module)
+ crateName := module.CrateName()
+ expectedResult := "fizz_buzz"
+
+ if crateName != expectedResult {
+ t.Errorf("CrateName() returned the wrong default crate name; expected '%#v', got '%#v'", expectedResult, crateName)
+ }
+}
+
+// Test to make sure dependencies are being picked up correctly.
+func TestDepsTracking(t *testing.T) {
+ ctx := testRust(t, `
+ rust_library_host_dylib {
+ name: "libfoo",
+ srcs: ["foo.rs"],
+ }
+ rust_library_host_rlib {
+ name: "libbar",
+ srcs: ["foo.rs"],
+ }
+ rust_proc_macro {
+ name: "libpm",
+ srcs: ["foo.rs"],
+ }
+ rust_binary_host {
+ name: "fizz-buzz",
+ dylibs: ["libfoo"],
+ rlibs: ["libbar"],
+ proc_macros: ["libpm"],
+ srcs: ["foo.rs"],
+ }
+ `)
+ module := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module)
+
+ // Since dependencies are added to AndroidMk* properties, we can check these to see if they've been picked up.
+ if !android.InList("libfoo", module.Properties.AndroidMkDylibs) {
+ t.Errorf("Dylib dependency not detected (dependency missing from AndroidMkDylibs)")
+ }
+
+ if !android.InList("libbar", module.Properties.AndroidMkRlibs) {
+ t.Errorf("Rlib dependency not detected (dependency missing from AndroidMkRlibs)")
+ }
+
+ if !android.InList("libpm", module.Properties.AndroidMkProcMacroLibs) {
+ t.Errorf("Proc_macro dependency not detected (dependency missing from AndroidMkProcMacroLibs)")
+ }
+
+}
+
+// Test to make sure proc_macros use host variants when building device modules.
+func TestProcMacroDeviceDeps(t *testing.T) {
+ ctx := testRust(t, `
+ rust_library_host_rlib {
+ name: "libbar",
+ srcs: ["foo.rs"],
+ }
+ rust_proc_macro {
+ name: "libpm",
+ rlibs: ["libbar"],
+ srcs: ["foo.rs"],
+ }
+ rust_binary {
+ name: "fizz-buzz",
+ proc_macros: ["libpm"],
+ srcs: ["foo.rs"],
+ }
+ `)
+ rustc := ctx.ModuleForTests("libpm", "linux_glibc_x86_64").Rule("rustc")
+
+ if !strings.Contains(rustc.Args["libFlags"], "libbar/linux_glibc_x86_64") {
+ t.Errorf("Proc_macro is not using host variant of dependent modules.")
+ }
+}
diff --git a/rust/testing.go b/rust/testing.go
new file mode 100644
index 0000000..92347f1
--- /dev/null
+++ b/rust/testing.go
@@ -0,0 +1,202 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// 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 rust
+
+import (
+ "android/soong/android"
+ "android/soong/cc"
+)
+
+func GatherRequiredDepsForTest() string {
+ bp := `
+ rust_prebuilt_dylib {
+ name: "libarena_x86_64-unknown-linux-gnu",
+ srcs: [""],
+ host_supported: true,
+ }
+ rust_prebuilt_dylib {
+ name: "libfmt_macros_x86_64-unknown-linux-gnu",
+ srcs: [""],
+ host_supported: true,
+ }
+ rust_prebuilt_dylib {
+ name: "libgraphviz_x86_64-unknown-linux-gnu",
+ srcs: [""],
+ host_supported: true,
+ }
+ rust_prebuilt_dylib {
+ name: "libserialize_x86_64-unknown-linux-gnu",
+ srcs: [""],
+ host_supported: true,
+ }
+ rust_prebuilt_dylib {
+ name: "libstd_x86_64-unknown-linux-gnu",
+ srcs: [""],
+ host_supported: true,
+ }
+ rust_prebuilt_dylib {
+ name: "libsyntax_x86_64-unknown-linux-gnu",
+ srcs: [""],
+ host_supported: true,
+ }
+ rust_prebuilt_dylib {
+ name: "libsyntax_ext_x86_64-unknown-linux-gnu",
+ srcs: [""],
+ host_supported: true,
+ }
+ rust_prebuilt_dylib {
+ name: "libsyntax_pos_x86_64-unknown-linux-gnu",
+ srcs: [""],
+ host_supported: true,
+ }
+ rust_prebuilt_dylib {
+ name: "libterm_x86_64-unknown-linux-gnu",
+ srcs: [""],
+ host_supported: true,
+ }
+ rust_prebuilt_dylib {
+ name: "libtest_x86_64-unknown-linux-gnu",
+ srcs: [""],
+ host_supported: true,
+ }
+
+ //////////////////////////////
+ // Device module requirements
+
+ toolchain_library {
+ name: "libgcc",
+ no_libcrt: true,
+ nocrt: true,
+ src: "",
+ system_shared_libs: [],
+ }
+ cc_library {
+ name: "libc",
+ no_libcrt: true,
+ nocrt: true,
+ system_shared_libs: [],
+ }
+ cc_library {
+ name: "libm",
+ no_libcrt: true,
+ nocrt: true,
+ system_shared_libs: [],
+ }
+ cc_library {
+ name: "libdl",
+ no_libcrt: true,
+ nocrt: true,
+ system_shared_libs: [],
+ }
+ cc_object {
+ name: "crtbegin_dynamic",
+ }
+
+ cc_object {
+ name: "crtend_android",
+ }
+ cc_library {
+ name: "liblog",
+ no_libcrt: true,
+ nocrt: true,
+ system_shared_libs: [],
+ }
+
+ //////////////////////////////
+ // cc module requirements
+
+ toolchain_library {
+ name: "libatomic",
+ src: "",
+ }
+ toolchain_library {
+ name: "libclang_rt.builtins-aarch64-android",
+ src: "",
+ }
+ toolchain_library {
+ name: "libgcc_stripped",
+ src: "",
+ }
+ cc_library {
+ name: "libc++_static",
+ no_libcrt: true,
+ nocrt: true,
+ system_shared_libs: [],
+ stl: "none",
+ }
+ cc_library {
+ name: "libc++demangle",
+ no_libcrt: true,
+ nocrt: true,
+ system_shared_libs: [],
+ stl: "none",
+ host_supported: false,
+ }
+ cc_library {
+ name: "libc++",
+ no_libcrt: true,
+ nocrt: true,
+ system_shared_libs: [],
+ stl: "none",
+ }
+ cc_library {
+ name: "libunwind_llvm",
+ no_libcrt: true,
+ nocrt: true,
+ system_shared_libs: [],
+ stl: "none",
+ }
+ `
+ return bp
+}
+
+func CreateTestContext(bp string) *android.TestContext {
+ ctx := android.NewTestArchContext()
+ ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(cc.LibraryFactory))
+ ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(cc.ObjectFactory))
+ ctx.RegisterModuleType("rust_binary", android.ModuleFactoryAdaptor(RustBinaryFactory))
+ ctx.RegisterModuleType("rust_binary_host", android.ModuleFactoryAdaptor(RustBinaryHostFactory))
+ ctx.RegisterModuleType("rust_library", android.ModuleFactoryAdaptor(RustLibraryFactory))
+ ctx.RegisterModuleType("rust_library_host", android.ModuleFactoryAdaptor(RustLibraryHostFactory))
+ ctx.RegisterModuleType("rust_library_host_rlib", android.ModuleFactoryAdaptor(RustLibraryRlibHostFactory))
+ ctx.RegisterModuleType("rust_library_host_dylib", android.ModuleFactoryAdaptor(RustLibraryDylibHostFactory))
+ ctx.RegisterModuleType("rust_library_rlib", android.ModuleFactoryAdaptor(RustLibraryRlibFactory))
+ ctx.RegisterModuleType("rust_library_dylib", android.ModuleFactoryAdaptor(RustLibraryDylibFactory))
+ ctx.RegisterModuleType("rust_proc_macro", android.ModuleFactoryAdaptor(ProcMacroFactory))
+ ctx.RegisterModuleType("rust_prebuilt_dylib", android.ModuleFactoryAdaptor(PrebuiltDylibFactory))
+ ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(cc.ToolchainLibraryFactory))
+ ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.BottomUp("rust_libraries", LibraryMutator).Parallel()
+
+ ctx.BottomUp("image", cc.ImageMutator).Parallel()
+ ctx.BottomUp("link", cc.LinkageMutator).Parallel()
+ ctx.BottomUp("version", cc.VersionMutator).Parallel()
+ ctx.BottomUp("begin", cc.BeginMutator).Parallel()
+ })
+
+ bp = bp + GatherRequiredDepsForTest()
+
+ mockFS := map[string][]byte{
+ "Android.bp": []byte(bp),
+ "foo.rs": nil,
+ "src/bar.rs": nil,
+ "liby.so": nil,
+ "libz.so": nil,
+ }
+
+ ctx.MockFileSystem(mockFS)
+
+ return ctx
+}
diff --git a/scripts/strip.sh b/scripts/strip.sh
index 4a1ed3f..40f0184 100755
--- a/scripts/strip.sh
+++ b/scripts/strip.sh
@@ -29,7 +29,6 @@
# --keep-mini-debug-info
# --keep-symbols
# --keep-symbols-and-debug-frame
-# --use-gnu-strip
# --remove-build-id
set -o pipefail
@@ -44,86 +43,55 @@
--keep-mini-debug-info Keep compressed debug info in out-file
--keep-symbols Keep symbols in out-file
--keep-symbols-and-debug-frame Keep symbols and .debug_frame in out-file
- --use-gnu-strip Use strip/objcopy instead of llvm-{strip,objcopy}
--remove-build-id Remove the gnu build-id section in out-file
EOF
exit 1
}
-# Without --use-gnu-strip, GNU strip is replaced with llvm-strip to work around
-# old GNU strip bug on lld output files, b/80093681.
-# Similary, calls to objcopy are replaced with llvm-objcopy,
-# with some exceptions.
-
do_strip() {
- # ${CROSS_COMPILE}strip --strip-all does not strip .ARM.attributes,
+ # GNU strip --strip-all does not strip .ARM.attributes,
# so we tell llvm-strip to keep it too.
- if [ -z "${use_gnu_strip}" ]; then
- "${CLANG_BIN}/llvm-strip" --strip-all --keep-section=.ARM.attributes "${infile}" -o "${outfile}.tmp"
- else
- "${CROSS_COMPILE}strip" --strip-all "${infile}" -o "${outfile}.tmp"
- fi
+ "${CLANG_BIN}/llvm-strip" --strip-all --keep-section=.ARM.attributes "${infile}" -o "${outfile}.tmp"
}
do_strip_keep_symbols_and_debug_frame() {
- REMOVE_SECTIONS=`"${CROSS_COMPILE}readelf" -S "${infile}" | awk '/.debug_/ {if ($2 != ".debug_frame") {print "--remove-section " $2}}' | xargs`
- if [ -z "${use_gnu_strip}" ]; then
- "${CLANG_BIN}/llvm-objcopy" "${infile}" "${outfile}.tmp" ${REMOVE_SECTIONS}
- else
- "${CROSS_COMPILE}objcopy" "${infile}" "${outfile}.tmp" ${REMOVE_SECTIONS}
- fi
+ REMOVE_SECTIONS=`"${CLANG_BIN}/llvm-readelf" -S "${infile}" | awk '/.debug_/ {if ($2 != ".debug_frame") {print "--remove-section " $2}}' | xargs`
+ "${CLANG_BIN}/llvm-objcopy" "${infile}" "${outfile}.tmp" ${REMOVE_SECTIONS}
}
do_strip_keep_symbols() {
- REMOVE_SECTIONS=`"${CROSS_COMPILE}readelf" -S "${infile}" | awk '/.debug_/ {print "--remove-section " $2}' | xargs`
- if [ -z "${use_gnu_strip}" ]; then
- "${CLANG_BIN}/llvm-objcopy" "${infile}" "${outfile}.tmp" ${REMOVE_SECTIONS}
- else
- "${CROSS_COMPILE}objcopy" "${infile}" "${outfile}.tmp" ${REMOVE_SECTIONS}
- fi
+ REMOVE_SECTIONS=`"${CLANG_BIN}/llvm-readelf" -S "${infile}" | awk '/.debug_/ {print "--remove-section " $2}' | xargs`
+ "${CLANG_BIN}/llvm-objcopy" "${infile}" "${outfile}.tmp" ${REMOVE_SECTIONS}
}
do_strip_keep_symbol_list() {
- if [ -z "${use_gnu_strip}" ]; then
- echo "do_strip_keep_symbol_list does not work with llvm-objcopy"
- echo "http://b/131631155"
- usage
- fi
-
echo "${symbols_to_keep}" | tr ',' '\n' > "${outfile}.symbolList"
- KEEP_SYMBOLS="-w --strip-unneeded-symbol=* --keep-symbols="
- KEEP_SYMBOLS+="${outfile}.symbolList"
- "${CROSS_COMPILE}objcopy" "${infile}" "${outfile}.tmp" ${KEEP_SYMBOLS}
+ KEEP_SYMBOLS="--strip-unneeded-symbol=* --keep-symbols="
+ KEEP_SYMBOLS+="${outfile}.symbolList"
+ "${CROSS_COMPILE}objcopy" -w "${infile}" "${outfile}.tmp" ${KEEP_SYMBOLS}
}
do_strip_keep_mini_debug_info() {
rm -f "${outfile}.dynsyms" "${outfile}.funcsyms" "${outfile}.keep_symbols" "${outfile}.debug" "${outfile}.mini_debuginfo" "${outfile}.mini_debuginfo.xz"
local fail=
- if [ -z "${use_gnu_strip}" ]; then
- "${CLANG_BIN}/llvm-strip" --strip-all --keep-section=.ARM.attributes --remove-section=.comment "${infile}" -o "${outfile}.tmp" || fail=true
- else
- "${CROSS_COMPILE}strip" --strip-all -R .comment "${infile}" -o "${outfile}.tmp" || fail=true
- fi
+ "${CLANG_BIN}/llvm-strip" --strip-all --keep-section=.ARM.attributes --remove-section=.comment "${infile}" -o "${outfile}.tmp" || fail=true
+
if [ -z $fail ]; then
- # Current prebult llvm-objcopy does not support the following flags:
- # --only-keep-debug --rename-section --keep-symbols
- # For the following use cases, ${CROSS_COMPILE}objcopy does fine with lld linked files,
- # except the --add-section flag.
+ # Current prebult llvm-objcopy does not support --only-keep-debug flag,
+ # and cannot process object files that are produced with the flag. Use
+ # GNU objcopy instead for now. (b/141010852)
"${CROSS_COMPILE}objcopy" --only-keep-debug "${infile}" "${outfile}.debug"
- "${CROSS_COMPILE}nm" -D "${infile}" --format=posix --defined-only 2> /dev/null | awk '{ print $1 }' | sort >"${outfile}.dynsyms"
- "${CROSS_COMPILE}nm" "${infile}" --format=posix --defined-only | awk '{ if ($2 == "T" || $2 == "t" || $2 == "D") print $1 }' | sort > "${outfile}.funcsyms"
+ "${CLANG_BIN}/llvm-nm" -D "${infile}" --format=posix --defined-only 2> /dev/null | awk '{ print $1 }' | sort >"${outfile}.dynsyms"
+ "${CLANG_BIN}/llvm-nm" "${infile}" --format=posix --defined-only | awk '{ if ($2 == "T" || $2 == "t" || $2 == "D") print $1 }' | sort > "${outfile}.funcsyms"
comm -13 "${outfile}.dynsyms" "${outfile}.funcsyms" > "${outfile}.keep_symbols"
echo >> "${outfile}.keep_symbols" # Ensure that the keep_symbols file is not empty.
"${CROSS_COMPILE}objcopy" --rename-section .debug_frame=saved_debug_frame "${outfile}.debug" "${outfile}.mini_debuginfo"
"${CROSS_COMPILE}objcopy" -S --remove-section .gdb_index --remove-section .comment --keep-symbols="${outfile}.keep_symbols" "${outfile}.mini_debuginfo"
"${CROSS_COMPILE}objcopy" --rename-section saved_debug_frame=.debug_frame "${outfile}.mini_debuginfo"
"${XZ}" "${outfile}.mini_debuginfo"
- if [ -z "${use_gnu_strip}" ]; then
- "${CLANG_BIN}/llvm-objcopy" --add-section .gnu_debugdata="${outfile}.mini_debuginfo.xz" "${outfile}.tmp"
- else
- "${CROSS_COMPILE}objcopy" --add-section .gnu_debugdata="${outfile}.mini_debuginfo.xz" "${outfile}.tmp"
- fi
+
+ "${CLANG_BIN}/llvm-objcopy" --add-section .gnu_debugdata="${outfile}.mini_debuginfo.xz" "${outfile}.tmp"
rm -f "${outfile}.dynsyms" "${outfile}.funcsyms" "${outfile}.keep_symbols" "${outfile}.debug" "${outfile}.mini_debuginfo" "${outfile}.mini_debuginfo.xz"
else
cp -f "${infile}" "${outfile}.tmp"
@@ -131,19 +99,11 @@
}
do_add_gnu_debuglink() {
- if [ -z "${use_gnu_strip}" ]; then
- "${CLANG_BIN}/llvm-objcopy" --add-gnu-debuglink="${infile}" "${outfile}.tmp"
- else
- "${CROSS_COMPILE}objcopy" --add-gnu-debuglink="${infile}" "${outfile}.tmp"
- fi
+ "${CLANG_BIN}/llvm-objcopy" --add-gnu-debuglink="${infile}" "${outfile}.tmp"
}
do_remove_build_id() {
- if [ -z "${use_gnu_strip}" ]; then
- "${CLANG_BIN}/llvm-strip" -remove-section=.note.gnu.build-id "${outfile}.tmp" -o "${outfile}.tmp.no-build-id"
- else
- "${CROSS_COMPILE}strip" --remove-section=.note.gnu.build-id "${outfile}.tmp" -o "${outfile}.tmp.no-build-id"
- fi
+ "${CLANG_BIN}/llvm-strip" --remove-section=.note.gnu.build-id "${outfile}.tmp" -o "${outfile}.tmp.no-build-id"
rm -f "${outfile}.tmp"
mv "${outfile}.tmp.no-build-id" "${outfile}.tmp"
}
@@ -161,7 +121,6 @@
keep-symbols) keep_symbols=true ;;
keep-symbols-and-debug-frame) keep_symbols_and_debug_frame=true ;;
remove-build-id) remove_build_id=true ;;
- use-gnu-strip) use_gnu_strip=true ;;
*) echo "Unknown option --${OPTARG}"; usage ;;
esac;;
?) usage ;;
@@ -234,18 +193,13 @@
rm -f "${outfile}"
mv "${outfile}.tmp" "${outfile}"
-if [ -z "${use_gnu_strip}" ]; then
- USED_STRIP_OBJCOPY="${CLANG_BIN}/llvm-strip ${CLANG_BIN}/llvm-objcopy"
-else
- USED_STRIP_OBJCOPY="${CROSS_COMPILE}strip"
-fi
-
cat <<EOF > "${depsfile}"
${outfile}: \
${infile} \
- ${CROSS_COMPILE}nm \
${CROSS_COMPILE}objcopy \
- ${CROSS_COMPILE}readelf \
- ${USED_STRIP_OBJCOPY}
+ ${CLANG_BIN}/llvm-nm \
+ ${CLANG_BIN}/llvm-objcopy \
+ ${CLANG_BIN}/llvm-readelf \
+ ${CLANG_BIN}/llvm-strip
EOF
diff --git a/sdk/sdk.go b/sdk/sdk.go
new file mode 100644
index 0000000..d189043
--- /dev/null
+++ b/sdk/sdk.go
@@ -0,0 +1,259 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// 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 sdk
+
+import (
+ "fmt"
+ "strconv"
+
+ "github.com/google/blueprint"
+
+ "android/soong/android"
+ // This package doesn't depend on the apex package, but import it to make its mutators to be
+ // registered before mutators in this package. See RegisterPostDepsMutators for more details.
+ _ "android/soong/apex"
+)
+
+func init() {
+ android.RegisterModuleType("sdk", ModuleFactory)
+ android.RegisterModuleType("sdk_snapshot", SnapshotModuleFactory)
+ android.PreDepsMutators(RegisterPreDepsMutators)
+ android.PostDepsMutators(RegisterPostDepsMutators)
+}
+
+type sdk struct {
+ android.ModuleBase
+ android.DefaultableModuleBase
+
+ properties sdkProperties
+
+ updateScript android.OutputPath
+ freezeScript android.OutputPath
+}
+
+type sdkProperties struct {
+ // The list of java libraries in this SDK
+ Java_libs []string
+ // The list of native libraries in this SDK
+ Native_shared_libs []string
+
+ Snapshot bool `blueprint:"mutated"`
+}
+
+// sdk defines an SDK which is a logical group of modules (e.g. native libs, headers, java libs, etc.)
+// which Mainline modules like APEX can choose to build with.
+func ModuleFactory() android.Module {
+ s := &sdk{}
+ s.AddProperties(&s.properties)
+ android.InitAndroidMultiTargetsArchModule(s, android.HostAndDeviceSupported, android.MultilibCommon)
+ android.InitDefaultableModule(s)
+ return s
+}
+
+// sdk_snapshot is a versioned snapshot of an SDK. This is an auto-generated module.
+func SnapshotModuleFactory() android.Module {
+ s := ModuleFactory()
+ s.(*sdk).properties.Snapshot = true
+ return s
+}
+
+func (s *sdk) snapshot() bool {
+ return s.properties.Snapshot
+}
+
+func (s *sdk) frozenVersions(ctx android.BaseModuleContext) []string {
+ if s.snapshot() {
+ panic(fmt.Errorf("frozenVersions() called for sdk_snapshot %q", ctx.ModuleName()))
+ }
+ versions := []string{}
+ ctx.WalkDeps(func(child android.Module, parent android.Module) bool {
+ depTag := ctx.OtherModuleDependencyTag(child)
+ if depTag == sdkMemberDepTag {
+ return true
+ }
+ if versionedDepTag, ok := depTag.(sdkMemberVesionedDepTag); ok {
+ v := versionedDepTag.version
+ if v != "current" && !android.InList(v, versions) {
+ versions = append(versions, versionedDepTag.version)
+ }
+ }
+ return false
+ })
+ return android.SortedUniqueStrings(versions)
+}
+
+func (s *sdk) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ s.buildSnapshotGenerationScripts(ctx)
+}
+
+func (s *sdk) AndroidMkEntries() android.AndroidMkEntries {
+ return s.androidMkEntriesForScript()
+}
+
+// RegisterPreDepsMutators registers pre-deps mutators to support modules implementing SdkAware
+// interface and the sdk module type. This function has been made public to be called by tests
+// outside of the sdk package
+func RegisterPreDepsMutators(ctx android.RegisterMutatorsContext) {
+ ctx.BottomUp("SdkMember", memberMutator).Parallel()
+ ctx.TopDown("SdkMember_deps", memberDepsMutator).Parallel()
+ ctx.BottomUp("SdkMemberInterVersion", memberInterVersionMutator).Parallel()
+}
+
+// RegisterPostDepshMutators registers post-deps mutators to support modules implementing SdkAware
+// interface and the sdk module type. This function has been made public to be called by tests
+// outside of the sdk package
+func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) {
+ // These must run AFTER apexMutator. Note that the apex package is imported even though there is
+ // no direct dependency to the package here. sdkDepsMutator sets the SDK requirements from an
+ // APEX to its dependents. Since different versions of the same SDK can be used by different
+ // APEXes, the apex and its dependents (which includes the dependencies to the sdk members)
+ // should have been mutated for the apex before the SDK requirements are set.
+ ctx.TopDown("SdkDepsMutator", sdkDepsMutator).Parallel()
+ ctx.BottomUp("SdkDepsReplaceMutator", sdkDepsReplaceMutator).Parallel()
+ ctx.TopDown("SdkRequirementCheck", sdkRequirementsMutator).Parallel()
+}
+
+type dependencyTag struct {
+ blueprint.BaseDependencyTag
+}
+
+// For dependencies from an SDK module to its members
+// e.g. mysdk -> libfoo and libbar
+var sdkMemberDepTag dependencyTag
+
+// For dependencies from an in-development version of an SDK member to frozen versions of the same member
+// e.g. libfoo -> libfoo.mysdk.11 and libfoo.mysdk.12
+type sdkMemberVesionedDepTag struct {
+ dependencyTag
+ member string
+ version string
+}
+
+// Step 1: create dependencies from an SDK module to its members.
+func memberMutator(mctx android.BottomUpMutatorContext) {
+ if m, ok := mctx.Module().(*sdk); ok {
+ mctx.AddVariationDependencies(nil, sdkMemberDepTag, m.properties.Java_libs...)
+
+ targets := mctx.MultiTargets()
+ for _, target := range targets {
+ mctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
+ {Mutator: "image", Variation: "core"},
+ {Mutator: "link", Variation: "shared"},
+ }...), sdkMemberDepTag, m.properties.Native_shared_libs...)
+ }
+ }
+}
+
+// Step 2: record that dependencies of SDK modules are members of the SDK modules
+func memberDepsMutator(mctx android.TopDownMutatorContext) {
+ if s, ok := mctx.Module().(*sdk); ok {
+ mySdkRef := android.ParseSdkRef(mctx, mctx.ModuleName(), "name")
+ if s.snapshot() && mySdkRef.Unversioned() {
+ mctx.PropertyErrorf("name", "sdk_snapshot should be named as <name>@<version>. "+
+ "Did you manually modify Android.bp?")
+ }
+ if !s.snapshot() && !mySdkRef.Unversioned() {
+ mctx.PropertyErrorf("name", "sdk shouldn't be named as <name>@<version>.")
+ }
+ if mySdkRef.Version != "" && mySdkRef.Version != "current" {
+ if _, err := strconv.Atoi(mySdkRef.Version); err != nil {
+ mctx.PropertyErrorf("name", "version %q is neither a number nor \"current\"", mySdkRef.Version)
+ }
+ }
+
+ mctx.VisitDirectDeps(func(child android.Module) {
+ if member, ok := child.(android.SdkAware); ok {
+ member.MakeMemberOf(mySdkRef)
+ }
+ })
+ }
+}
+
+// Step 3: create dependencies from the unversioned SDK member to snapshot versions
+// of the same member. By having these dependencies, they are mutated for multiple Mainline modules
+// (apex and apk), each of which might want different sdks to be built with. For example, if both
+// apex A and B are referencing libfoo which is a member of sdk 'mysdk', the two APEXes can be
+// built with libfoo.mysdk.11 and libfoo.mysdk.12, respectively depending on which sdk they are
+// using.
+func memberInterVersionMutator(mctx android.BottomUpMutatorContext) {
+ if m, ok := mctx.Module().(android.SdkAware); ok && m.IsInAnySdk() {
+ if !m.ContainingSdk().Unversioned() {
+ memberName := m.MemberName()
+ tag := sdkMemberVesionedDepTag{member: memberName, version: m.ContainingSdk().Version}
+ mctx.AddReverseDependency(mctx.Module(), tag, memberName)
+ }
+ }
+}
+
+// Step 4: transitively ripple down the SDK requirements from the root modules like APEX to its
+// descendants
+func sdkDepsMutator(mctx android.TopDownMutatorContext) {
+ if m, ok := mctx.Module().(android.SdkAware); ok {
+ // Module types for Mainline modules (e.g. APEX) are expected to implement RequiredSdks()
+ // by reading its own properties like `uses_sdks`.
+ requiredSdks := m.RequiredSdks()
+ if len(requiredSdks) > 0 {
+ mctx.VisitDirectDeps(func(m android.Module) {
+ if dep, ok := m.(android.SdkAware); ok {
+ dep.BuildWithSdks(requiredSdks)
+ }
+ })
+ }
+ }
+}
+
+// Step 5: if libfoo.mysdk.11 is in the context where version 11 of mysdk is requested, the
+// versioned module is used instead of the un-versioned (in-development) module libfoo
+func sdkDepsReplaceMutator(mctx android.BottomUpMutatorContext) {
+ if m, ok := mctx.Module().(android.SdkAware); ok && m.IsInAnySdk() {
+ if sdk := m.ContainingSdk(); !sdk.Unversioned() {
+ if m.RequiredSdks().Contains(sdk) {
+ // Note that this replacement is done only for the modules that have the same
+ // variations as the current module. Since current module is already mutated for
+ // apex references in other APEXes are not affected by this replacement.
+ memberName := m.MemberName()
+ mctx.ReplaceDependencies(memberName)
+ }
+ }
+ }
+}
+
+// Step 6: ensure that the dependencies from outside of the APEX are all from the required SDKs
+func sdkRequirementsMutator(mctx android.TopDownMutatorContext) {
+ if m, ok := mctx.Module().(interface {
+ DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool
+ RequiredSdks() android.SdkRefs
+ }); ok {
+ requiredSdks := m.RequiredSdks()
+ if len(requiredSdks) == 0 {
+ return
+ }
+ mctx.VisitDirectDeps(func(dep android.Module) {
+ if mctx.OtherModuleDependencyTag(dep) == android.DefaultsDepTag {
+ // dependency to defaults is always okay
+ return
+ }
+
+ // If the dep is from outside of the APEX, but is not in any of the
+ // required SDKs, we know that the dep is a violation.
+ if sa, ok := dep.(android.SdkAware); ok {
+ if !m.DepIsInSameApex(mctx, dep) && !requiredSdks.Contains(sa.ContainingSdk()) {
+ mctx.ModuleErrorf("depends on %q (in SDK %q) that isn't part of the required SDKs: %v",
+ sa.Name(), sa.ContainingSdk(), requiredSdks)
+ }
+ }
+ })
+ }
+}
diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go
new file mode 100644
index 0000000..664bb7c
--- /dev/null
+++ b/sdk/sdk_test.go
@@ -0,0 +1,403 @@
+// 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 sdk
+
+import (
+ "io/ioutil"
+ "os"
+ "strings"
+ "testing"
+
+ "android/soong/android"
+ "android/soong/apex"
+ "android/soong/cc"
+ "android/soong/java"
+)
+
+func testSdkContext(t *testing.T, bp string) (*android.TestContext, android.Config) {
+ config := android.TestArchConfig(buildDir, nil)
+ ctx := android.NewTestArchContext()
+
+ // from android package
+ ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
+ ctx.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.BottomUp("prebuilts", android.PrebuiltMutator).Parallel()
+ })
+ ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.TopDown("prebuilt_select", android.PrebuiltSelectModuleMutator).Parallel()
+ ctx.BottomUp("prebuilt_postdeps", android.PrebuiltPostDepsMutator).Parallel()
+ })
+
+ // from java package
+ ctx.RegisterModuleType("android_app_certificate", android.ModuleFactoryAdaptor(java.AndroidAppCertificateFactory))
+ ctx.RegisterModuleType("java_library", android.ModuleFactoryAdaptor(java.LibraryFactory))
+ ctx.RegisterModuleType("java_import", android.ModuleFactoryAdaptor(java.ImportFactory))
+
+ // from cc package
+ ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(cc.LibraryFactory))
+ ctx.RegisterModuleType("cc_library_shared", android.ModuleFactoryAdaptor(cc.LibrarySharedFactory))
+ ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(cc.ObjectFactory))
+ ctx.RegisterModuleType("cc_prebuilt_library_shared", android.ModuleFactoryAdaptor(cc.PrebuiltSharedLibraryFactory))
+ ctx.RegisterModuleType("cc_prebuilt_library_static", android.ModuleFactoryAdaptor(cc.PrebuiltStaticLibraryFactory))
+ ctx.RegisterModuleType("llndk_library", android.ModuleFactoryAdaptor(cc.LlndkLibraryFactory))
+ ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(cc.ToolchainLibraryFactory))
+ ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.BottomUp("image", cc.ImageMutator).Parallel()
+ ctx.BottomUp("link", cc.LinkageMutator).Parallel()
+ ctx.BottomUp("vndk", cc.VndkMutator).Parallel()
+ ctx.BottomUp("test_per_src", cc.TestPerSrcMutator).Parallel()
+ ctx.BottomUp("version", cc.VersionMutator).Parallel()
+ ctx.BottomUp("begin", cc.BeginMutator).Parallel()
+ })
+
+ // from apex package
+ ctx.RegisterModuleType("apex", android.ModuleFactoryAdaptor(apex.BundleFactory))
+ ctx.RegisterModuleType("apex_key", android.ModuleFactoryAdaptor(apex.ApexKeyFactory))
+ ctx.PostDepsMutators(apex.RegisterPostDepsMutators)
+
+ // from this package
+ ctx.RegisterModuleType("sdk", android.ModuleFactoryAdaptor(ModuleFactory))
+ ctx.RegisterModuleType("sdk_snapshot", android.ModuleFactoryAdaptor(SnapshotModuleFactory))
+ ctx.PreDepsMutators(RegisterPreDepsMutators)
+ ctx.PostDepsMutators(RegisterPostDepsMutators)
+
+ ctx.Register()
+
+ bp = bp + `
+ apex_key {
+ name: "myapex.key",
+ public_key: "myapex.avbpubkey",
+ private_key: "myapex.pem",
+ }
+
+ android_app_certificate {
+ name: "myapex.cert",
+ certificate: "myapex",
+ }
+ ` + cc.GatherRequiredDepsForTest(android.Android)
+
+ ctx.MockFileSystem(map[string][]byte{
+ "Android.bp": []byte(bp),
+ "build/make/target/product/security": nil,
+ "apex_manifest.json": nil,
+ "system/sepolicy/apex/myapex-file_contexts": nil,
+ "system/sepolicy/apex/myapex2-file_contexts": nil,
+ "myapex.avbpubkey": nil,
+ "myapex.pem": nil,
+ "myapex.x509.pem": nil,
+ "myapex.pk8": nil,
+ "Test.java": nil,
+ "Test.cpp": nil,
+ "libfoo.so": nil,
+ })
+
+ return ctx, config
+}
+
+func testSdk(t *testing.T, bp string) (*android.TestContext, android.Config) {
+ ctx, config := testSdkContext(t, bp)
+ _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+ android.FailIfErrored(t, errs)
+ _, errs = ctx.PrepareBuildActions(config)
+ android.FailIfErrored(t, errs)
+ return ctx, config
+}
+
+func testSdkError(t *testing.T, pattern, bp string) {
+ t.Helper()
+ ctx, config := testSdkContext(t, bp)
+ _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+ if len(errs) > 0 {
+ android.FailIfNoMatchingErrors(t, pattern, errs)
+ return
+ }
+ _, errs = ctx.PrepareBuildActions(config)
+ if len(errs) > 0 {
+ android.FailIfNoMatchingErrors(t, pattern, errs)
+ return
+ }
+
+ t.Fatalf("missing expected error %q (0 errors are returned)", pattern)
+}
+
+// ensure that 'result' contains 'expected'
+func ensureContains(t *testing.T, result string, expected string) {
+ t.Helper()
+ if !strings.Contains(result, expected) {
+ t.Errorf("%q is not found in %q", expected, result)
+ }
+}
+
+// ensures that 'result' does not contain 'notExpected'
+func ensureNotContains(t *testing.T, result string, notExpected string) {
+ t.Helper()
+ if strings.Contains(result, notExpected) {
+ t.Errorf("%q is found in %q", notExpected, result)
+ }
+}
+
+func ensureListContains(t *testing.T, result []string, expected string) {
+ t.Helper()
+ if !android.InList(expected, result) {
+ t.Errorf("%q is not found in %v", expected, result)
+ }
+}
+
+func ensureListNotContains(t *testing.T, result []string, notExpected string) {
+ t.Helper()
+ if android.InList(notExpected, result) {
+ t.Errorf("%q is found in %v", notExpected, result)
+ }
+}
+
+func pathsToStrings(paths android.Paths) []string {
+ ret := []string{}
+ for _, p := range paths {
+ ret = append(ret, p.String())
+ }
+ return ret
+}
+
+func TestBasicSdkWithJava(t *testing.T) {
+ ctx, _ := testSdk(t, `
+ sdk {
+ name: "mysdk",
+ java_libs: ["sdkmember"],
+ }
+
+ sdk_snapshot {
+ name: "mysdk@1",
+ java_libs: ["sdkmember_mysdk_1"],
+ }
+
+ sdk_snapshot {
+ name: "mysdk@2",
+ java_libs: ["sdkmember_mysdk_2"],
+ }
+
+ java_import {
+ name: "sdkmember",
+ prefer: false,
+ host_supported: true,
+ }
+
+ java_import {
+ name: "sdkmember_mysdk_1",
+ sdk_member_name: "sdkmember",
+ host_supported: true,
+ }
+
+ java_import {
+ name: "sdkmember_mysdk_2",
+ sdk_member_name: "sdkmember",
+ host_supported: true,
+ }
+
+ java_library {
+ name: "myjavalib",
+ srcs: ["Test.java"],
+ libs: ["sdkmember"],
+ system_modules: "none",
+ sdk_version: "none",
+ compile_dex: true,
+ host_supported: true,
+ }
+
+ apex {
+ name: "myapex",
+ java_libs: ["myjavalib"],
+ uses_sdks: ["mysdk@1"],
+ key: "myapex.key",
+ certificate: ":myapex.cert",
+ }
+
+ apex {
+ name: "myapex2",
+ java_libs: ["myjavalib"],
+ uses_sdks: ["mysdk@2"],
+ key: "myapex.key",
+ certificate: ":myapex.cert",
+ }
+ `)
+
+ sdkMemberV1 := ctx.ModuleForTests("sdkmember_mysdk_1", "android_common_myapex").Rule("combineJar").Output
+ sdkMemberV2 := ctx.ModuleForTests("sdkmember_mysdk_2", "android_common_myapex2").Rule("combineJar").Output
+
+ javalibForMyApex := ctx.ModuleForTests("myjavalib", "android_common_myapex")
+ javalibForMyApex2 := ctx.ModuleForTests("myjavalib", "android_common_myapex2")
+
+ // Depending on the uses_sdks value, different libs are linked
+ ensureListContains(t, pathsToStrings(javalibForMyApex.Rule("javac").Implicits), sdkMemberV1.String())
+ ensureListContains(t, pathsToStrings(javalibForMyApex2.Rule("javac").Implicits), sdkMemberV2.String())
+}
+
+func TestBasicSdkWithCc(t *testing.T) {
+ ctx, _ := testSdk(t, `
+ sdk {
+ name: "mysdk",
+ native_shared_libs: ["sdkmember"],
+ }
+
+ sdk_snapshot {
+ name: "mysdk@1",
+ native_shared_libs: ["sdkmember_mysdk_1"],
+ }
+
+ sdk_snapshot {
+ name: "mysdk@2",
+ native_shared_libs: ["sdkmember_mysdk_2"],
+ }
+
+ cc_prebuilt_library_shared {
+ name: "sdkmember",
+ srcs: ["libfoo.so"],
+ prefer: false,
+ system_shared_libs: [],
+ stl: "none",
+ }
+
+ cc_prebuilt_library_shared {
+ name: "sdkmember_mysdk_1",
+ sdk_member_name: "sdkmember",
+ srcs: ["libfoo.so"],
+ system_shared_libs: [],
+ stl: "none",
+ }
+
+ cc_prebuilt_library_shared {
+ name: "sdkmember_mysdk_2",
+ sdk_member_name: "sdkmember",
+ srcs: ["libfoo.so"],
+ system_shared_libs: [],
+ stl: "none",
+ }
+
+ cc_library_shared {
+ name: "mycpplib",
+ srcs: ["Test.cpp"],
+ shared_libs: ["sdkmember"],
+ system_shared_libs: [],
+ stl: "none",
+ }
+
+ apex {
+ name: "myapex",
+ native_shared_libs: ["mycpplib"],
+ uses_sdks: ["mysdk@1"],
+ key: "myapex.key",
+ certificate: ":myapex.cert",
+ }
+
+ apex {
+ name: "myapex2",
+ native_shared_libs: ["mycpplib"],
+ uses_sdks: ["mysdk@2"],
+ key: "myapex.key",
+ certificate: ":myapex.cert",
+ }
+ `)
+
+ sdkMemberV1 := ctx.ModuleForTests("sdkmember_mysdk_1", "android_arm64_armv8-a_core_shared_myapex").Rule("toc").Output
+ sdkMemberV2 := ctx.ModuleForTests("sdkmember_mysdk_2", "android_arm64_armv8-a_core_shared_myapex2").Rule("toc").Output
+
+ cpplibForMyApex := ctx.ModuleForTests("mycpplib", "android_arm64_armv8-a_core_shared_myapex")
+ cpplibForMyApex2 := ctx.ModuleForTests("mycpplib", "android_arm64_armv8-a_core_shared_myapex2")
+
+ // Depending on the uses_sdks value, different libs are linked
+ ensureListContains(t, pathsToStrings(cpplibForMyApex.Rule("ld").Implicits), sdkMemberV1.String())
+ ensureListContains(t, pathsToStrings(cpplibForMyApex2.Rule("ld").Implicits), sdkMemberV2.String())
+}
+
+func TestDepNotInRequiredSdks(t *testing.T) {
+ testSdkError(t, `module "myjavalib".*depends on "otherlib".*that isn't part of the required SDKs:.*`, `
+ sdk {
+ name: "mysdk",
+ java_libs: ["sdkmember"],
+ }
+
+ sdk_snapshot {
+ name: "mysdk@1",
+ java_libs: ["sdkmember_mysdk_1"],
+ }
+
+ java_import {
+ name: "sdkmember",
+ prefer: false,
+ host_supported: true,
+ }
+
+ java_import {
+ name: "sdkmember_mysdk_1",
+ sdk_member_name: "sdkmember",
+ host_supported: true,
+ }
+
+ java_library {
+ name: "myjavalib",
+ srcs: ["Test.java"],
+ libs: [
+ "sdkmember",
+ "otherlib",
+ ],
+ system_modules: "none",
+ sdk_version: "none",
+ compile_dex: true,
+ host_supported: true,
+ }
+
+ // this lib is no in mysdk
+ java_library {
+ name: "otherlib",
+ srcs: ["Test.java"],
+ system_modules: "none",
+ sdk_version: "none",
+ compile_dex: true,
+ host_supported: true,
+ }
+
+ apex {
+ name: "myapex",
+ java_libs: ["myjavalib"],
+ uses_sdks: ["mysdk@1"],
+ key: "myapex.key",
+ certificate: ":myapex.cert",
+ }
+ `)
+}
+
+var buildDir string
+
+func setUp() {
+ var err error
+ buildDir, err = ioutil.TempDir("", "soong_sdk_test")
+ if err != nil {
+ panic(err)
+ }
+}
+
+func tearDown() {
+ os.RemoveAll(buildDir)
+}
+
+func TestMain(m *testing.M) {
+ run := func() int {
+ setUp()
+ defer tearDown()
+
+ return m.Run()
+ }
+
+ os.Exit(run())
+}
diff --git a/sdk/update.go b/sdk/update.go
new file mode 100644
index 0000000..5235c9e
--- /dev/null
+++ b/sdk/update.go
@@ -0,0 +1,228 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// 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 sdk
+
+import (
+ "fmt"
+ "io"
+ "path/filepath"
+ "strconv"
+ "strings"
+
+ "github.com/google/blueprint/proptools"
+
+ "android/soong/android"
+ "android/soong/java"
+)
+
+var pctx = android.NewPackageContext("android/soong/sdk")
+
+// generatedFile abstracts operations for writing contents into a file and emit a build rule
+// for the file.
+type generatedFile struct {
+ path android.OutputPath
+ content strings.Builder
+}
+
+func newGeneratedFile(ctx android.ModuleContext, name string) *generatedFile {
+ return &generatedFile{
+ path: android.PathForModuleOut(ctx, name).OutputPath,
+ }
+}
+
+func (gf *generatedFile) printfln(format string, args ...interface{}) {
+ // ninja consumes newline characters in rspfile_content. Prevent it by
+ // escaping the backslash in the newline character. The extra backshash
+ // is removed when the rspfile is written to the actual script file
+ fmt.Fprintf(&(gf.content), format+"\\n", args...)
+}
+
+func (gf *generatedFile) build(pctx android.PackageContext, ctx android.BuilderContext, implicits android.Paths) {
+ rb := android.NewRuleBuilder()
+ // convert \\n to \n
+ rb.Command().
+ Implicits(implicits).
+ Text("echo").Text(proptools.ShellEscape(gf.content.String())).
+ Text("| sed 's/\\\\n/\\n/g' >").Output(gf.path)
+ rb.Command().
+ Text("chmod a+x").Output(gf.path)
+ rb.Build(pctx, ctx, gf.path.Base(), "Build "+gf.path.Base())
+}
+
+func (s *sdk) javaMemberNames(ctx android.ModuleContext) []string {
+ result := []string{}
+ ctx.VisitDirectDeps(func(m android.Module) {
+ if _, ok := m.(*java.Library); ok {
+ result = append(result, m.Name())
+ }
+ })
+ return result
+}
+
+// buildAndroidBp creates the blueprint file that defines prebuilt modules for each of
+// the SDK members, and the sdk_snapshot module for the specified version
+func (s *sdk) buildAndroidBp(ctx android.ModuleContext, version string) android.OutputPath {
+ bp := newGeneratedFile(ctx, "blueprint-"+version+".sh")
+
+ makePrebuiltName := func(name string) string {
+ return ctx.ModuleName() + "_" + name + string(android.SdkVersionSeparator) + version
+ }
+
+ javaLibs := s.javaMemberNames(ctx)
+ for _, name := range javaLibs {
+ prebuiltName := makePrebuiltName(name)
+ jar := filepath.Join("java", name, "stub.jar")
+
+ bp.printfln("java_import {")
+ bp.printfln(" name: %q,", prebuiltName)
+ bp.printfln(" jars: [%q],", jar)
+ bp.printfln(" sdk_member_name: %q,", name)
+ bp.printfln("}")
+ bp.printfln("")
+
+ // This module is for the case when the source tree for the unversioned module
+ // doesn't exist (i.e. building in an unbundled tree). "prefer:" is set to false
+ // so that this module does not eclipse the unversioned module if it exists.
+ bp.printfln("java_import {")
+ bp.printfln(" name: %q,", name)
+ bp.printfln(" jars: [%q],", jar)
+ bp.printfln(" prefer: false,")
+ bp.printfln("}")
+ bp.printfln("")
+
+ }
+
+ // TODO(jiyong): emit cc_prebuilt_library_shared for the native libs
+
+ bp.printfln("sdk_snapshot {")
+ bp.printfln(" name: %q,", ctx.ModuleName()+string(android.SdkVersionSeparator)+version)
+ bp.printfln(" java_libs: [")
+ for _, n := range javaLibs {
+ bp.printfln(" %q,", makePrebuiltName(n))
+ }
+ bp.printfln(" ],")
+ // TODO(jiyong): emit native_shared_libs
+ bp.printfln("}")
+ bp.printfln("")
+
+ bp.build(pctx, ctx, nil)
+ return bp.path
+}
+
+func (s *sdk) buildScript(ctx android.ModuleContext, version string) android.OutputPath {
+ sh := newGeneratedFile(ctx, "update_prebuilt-"+version+".sh")
+
+ snapshotRoot := filepath.Join(ctx.ModuleDir(), version)
+ aidlIncludeDir := filepath.Join(snapshotRoot, "aidl")
+ javaStubsDir := filepath.Join(snapshotRoot, "java")
+
+ sh.printfln("#!/bin/bash")
+ sh.printfln("echo Updating snapshot of %s in %s", ctx.ModuleName(), snapshotRoot)
+ sh.printfln("pushd $ANDROID_BUILD_TOP > /dev/null")
+ sh.printfln("rm -rf %s", snapshotRoot)
+ sh.printfln("mkdir -p %s", aidlIncludeDir)
+ sh.printfln("mkdir -p %s", javaStubsDir)
+ // TODO(jiyong): mkdir the 'native' dir
+
+ var implicits android.Paths
+ ctx.VisitDirectDeps(func(m android.Module) {
+ if javaLib, ok := m.(*java.Library); ok {
+ headerJars := javaLib.HeaderJars()
+ if len(headerJars) != 1 {
+ panic(fmt.Errorf("there must be only one header jar from %q", m.Name()))
+ }
+ implicits = append(implicits, headerJars...)
+
+ exportedAidlIncludeDirs := javaLib.AidlIncludeDirs()
+ for _, dir := range exportedAidlIncludeDirs {
+ // Using tar to copy with the directory structure
+ // TODO(jiyong): copy parcelable declarations only
+ sh.printfln("find %s -name \"*.aidl\" | tar cf - -T - | (cd %s; tar xf -)",
+ dir.String(), aidlIncludeDir)
+ }
+
+ copiedHeaderJar := filepath.Join(javaStubsDir, m.Name(), "stub.jar")
+ sh.printfln("mkdir -p $(dirname %s) && cp %s %s",
+ copiedHeaderJar, headerJars[0].String(), copiedHeaderJar)
+ }
+ // TODO(jiyong): emit the commands for copying the headers and stub libraries for native libs
+ })
+
+ bp := s.buildAndroidBp(ctx, version)
+ implicits = append(implicits, bp)
+ sh.printfln("cp %s %s", bp.String(), filepath.Join(snapshotRoot, "Android.bp"))
+
+ sh.printfln("popd > /dev/null")
+ sh.printfln("rm -- \"$0\"") // self deleting so that stale script is not used
+ sh.printfln("echo Done")
+
+ sh.build(pctx, ctx, implicits)
+ return sh.path
+}
+
+func (s *sdk) buildSnapshotGenerationScripts(ctx android.ModuleContext) {
+ if s.snapshot() {
+ // we don't need a script for sdk_snapshot.. as they are frozen
+ return
+ }
+
+ // script to update the 'current' snapshot
+ s.updateScript = s.buildScript(ctx, "current")
+
+ versions := s.frozenVersions(ctx)
+ newVersion := "1"
+ if len(versions) >= 1 {
+ lastVersion := versions[len(versions)-1]
+ lastVersionNum, err := strconv.Atoi(lastVersion)
+ if err != nil {
+ panic(err)
+ return
+ }
+ newVersion = strconv.Itoa(lastVersionNum + 1)
+ }
+ // script to create a new frozen version of snapshot
+ s.freezeScript = s.buildScript(ctx, newVersion)
+}
+
+func (s *sdk) androidMkEntriesForScript() android.AndroidMkEntries {
+ if s.snapshot() {
+ // we don't need a script for sdk_snapshot.. as they are frozen
+ return android.AndroidMkEntries{}
+ }
+
+ entries := android.AndroidMkEntries{
+ Class: "FAKE",
+ // TODO(jiyong): remove this? but androidmk.go expects OutputFile to be specified anyway
+ OutputFile: android.OptionalPathForPath(s.updateScript),
+ Include: "$(BUILD_SYSTEM)/base_rules.mk",
+ ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+ func(entries *android.AndroidMkEntries) {
+ entries.AddStrings("LOCAL_ADDITIONAL_DEPENDENCIES",
+ s.updateScript.String(), s.freezeScript.String())
+ },
+ },
+ ExtraFooters: []android.AndroidMkExtraFootersFunc{
+ func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
+ fmt.Fprintln(w, "$(LOCAL_BUILT_MODULE): $(LOCAL_ADDITIONAL_DEPENDENCIES)")
+ fmt.Fprintln(w, " touch $@")
+ fmt.Fprintln(w, " echo ##################################################")
+ fmt.Fprintln(w, " echo To update current SDK: execute", s.updateScript.String())
+ fmt.Fprintln(w, " echo To freeze current SDK: execute", s.freezeScript.String())
+ fmt.Fprintln(w, " echo ##################################################")
+ },
+ },
+ }
+ return entries
+}
diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go
index c7669bd..a876341 100644
--- a/sysprop/sysprop_library.go
+++ b/sysprop/sysprop_library.go
@@ -32,6 +32,86 @@
name string
}
+type syspropGenProperties struct {
+ Srcs []string `android:"path"`
+ Scope string
+}
+
+type syspropJavaGenRule struct {
+ android.ModuleBase
+
+ properties syspropGenProperties
+
+ genSrcjars android.Paths
+}
+
+var _ android.OutputFileProducer = (*syspropJavaGenRule)(nil)
+
+var (
+ syspropJava = pctx.AndroidStaticRule("syspropJava",
+ blueprint.RuleParams{
+ Command: `rm -rf $out.tmp && mkdir -p $out.tmp && ` +
+ `$syspropJavaCmd --scope $scope --java-output-dir $out.tmp $in && ` +
+ `$soongZipCmd -jar -o $out -C $out.tmp -D $out.tmp && rm -rf $out.tmp`,
+ CommandDeps: []string{
+ "$syspropJavaCmd",
+ "$soongZipCmd",
+ },
+ }, "scope")
+)
+
+func init() {
+ pctx.HostBinToolVariable("soongZipCmd", "soong_zip")
+ pctx.HostBinToolVariable("syspropJavaCmd", "sysprop_java")
+
+ android.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.BottomUp("sysprop_deps", syspropDepsMutator).Parallel()
+ })
+}
+
+func (g *syspropJavaGenRule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ var checkApiFileTimeStamp android.WritablePath
+
+ ctx.VisitDirectDeps(func(dep android.Module) {
+ if m, ok := dep.(*syspropLibrary); ok {
+ checkApiFileTimeStamp = m.checkApiFileTimeStamp
+ }
+ })
+
+ for _, syspropFile := range android.PathsForModuleSrc(ctx, g.properties.Srcs) {
+ srcJarFile := android.GenPathWithExt(ctx, "sysprop", syspropFile, "srcjar")
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: syspropJava,
+ Description: "sysprop_java " + syspropFile.Rel(),
+ Output: srcJarFile,
+ Input: syspropFile,
+ Implicit: checkApiFileTimeStamp,
+ Args: map[string]string{
+ "scope": g.properties.Scope,
+ },
+ })
+
+ g.genSrcjars = append(g.genSrcjars, srcJarFile)
+ }
+}
+
+func (g *syspropJavaGenRule) OutputFiles(tag string) (android.Paths, error) {
+ switch tag {
+ case "":
+ return g.genSrcjars, nil
+ default:
+ return nil, fmt.Errorf("unsupported module reference tag %q", tag)
+ }
+}
+
+func syspropJavaGenFactory() android.Module {
+ g := &syspropJavaGenRule{}
+ g.AddProperties(&g.properties)
+ android.InitAndroidModule(g)
+ return g
+}
+
type syspropLibrary struct {
android.ModuleBase
@@ -81,13 +161,29 @@
return "lib" + m.BaseModuleName()
}
+func (m *syspropLibrary) javaGenModuleName() string {
+ return m.BaseModuleName() + "_java_gen"
+}
+
func (m *syspropLibrary) BaseModuleName() string {
return m.ModuleBase.Name()
}
func (m *syspropLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- m.currentApiFile = android.PathForSource(ctx, ctx.ModuleDir(), "api", m.BaseModuleName()+"-current.txt")
- m.latestApiFile = android.PathForSource(ctx, ctx.ModuleDir(), "api", m.BaseModuleName()+"-latest.txt")
+ baseModuleName := m.BaseModuleName()
+
+ for _, syspropFile := range android.PathsForModuleSrc(ctx, m.properties.Srcs) {
+ if syspropFile.Ext() != ".sysprop" {
+ ctx.PropertyErrorf("srcs", "srcs contains non-sysprop file %q", syspropFile.String())
+ }
+ }
+
+ if ctx.Failed() {
+ return
+ }
+
+ m.currentApiFile = android.PathForSource(ctx, ctx.ModuleDir(), "api", baseModuleName+"-current.txt")
+ m.latestApiFile = android.PathForSource(ctx, ctx.ModuleDir(), "api", baseModuleName+"-latest.txt")
// dump API rule
rule := android.NewRuleBuilder()
@@ -96,7 +192,7 @@
BuiltTool(ctx, "sysprop_api_dump").
Output(m.dumpedApiFile).
Inputs(android.PathsForModuleSrc(ctx, m.properties.Srcs))
- rule.Build(pctx, ctx, m.BaseModuleName()+"_api_dump", m.BaseModuleName()+" api dump")
+ rule.Build(pctx, ctx, baseModuleName+"_api_dump", baseModuleName+" api dump")
// check API rule
rule = android.NewRuleBuilder()
@@ -105,8 +201,8 @@
msg := fmt.Sprintf(`\n******************************\n`+
`API of sysprop_library %s doesn't match with current.txt\n`+
`Please update current.txt by:\n`+
- `rm -rf %q && cp -f %q %q\n`+
- `******************************\n`, m.BaseModuleName(),
+ `m %s-dump-api && rm -rf %q && cp -f %q %q\n`+
+ `******************************\n`, baseModuleName, baseModuleName,
m.currentApiFile.String(), m.dumpedApiFile.String(), m.currentApiFile.String())
rule.Command().
@@ -121,7 +217,7 @@
msg = fmt.Sprintf(`\n******************************\n`+
`API of sysprop_library %s doesn't match with latest version\n`+
`Please fix the breakage and rebuild.\n`+
- `******************************\n`, m.BaseModuleName())
+ `******************************\n`, baseModuleName)
rule.Command().
Text("( ").
@@ -138,7 +234,7 @@
Text("touch").
Output(m.checkApiFileTimeStamp)
- rule.Build(pctx, ctx, m.BaseModuleName()+"_check_api", m.BaseModuleName()+" check api")
+ rule.Build(pctx, ctx, baseModuleName+"_check_api", baseModuleName+" check api")
}
func (m *syspropLibrary) AndroidMk() android.AndroidMkData {
@@ -153,13 +249,13 @@
fmt.Fprintf(w, "include $(BUILD_SYSTEM)/base_rules.mk\n\n")
fmt.Fprintf(w, "$(LOCAL_BUILT_MODULE): %s\n", m.checkApiFileTimeStamp.String())
fmt.Fprintf(w, "\ttouch $@\n\n")
- fmt.Fprintf(w, ".PHONY: %s-check-api\n\n", name)
+ fmt.Fprintf(w, ".PHONY: %s-check-api %s-dump-api\n\n", name, name)
+
+ // dump API rule
+ fmt.Fprintf(w, "%s-dump-api: %s\n\n", name, m.dumpedApiFile.String())
// check API rule
fmt.Fprintf(w, "%s-check-api: %s\n\n", name, m.checkApiFileTimeStamp.String())
-
- // "make {sysprop_library}" should also build the C++ library
- fmt.Fprintf(w, "%s: %s\n\n", name, m.CcModuleName())
}}
}
@@ -263,14 +359,38 @@
ccProps.Sysprop.Platform = proptools.BoolPtr(owner == "Platform")
ccProps.Header_libs = []string{"libbase_headers"}
ccProps.Shared_libs = []string{"liblog"}
-
- // add sysprop_library module to perform check API
- ccProps.Required = []string{m.Name()}
- ccProps.Sysprop.Platform = proptools.BoolPtr(owner == "Platform")
ccProps.Recovery_available = m.properties.Recovery_available
ccProps.Vendor_available = m.properties.Vendor_available
- ctx.CreateModule(android.ModuleFactoryAdaptor(cc.LibraryFactory), &ccProps)
+ ctx.CreateModule(cc.LibraryFactory, &ccProps)
+
+ // internal scope contains all properties
+ // public scope only contains public properties
+ // use public if the owner is different from client
+ scope := "internal"
+ isProduct := ctx.ProductSpecific()
+ isVendor := ctx.SocSpecific()
+ isOwnerPlatform := owner == "Platform"
+
+ if isProduct {
+ // product can't own any sysprop_library now, so product must use public scope
+ scope = "public"
+ } else if isVendor && !isOwnerPlatform {
+ // vendor and odm can't use system's internal property.
+ scope = "public"
+ }
+
+ javaGenProps := struct {
+ Srcs []string
+ Scope string
+ Name *string
+ }{
+ Srcs: m.properties.Srcs,
+ Scope: scope,
+ Name: proptools.StringPtr(m.javaGenModuleName()),
+ }
+
+ ctx.CreateModule(syspropJavaGenFactory, &javaGenProps)
javaProps := struct {
Name *string
@@ -278,27 +398,26 @@
Soc_specific *bool
Device_specific *bool
Product_specific *bool
- Sysprop struct {
- Platform *bool
- }
- Required []string
- Sdk_version *string
- Installable *bool
- Libs []string
+ Required []string
+ Sdk_version *string
+ Installable *bool
+ Libs []string
}{}
javaProps.Name = proptools.StringPtr(m.BaseModuleName())
- javaProps.Srcs = m.properties.Srcs
+ javaProps.Srcs = []string{":" + *javaGenProps.Name}
javaProps.Soc_specific = proptools.BoolPtr(socSpecific)
javaProps.Device_specific = proptools.BoolPtr(deviceSpecific)
javaProps.Product_specific = proptools.BoolPtr(productSpecific)
javaProps.Installable = m.properties.Installable
-
- // add sysprop_library module to perform check API
- javaProps.Required = []string{m.Name()}
javaProps.Sdk_version = proptools.StringPtr("core_current")
- javaProps.Sysprop.Platform = proptools.BoolPtr(owner == "Platform")
javaProps.Libs = []string{stub}
- ctx.CreateModule(android.ModuleFactoryAdaptor(java.LibraryFactory), &javaProps)
+ ctx.CreateModule(java.LibraryFactory, &javaProps)
+}
+
+func syspropDepsMutator(ctx android.BottomUpMutatorContext) {
+ if m, ok := ctx.Module().(*syspropLibrary); ok {
+ ctx.AddReverseDependency(m, nil, m.javaGenModuleName())
+ }
}
diff --git a/sysprop/sysprop_test.go b/sysprop/sysprop_test.go
index 5345770..6b4337a 100644
--- a/sysprop/sysprop_test.go
+++ b/sysprop/sysprop_test.go
@@ -62,6 +62,9 @@
ctx.PreArchMutators(android.RegisterPrebuiltsPreArchMutators)
ctx.PreArchMutators(android.RegisterPrebuiltsPostDepsMutators)
ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
+ ctx.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.BottomUp("sysprop_deps", syspropDepsMutator).Parallel()
+ })
ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(cc.LibraryFactory))
ctx.RegisterModuleType("cc_library_headers", android.ModuleFactoryAdaptor(cc.LibraryHeaderFactory))
@@ -282,10 +285,10 @@
// Check for generated cc_library
for _, variant := range []string{
- "android_arm_armv7-a-neon_vendor_shared",
- "android_arm_armv7-a-neon_vendor_static",
- "android_arm64_armv8-a_vendor_shared",
- "android_arm64_armv8-a_vendor_static",
+ "android_arm_armv7-a-neon_vendor.VER_shared",
+ "android_arm_armv7-a-neon_vendor.VER_static",
+ "android_arm64_armv8-a_vendor.VER_shared",
+ "android_arm64_armv8-a_vendor.VER_static",
} {
ctx.ModuleForTests("libsysprop-platform", variant)
ctx.ModuleForTests("libsysprop-vendor", variant)
@@ -309,15 +312,15 @@
// Check for exported includes
coreVariant := "android_arm64_armv8-a_core_static"
- vendorVariant := "android_arm64_armv8-a_vendor_static"
+ vendorVariant := "android_arm64_armv8-a_vendor.VER_static"
platformInternalPath := "libsysprop-platform/android_arm64_armv8-a_core_static/gen/sysprop/include"
platformPublicCorePath := "libsysprop-platform/android_arm64_armv8-a_core_static/gen/sysprop/public/include"
- platformPublicVendorPath := "libsysprop-platform/android_arm64_armv8-a_vendor_static/gen/sysprop/public/include"
+ platformPublicVendorPath := "libsysprop-platform/android_arm64_armv8-a_vendor.VER_static/gen/sysprop/public/include"
platformOnProductPath := "libsysprop-platform-on-product/android_arm64_armv8-a_core_static/gen/sysprop/public/include"
- vendorInternalPath := "libsysprop-vendor/android_arm64_armv8-a_vendor_static/gen/sysprop/include"
+ vendorInternalPath := "libsysprop-vendor/android_arm64_armv8-a_vendor.VER_static/gen/sysprop/include"
vendorPublicPath := "libsysprop-vendor/android_arm64_armv8-a_core_static/gen/sysprop/public/include"
platformClient := ctx.ModuleForTests("cc-client-platform", coreVariant)
diff --git a/tradefed/autogen.go b/tradefed/autogen.go
index 952b022..3d30cfa 100644
--- a/tradefed/autogen.go
+++ b/tradefed/autogen.go
@@ -24,6 +24,8 @@
"android/soong/android"
)
+const test_xml_indent = " "
+
func getTestConfigTemplate(ctx android.ModuleContext, prop *string) android.OptionalPath {
return ctx.ExpandOptionalSource(prop, "test_config_template")
}
@@ -42,10 +44,11 @@
CommandDeps: []string{"$template"},
}, "name", "template", "extraConfigs")
-func testConfigPath(ctx android.ModuleContext, prop *string, testSuites []string) (path android.Path, autogenPath android.WritablePath) {
- if p := getTestConfig(ctx, prop); p != nil {
+func testConfigPath(ctx android.ModuleContext, prop *string, testSuites []string, autoGenConfig *bool) (path android.Path, autogenPath android.WritablePath) {
+ p := getTestConfig(ctx, prop)
+ if !Bool(autoGenConfig) && p != nil {
return p, nil
- } else if !android.InList("cts", testSuites) {
+ } else if !android.InList("cts", testSuites) && BoolDefault(autoGenConfig, true) {
outputFile := android.PathForModuleOut(ctx, ctx.ModuleName()+".config")
return nil, outputFile
} else {
@@ -71,14 +74,34 @@
return fmt.Sprintf(`<option name="%s" value="%s" />`, o.Name, o.Value)
}
-type Preparer struct {
- Class string
+// It can be a template of object or target_preparer.
+type Object struct {
+ // Set it as a target_preparer if object type == "target_preparer".
+ Type string
+ Class string
+ Options []Option
}
-var _ Config = Preparer{}
+var _ Config = Object{}
-func (p Preparer) Config() string {
- return fmt.Sprintf(`<target_preparer class="%s" />`, p.Class)
+func (ob Object) Config() string {
+ var optionStrings []string
+ for _, option := range ob.Options {
+ optionStrings = append(optionStrings, option.Config())
+ }
+ var options string
+ if len(ob.Options) == 0 {
+ options = ""
+ } else {
+ optionDelimiter := fmt.Sprintf("\\n%s%s", test_xml_indent, test_xml_indent)
+ options = optionDelimiter + strings.Join(optionStrings, optionDelimiter)
+ }
+ if ob.Type == "target_preparer" {
+ return fmt.Sprintf(`<target_preparer class="%s">%s\n%s</target_preparer>`, ob.Class, options, test_xml_indent)
+ } else {
+ return fmt.Sprintf(`<object type="%s" class="%s">%s\n%s</object>`, ob.Type, ob.Class, options, test_xml_indent)
+ }
+
}
func autogenTemplate(ctx android.ModuleContext, output android.WritablePath, template string, configs []Config) {
@@ -86,7 +109,7 @@
for _, config := range configs {
configStrings = append(configStrings, config.Config())
}
- extraConfigs := strings.Join(configStrings, "\n ")
+ extraConfigs := strings.Join(configStrings, fmt.Sprintf("\\n%s", test_xml_indent))
extraConfigs = proptools.NinjaAndShellEscape(extraConfigs)
ctx.Build(pctx, android.BuildParams{
@@ -102,8 +125,8 @@
}
func AutoGenNativeTestConfig(ctx android.ModuleContext, testConfigProp *string,
- testConfigTemplateProp *string, testSuites []string, config []Config) android.Path {
- path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites)
+ testConfigTemplateProp *string, testSuites []string, config []Config, autoGenConfig *bool) android.Path {
+ path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig)
if autogenPath != nil {
templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
if templatePath.Valid() {
@@ -121,8 +144,8 @@
}
func AutoGenNativeBenchmarkTestConfig(ctx android.ModuleContext, testConfigProp *string,
- testConfigTemplateProp *string, testSuites []string, configs []Config) android.Path {
- path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites)
+ testConfigTemplateProp *string, testSuites []string, configs []Config, autoGenConfig *bool) android.Path {
+ path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig)
if autogenPath != nil {
templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
if templatePath.Valid() {
@@ -135,8 +158,9 @@
return path
}
-func AutoGenJavaTestConfig(ctx android.ModuleContext, testConfigProp *string, testConfigTemplateProp *string, testSuites []string) android.Path {
- path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites)
+func AutoGenJavaTestConfig(ctx android.ModuleContext, testConfigProp *string, testConfigTemplateProp *string,
+ testSuites []string, autoGenConfig *bool) android.Path {
+ path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig)
if autogenPath != nil {
templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
if templatePath.Valid() {
@@ -154,9 +178,9 @@
}
func AutoGenPythonBinaryHostTestConfig(ctx android.ModuleContext, testConfigProp *string,
- testConfigTemplateProp *string, testSuites []string) android.Path {
+ testConfigTemplateProp *string, testSuites []string, autoGenConfig *bool) android.Path {
- path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites)
+ path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig)
if autogenPath != nil {
templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
if templatePath.Valid() {
@@ -178,8 +202,9 @@
},
}, "name", "template")
-func AutoGenInstrumentationTestConfig(ctx android.ModuleContext, testConfigProp *string, testConfigTemplateProp *string, manifest android.Path, testSuites []string) android.Path {
- path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites)
+func AutoGenInstrumentationTestConfig(ctx android.ModuleContext, testConfigProp *string,
+ testConfigTemplateProp *string, manifest android.Path, testSuites []string, autoGenConfig *bool) android.Path {
+ path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig)
if autogenPath != nil {
template := "${InstrumentationTestConfigTemplate}"
moduleTemplate := getTestConfigTemplate(ctx, testConfigTemplateProp)
@@ -200,3 +225,6 @@
}
return path
}
+
+var Bool = proptools.Bool
+var BoolDefault = proptools.BoolDefault
diff --git a/ui/build/cleanbuild.go b/ui/build/cleanbuild.go
index bfe2c36..1dbeb26 100644
--- a/ui/build/cleanbuild.go
+++ b/ui/build/cleanbuild.go
@@ -87,6 +87,7 @@
// otherwise we'd have to rebuild any generated files created with
// those tools.
removeGlobs(ctx,
+ hostOut("apex"),
hostOut("obj/NOTICE_FILES"),
hostOut("obj/PACKAGING"),
hostOut("coverage"),
@@ -106,6 +107,8 @@
productOut("obj/NOTICE_FILES"),
productOut("obj/PACKAGING"),
productOut("ramdisk"),
+ productOut("debug_ramdisk"),
+ productOut("test_harness_ramdisk"),
productOut("recovery"),
productOut("root"),
productOut("system"),
diff --git a/ui/build/config.go b/ui/build/config.go
index 665d2f0..919b9ce 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -16,7 +16,6 @@
import (
"io/ioutil"
- "log"
"os"
"path/filepath"
"runtime"
@@ -189,36 +188,40 @@
checkTopDir(ctx)
if srcDir := absPath(ctx, "."); strings.ContainsRune(srcDir, ' ') {
- log.Println("You are building in a directory whose absolute path contains a space character:")
- log.Println()
- log.Printf("%q\n", srcDir)
- log.Println()
- log.Fatalln("Directory names containing spaces are not supported")
+ ctx.Println("You are building in a directory whose absolute path contains a space character:")
+ ctx.Println()
+ ctx.Printf("%q\n", srcDir)
+ ctx.Println()
+ ctx.Fatalln("Directory names containing spaces are not supported")
}
if outDir := ret.OutDir(); strings.ContainsRune(outDir, ' ') {
- log.Println("The absolute path of your output directory ($OUT_DIR) contains a space character:")
- log.Println()
- log.Printf("%q\n", outDir)
- log.Println()
- log.Fatalln("Directory names containing spaces are not supported")
+ ctx.Println("The absolute path of your output directory ($OUT_DIR) contains a space character:")
+ ctx.Println()
+ ctx.Printf("%q\n", outDir)
+ ctx.Println()
+ ctx.Fatalln("Directory names containing spaces are not supported")
}
if distDir := ret.DistDir(); strings.ContainsRune(distDir, ' ') {
- log.Println("The absolute path of your dist directory ($DIST_DIR) contains a space character:")
- log.Println()
- log.Printf("%q\n", distDir)
- log.Println()
- log.Fatalln("Directory names containing spaces are not supported")
+ ctx.Println("The absolute path of your dist directory ($DIST_DIR) contains a space character:")
+ ctx.Println()
+ ctx.Printf("%q\n", distDir)
+ ctx.Println()
+ ctx.Fatalln("Directory names containing spaces are not supported")
}
// Configure Java-related variables, including adding it to $PATH
java8Home := filepath.Join("prebuilts/jdk/jdk8", ret.HostPrebuiltTag())
java9Home := filepath.Join("prebuilts/jdk/jdk9", ret.HostPrebuiltTag())
+ java11Home := filepath.Join("prebuilts/jdk/jdk11", ret.HostPrebuiltTag())
javaHome := func() string {
if override, ok := ret.environ.Get("OVERRIDE_ANDROID_JAVA_HOME"); ok {
return override
}
+ if toolchain11, ok := ret.environ.Get("EXPERIMENTAL_USE_OPENJDK11_TOOLCHAIN"); ok && toolchain11 == "true" {
+ return java11Home
+ }
return java9Home
}()
absJavaHome := absPath(ctx, javaHome)
@@ -229,11 +232,13 @@
if path, ok := ret.environ.Get("PATH"); ok && path != "" {
newPath = append(newPath, path)
}
+
ret.environ.Unset("OVERRIDE_ANDROID_JAVA_HOME")
ret.environ.Set("JAVA_HOME", absJavaHome)
ret.environ.Set("ANDROID_JAVA_HOME", javaHome)
ret.environ.Set("ANDROID_JAVA8_HOME", java8Home)
ret.environ.Set("ANDROID_JAVA9_HOME", java9Home)
+ ret.environ.Set("ANDROID_JAVA11_HOME", java11Home)
ret.environ.Set("PATH", strings.Join(newPath, string(filepath.ListSeparator)))
outDir := ret.OutDir()
diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go
index 6b9eac1..4270bb1 100644
--- a/ui/build/dumpvars.go
+++ b/ui/build/dumpvars.go
@@ -17,6 +17,8 @@
import (
"bytes"
"fmt"
+ "io/ioutil"
+ "os"
"strings"
"android/soong/ui/metrics"
@@ -40,6 +42,7 @@
soongUiVars := map[string]func() string{
"OUT_DIR": func() string { return config.OutDir() },
"DIST_DIR": func() string { return config.DistDir() },
+ "TMPDIR": func() string { return absPath(ctx, config.TempDir()) },
}
makeVars := make([]string, 0, len(vars))
@@ -51,7 +54,17 @@
var ret map[string]string
if len(makeVars) > 0 {
- var err error
+ tmpDir, err := ioutil.TempDir("", "dumpvars")
+ if err != nil {
+ return nil, err
+ }
+ defer os.RemoveAll(tmpDir)
+
+ // It's not safe to use the same TMPDIR as the build, as that can be removed.
+ config.Environment().Set("TMPDIR", tmpDir)
+
+ SetupLitePath(ctx, config)
+
ret, err = dumpMakeVars(ctx, config, goals, makeVars, false)
if err != nil {
return ret, err
@@ -208,6 +221,8 @@
"DEFAULT_WARNING_BUILD_MODULE_TYPES",
"DEFAULT_ERROR_BUILD_MODULE_TYPES",
+ "BUILD_BROKEN_PREBUILT_ELF_FILES",
+ "BUILD_BROKEN_TREBLE_SYSPROP_NEVERALLOW",
"BUILD_BROKEN_USES_BUILD_AUX_EXECUTABLE",
"BUILD_BROKEN_USES_BUILD_AUX_STATIC_LIBRARY",
"BUILD_BROKEN_USES_BUILD_COPY_HEADERS",
diff --git a/ui/build/path.go b/ui/build/path.go
index 0e1c02c..c34ba1b 100644
--- a/ui/build/path.go
+++ b/ui/build/path.go
@@ -18,6 +18,7 @@
"fmt"
"io/ioutil"
"os"
+ "os/exec"
"path/filepath"
"runtime"
"strings"
@@ -53,6 +54,51 @@
return ret
}
+// A "lite" version of SetupPath used for dumpvars, or other places that need
+// minimal overhead (but at the expense of logging).
+func SetupLitePath(ctx Context, config Config) {
+ if config.pathReplaced {
+ return
+ }
+
+ ctx.BeginTrace(metrics.RunSetupTool, "litepath")
+ defer ctx.EndTrace()
+
+ origPath, _ := config.Environment().Get("PATH")
+ myPath, _ := config.Environment().Get("TMPDIR")
+ myPath = filepath.Join(myPath, "path")
+ ensureEmptyDirectoriesExist(ctx, myPath)
+
+ os.Setenv("PATH", origPath)
+ for name, pathConfig := range paths.Configuration {
+ if !pathConfig.Symlink {
+ continue
+ }
+
+ origExec, err := exec.LookPath(name)
+ if err != nil {
+ continue
+ }
+ origExec, err = filepath.Abs(origExec)
+ if err != nil {
+ continue
+ }
+
+ err = os.Symlink(origExec, filepath.Join(myPath, name))
+ if err != nil {
+ ctx.Fatalln("Failed to create symlink:", err)
+ }
+ }
+
+ myPath, _ = filepath.Abs(myPath)
+
+ prebuiltsPath, _ := filepath.Abs("prebuilts/build-tools/path/" + runtime.GOOS + "-x86")
+ myPath = prebuiltsPath + string(os.PathListSeparator) + myPath
+
+ config.Environment().Set("PATH", myPath)
+ config.pathReplaced = true
+}
+
func SetupPath(ctx Context, config Config) {
if config.pathReplaced {
return
diff --git a/ui/build/paths/config.go b/ui/build/paths/config.go
index 38e80e0..1bd3c98 100644
--- a/ui/build/paths/config.go
+++ b/ui/build/paths/config.go
@@ -117,24 +117,21 @@
"ld.gold": Forbidden,
"pkg-config": Forbidden,
- // These are currently Linux-only toybox tools (but can be switched now).
- "date": LinuxOnlyPrebuilt,
- "stat": LinuxOnlyPrebuilt,
-
// These are toybox tools that only work on Linux.
"pgrep": LinuxOnlyPrebuilt,
"pkill": LinuxOnlyPrebuilt,
"ps": LinuxOnlyPrebuilt,
+
+ // The toybox xargs is currently breaking the mac build.
+ "xargs": LinuxOnlyPrebuilt,
}
func init() {
if runtime.GOOS == "darwin" {
- // TODO: move Darwin off md5 and onto our md5sum prebuilt.
- Configuration["md5"] = Allowed
Configuration["sw_vers"] = Allowed
Configuration["xcrun"] = Allowed
- // We don't have darwin prebuilts for some tools (like toybox),
+ // We don't have darwin prebuilts for some tools,
// so allow the host versions.
for name, config := range Configuration {
if config.LinuxOnlyPrebuilt {
diff --git a/ui/terminal/smart_status.go b/ui/terminal/smart_status.go
index 57f71ab..efcfd43 100644
--- a/ui/terminal/smart_status.go
+++ b/ui/terminal/smart_status.go
@@ -189,7 +189,7 @@
fmt.Fprintf(s.writer, ansi.resetScrollingMargins())
_, height, _ := termSize(s.writer)
// Move the cursor to the top of the now-blank, previously non-scrolling region
- fmt.Fprintf(s.writer, ansi.setCursor(height-s.tableHeight, 0))
+ fmt.Fprintf(s.writer, ansi.setCursor(height-s.tableHeight, 1))
// Turn the cursor back on
fmt.Fprintf(s.writer, ansi.showCursor())
}
@@ -334,52 +334,44 @@
scrollingHeight := s.termHeight - s.tableHeight
// Update the scrolling region in case the height of the terminal changed
- fmt.Fprint(s.writer, ansi.setScrollingMargins(0, scrollingHeight))
- // Move the cursor to the first line of the non-scrolling region
- fmt.Fprint(s.writer, ansi.setCursor(scrollingHeight+1, 0))
+
+ fmt.Fprint(s.writer, ansi.setScrollingMargins(1, scrollingHeight))
// Write as many status lines as fit in the table
- var tableLine int
- var runningAction actionTableEntry
- for tableLine, runningAction = range s.runningActions {
+ for tableLine := 0; tableLine < s.tableHeight; tableLine++ {
if tableLine >= s.tableHeight {
break
}
+ // Move the cursor to the correct line of the non-scrolling region
+ fmt.Fprint(s.writer, ansi.setCursor(scrollingHeight+1+tableLine, 1))
- seconds := int(time.Since(runningAction.startTime).Round(time.Second).Seconds())
+ if tableLine < len(s.runningActions) {
+ runningAction := s.runningActions[tableLine]
- desc := runningAction.action.Description
- if desc == "" {
- desc = runningAction.action.Command
+ seconds := int(time.Since(runningAction.startTime).Round(time.Second).Seconds())
+
+ desc := runningAction.action.Description
+ if desc == "" {
+ desc = runningAction.action.Command
+ }
+
+ color := ""
+ if seconds >= 60 {
+ color = ansi.red() + ansi.bold()
+ } else if seconds >= 30 {
+ color = ansi.yellow() + ansi.bold()
+ }
+
+ durationStr := fmt.Sprintf(" %2d:%02d ", seconds/60, seconds%60)
+ desc = elide(desc, s.termWidth-len(durationStr))
+ durationStr = color + durationStr + ansi.regular()
+ fmt.Fprint(s.writer, durationStr, desc)
}
-
- color := ""
- if seconds >= 60 {
- color = ansi.red() + ansi.bold()
- } else if seconds >= 30 {
- color = ansi.yellow() + ansi.bold()
- }
-
- durationStr := fmt.Sprintf(" %2d:%02d ", seconds/60, seconds%60)
- desc = elide(desc, s.termWidth-len(durationStr))
- durationStr = color + durationStr + ansi.regular()
-
- fmt.Fprint(s.writer, durationStr, desc, ansi.clearToEndOfLine())
- if tableLine < s.tableHeight-1 {
- fmt.Fprint(s.writer, "\n")
- }
- }
-
- // Clear any remaining lines in the table
- for ; tableLine < s.tableHeight; tableLine++ {
fmt.Fprint(s.writer, ansi.clearToEndOfLine())
- if tableLine < s.tableHeight-1 {
- fmt.Fprint(s.writer, "\n")
- }
}
// Move the cursor back to the last line of the scrolling region
- fmt.Fprint(s.writer, ansi.setCursor(scrollingHeight, 0))
+ fmt.Fprint(s.writer, ansi.setCursor(scrollingHeight, 1))
}
var ansi = ansiImpl{}
diff --git a/ui/terminal/status.go b/ui/terminal/status.go
index 69a2a09..60dfc70 100644
--- a/ui/terminal/status.go
+++ b/ui/terminal/status.go
@@ -26,10 +26,10 @@
//
// statusFormat takes nearly all the same options as NINJA_STATUS.
// %c is currently unsupported.
-func NewStatusOutput(w io.Writer, statusFormat string, quietBuild bool) status.StatusOutput {
+func NewStatusOutput(w io.Writer, statusFormat string, forceDumbOutput, quietBuild bool) status.StatusOutput {
formatter := newFormatter(statusFormat, quietBuild)
- if isSmartTerminal(w) {
+ if !forceDumbOutput && isSmartTerminal(w) {
return NewSmartStatusOutput(w, formatter)
} else {
return NewDumbStatusOutput(w, formatter)
diff --git a/ui/terminal/status_test.go b/ui/terminal/status_test.go
index 81aa238..9f60829 100644
--- a/ui/terminal/status_test.go
+++ b/ui/terminal/status_test.go
@@ -94,7 +94,7 @@
t.Run("smart", func(t *testing.T) {
smart := &fakeSmartTerminal{termWidth: 40}
- stat := NewStatusOutput(smart, "", false)
+ stat := NewStatusOutput(smart, "", false, false)
tt.calls(stat)
stat.Flush()
@@ -105,7 +105,7 @@
t.Run("dumb", func(t *testing.T) {
dumb := &bytes.Buffer{}
- stat := NewStatusOutput(dumb, "", false)
+ stat := NewStatusOutput(dumb, "", false, false)
tt.calls(stat)
stat.Flush()
@@ -113,6 +113,17 @@
t.Errorf("want:\n%q\ngot:\n%q", w, g)
}
})
+
+ t.Run("force dumb", func(t *testing.T) {
+ smart := &fakeSmartTerminal{termWidth: 40}
+ stat := NewStatusOutput(smart, "", true, false)
+ tt.calls(stat)
+ stat.Flush()
+
+ if g, w := smart.String(), tt.dumb; g != w {
+ t.Errorf("want:\n%q\ngot:\n%q", w, g)
+ }
+ })
})
}
}
@@ -258,7 +269,7 @@
os.Setenv(tableHeightEnVar, "")
smart := &fakeSmartTerminal{termWidth: 40}
- stat := NewStatusOutput(smart, "", false)
+ stat := NewStatusOutput(smart, "", false, false)
smartStat := stat.(*smartStatusOutput)
smartStat.sigwinchHandled = make(chan bool)
diff --git a/vnames.json b/vnames.json
new file mode 100644
index 0000000..f9d3adc
--- /dev/null
+++ b/vnames.json
@@ -0,0 +1,18 @@
+[
+ {
+ "pattern": "out/(.*)",
+ "vname": {
+ "corpus": "android.googlesource.com/platform/superproject",
+ "root": "out",
+ "path": "@1@"
+ }
+ },
+ {
+ "pattern": "(.*)",
+ "vname": {
+ "corpus": "android.googlesource.com/platform/superproject",
+ "path": "@1@"
+ }
+ }
+]
+
diff --git a/xml/xml_test.go b/xml/xml_test.go
index ae3e9fe..f2a440f 100644
--- a/xml/xml_test.go
+++ b/xml/xml_test.go
@@ -15,15 +15,40 @@
package xml
import (
- "android/soong/android"
"io/ioutil"
"os"
"testing"
+
+ "android/soong/android"
)
+var buildDir string
+
+func setUp() {
+ var err error
+ buildDir, err = ioutil.TempDir("", "soong_xml_test")
+ if err != nil {
+ panic(err)
+ }
+}
+
+func tearDown() {
+ os.RemoveAll(buildDir)
+}
+
+func TestMain(m *testing.M) {
+ run := func() int {
+ setUp()
+ defer tearDown()
+
+ return m.Run()
+ }
+
+ os.Exit(run())
+}
+
func testXml(t *testing.T, bp string) *android.TestContext {
- config, buildDir := setup(t)
- defer teardown(buildDir)
+ config := android.TestArchConfig(buildDir, nil)
ctx := android.NewTestArchContext()
ctx.RegisterModuleType("prebuilt_etc", android.ModuleFactoryAdaptor(android.PrebuiltEtcFactory))
ctx.RegisterModuleType("prebuilt_etc_xml", android.ModuleFactoryAdaptor(PrebuiltEtcXmlFactory))
@@ -45,21 +70,6 @@
return ctx
}
-func setup(t *testing.T) (config android.Config, buildDir string) {
- buildDir, err := ioutil.TempDir("", "soong_xml_test")
- if err != nil {
- t.Fatal(err)
- }
-
- config = android.TestArchConfig(buildDir, nil)
-
- return
-}
-
-func teardown(buildDir string) {
- os.RemoveAll(buildDir)
-}
-
func assertEqual(t *testing.T, name, expected, actual string) {
t.Helper()
if expected != actual {
@@ -103,5 +113,5 @@
}
m := ctx.ModuleForTests("foo.xml", "android_arm64_armv8-a").Module().(*prebuiltEtcXml)
- assertEqual(t, "installDir", "target/product/test_device/system/etc", m.InstallDirPath().RelPathString())
+ assertEqual(t, "installDir", buildDir+"/target/product/test_device/system/etc", m.InstallDirPath().String())
}