Merge "Go back to the native mac xargs for now."
diff --git a/android/apex.go b/android/apex.go
index 557febf..c548095 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,18 +75,11 @@
// 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
}
type ApexProperties struct {
- // Whether this module should not be part of any APEX. Default is false.
- // TODO(b/128708192): remove this as this is equal to apex_available: [":platform"]
- 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".
@@ -143,10 +135,6 @@
return false
}
-func (m *ApexModuleBase) NoApex() bool {
- return proptools.Bool(m.ApexProperties.No_apex)
-}
-
const (
availableToPlatform = "//apex_available:platform"
availableToAnyApex = "//apex_available:anyapex"
@@ -167,7 +155,7 @@
if n == availableToPlatform || n == availableToAnyApex {
continue
}
- if !mctx.OtherModuleExists(n) {
+ if !mctx.OtherModuleExists(n) && !mctx.Config().AllowMissingDependencies() {
mctx.PropertyErrorf("apex_available", "%q is not a valid module name", n)
}
}
diff --git a/android/arch.go b/android/arch.go
index b5b52a9..348b064 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -527,7 +527,6 @@
CpuVariant string
Abi []string
ArchFeatures []string
- Native bool
}
func (a Arch) String() string {
@@ -1361,11 +1360,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 != "" {
@@ -1513,7 +1507,7 @@
if err != nil {
return nil, err
}
- arch.Native = false
+
ret = append(ret, Target{
Os: Android,
Arch: arch,
@@ -1542,7 +1536,6 @@
ArchVariant: stringPtr(archVariant),
CpuVariant: stringPtr(cpuVariant),
Abi: abi,
- Native: true,
}
if a.ArchVariant == a.ArchType.Name || a.ArchVariant == "generic" {
diff --git a/android/config.go b/android/config.go
index d03d38e..26c4e6e 100644
--- a/android/config.go
+++ b/android/config.go
@@ -93,6 +93,10 @@
BuildOsVariant string
BuildOsCommonVariant string
+ // multilibConflicts for an ArchType is true if there is earlier configured device architecture with the same
+ // multilib value.
+ multilibConflicts map[ArchType]bool
+
deviceConfig *deviceConfig
srcDir string // the path of the root source directory
@@ -240,10 +244,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 +259,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 +276,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, "", ""},
@@ -305,8 +309,9 @@
env: originalEnv,
- srcDir: srcDir,
- buildDir: buildDir,
+ srcDir: srcDir,
+ buildDir: buildDir,
+ multilibConflicts: make(map[ArchType]bool),
}
config.deviceConfig = &deviceConfig{
@@ -360,6 +365,14 @@
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()
@@ -852,6 +865,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 +1026,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/module.go b/android/module.go
index 6988ac0..5d1a609 100644
--- a/android/module.go
+++ b/android/module.go
@@ -514,8 +514,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()
@@ -597,7 +608,7 @@
nameProperties nameProperties
commonProperties commonProperties
- variableProperties variableProperties
+ variableProperties interface{}
hostAndDeviceProperties hostAndDeviceProperties
generalProperties []interface{}
archProperties [][]interface{}
diff --git a/android/mutator.go b/android/mutator.go
index 510e63c..88ac521 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"
)
@@ -244,8 +246,23 @@
}
func (t *topDownMutatorContext) CreateModule(factory ModuleFactory, props ...interface{}) Module {
- inherited := []interface{}{&t.Module().base().commonProperties, &t.Module().base().variableProperties}
+ 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
}
diff --git a/android/variable.go b/android/variable.go
index 3f2b9e9..41943b0 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -122,7 +122,7 @@
} `android:"arch_variant"`
}
-var zeroProductVariables variableProperties
+var zeroProductVariables interface{} = variableProperties{}
type productVariables struct {
// Suffix to add to generated Makefiles
@@ -366,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)
@@ -496,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/apex/apex.go b/apex/apex.go
index 81660d5..bb90cb9 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -149,15 +149,6 @@
androidAppTag = dependencyTag{name: "androidApp"}
)
-var (
- whitelistNoApex = map[string][]string{
- "apex_test_build_features": []string{"libbinder"},
- "com.android.media.swcodec": []string{"libbinder"},
- "test_com.android.media.swcodec": []string{"libbinder"},
- "com.android.vndk": []string{"libbinder"},
- }
-)
-
func init() {
pctx.Import("android/soong/android")
pctx.Import("android/soong/java")
@@ -196,6 +187,12 @@
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) {
@@ -282,14 +279,40 @@
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() {
@@ -869,9 +892,7 @@
dirInApex = "lib64"
}
dirInApex = filepath.Join(dirInApex, ccMod.RelativeInstallPath())
- if !ccMod.Arch().Native {
- dirInApex = filepath.Join(dirInApex, ccMod.Arch().ArchType.String())
- } else if ccMod.Target().NativeBridge == android.NativeBridgeEnabled {
+ if ccMod.Target().NativeBridge == android.NativeBridgeEnabled {
dirInApex = filepath.Join(dirInApex, ccMod.Target().NativeBridgeRelativePath)
}
if handleSpecialLibs && cc.InstallToBootstrap(ccMod.BaseModuleName(), config) {
@@ -894,9 +915,7 @@
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()
@@ -1172,10 +1191,6 @@
}
} else if am.CanHaveApexVariants() && am.IsInstallableToApex() {
ctx.ModuleErrorf("unexpected tag %q for indirect dependency %q", depTag, depName)
- } else if depTag == android.DefaultsDepTag {
- return false
- } else if am.NoApex() && !android.InList(depName, whitelistNoApex[ctx.ModuleName()]) {
- ctx.ModuleErrorf("tries to include no_apex module %s", depName)
}
}
}
@@ -1207,22 +1222,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
- 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
+ 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
+ }
}
}
}
@@ -1267,7 +1274,8 @@
// 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}
- a.flattenedOutput = android.PathForModuleInstall(&factx, "apex", factx.ModuleName())
+ apexName := proptools.StringDefault(a.properties.Apex_name, ctx.ModuleName())
+ a.flattenedOutput = android.PathForModuleInstall(&factx, "apex", apexName)
if a.apexTypes.zip() {
a.buildUnflattenedApex(ctx, zipApex)
@@ -1567,8 +1575,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)
@@ -1599,7 +1608,7 @@
}}
}
-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 {
@@ -1623,12 +1632,11 @@
fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
fmt.Fprintln(w, "LOCAL_MODULE :=", fi.moduleName+suffix)
// /apex/<apex_name>/{lib|framework|...}
- pathWhenActivated := filepath.Join("$(PRODUCT_OUT)", "apex",
- proptools.StringDefault(a.properties.Apex_name, name), fi.installDir)
+ 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(a.installDir.ToMakePath().String(),
- name, fi.installDir))
+ apexName, fi.installDir))
if !a.isFlattenedVariant() {
fmt.Fprintln(w, "LOCAL_SOONG_SYMBOL_PATH :=", pathWhenActivated)
}
@@ -1708,7 +1716,8 @@
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.isFlattenedVariant() {
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 413d084..ae0ea7d 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -102,9 +102,6 @@
ctx.RegisterModuleType("apex_defaults", android.ModuleFactoryAdaptor(defaultsFactory))
ctx.RegisterModuleType("prebuilt_apex", android.ModuleFactoryAdaptor(PrebuiltFactory))
- ctx.RegisterModuleType("cc_defaults", android.ModuleFactoryAdaptor(func() android.Module {
- return cc.DefaultsFactory()
- }))
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))
@@ -1501,10 +1498,10 @@
}
`, withTargets(map[android.OsType][]android.Target{
android.Android: []android.Target{
- {Os: android.Android, Arch: android.Arch{ArchType: android.Arm64, ArchVariant: "armv8-a", Native: true, Abi: []string{"arm64-v8a"}}, NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""},
- {Os: android.Android, Arch: android.Arch{ArchType: android.Arm, ArchVariant: "armv7-a-neon", Native: true, Abi: []string{"armeabi-v7a"}}, NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""},
- {Os: android.Android, Arch: android.Arch{ArchType: android.X86_64, ArchVariant: "silvermont", Native: true, Abi: []string{"arm64-v8a"}}, NativeBridge: android.NativeBridgeEnabled, NativeBridgeHostArchName: "arm64", NativeBridgeRelativePath: "x86_64"},
- {Os: android.Android, Arch: android.Arch{ArchType: android.X86, ArchVariant: "silvermont", Native: true, Abi: []string{"armeabi-v7a"}}, NativeBridge: android.NativeBridgeEnabled, NativeBridgeHostArchName: "arm", NativeBridgeRelativePath: "x86"},
+ {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"},
},
}))
@@ -2183,200 +2180,6 @@
`)
}
-func TestApexUsesFailsIfUseNoApex(t *testing.T) {
- // 'no_apex' prevents a module to be included in an apex
- testApexError(t, `tries to include no_apex module mylib2`, `
- apex {
- name: "commonapex",
- key: "myapex.key",
- native_shared_libs: ["mylib"],
- }
-
- apex_key {
- name: "myapex.key",
- public_key: "testkey.avbpubkey",
- private_key: "testkey.pem",
- }
-
- cc_library {
- name: "mylib",
- srcs: ["mylib.cpp"],
- shared_libs: ["mylib2"],
- system_shared_libs: [],
- stl: "none",
- }
-
- cc_library {
- name: "mylib2",
- srcs: ["mylib.cpp"],
- system_shared_libs: [],
- stl: "none",
- no_apex: true,
- }
- `)
-
- // respect 'no_apex' even with static link
- testApexError(t, `tries to include no_apex module mylib2`, `
- apex {
- name: "commonapex",
- key: "myapex.key",
- native_shared_libs: ["mylib"],
- }
-
- apex_key {
- name: "myapex.key",
- public_key: "testkey.avbpubkey",
- 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,
- }
- `)
-
- // 'no_apex' can be applied via defaults
- testApexError(t, `tries to include no_apex module mylib2`, `
- apex {
- name: "commonapex",
- key: "myapex.key",
- native_shared_libs: ["mylib"],
- }
-
- apex_key {
- name: "myapex.key",
- public_key: "testkey.avbpubkey",
- private_key: "testkey.pem",
- }
-
- cc_library {
- name: "mylib",
- srcs: ["mylib.cpp"],
- static_libs: ["mylib2"],
- system_shared_libs: [],
- stl: "none",
- }
-
- cc_defaults {
- name: "mylib2_defaults",
- system_shared_libs: [],
- stl: "none",
- no_apex: true,
- }
-
- cc_library {
- name: "mylib2",
- srcs: ["mylib.cpp"],
- defaults: ["mylib2_defaults"],
- }
- `)
-}
-
-func TestNoApexWorksWithWhitelist(t *testing.T) {
-
- testApex(t, `
- apex {
- name: "myapex",
- key: "myapex.key",
- native_shared_libs: ["mylib"],
- }
-
- apex_key {
- name: "myapex.key",
- public_key: "testkey.avbpubkey",
- private_key: "testkey.pem",
- }
-
- cc_library {
- name: "mylib",
- srcs: ["mylib.cpp"],
- shared_libs: ["mylib2"],
- system_shared_libs: [],
- stl: "none",
- }
-
- cc_defaults {
- name: "mylib2_defaults",
- system_shared_libs: [],
- stl: "none",
- no_apex: true,
- }
-
- cc_library {
- name: "mylib2",
- srcs: ["mylib.cpp"],
- defaults: ["mylib2_defaults"],
- }
- `, func(fs map[string][]byte, config android.Config) {
- whitelistNoApex = map[string][]string{
- "myapex": []string{"mylib2"},
- }
- })
-}
-
-func TestNoApexCanBeDependedOnViaStubs(t *testing.T) {
- ctx, _ := testApex(t, `
- apex {
- name: "myapex",
- key: "myapex.key",
- native_shared_libs: ["mylib"],
- }
-
- apex_key {
- name: "myapex.key",
- public_key: "testkey.avbpubkey",
- private_key: "testkey.pem",
- }
-
- cc_library {
- name: "mylib",
- srcs: ["mylib.cpp"],
- shared_libs: ["mylib2"],
- system_shared_libs: [],
- stl: "none",
- }
-
- cc_library {
- name: "mylib2",
- srcs: ["mylib.cpp"],
- shared_libs: ["mylib3"],
- system_shared_libs: [],
- stl: "none",
- stubs: {
- versions: ["1", "2", "3"],
- },
- }
-
- // this won't be included in "myapex", so 'no_apex' is still valid in this case.
- cc_library {
- name: "mylib3",
- srcs: ["mylib.cpp"],
- system_shared_libs: [],
- stl: "none",
- no_apex: true,
- }
- `)
-
- module := ctx.ModuleForTests("myapex", "android_common_myapex")
- 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")
-}
-
func TestErrorsIfDepsAreNotEnabled(t *testing.T) {
testApexError(t, `module "myapex" .* depends on disabled module "libfoo"`, `
apex {
diff --git a/cc/binary.go b/cc/binary.go
index 0d69405..9f18d6c 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -453,7 +453,7 @@
// 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
+ 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/cc.go b/cc/cc.go
index 0f2cb4c..9031afe 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -552,8 +552,10 @@
}
})
android.InitAndroidArchModule(c, c.hod, c.multilib)
- android.InitApexModule(c)
+
android.InitDefaultableModule(c)
+
+ android.InitApexModule(c)
android.InitSdkAwareModule(c)
return c
@@ -2229,8 +2231,8 @@
&android.ProtoProperties{},
)
- android.InitApexModule(module)
android.InitDefaultsModule(module)
+ android.InitApexModule(module)
return module
}
diff --git a/cc/installer.go b/cc/installer.go
index 610252c..9fdc88a 100644
--- a/cc/installer.go
+++ b/cc/installer.go
@@ -66,11 +66,10 @@
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 d8c9b90..0fb3c78 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -1048,7 +1048,7 @@
// 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
+ translatedArch := ctx.Target().NativeBridge == android.NativeBridgeEnabled
if InstallToBootstrap(ctx.baseModuleName(), ctx.Config()) && !library.buildStubs() && !translatedArch && !ctx.inRecovery() {
if ctx.Device() {
library.installSymlinkToRuntimeApex(ctx, file)
diff --git a/genrule/genrule.go b/genrule/genrule.go
index b8b0e01..c21df4c 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 {
@@ -169,10 +185,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 +293,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 +471,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 +492,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: blueprint.Phony,
- Output: phonyFile,
- Inputs: g.outputFiles,
- })
-
- g.outputDeps = android.Paths{phonyFile}
- }
}
// Collect information for opening IDE project files in java/jdeps.go.
@@ -465,7 +513,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 +550,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 +635,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 +653,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/java/config/config.go b/java/config/config.go
index ce62b93..f418ee7 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -86,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",
diff --git a/java/config/makevars.go b/java/config/makevars.go
index c40f4fc..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}")
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index db6b455..b48871e 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -126,10 +126,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
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index 8c699b8..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)
}
diff --git a/java/system_modules.go b/java/system_modules.go
index 43e4e11..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(),
},
})
@@ -123,7 +124,7 @@
system.headerJars = jars
- system.outputDir, system.outputDeps = TransformJarsToSystemModules(ctx, "java.base", jars)
+ system.outputDir, system.outputDeps = TransformJarsToSystemModules(ctx, jars)
}
func (system *SystemModules) DepsMutator(ctx android.BottomUpMutatorContext) {
diff --git a/python/installer.go b/python/installer.go
index b0a25b9..396f036 100644
--- a/python/installer.go
+++ b/python/installer.go
@@ -52,7 +52,7 @@
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/rust/compiler.go b/rust/compiler.go
index 6d74010..3f02835 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -184,7 +184,7 @@
if ctx.toolchain().Is64Bit() && compiler.dir64 != "" {
dir = compiler.dir64
}
- if (!ctx.Host() && !ctx.Arch().Native) || ctx.Target().NativeBridge == android.NativeBridgeEnabled {
+ if !ctx.Host() || ctx.Target().NativeBridge == android.NativeBridgeEnabled {
dir = filepath.Join(dir, ctx.Arch().ArchType.String())
}
return android.PathForModuleInstall(ctx, dir, compiler.subDir,
diff --git a/ui/build/cleanbuild.go b/ui/build/cleanbuild.go
index 0a2b510..1dbeb26 100644
--- a/ui/build/cleanbuild.go
+++ b/ui/build/cleanbuild.go
@@ -107,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 def3345..919b9ce 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -214,10 +214,14 @@
// 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)
@@ -228,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 82b2750..8581387 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
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