Merge "Print product vars in board config launcher"
diff --git a/android/apex.go b/android/apex.go
index b9efe4e..6b4054d 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -854,7 +854,6 @@
}
return list
}(map[string]int{
- "adbd": 30,
"android.net.ipsec.ike": 30,
"androidx.annotation_annotation-nodeps": 29,
"androidx.arch.core_core-common-nodeps": 29,
@@ -879,18 +878,6 @@
"kotlinx-coroutines-android-nodeps": 30,
"kotlinx-coroutines-core": 28,
"kotlinx-coroutines-core-nodeps": 30,
- "libadb_crypto": 30,
- "libadb_pairing_auth": 30,
- "libadb_pairing_connection": 30,
- "libadb_pairing_server": 30,
- "libadb_protos": 30,
- "libadb_tls_connection": 30,
- "libadbconnection_client": 30,
- "libadbconnection_server": 30,
- "libadbd_core": 30,
- "libadbd_services": 30,
- "libadbd": 30,
- "libapp_processes_protos_lite": 30,
"libasyncio": 30,
"libbrotli": 30,
"libbuildversion": 30,
diff --git a/android/bazel.go b/android/bazel.go
index bf214a5..e97acff 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -15,7 +15,6 @@
package android
import (
- "android/soong/bazel"
"fmt"
"io/ioutil"
"path/filepath"
@@ -25,18 +24,35 @@
"github.com/google/blueprint/proptools"
)
+type bazelModuleProperties struct {
+ // The label of the Bazel target replacing this Soong module. When run in conversion mode, this
+ // will import the handcrafted build target into the autogenerated file. Note: this may result in
+ // a conflict due to duplicate targets if bp2build_available is also set.
+ Label *string
+
+ // If true, bp2build will generate the converted Bazel target for this module. Note: this may
+ // cause a conflict due to the duplicate targets if label is also set.
+ //
+ // This is a bool pointer to support tristates: true, false, not set.
+ //
+ // To opt-in a module, set bazel_module: { bp2build_available: true }
+ // To opt-out a module, set bazel_module: { bp2build_available: false }
+ // To defer the default setting for the directory, do not set the value.
+ Bp2build_available *bool
+}
+
// Properties contains common module properties for Bazel migration purposes.
type properties struct {
// In USE_BAZEL_ANALYSIS=1 mode, this represents the Bazel target replacing
// this Soong module.
- Bazel_module bazel.BazelModuleProperties
+ Bazel_module bazelModuleProperties
}
// namespacedVariableProperties is a map from a string representing a Soong
-// config variable namespace, like "android" or "vendor_name" to a struct
-// pointer representing the soong_config_variables property of a module created
-// by a soong_config_module_type or soong_config_module_type_import.
-type namespacedVariableProperties map[string]interface{}
+// config variable namespace, like "android" or "vendor_name" to a slice of
+// pointer to a struct containing a single field called Soong_config_variables
+// whose value mirrors the structure in the Blueprint file.
+type namespacedVariableProperties map[string][]interface{}
// BazelModuleBase contains the property structs with metadata for modules which can be converted to
// Bazel.
@@ -68,11 +84,19 @@
convertWithBp2build(ctx BazelConversionContext, module blueprint.Module) bool
GetBazelBuildFileContents(c Config, path, name string) (string, error)
- // For namespaced config variable support
+ // namespacedVariableProps is a map from a soong config variable namespace
+ // (e.g. acme, android) to a map of interfaces{}, which are really
+ // reflect.Struct pointers, representing the value of the
+ // soong_config_variables property of a module. The struct pointer is the
+ // one with the single member called Soong_config_variables, which itself is
+ // a struct containing fields for each supported feature in that namespace.
+ //
+ // The reason for using an slice of interface{} is to support defaults
+ // propagation of the struct pointers.
namespacedVariableProps() namespacedVariableProperties
setNamespacedVariableProps(props namespacedVariableProperties)
BaseModuleType() string
- SetBaseModuleType(string)
+ SetBaseModuleType(baseModuleType string)
}
// BazelModule is a lightweight wrapper interface around Module for Bazel-convertible modules.
@@ -237,6 +261,7 @@
"packages/modules/adb/proto": Bp2BuildDefaultTrueRecursively,
"packages/modules/adb/tls": Bp2BuildDefaultTrueRecursively,
"prebuilts/clang/host/linux-x86": Bp2BuildDefaultTrueRecursively,
+ "system/apex": Bp2BuildDefaultFalse, // TODO(b/207466993): flaky failures
"system/core/diagnose_usb": Bp2BuildDefaultTrueRecursively,
"system/core/libasyncio": Bp2BuildDefaultTrue,
"system/core/libcrypto_utils": Bp2BuildDefaultTrueRecursively,
diff --git a/android/config.go b/android/config.go
index 6f05565..5ee28e7 100644
--- a/android/config.go
+++ b/android/config.go
@@ -155,9 +155,10 @@
fs pathtools.FileSystem
mockBpList string
- runningAsBp2Build bool
- bp2buildPackageConfig Bp2BuildConfig
- bp2buildModuleTypeConfig map[string]bool
+ runningAsBp2Build bool
+ bp2buildPackageConfig Bp2BuildConfig
+ bp2buildModuleTypeConfig map[string]bool
+ Bp2buildSoongConfigDefinitions soongconfig.Bp2BuildSoongConfigDefinitions
// If testAllowNonExistentPaths is true then PathForSource and PathForModuleSrc won't error
// in tests when a path doesn't exist.
diff --git a/android/defaults.go b/android/defaults.go
index be80cf1..9046002 100644
--- a/android/defaults.go
+++ b/android/defaults.go
@@ -213,10 +213,60 @@
var _ Defaults = (*DefaultsModuleBase)(nil)
+// applyNamespacedVariableDefaults only runs in bp2build mode for
+// defaultable/defaults modules. Its purpose is to merge namespaced product
+// variable props from defaults deps, even if those defaults are custom module
+// types created from soong_config_module_type, e.g. one that's wrapping a
+// cc_defaults or java_defaults.
+func applyNamespacedVariableDefaults(defaultDep Defaults, ctx TopDownMutatorContext) {
+ var dep, b Bazelable
+
+ dep, ok := defaultDep.(Bazelable)
+ if !ok {
+ if depMod, ok := defaultDep.(Module); ok {
+ // Track that this dependency hasn't been converted to bp2build yet.
+ ctx.AddUnconvertedBp2buildDep(depMod.Name())
+ return
+ } else {
+ panic("Expected default dep to be a Module.")
+ }
+ }
+
+ b, ok = ctx.Module().(Bazelable)
+ if !ok {
+ return
+ }
+
+ // namespacedVariableProps is a map from namespaces (e.g. acme, android,
+ // vendor_foo) to a slice of soong_config_variable struct pointers,
+ // containing properties for that particular module.
+ src := dep.namespacedVariableProps()
+ dst := b.namespacedVariableProps()
+ if dst == nil {
+ dst = make(namespacedVariableProperties)
+ }
+
+ // Propagate all soong_config_variable structs from the dep. We'll merge the
+ // actual property values later in variable.go.
+ for namespace := range src {
+ if dst[namespace] == nil {
+ dst[namespace] = []interface{}{}
+ }
+ for _, i := range src[namespace] {
+ dst[namespace] = append(dst[namespace], i)
+ }
+ }
+
+ b.setNamespacedVariableProps(dst)
+}
+
func (defaultable *DefaultableModuleBase) applyDefaults(ctx TopDownMutatorContext,
defaultsList []Defaults) {
for _, defaults := range defaultsList {
+ if ctx.Config().runningAsBp2Build {
+ applyNamespacedVariableDefaults(defaults, ctx)
+ }
for _, prop := range defaultable.defaultableProperties {
if prop == defaultable.defaultableVariableProperties {
defaultable.applyDefaultVariableProperties(ctx, defaults, prop)
diff --git a/android/defs.go b/android/defs.go
index c8e2e9b..362b382 100644
--- a/android/defs.go
+++ b/android/defs.go
@@ -52,10 +52,10 @@
// A copy rule.
Cp = pctx.AndroidStaticRule("Cp",
blueprint.RuleParams{
- Command: "rm -f $out && cp $cpPreserveSymlinks $cpFlags $in $out",
+ Command: "rm -f $out && cp $cpPreserveSymlinks $cpFlags $in $out$extraCmds",
Description: "cp $out",
},
- "cpFlags")
+ "cpFlags", "extraCmds")
// A copy rule that only updates the output if it changed.
CpIfChanged = pctx.AndroidStaticRule("CpIfChanged",
@@ -68,10 +68,10 @@
CpExecutable = pctx.AndroidStaticRule("CpExecutable",
blueprint.RuleParams{
- Command: "rm -f $out && cp $cpPreserveSymlinks $cpFlags $in $out && chmod +x $out",
+ Command: "rm -f $out && cp $cpPreserveSymlinks $cpFlags $in $out && chmod +x $out$extraCmds",
Description: "cp $out",
},
- "cpFlags")
+ "cpFlags", "extraCmds")
// A timestamp touch rule.
Touch = pctx.AndroidStaticRule("Touch",
diff --git a/android/makevars.go b/android/makevars.go
index 665d576..ece7091 100644
--- a/android/makevars.go
+++ b/android/makevars.go
@@ -456,6 +456,9 @@
for _, dep := range install.implicitDeps {
fmt.Fprintf(buf, " %s", dep.String())
}
+ if extraFiles := install.extraFiles; extraFiles != nil {
+ fmt.Fprintf(buf, " %s", extraFiles.zip.String())
+ }
if len(install.orderOnlyDeps) > 0 {
fmt.Fprintf(buf, " |")
}
@@ -463,12 +466,14 @@
fmt.Fprintf(buf, " %s", dep.String())
}
fmt.Fprintln(buf)
-
- fmt.Fprintf(buf, "\trm -f $@ && cp -f %s $< $@", preserveSymlinksFlag)
+ fmt.Fprintln(buf, "\t@echo \"Install $@\"")
+ fmt.Fprintf(buf, "\trm -f $@ && cp -f %s $< $@\n", preserveSymlinksFlag)
if install.executable {
- fmt.Fprintf(buf, " && chmod +x $@")
+ fmt.Fprintf(buf, "\tchmod +x $@\n")
}
- fmt.Fprintln(buf)
+ if extraFiles := install.extraFiles; extraFiles != nil {
+ fmt.Fprintf(buf, "\tunzip -qDD -d '%s' '%s'\n", extraFiles.dir.String(), extraFiles.zip.String())
+ }
fmt.Fprintln(buf)
}
@@ -504,6 +509,7 @@
fromStr = symlink.absFrom
}
+ fmt.Fprintln(buf, "\t@echo \"Symlink $@\"")
fmt.Fprintf(buf, "\trm -f $@ && ln -sfn %s $@", fromStr)
fmt.Fprintln(buf)
fmt.Fprintln(buf)
diff --git a/android/module.go b/android/module.go
index c778078..e100330 100644
--- a/android/module.go
+++ b/android/module.go
@@ -381,6 +381,16 @@
// for which IsInstallDepNeeded returns true.
InstallFile(installPath InstallPath, name string, srcPath Path, deps ...Path) InstallPath
+ // InstallFileWithExtraFilesZip creates a rule to copy srcPath to name in the installPath
+ // directory, and also unzip a zip file containing extra files to install into the same
+ // directory.
+ //
+ // The installed file will be returned by FilesToInstall(), and the PackagingSpec for the
+ // installed file will be returned by PackagingSpecs() on this module or by
+ // TransitivePackagingSpecs() on modules that depend on this module through dependency tags
+ // for which IsInstallDepNeeded returns true.
+ InstallFileWithExtraFilesZip(installPath InstallPath, name string, srcPath Path, extraZip Path, deps ...Path) InstallPath
+
// InstallSymlink creates a rule to create a symlink from src srcPath to name in the installPath
// directory.
//
@@ -2235,10 +2245,16 @@
implicitDeps Paths
orderOnlyDeps Paths
executable bool
+ extraFiles *extraFilesZip
absFrom string
}
+type extraFilesZip struct {
+ zip Path
+ dir InstallPath
+}
+
type katiInstalls []katiInstall
// BuiltInstalled returns the katiInstalls in the form used by $(call copy-many-files) in Make, a
@@ -2852,12 +2868,20 @@
func (m *moduleContext) InstallFile(installPath InstallPath, name string, srcPath Path,
deps ...Path) InstallPath {
- return m.installFile(installPath, name, srcPath, deps, false)
+ return m.installFile(installPath, name, srcPath, deps, false, nil)
}
func (m *moduleContext) InstallExecutable(installPath InstallPath, name string, srcPath Path,
deps ...Path) InstallPath {
- return m.installFile(installPath, name, srcPath, deps, true)
+ return m.installFile(installPath, name, srcPath, deps, true, nil)
+}
+
+func (m *moduleContext) InstallFileWithExtraFilesZip(installPath InstallPath, name string, srcPath Path,
+ extraZip Path, deps ...Path) InstallPath {
+ return m.installFile(installPath, name, srcPath, deps, false, &extraFilesZip{
+ zip: extraZip,
+ dir: installPath,
+ })
}
func (m *moduleContext) PackageFile(installPath InstallPath, name string, srcPath Path) PackagingSpec {
@@ -2878,7 +2902,8 @@
return spec
}
-func (m *moduleContext) installFile(installPath InstallPath, name string, srcPath Path, deps []Path, executable bool) InstallPath {
+func (m *moduleContext) installFile(installPath InstallPath, name string, srcPath Path, deps []Path,
+ executable bool, extraZip *extraFilesZip) InstallPath {
fullInstallPath := installPath.Join(m, name)
m.module.base().hooks.runInstallHooks(m, srcPath, fullInstallPath, false)
@@ -2906,6 +2931,7 @@
implicitDeps: implicitDeps,
orderOnlyDeps: orderOnlyDeps,
executable: executable,
+ extraFiles: extraZip,
})
} else {
rule := Cp
@@ -2913,6 +2939,13 @@
rule = CpExecutable
}
+ extraCmds := ""
+ if extraZip != nil {
+ extraCmds += fmt.Sprintf(" && unzip -qDD -d '%s' '%s'",
+ extraZip.dir.String(), extraZip.zip.String())
+ implicitDeps = append(implicitDeps, extraZip.zip)
+ }
+
m.Build(pctx, BuildParams{
Rule: rule,
Description: "install " + fullInstallPath.Base(),
@@ -2921,6 +2954,9 @@
Implicits: implicitDeps,
OrderOnly: orderOnlyDeps,
Default: !m.Config().KatiEnabled(),
+ Args: map[string]string{
+ "extraCmds": extraCmds,
+ },
})
}
diff --git a/android/neverallow.go b/android/neverallow.go
index 04366d3..b36bf04 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -214,8 +214,11 @@
return []Rule{
NeverAllow().
ModuleType("makefile_goal").
+ // TODO(b/33691272): remove this after migrating seapp to Soong
+ Without("product_out_path", "obj/ETC/plat_seapp_contexts_intermediates/plat_seapp_contexts").
+ Without("product_out_path", "obj/ETC/plat_seapp_neverallows_intermediates/plat_seapp_neverallows").
WithoutMatcher("product_out_path", Regexp("^boot[0-9a-zA-Z.-]*[.]img$")).
- Because("Only boot images may be imported as a makefile goal."),
+ Because("Only boot images and seapp contexts may be imported as a makefile goal."),
}
}
diff --git a/android/neverallow_test.go b/android/neverallow_test.go
index 35aadd8..edda244 100644
--- a/android/neverallow_test.go
+++ b/android/neverallow_test.go
@@ -293,7 +293,7 @@
`),
},
expectedErrors: []string{
- "Only boot images may be imported as a makefile goal.",
+ "Only boot images and seapp contexts may be imported as a makefile goal.",
},
},
}
diff --git a/android/soong_config_modules.go b/android/soong_config_modules.go
index 065440d..91bbce6 100644
--- a/android/soong_config_modules.go
+++ b/android/soong_config_modules.go
@@ -380,6 +380,9 @@
}
mtDef, errs := soongconfig.Parse(r, from)
+ if ctx.Config().runningAsBp2Build {
+ ctx.Config().Bp2buildSoongConfigDefinitions.AddVars(*mtDef)
+ }
if len(errs) > 0 {
reportErrors(ctx, from, errs...)
@@ -415,14 +418,13 @@
if !conditionalFactoryProps.IsValid() {
return factory
}
- useBp2buildHook := bp2build && proptools.BoolDefault(moduleType.Bp2buildAvailable, false)
return func() (blueprint.Module, []interface{}) {
module, props := factory()
conditionalProps := proptools.CloneEmptyProperties(conditionalFactoryProps)
props = append(props, conditionalProps.Interface())
- if useBp2buildHook {
+ if bp2build {
// The loadhook is different for bp2build, since we don't want to set a specific
// set of property values based on a vendor var -- we want __all of them__ to
// generate select statements, so we put the entire soong_config_variables
@@ -434,7 +436,7 @@
// Instead of applying all properties, keep the entire conditionalProps struct as
// part of the custom module so dependent modules can create the selects accordingly
m.setNamespacedVariableProps(namespacedVariableProperties{
- moduleType.ConfigNamespace: conditionalProps.Interface(),
+ moduleType.ConfigNamespace: []interface{}{conditionalProps.Interface()},
})
}
})
diff --git a/android/soongconfig/modules.go b/android/soongconfig/modules.go
index 1af89ba..3a93f47 100644
--- a/android/soongconfig/modules.go
+++ b/android/soongconfig/modules.go
@@ -15,7 +15,6 @@
package soongconfig
import (
- "android/soong/bazel"
"fmt"
"io"
"reflect"
@@ -121,8 +120,6 @@
// the list of properties that this module type will extend.
Properties []string
-
- Bazel_module bazel.BazelModuleProperties
}
func processModuleTypeDef(v *SoongConfigDefinition, def *parser.Module) (errs []error) {
@@ -233,6 +230,96 @@
variables map[string]soongConfigVariable
}
+// Bp2BuildSoongConfigDefinition keeps a global record of all soong config
+// string vars, bool vars and value vars created by every
+// soong_config_module_type in this build.
+type Bp2BuildSoongConfigDefinitions struct {
+ StringVars map[string]map[string]bool
+ BoolVars map[string]bool
+ ValueVars map[string]bool
+}
+
+// SoongConfigVariablesForBp2build extracts information from a
+// SoongConfigDefinition that bp2build needs to generate constraint settings and
+// values for, in order to migrate soong_config_module_type usages to Bazel.
+func (defs *Bp2BuildSoongConfigDefinitions) AddVars(mtDef SoongConfigDefinition) {
+ if defs.StringVars == nil {
+ defs.StringVars = make(map[string]map[string]bool)
+ }
+ if defs.BoolVars == nil {
+ defs.BoolVars = make(map[string]bool)
+ }
+ if defs.ValueVars == nil {
+ defs.ValueVars = make(map[string]bool)
+ }
+ for _, moduleType := range mtDef.ModuleTypes {
+ for _, v := range moduleType.Variables {
+ key := strings.Join([]string{moduleType.ConfigNamespace, v.variableProperty()}, "__")
+ if strVar, ok := v.(*stringVariable); ok {
+ if _, ok := defs.StringVars[key]; !ok {
+ defs.StringVars[key] = make(map[string]bool, 0)
+ }
+ for _, value := range strVar.values {
+ defs.StringVars[key][value] = true
+ }
+ } else if _, ok := v.(*boolVariable); ok {
+ defs.BoolVars[key] = true
+ } else if _, ok := v.(*valueVariable); ok {
+ defs.ValueVars[key] = true
+ } else {
+ panic(fmt.Errorf("Unsupported variable type: %+v", v))
+ }
+ }
+ }
+}
+
+// This is a copy of the one available in soong/android/util.go, but depending
+// on the android package causes a cyclic dependency. A refactoring here is to
+// extract common utils out from android/utils.go for other packages like this.
+func sortedStringKeys(m interface{}) []string {
+ v := reflect.ValueOf(m)
+ if v.Kind() != reflect.Map {
+ panic(fmt.Sprintf("%#v is not a map", m))
+ }
+ keys := v.MapKeys()
+ s := make([]string, 0, len(keys))
+ for _, key := range keys {
+ s = append(s, key.String())
+ }
+ sort.Strings(s)
+ return s
+}
+
+// String emits the Soong config variable definitions as Starlark dictionaries.
+func (defs Bp2BuildSoongConfigDefinitions) String() string {
+ ret := ""
+ ret += "soong_config_bool_variables = {\n"
+ for _, boolVar := range sortedStringKeys(defs.BoolVars) {
+ ret += fmt.Sprintf(" \"%s\": True,\n", boolVar)
+ }
+ ret += "}\n"
+ ret += "\n"
+
+ ret += "soong_config_value_variables = {\n"
+ for _, valueVar := range sortedStringKeys(defs.ValueVars) {
+ ret += fmt.Sprintf(" \"%s\": True,\n", valueVar)
+ }
+ ret += "}\n"
+ ret += "\n"
+
+ ret += "soong_config_string_variables = {\n"
+ for _, stringVar := range sortedStringKeys(defs.StringVars) {
+ ret += fmt.Sprintf(" \"%s\": [\n", stringVar)
+ for _, choice := range sortedStringKeys(defs.StringVars[stringVar]) {
+ ret += fmt.Sprintf(" \"%s\",\n", choice)
+ }
+ ret += fmt.Sprintf(" ],\n")
+ }
+ ret += "}"
+
+ return ret
+}
+
// CreateProperties returns a reflect.Value of a newly constructed type that contains the desired
// property layout for the Soong config variables, with each possible value an interface{} that
// contains a nil pointer to another newly constructed type that contains the affectable properties.
@@ -436,7 +523,6 @@
affectableProperties []string
variableNames []string
- Bp2buildAvailable *bool
}
func newModuleType(props *ModuleTypeProperties) (*ModuleType, []error) {
@@ -445,7 +531,6 @@
ConfigNamespace: props.Config_namespace,
BaseModuleType: props.Module_type,
variableNames: props.Variables,
- Bp2buildAvailable: props.Bazel_module.Bp2build_available,
}
for _, name := range props.Bool_variables {
diff --git a/android/soongconfig/modules_test.go b/android/soongconfig/modules_test.go
index 48cdfe7..b14f8b4 100644
--- a/android/soongconfig/modules_test.go
+++ b/android/soongconfig/modules_test.go
@@ -364,3 +364,117 @@
}
}
}
+
+func Test_Bp2BuildSoongConfigDefinitions(t *testing.T) {
+ testCases := []struct {
+ defs Bp2BuildSoongConfigDefinitions
+ expected string
+ }{
+ {
+ defs: Bp2BuildSoongConfigDefinitions{},
+ expected: `soong_config_bool_variables = {
+}
+
+soong_config_value_variables = {
+}
+
+soong_config_string_variables = {
+}`}, {
+ defs: Bp2BuildSoongConfigDefinitions{
+ BoolVars: map[string]bool{
+ "bool_var": true,
+ },
+ },
+ expected: `soong_config_bool_variables = {
+ "bool_var": True,
+}
+
+soong_config_value_variables = {
+}
+
+soong_config_string_variables = {
+}`}, {
+ defs: Bp2BuildSoongConfigDefinitions{
+ ValueVars: map[string]bool{
+ "value_var": true,
+ },
+ },
+ expected: `soong_config_bool_variables = {
+}
+
+soong_config_value_variables = {
+ "value_var": True,
+}
+
+soong_config_string_variables = {
+}`}, {
+ defs: Bp2BuildSoongConfigDefinitions{
+ StringVars: map[string]map[string]bool{
+ "string_var": map[string]bool{
+ "choice1": true,
+ "choice2": true,
+ "choice3": true,
+ },
+ },
+ },
+ expected: `soong_config_bool_variables = {
+}
+
+soong_config_value_variables = {
+}
+
+soong_config_string_variables = {
+ "string_var": [
+ "choice1",
+ "choice2",
+ "choice3",
+ ],
+}`}, {
+ defs: Bp2BuildSoongConfigDefinitions{
+ BoolVars: map[string]bool{
+ "bool_var_one": true,
+ },
+ ValueVars: map[string]bool{
+ "value_var_one": true,
+ "value_var_two": true,
+ },
+ StringVars: map[string]map[string]bool{
+ "string_var_one": map[string]bool{
+ "choice1": true,
+ "choice2": true,
+ "choice3": true,
+ },
+ "string_var_two": map[string]bool{
+ "foo": true,
+ "bar": true,
+ },
+ },
+ },
+ expected: `soong_config_bool_variables = {
+ "bool_var_one": True,
+}
+
+soong_config_value_variables = {
+ "value_var_one": True,
+ "value_var_two": True,
+}
+
+soong_config_string_variables = {
+ "string_var_one": [
+ "choice1",
+ "choice2",
+ "choice3",
+ ],
+ "string_var_two": [
+ "bar",
+ "foo",
+ ],
+}`},
+ }
+ for _, test := range testCases {
+ actual := test.defs.String()
+ if actual != test.expected {
+ t.Errorf("Expected:\n%s\nbut got:\n%s", test.expected, actual)
+ }
+ }
+}
diff --git a/android/variable.go b/android/variable.go
index 89cd59e..fe828d3 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -564,6 +564,10 @@
FullConfig string
}
+func (p *ProductConfigProperty) AlwaysEmit() bool {
+ return p.Namespace != ""
+}
+
func (p *ProductConfigProperty) ConfigurationAxis() bazel.ConfigurationAxis {
if p.Namespace == "" {
return bazel.ProductVariableConfigurationAxis(p.FullConfig)
@@ -640,19 +644,135 @@
}
if m, ok := module.(Bazelable); ok && m.namespacedVariableProps() != nil {
- for namespace, namespacedVariableProp := range m.namespacedVariableProps() {
- productVariableValues(
- soongconfig.SoongConfigProperty,
- namespacedVariableProp,
- namespace,
- "",
- &productConfigProperties)
+ for namespace, namespacedVariableProps := range m.namespacedVariableProps() {
+ for _, namespacedVariableProp := range namespacedVariableProps {
+ productVariableValues(
+ soongconfig.SoongConfigProperty,
+ namespacedVariableProp,
+ namespace,
+ "",
+ &productConfigProperties)
+ }
}
}
+ productConfigProperties.zeroValuesForNamespacedVariables()
+
return productConfigProperties
}
+// zeroValuesForNamespacedVariables ensures that selects that contain __only__
+// conditions default values have zero values set for the other non-default
+// values for that select statement.
+//
+// If the ProductConfigProperties map contains these items, as parsed from the .bp file:
+//
+// library_linking_strategy: {
+// prefer_static: {
+// static_libs: [
+// "lib_a",
+// "lib_b",
+// ],
+// },
+// conditions_default: {
+// shared_libs: [
+// "lib_a",
+// "lib_b",
+// ],
+// },
+// },
+//
+// Static_libs {Library_linking_strategy ANDROID prefer_static} [lib_a lib_b]
+// Shared_libs {Library_linking_strategy ANDROID conditions_default} [lib_a lib_b]
+//
+// We need to add this:
+//
+// Shared_libs {Library_linking_strategy ANDROID prefer_static} []
+//
+// so that the following gets generated for the "dynamic_deps" attribute,
+// instead of putting lib_a and lib_b directly into dynamic_deps without a
+// select:
+//
+// dynamic_deps = select({
+// "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": [],
+// "//conditions:default": [
+// "//foo/bar:lib_a",
+// "//foo/bar:lib_b",
+// ],
+// }),
+func (props *ProductConfigProperties) zeroValuesForNamespacedVariables() {
+ // A map of product config properties to the zero values of their respective
+ // property value.
+ zeroValues := make(map[ProductConfigProperty]interface{})
+
+ // A map of prop names (e.g. cflags) to product config properties where the
+ // (prop name, ProductConfigProperty) tuple contains a non-conditions_default key.
+ //
+ // e.g.
+ //
+ // prefer_static: {
+ // static_libs: [
+ // "lib_a",
+ // "lib_b",
+ // ],
+ // },
+ // conditions_default: {
+ // shared_libs: [
+ // "lib_a",
+ // "lib_b",
+ // ],
+ // },
+ //
+ // The tuple of ("static_libs", prefer_static) would be in this map.
+ hasNonDefaultValue := make(map[string]map[ProductConfigProperty]bool)
+
+ // Iterate over all added soong config variables.
+ for propName, v := range *props {
+ for p, intf := range v {
+ if p.Namespace == "" {
+ // If there's no namespace, this isn't a soong config variable,
+ // i.e. this is a product variable. product variables have no
+ // conditions_defaults, so skip them.
+ continue
+ }
+ if p.FullConfig == bazel.ConditionsDefaultConfigKey {
+ // Skip conditions_defaults.
+ continue
+ }
+ if hasNonDefaultValue[propName] == nil {
+ hasNonDefaultValue[propName] = make(map[ProductConfigProperty]bool)
+ hasNonDefaultValue[propName][p] = false
+ }
+ // Create the zero value of the variable.
+ if _, exists := zeroValues[p]; !exists {
+ zeroValue := reflect.Zero(reflect.ValueOf(intf).Type()).Interface()
+ if zeroValue == nil {
+ panic(fmt.Errorf("Expected non-nil zero value for product/config variable %+v\n", intf))
+ }
+ zeroValues[p] = zeroValue
+ }
+ hasNonDefaultValue[propName][p] = true
+ }
+ }
+
+ for propName := range *props {
+ for p, zeroValue := range zeroValues {
+ // Ignore variables that already have a non-default value for that axis
+ if exists, _ := hasNonDefaultValue[propName][p]; !exists {
+ // fmt.Println(propName, p.Namespace, p.Name, p.FullConfig, zeroValue)
+ // Insert the zero value for this propname + product config value.
+ props.AddProductConfigProperty(
+ propName,
+ p.Namespace,
+ p.Name,
+ p.FullConfig,
+ zeroValue,
+ )
+ }
+ }
+ }
+}
+
func (p *ProductConfigProperties) AddProductConfigProperty(
propertyName, namespace, productVariableName, config string, property interface{}) {
if (*p)[propertyName] == nil {
@@ -665,7 +785,19 @@
FullConfig: config, // e.g. size, feature1-x86, size__conditions_default
}
- (*p)[propertyName][productConfigProp] = property
+ if existing, ok := (*p)[propertyName][productConfigProp]; ok && namespace != "" {
+ switch dst := existing.(type) {
+ case []string:
+ if src, ok := property.([]string); ok {
+ dst = append(dst, src...)
+ (*p)[propertyName][productConfigProp] = dst
+ }
+ default:
+ panic(fmt.Errorf("TODO: handle merging value %s", existing))
+ }
+ } else {
+ (*p)[propertyName][productConfigProp] = property
+ }
}
var (
@@ -701,19 +833,10 @@
return v, true
}
-// productVariableValues uses reflection to convert a property struct for
-// product_variables and soong_config_variables to structs that can be generated
-// as select statements.
-func productVariableValues(
- fieldName string, variableProps interface{}, namespace, suffix string, productConfigProperties *ProductConfigProperties) {
- if suffix != "" {
- suffix = "-" + suffix
- }
-
- // variableValues represent the product_variables or soong_config_variables
- // struct.
- variableValues := reflect.ValueOf(variableProps).Elem().FieldByName(fieldName)
-
+func (productConfigProperties *ProductConfigProperties) AddProductConfigProperties(namespace, suffix string, variableValues reflect.Value) {
+ // variableValues can either be a product_variables or
+ // soong_config_variables struct.
+ //
// Example of product_variables:
//
// product_variables: {
@@ -818,9 +941,10 @@
field.Field(k).Interface(), // e.g. ["-DDEFAULT"], ["foo", "bar"]
)
}
- } else {
- // Not a conditions_default or a struct prop, i.e. regular
- // product variables, or not a string-typed config var.
+ } else if property.Kind() != reflect.Interface {
+ // If not an interface, then this is not a conditions_default or
+ // a struct prop. That is, this is a regular product variable,
+ // or a bool/value config variable.
config := productVariableName + suffix
productConfigProperties.AddProductConfigProperty(
propertyName,
@@ -834,6 +958,20 @@
}
}
+// productVariableValues uses reflection to convert a property struct for
+// product_variables and soong_config_variables to structs that can be generated
+// as select statements.
+func productVariableValues(
+ fieldName string, variableProps interface{}, namespace, suffix string, productConfigProperties *ProductConfigProperties) {
+ if suffix != "" {
+ suffix = "-" + suffix
+ }
+
+ // variableValues represent the product_variables or soong_config_variables struct.
+ variableValues := reflect.ValueOf(variableProps).Elem().FieldByName(fieldName)
+ productConfigProperties.AddProductConfigProperties(namespace, suffix, variableValues)
+}
+
func VariableMutator(mctx BottomUpMutatorContext) {
var module Module
var ok bool
diff --git a/apex/androidmk.go b/apex/androidmk.go
index a7a0107..7764b6b 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -108,18 +108,6 @@
return moduleNames
}
- var postInstallCommands []string
- for _, fi := range a.filesInfo {
- if a.linkToSystemLib && fi.transitiveDep && fi.availableToPlatform() {
- // TODO(jiyong): pathOnDevice should come from fi.module, not being calculated here
- linkTarget := filepath.Join("/system", fi.path())
- linkPath := filepath.Join(a.installDir.ToMakePath().String(), apexBundleName, fi.path())
- mkdirCmd := "mkdir -p " + filepath.Dir(linkPath)
- linkCmd := "ln -sfn " + linkTarget + " " + linkPath
- postInstallCommands = append(postInstallCommands, mkdirCmd, linkCmd)
- }
- }
-
seenDataOutPaths := make(map[string]bool)
for _, fi := range a.filesInfo {
@@ -193,6 +181,8 @@
// we will have duplicated notice entries.
fmt.Fprintln(w, "LOCAL_NO_NOTICE_FILE := true")
}
+ fmt.Fprintln(w, "LOCAL_SOONG_INSTALLED_MODULE :=", filepath.Join(modulePath, fi.stem()))
+ fmt.Fprintln(w, "LOCAL_SOONG_INSTALL_PAIRS :=", fi.builtFile.String()+":"+filepath.Join(modulePath, fi.stem()))
fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", fi.builtFile.String())
fmt.Fprintln(w, "LOCAL_MODULE_CLASS :=", fi.class.nameInMake())
if fi.module != nil {
@@ -263,7 +253,7 @@
if !ok {
panic(fmt.Sprintf("Expected %s to be AndroidAppSet", fi.module))
}
- fmt.Fprintln(w, "LOCAL_APK_SET_INSTALL_FILE :=", as.InstallFile())
+ fmt.Fprintln(w, "LOCAL_APK_SET_INSTALL_FILE :=", as.PackedAdditionalOutputs().String())
fmt.Fprintln(w, "LOCAL_APKCERTS_FILE :=", as.APKCertsFile().String())
fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_android_app_set.mk")
case nativeSharedLib, nativeExecutable, nativeTest:
@@ -302,18 +292,10 @@
if len(patterns) > 0 {
fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES :=", strings.Join(patterns, " "))
}
- if len(a.compatSymlinks) > 0 {
- // For flattened apexes, compat symlinks are attached to apex_manifest.json which is guaranteed for every apex
- postInstallCommands = append(postInstallCommands, a.compatSymlinks...)
- }
}
// File_contexts of flattened APEXes should be merged into file_contexts.bin
fmt.Fprintln(w, "LOCAL_FILE_CONTEXTS :=", a.fileContexts)
-
- if len(postInstallCommands) > 0 {
- fmt.Fprintln(w, "LOCAL_POST_INSTALL_CMD :=", strings.Join(postInstallCommands, " && "))
- }
}
fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
}
@@ -394,6 +376,8 @@
}
fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", name+stemSuffix)
fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE :=", !a.installable())
+ fmt.Fprintln(w, "LOCAL_SOONG_INSTALLED_MODULE :=", a.installedFile.String())
+ fmt.Fprintln(w, "LOCAL_SOONG_INSTALL_PAIRS :=", a.outputFile.String()+":"+a.installedFile.String())
// Because apex writes .mk with Custom(), we need to write manually some common properties
// which are available via data.Entries
@@ -418,16 +402,6 @@
fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES +=", strings.Join(a.requiredDeps, " "))
}
a.writeRequiredModules(w, name)
- var postInstallCommands []string
- if a.prebuiltFileToDelete != "" {
- postInstallCommands = append(postInstallCommands, "rm -rf "+
- filepath.Join(a.installDir.ToMakePath().String(), a.prebuiltFileToDelete))
- }
- // For unflattened apexes, compat symlinks are attached to apex package itself as LOCAL_POST_INSTALL_CMD
- postInstallCommands = append(postInstallCommands, a.compatSymlinks...)
- if len(postInstallCommands) > 0 {
- fmt.Fprintln(w, "LOCAL_POST_INSTALL_CMD :=", strings.Join(postInstallCommands, " && "))
- }
if a.mergedNotices.Merged.Valid() {
fmt.Fprintln(w, "LOCAL_NOTICE_FILE :=", a.mergedNotices.Merged.Path().String())
@@ -455,7 +429,7 @@
}
distCoverageFiles(w, "ndk_apis_usedby_apex", a.nativeApisUsedByModuleFile.String())
- distCoverageFiles(w, "ndk_apis_usedby_apex", a.nativeApisBackedByModuleFile.String())
+ distCoverageFiles(w, "ndk_apis_backedby_apex", a.nativeApisBackedByModuleFile.String())
distCoverageFiles(w, "java_apis_used_by_apex", a.javaApisUsedByModuleFile.String())
}
}}
diff --git a/apex/apex.go b/apex/apex.go
index 378efe6..c1a4b40 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -409,14 +409,14 @@
// vendor/google/build/build_unbundled_mainline_module.sh for more detail.
bundleModuleFile android.WritablePath
- // Target path to install this APEX. Usually out/target/product/<device>/<partition>/apex.
+ // Target directory to install this APEX. Usually out/target/product/<device>/<partition>/apex.
installDir android.InstallPath
- // List of commands to create symlinks for backward compatibility. These commands will be
- // attached as LOCAL_POST_INSTALL_CMD to apex package itself (for unflattened build) or
- // apex_manifest (for flattened build) so that compat symlinks are always installed
- // regardless of TARGET_FLATTEN_APEX setting.
- compatSymlinks []string
+ // Path where this APEX was installed.
+ installedFile android.InstallPath
+
+ // Installed locations of symlinks for backward compatibility.
+ compatSymlinks android.InstallPaths
// Text file having the list of individual files that are included in this APEX. Used for
// debugging purpose.
@@ -442,6 +442,10 @@
modulePaths []string
}
+func (*apexBundle) InstallBypassMake() bool {
+ return true
+}
+
// apexFileClass represents a type of file that can be included in APEX.
type apexFileClass int
@@ -2097,7 +2101,9 @@
a.linkToSystemLib = false
}
- a.compatSymlinks = makeCompatSymlinks(a.BaseModuleName(), ctx)
+ if a.properties.ApexType != zipApex {
+ a.compatSymlinks = makeCompatSymlinks(a.BaseModuleName(), ctx, a.primaryApexType)
+ }
////////////////////////////////////////////////////////////////////////////////////////////
// 4) generate the build rules to create the APEX. This is done in builder.go.
@@ -2662,7 +2668,6 @@
"libbuildversion",
"libmath",
"libprocpartition",
- "libsync",
}
//
// Module separator
@@ -2770,7 +2775,6 @@
"libstagefright_metadatautils",
"libstagefright_mpeg2extractor",
"libstagefright_mpeg2support",
- "libsync",
"libui",
"libui_headers",
"libunwindstack",
@@ -2911,7 +2915,6 @@
"libstagefright_m4vh263dec",
"libstagefright_m4vh263enc",
"libstagefright_mp3dec",
- "libsync",
"libui",
"libui_headers",
"libunwindstack",
diff --git a/apex/builder.go b/apex/builder.go
index 2e21ddf..0880e2b 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -414,18 +414,35 @@
func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) {
apexType := a.properties.ApexType
suffix := apexType.suffix()
+ apexName := proptools.StringDefault(a.properties.Apex_name, a.BaseModuleName())
////////////////////////////////////////////////////////////////////////////////////////////
// Step 1: copy built files to appropriate directories under the image directory
imageDir := android.PathForModuleOut(ctx, "image"+suffix)
+ installSymbolFiles := !ctx.Config().KatiEnabled() || a.ExportedToMake()
+
+ // b/140136207. When there are overriding APEXes for a VNDK APEX, the symbols file for the overridden
+ // APEX and the overriding APEX will have the same installation paths at /apex/com.android.vndk.v<ver>
+ // as their apexName will be the same. To avoid the path conflicts, skip installing the symbol files
+ // for the overriding VNDK APEXes.
+ if a.vndkApex && len(a.overridableProperties.Overrides) > 0 {
+ installSymbolFiles = false
+ }
+
+ // Avoid creating duplicate build rules for multi-installed APEXes.
+ if proptools.BoolDefault(a.properties.Multi_install_skip_symbol_files, false) {
+ installSymbolFiles = false
+ }
+
// TODO(jiyong): use the RuleBuilder
var copyCommands []string
var implicitInputs []android.Path
+ pathWhenActivated := android.PathForModuleInPartitionInstall(ctx, "apex", apexName)
for _, fi := range a.filesInfo {
destPath := imageDir.Join(ctx, fi.path()).String()
-
+ var installedPath android.InstallPath
// Prepare the destination path
destPathDir := filepath.Dir(destPath)
if fi.class == appSet {
@@ -442,11 +459,22 @@
} else {
if fi.class == appSet {
copyCommands = append(copyCommands,
- fmt.Sprintf("unzip -qDD -d %s %s", destPathDir, fi.builtFile.String()))
+ fmt.Sprintf("unzip -qDD -d %s %s", destPathDir,
+ fi.module.(*java.AndroidAppSet).PackedAdditionalOutputs().String()))
+ if installSymbolFiles {
+ installedPath = ctx.InstallFileWithExtraFilesZip(pathWhenActivated.Join(ctx, fi.installDir),
+ fi.stem(), fi.builtFile, fi.module.(*java.AndroidAppSet).PackedAdditionalOutputs())
+ }
} else {
copyCommands = append(copyCommands, "cp -f "+fi.builtFile.String()+" "+destPath)
+ if installSymbolFiles {
+ installedPath = ctx.InstallFile(pathWhenActivated.Join(ctx, fi.installDir), fi.stem(), fi.builtFile)
+ }
}
implicitInputs = append(implicitInputs, fi.builtFile)
+ if installSymbolFiles {
+ implicitInputs = append(implicitInputs, installedPath)
+ }
}
// Create additional symlinks pointing the file inside the APEX (if any). Note that
@@ -454,6 +482,10 @@
for _, symlinkPath := range fi.symlinkPaths() {
symlinkDest := imageDir.Join(ctx, symlinkPath).String()
copyCommands = append(copyCommands, "ln -sfn "+filepath.Base(destPath)+" "+symlinkDest)
+ if installSymbolFiles {
+ installedSymlink := ctx.InstallSymlink(pathWhenActivated.Join(ctx, filepath.Dir(symlinkPath)), filepath.Base(symlinkPath), installedPath)
+ implicitInputs = append(implicitInputs, installedSymlink)
+ }
}
// Copy the test files (if any)
@@ -472,6 +504,11 @@
}
}
implicitInputs = append(implicitInputs, a.manifestPbOut)
+ if installSymbolFiles {
+ installedManifest := ctx.InstallFile(pathWhenActivated, "apex_manifest.pb", a.manifestPbOut)
+ installedKey := ctx.InstallFile(pathWhenActivated, "apex_pubkey", a.publicKeyFile)
+ implicitInputs = append(implicitInputs, installedManifest, installedKey)
+ }
////////////////////////////////////////////////////////////////////////////////////////////
// Step 1.a: Write the list of files in this APEX to a txt file and compare it against
@@ -840,47 +877,55 @@
a.outputFile = signedCompressedOutputFile
}
+ installSuffix := suffix
+ if a.isCompressed {
+ installSuffix = imageCapexSuffix
+ }
+
// Install to $OUT/soong/{target,host}/.../apex.
- ctx.InstallFile(a.installDir, a.Name()+suffix, a.outputFile)
+ a.installedFile = ctx.InstallFile(a.installDir, a.Name()+installSuffix, a.outputFile,
+ a.compatSymlinks.Paths()...)
// installed-files.txt is dist'ed
a.installedFilesFile = a.buildInstalledFilesFile(ctx, a.outputFile, imageDir)
}
-// Context "decorator", overriding the InstallBypassMake method to always reply `true`.
-type flattenedApexContext struct {
- android.ModuleContext
-}
-
-func (c *flattenedApexContext) InstallBypassMake() bool {
- return true
-}
-
// buildFlattenedApex creates rules for a flattened APEX. Flattened APEX actually doesn't have a
// single output file. It is a phony target for all the files under /system/apex/<name> directory.
// This function creates the installation rules for the files.
func (a *apexBundle) buildFlattenedApex(ctx android.ModuleContext) {
bundleName := a.Name()
+ installedSymlinks := append(android.InstallPaths(nil), a.compatSymlinks...)
if a.installable() {
for _, fi := range a.filesInfo {
dir := filepath.Join("apex", bundleName, fi.installDir)
- target := ctx.InstallFile(android.PathForModuleInstall(ctx, dir), fi.stem(), fi.builtFile)
- for _, sym := range fi.symlinks {
- ctx.InstallSymlink(android.PathForModuleInstall(ctx, dir), sym, target)
+ installDir := android.PathForModuleInstall(ctx, dir)
+ if a.linkToSystemLib && fi.transitiveDep && fi.availableToPlatform() {
+ // TODO(jiyong): pathOnDevice should come from fi.module, not being calculated here
+ pathOnDevice := filepath.Join("/system", fi.path())
+ installedSymlinks = append(installedSymlinks,
+ ctx.InstallAbsoluteSymlink(installDir, fi.stem(), pathOnDevice))
+ } else {
+ target := ctx.InstallFile(installDir, fi.stem(), fi.builtFile)
+ for _, sym := range fi.symlinks {
+ installedSymlinks = append(installedSymlinks,
+ ctx.InstallSymlink(installDir, sym, target))
+ }
}
}
+
+ // Create install rules for the files added in GenerateAndroidBuildActions after
+ // buildFlattenedApex is called. Add the links to system libs (if any) as dependencies
+ // of the apex_manifest.pb file since it is always present.
+ dir := filepath.Join("apex", bundleName)
+ installDir := android.PathForModuleInstall(ctx, dir)
+ ctx.InstallFile(installDir, "apex_manifest.pb", a.manifestPbOut, installedSymlinks.Paths()...)
+ ctx.InstallFile(installDir, "apex_pubkey", a.publicKeyFile)
}
a.fileContexts = a.buildFileContexts(ctx)
- // 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).
- // TODO(jiyong): Why do we need to set outputFile for flattened APEX? We don't seem to use
- // it and it actually points to a path that can never be built. Remove this.
- factx := flattenedApexContext{ctx}
- a.outputFile = android.PathForModuleInstall(&factx, "apex", bundleName)
+ a.outputFile = android.PathForModuleInstall(ctx, "apex", bundleName)
}
// getCertificateAndPrivateKey retrieves the cert and the private key that will be used to sign
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index 61e7a0b..5b070c6 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -17,11 +17,13 @@
import (
"fmt"
"io"
+ "path/filepath"
"strconv"
"strings"
"android/soong/android"
"android/soong/java"
+
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
)
@@ -53,18 +55,17 @@
installDir android.InstallPath
installFilename string
+ installedFile android.InstallPath
outputApex android.WritablePath
// A list of apexFile objects created in prebuiltCommon.initApexFilesForAndroidMk which are used
// to create make modules in prebuiltCommon.AndroidMkEntries.
apexFilesForAndroidMk []apexFile
- // list of commands to create symlinks for backward compatibility.
- // these commands will be attached as LOCAL_POST_INSTALL_CMD
- compatSymlinks []string
+ // Installed locations of symlinks for backward compatibility.
+ compatSymlinks android.InstallPaths
- hostRequired []string
- postInstallCommands []string
+ hostRequired []string
}
type sanitizedPrebuilt interface {
@@ -223,13 +224,10 @@
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
entries.SetString("LOCAL_MODULE_PATH", p.installDir.ToMakePath().String())
entries.SetString("LOCAL_MODULE_STEM", p.installFilename)
+ entries.SetPath("LOCAL_SOONG_INSTALLED_MODULE", p.installedFile)
+ entries.SetString("LOCAL_SOONG_INSTALL_PAIRS", p.outputApex.String()+":"+p.installedFile.String())
entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", !p.installable())
entries.AddStrings("LOCAL_OVERRIDES_MODULES", p.prebuiltCommonProperties.Overrides...)
- postInstallCommands := append([]string{}, p.postInstallCommands...)
- postInstallCommands = append(postInstallCommands, p.compatSymlinks...)
- if len(postInstallCommands) > 0 {
- entries.SetString("LOCAL_POST_INSTALL_CMD", strings.Join(postInstallCommands, " && "))
- }
p.addRequiredModules(entries)
},
},
@@ -259,6 +257,9 @@
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
entries.SetString("LOCAL_MODULE_PATH", p.installDir.ToMakePath().String())
+ entries.SetString("LOCAL_SOONG_INSTALLED_MODULE :=", filepath.Join(p.installDir.String(), fi.stem()))
+ entries.SetString("LOCAL_SOONG_INSTALL_PAIRS :=",
+ fi.builtFile.String()+":"+filepath.Join(p.installDir.String(), fi.stem()))
// soong_java_prebuilt.mk sets LOCAL_MODULE_SUFFIX := .jar Therefore
// we need to remove the suffix from LOCAL_MODULE_STEM, otherwise
@@ -471,6 +472,10 @@
inputApex android.Path
}
+func (p *Prebuilt) InstallBypassMake() bool {
+ return true
+}
+
type ApexFileProperties struct {
// the path to the prebuilt .apex file to import.
//
@@ -756,15 +761,15 @@
// Save the files that need to be made available to Make.
p.initApexFilesForAndroidMk(ctx)
- if p.installable() {
- ctx.InstallFile(p.installDir, p.installFilename, p.inputApex)
- }
-
// in case that prebuilt_apex replaces source apex (using prefer: prop)
- p.compatSymlinks = makeCompatSymlinks(p.BaseModuleName(), ctx)
+ p.compatSymlinks = makeCompatSymlinks(p.BaseModuleName(), ctx, true)
// or that prebuilt_apex overrides other apexes (using overrides: prop)
for _, overridden := range p.prebuiltCommonProperties.Overrides {
- p.compatSymlinks = append(p.compatSymlinks, makeCompatSymlinks(overridden, ctx)...)
+ p.compatSymlinks = append(p.compatSymlinks, makeCompatSymlinks(overridden, ctx, true)...)
+ }
+
+ if p.installable() {
+ p.installedFile = ctx.InstallFile(p.installDir, p.installFilename, p.inputApex, p.compatSymlinks.Paths()...)
}
}
@@ -964,10 +969,10 @@
}
// in case that apex_set replaces source apex (using prefer: prop)
- a.compatSymlinks = makeCompatSymlinks(a.BaseModuleName(), ctx)
+ a.compatSymlinks = makeCompatSymlinks(a.BaseModuleName(), ctx, true)
// or that apex_set overrides other apexes (using overrides: prop)
for _, overridden := range a.prebuiltCommonProperties.Overrides {
- a.compatSymlinks = append(a.compatSymlinks, makeCompatSymlinks(overridden, ctx)...)
+ a.compatSymlinks = append(a.compatSymlinks, makeCompatSymlinks(overridden, ctx, true)...)
}
}
diff --git a/apex/vndk.go b/apex/vndk.go
index 75c0fb0..cf525a8 100644
--- a/apex/vndk.go
+++ b/apex/vndk.go
@@ -15,7 +15,6 @@
package apex
import (
- "path/filepath"
"strings"
"android/soong/android"
@@ -96,11 +95,14 @@
}
// name is module.BaseModuleName() which is used as LOCAL_MODULE_NAME and also LOCAL_OVERRIDES_*
-func makeCompatSymlinks(name string, ctx android.ModuleContext) (symlinks []string) {
+func makeCompatSymlinks(name string, ctx android.ModuleContext, primaryApex bool) (symlinks android.InstallPaths) {
// small helper to add symlink commands
- addSymlink := func(target, dir, linkName string) {
- link := filepath.Join(dir, linkName)
- symlinks = append(symlinks, "mkdir -p "+dir+" && rm -rf "+link+" && ln -sf "+target+" "+link)
+ addSymlink := func(target string, dir android.InstallPath, linkName string) {
+ if primaryApex {
+ symlinks = append(symlinks, ctx.InstallAbsoluteSymlink(dir, linkName, target))
+ } else {
+ symlinks = append(symlinks, dir.Join(ctx, linkName))
+ }
}
// TODO(b/142911355): [VNDK APEX] Fix hard-coded references to /system/lib/vndk
@@ -118,14 +120,15 @@
// the name of vndk apex is formatted "com.android.vndk.v" + version
apexName := vndkApexNamePrefix + vndkVersion
if ctx.Config().Android64() {
- addSymlink("/apex/"+apexName+"/lib64", "$(TARGET_OUT)/lib64", "vndk-sp-"+vndkVersion)
- addSymlink("/apex/"+apexName+"/lib64", "$(TARGET_OUT)/lib64", "vndk-"+vndkVersion)
+ dir := android.PathForModuleInPartitionInstall(ctx, "system", "lib64")
+ addSymlink("/apex/"+apexName+"/lib64", dir, "vndk-sp-"+vndkVersion)
+ addSymlink("/apex/"+apexName+"/lib64", dir, "vndk-"+vndkVersion)
}
if !ctx.Config().Android64() || ctx.DeviceConfig().DeviceSecondaryArch() != "" {
- addSymlink("/apex/"+apexName+"/lib", "$(TARGET_OUT)/lib", "vndk-sp-"+vndkVersion)
- addSymlink("/apex/"+apexName+"/lib", "$(TARGET_OUT)/lib", "vndk-"+vndkVersion)
+ dir := android.PathForModuleInPartitionInstall(ctx, "system", "lib")
+ addSymlink("/apex/"+apexName+"/lib", dir, "vndk-sp-"+vndkVersion)
+ addSymlink("/apex/"+apexName+"/lib", dir, "vndk-"+vndkVersion)
}
- return
}
// http://b/121248172 - create a link from /system/usr/icu to
@@ -133,19 +136,25 @@
// A symlink can't overwrite a directory and the /system/usr/icu directory once
// existed so the required structure must be created whatever we find.
if name == "com.android.i18n" {
- addSymlink("/apex/com.android.i18n/etc/icu", "$(TARGET_OUT)/usr", "icu")
- return
+ dir := android.PathForModuleInPartitionInstall(ctx, "system", "usr")
+ addSymlink("/apex/com.android.i18n/etc/icu", dir, "icu")
}
// TODO(b/124106384): Clean up compat symlinks for ART binaries.
- if name == "com.android.art" || strings.HasPrefix(name, "com.android.art.") {
- addSymlink("/apex/com.android.art/bin/dalvikvm", "$(TARGET_OUT)/bin", "dalvikvm")
+ if name == "com.android.art" {
+ dir := android.PathForModuleInPartitionInstall(ctx, "system", "bin")
+ addSymlink("/apex/com.android.art/bin/dalvikvm", dir, "dalvikvm")
dex2oat := "dex2oat32"
if ctx.Config().Android64() {
dex2oat = "dex2oat64"
}
- addSymlink("/apex/com.android.art/bin/"+dex2oat, "$(TARGET_OUT)/bin", "dex2oat")
- return
+ addSymlink("/apex/com.android.art/bin/"+dex2oat, dir, "dex2oat")
+ } else if name == "com.android.art" || strings.HasPrefix(name, "com.android.art.") {
+ dir := android.PathForModuleInPartitionInstall(ctx, "system", "bin")
+ symlinks = append(symlinks,
+ dir.Join(ctx, "dalvikvm"),
+ dir.Join(ctx, "dex2oat"))
}
- return
+
+ return symlinks
}
diff --git a/bazel/properties.go b/bazel/properties.go
index a438481..b370bbf 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -24,23 +24,6 @@
"github.com/google/blueprint"
)
-type BazelModuleProperties struct {
- // The label of the Bazel target replacing this Soong module. When run in conversion mode, this
- // will import the handcrafted build target into the autogenerated file. Note: this may result in
- // a conflict due to duplicate targets if bp2build_available is also set.
- Label *string
-
- // If true, bp2build will generate the converted Bazel target for this module. Note: this may
- // cause a conflict due to the duplicate targets if label is also set.
- //
- // This is a bool pointer to support tristates: true, false, not set.
- //
- // To opt-in a module, set bazel_module: { bp2build_available: true }
- // To opt-out a module, set bazel_module: { bp2build_available: false }
- // To defer the default setting for the directory, do not set the value.
- Bp2build_available *bool
-}
-
// BazelTargetModuleProperties contain properties and metadata used for
// Blueprint to BUILD file conversion.
type BazelTargetModuleProperties struct {
@@ -417,6 +400,12 @@
// This mode facilitates use of attribute defaults: an empty list should
// override the default.
ForceSpecifyEmptyList bool
+
+ // If true, signal the intent to the code generator to emit all select keys,
+ // even if the Includes list for that key is empty. This mode facilitates
+ // specific select statements where an empty list for a non-default select
+ // key has a meaning.
+ EmitEmptyList bool
}
type configurableLabelLists map[ConfigurationAxis]labelListSelectValues
diff --git a/bp2build/Android.bp b/bp2build/Android.bp
index 1250e92..9b66354 100644
--- a/bp2build/Android.bp
+++ b/bp2build/Android.bp
@@ -18,6 +18,7 @@
],
deps: [
"soong-android",
+ "soong-android-soongconfig",
"soong-apex",
"soong-bazel",
"soong-cc",
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index aa1cf70..10ee582 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -532,8 +532,8 @@
// prettyPrint a property value into the equivalent Starlark representation
// recursively.
-func prettyPrint(propertyValue reflect.Value, indent int) (string, error) {
- if isZero(propertyValue) {
+func prettyPrint(propertyValue reflect.Value, indent int, emitZeroValues bool) (string, error) {
+ if !emitZeroValues && isZero(propertyValue) {
// A property value being set or unset actually matters -- Soong does set default
// values for unset properties, like system_shared_libs = ["libc", "libm", "libdl"] at
// https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/linker.go;l=281-287;drc=f70926eef0b9b57faf04c17a1062ce50d209e480
@@ -556,7 +556,7 @@
case reflect.Int, reflect.Uint, reflect.Int64:
ret = fmt.Sprintf("%v", propertyValue.Interface())
case reflect.Ptr:
- return prettyPrint(propertyValue.Elem(), indent)
+ return prettyPrint(propertyValue.Elem(), indent, emitZeroValues)
case reflect.Slice:
if propertyValue.Len() == 0 {
return "[]", nil
@@ -565,7 +565,7 @@
if propertyValue.Len() == 1 {
// Single-line list for list with only 1 element
ret += "["
- indexedValue, err := prettyPrint(propertyValue.Index(0), indent)
+ indexedValue, err := prettyPrint(propertyValue.Index(0), indent, emitZeroValues)
if err != nil {
return "", err
}
@@ -575,7 +575,7 @@
// otherwise, use a multiline list.
ret += "[\n"
for i := 0; i < propertyValue.Len(); i++ {
- indexedValue, err := prettyPrint(propertyValue.Index(i), indent+1)
+ indexedValue, err := prettyPrint(propertyValue.Index(i), indent+1, emitZeroValues)
if err != nil {
return "", err
}
@@ -660,7 +660,7 @@
}
propertyName := proptools.PropertyNameForField(field.Name)
- prettyPrintedValue, err := prettyPrint(fieldValue, indent+1)
+ prettyPrintedValue, err := prettyPrint(fieldValue, indent+1, false)
if err != nil {
panic(
fmt.Errorf(
diff --git a/bp2build/configurability.go b/bp2build/configurability.go
index 0bcf91d..c953259 100644
--- a/bp2build/configurability.go
+++ b/bp2build/configurability.go
@@ -95,7 +95,7 @@
continue
}
selectKey := axis.SelectKey(config)
- if use, value := labelListSelectValue(selectKey, labels); use {
+ if use, value := labelListSelectValue(selectKey, labels, list.EmitEmptyList); use {
archSelects[selectKey] = value
}
}
@@ -107,8 +107,8 @@
return value, ret
}
-func labelListSelectValue(selectKey string, list bazel.LabelList) (bool, reflect.Value) {
- if selectKey == bazel.ConditionsDefaultSelectKey || len(list.Includes) > 0 {
+func labelListSelectValue(selectKey string, list bazel.LabelList, emitEmptyList bool) (bool, reflect.Value) {
+ if selectKey == bazel.ConditionsDefaultSelectKey || emitEmptyList || len(list.Includes) > 0 {
return true, reflect.ValueOf(list.Includes)
} else if len(list.Excludes) > 0 {
// if there is still an excludes -- we need to have an empty list for this select & use the
@@ -129,6 +129,7 @@
var value reflect.Value
var configurableAttrs []selects
var defaultSelectValue *string
+ var emitZeroValues bool
// If true, print the default attribute value, even if the attribute is zero.
shouldPrintDefault := false
switch list := v.(type) {
@@ -137,6 +138,7 @@
defaultSelectValue = &emptyBazelList
case bazel.LabelListAttribute:
value, configurableAttrs = getLabelListValues(list)
+ emitZeroValues = list.EmitEmptyList
defaultSelectValue = &emptyBazelList
if list.ForceSpecifyEmptyList && (!value.IsNil() || list.HasConfigurableValues()) {
shouldPrintDefault = true
@@ -154,7 +156,7 @@
var err error
ret := ""
if value.Kind() != reflect.Invalid {
- s, err := prettyPrint(value, indent)
+ s, err := prettyPrint(value, indent, false) // never emit zero values for the base value
if err != nil {
return ret, err
}
@@ -163,7 +165,7 @@
}
// Convenience function to append selects components to an attribute value.
appendSelects := func(selectsData selects, defaultValue *string, s string) (string, error) {
- selectMap, err := prettyPrintSelectMap(selectsData, defaultValue, indent)
+ selectMap, err := prettyPrintSelectMap(selectsData, defaultValue, indent, emitZeroValues)
if err != nil {
return "", err
}
@@ -190,7 +192,7 @@
// prettyPrintSelectMap converts a map of select keys to reflected Values as a generic way
// to construct a select map for any kind of attribute type.
-func prettyPrintSelectMap(selectMap map[string]reflect.Value, defaultValue *string, indent int) (string, error) {
+func prettyPrintSelectMap(selectMap map[string]reflect.Value, defaultValue *string, indent int, emitZeroValues bool) (string, error) {
if selectMap == nil {
return "", nil
}
@@ -202,11 +204,11 @@
continue
}
value := selectMap[selectKey]
- if isZero(value) {
+ if isZero(value) && !emitZeroValues {
// Ignore zero values to not generate empty lists.
continue
}
- s, err := prettyPrintSelectEntry(value, selectKey, indent)
+ s, err := prettyPrintSelectEntry(value, selectKey, indent, emitZeroValues)
if err != nil {
return "", err
}
@@ -227,7 +229,7 @@
ret += selects
// Handle the default condition
- s, err := prettyPrintSelectEntry(selectMap[bazel.ConditionsDefaultSelectKey], bazel.ConditionsDefaultSelectKey, indent)
+ s, err := prettyPrintSelectEntry(selectMap[bazel.ConditionsDefaultSelectKey], bazel.ConditionsDefaultSelectKey, indent, emitZeroValues)
if err != nil {
return "", err
}
@@ -249,9 +251,9 @@
// prettyPrintSelectEntry converts a reflect.Value into an entry in a select map
// with a provided key.
-func prettyPrintSelectEntry(value reflect.Value, key string, indent int) (string, error) {
+func prettyPrintSelectEntry(value reflect.Value, key string, indent int, emitZeroValues bool) (string, error) {
s := makeIndent(indent + 1)
- v, err := prettyPrint(value, indent+1)
+ v, err := prettyPrint(value, indent+1, emitZeroValues)
if err != nil {
return "", err
}
diff --git a/bp2build/conversion.go b/bp2build/conversion.go
index 944cb83..81a4b26 100644
--- a/bp2build/conversion.go
+++ b/bp2build/conversion.go
@@ -25,6 +25,8 @@
files = append(files, newFile("metrics", "converted_modules.txt", strings.Join(metrics.convertedModules, "\n")))
+ files = append(files, newFile("product_config", "soong_config_variables.bzl", cfg.Bp2buildSoongConfigDefinitions.String()))
+
return files
}
diff --git a/bp2build/conversion_test.go b/bp2build/conversion_test.go
index d09238a..3e6d9e6 100644
--- a/bp2build/conversion_test.go
+++ b/bp2build/conversion_test.go
@@ -82,7 +82,8 @@
}
func TestCreateBazelFiles_Bp2Build_CreatesDefaultFiles(t *testing.T) {
- files := CreateSoongInjectionFiles(android.Config{}, CodegenMetrics{})
+ testConfig := android.TestConfig("", make(map[string]string), "", make(map[string][]byte))
+ files := CreateSoongInjectionFiles(testConfig, CodegenMetrics{})
expectedFilePaths := []bazelFilepath{
{
@@ -97,6 +98,10 @@
dir: "metrics",
basename: "converted_modules.txt",
},
+ {
+ dir: "product_config",
+ basename: "soong_config_variables.bzl",
+ },
}
if len(files) != len(expectedFilePaths) {
diff --git a/bp2build/soong_config_module_type_conversion_test.go b/bp2build/soong_config_module_type_conversion_test.go
index 2e6f54c..d21db04 100644
--- a/bp2build/soong_config_module_type_conversion_test.go
+++ b/bp2build/soong_config_module_type_conversion_test.go
@@ -32,6 +32,8 @@
ctx.RegisterModuleType("soong_config_module_type", android.SoongConfigModuleTypeFactory)
ctx.RegisterModuleType("soong_config_string_variable", android.SoongConfigStringVariableDummyFactory)
ctx.RegisterModuleType("soong_config_bool_variable", android.SoongConfigBoolVariableDummyFactory)
+
+ ctx.RegisterModuleType("cc_library", cc.LibraryFactory)
}
func TestSoongConfigModuleType(t *testing.T) {
@@ -42,7 +44,6 @@
config_namespace: "acme",
bool_variables: ["feature1"],
properties: ["cflags"],
- bazel_module: { bp2build_available: true },
}
custom_cc_library_static {
@@ -83,7 +84,6 @@
config_namespace: "acme",
bool_variables: ["feature1"],
properties: ["cflags"],
- bazel_module: { bp2build_available: true },
}
`
bp := `
@@ -138,7 +138,6 @@
config_namespace: "acme",
variables: ["board"],
properties: ["cflags"],
- bazel_module: { bp2build_available: true },
}
custom_cc_library_static {
@@ -199,7 +198,6 @@
config_namespace: "acme",
variables: ["feature1", "feature2", "board"],
properties: ["cflags"],
- bazel_module: { bp2build_available: true },
}
custom_cc_library_static {
@@ -269,7 +267,6 @@
config_namespace: "acme",
variables: ["board"],
properties: ["cflags", "static_libs"],
- bazel_module: { bp2build_available: true },
}
custom_cc_library_static {
@@ -324,3 +321,527 @@
local_includes = ["."],
)`}})
}
+
+func TestSoongConfigModuleType_Defaults_SingleNamespace(t *testing.T) {
+ bp := `
+soong_config_module_type {
+ name: "vendor_foo_cc_defaults",
+ module_type: "cc_defaults",
+ config_namespace: "vendor_foo",
+ bool_variables: ["feature"],
+ properties: ["cflags", "cppflags"],
+}
+
+vendor_foo_cc_defaults {
+ name: "foo_defaults_1",
+ soong_config_variables: {
+ feature: {
+ cflags: ["-cflag_feature_1"],
+ conditions_default: {
+ cflags: ["-cflag_default_1"],
+ },
+ },
+ },
+}
+
+vendor_foo_cc_defaults {
+ name: "foo_defaults_2",
+ defaults: ["foo_defaults_1"],
+ soong_config_variables: {
+ feature: {
+ cflags: ["-cflag_feature_2"],
+ conditions_default: {
+ cflags: ["-cflag_default_2"],
+ },
+ },
+ },
+}
+
+cc_library_static {
+ name: "lib",
+ defaults: ["foo_defaults_2"],
+ bazel_module: { bp2build_available: true },
+}
+`
+
+ runSoongConfigModuleTypeTest(t, bp2buildTestCase{
+ description: "soong config variables - defaults with a single namespace",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ blueprint: bp,
+ expectedBazelTargets: []string{`cc_library_static(
+ name = "lib",
+ copts = select({
+ "//build/bazel/product_variables:vendor_foo__feature__enabled": [
+ "-cflag_feature_2",
+ "-cflag_feature_1",
+ ],
+ "//conditions:default": [
+ "-cflag_default_2",
+ "-cflag_default_1",
+ ],
+ }),
+ local_includes = ["."],
+)`}})
+}
+
+func TestSoongConfigModuleType_MultipleDefaults_SingleNamespace(t *testing.T) {
+ bp := `
+soong_config_module_type {
+ name: "foo_cc_defaults",
+ module_type: "cc_defaults",
+ config_namespace: "acme",
+ bool_variables: ["feature"],
+ properties: ["cflags"],
+}
+
+soong_config_module_type {
+ name: "bar_cc_defaults",
+ module_type: "cc_defaults",
+ config_namespace: "acme",
+ bool_variables: ["feature"],
+ properties: ["cflags", "asflags"],
+}
+
+foo_cc_defaults {
+ name: "foo_defaults",
+ soong_config_variables: {
+ feature: {
+ cflags: ["-cflag_foo"],
+ conditions_default: {
+ cflags: ["-cflag_default_foo"],
+ },
+ },
+ },
+}
+
+bar_cc_defaults {
+ name: "bar_defaults",
+ srcs: ["file.S"],
+ soong_config_variables: {
+ feature: {
+ cflags: ["-cflag_bar"],
+ asflags: ["-asflag_bar"],
+ conditions_default: {
+ asflags: ["-asflag_default_bar"],
+ cflags: ["-cflag_default_bar"],
+ },
+ },
+ },
+}
+
+cc_library_static {
+ name: "lib",
+ defaults: ["foo_defaults", "bar_defaults"],
+ bazel_module: { bp2build_available: true },
+}
+
+cc_library_static {
+ name: "lib2",
+ defaults: ["bar_defaults", "foo_defaults"],
+ bazel_module: { bp2build_available: true },
+}
+`
+
+ runSoongConfigModuleTypeTest(t, bp2buildTestCase{
+ description: "soong config variables - multiple defaults with a single namespace",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ blueprint: bp,
+ expectedBazelTargets: []string{`cc_library_static(
+ name = "lib",
+ asflags = select({
+ "//build/bazel/product_variables:acme__feature__enabled": ["-asflag_bar"],
+ "//conditions:default": ["-asflag_default_bar"],
+ }),
+ copts = select({
+ "//build/bazel/product_variables:acme__feature__enabled": [
+ "-cflag_foo",
+ "-cflag_bar",
+ ],
+ "//conditions:default": [
+ "-cflag_default_foo",
+ "-cflag_default_bar",
+ ],
+ }),
+ local_includes = ["."],
+ srcs_as = ["file.S"],
+)`,
+ `cc_library_static(
+ name = "lib2",
+ asflags = select({
+ "//build/bazel/product_variables:acme__feature__enabled": ["-asflag_bar"],
+ "//conditions:default": ["-asflag_default_bar"],
+ }),
+ copts = select({
+ "//build/bazel/product_variables:acme__feature__enabled": [
+ "-cflag_bar",
+ "-cflag_foo",
+ ],
+ "//conditions:default": [
+ "-cflag_default_bar",
+ "-cflag_default_foo",
+ ],
+ }),
+ local_includes = ["."],
+ srcs_as = ["file.S"],
+)`}})
+}
+
+func TestSoongConfigModuleType_Defaults_MultipleNamespaces(t *testing.T) {
+ bp := `
+soong_config_module_type {
+ name: "vendor_foo_cc_defaults",
+ module_type: "cc_defaults",
+ config_namespace: "vendor_foo",
+ bool_variables: ["feature"],
+ properties: ["cflags"],
+}
+
+soong_config_module_type {
+ name: "vendor_bar_cc_defaults",
+ module_type: "cc_defaults",
+ config_namespace: "vendor_bar",
+ bool_variables: ["feature"],
+ properties: ["cflags"],
+}
+
+soong_config_module_type {
+ name: "vendor_qux_cc_defaults",
+ module_type: "cc_defaults",
+ config_namespace: "vendor_qux",
+ bool_variables: ["feature"],
+ properties: ["cflags"],
+}
+
+vendor_foo_cc_defaults {
+ name: "foo_defaults",
+ soong_config_variables: {
+ feature: {
+ cflags: ["-DVENDOR_FOO_FEATURE"],
+ conditions_default: {
+ cflags: ["-DVENDOR_FOO_DEFAULT"],
+ },
+ },
+ },
+}
+
+vendor_bar_cc_defaults {
+ name: "bar_defaults",
+ soong_config_variables: {
+ feature: {
+ cflags: ["-DVENDOR_BAR_FEATURE"],
+ conditions_default: {
+ cflags: ["-DVENDOR_BAR_DEFAULT"],
+ },
+ },
+ },
+}
+
+vendor_qux_cc_defaults {
+ name: "qux_defaults",
+ defaults: ["bar_defaults"],
+ soong_config_variables: {
+ feature: {
+ cflags: ["-DVENDOR_QUX_FEATURE"],
+ conditions_default: {
+ cflags: ["-DVENDOR_QUX_DEFAULT"],
+ },
+ },
+ },
+}
+
+cc_library_static {
+ name: "lib",
+ defaults: ["foo_defaults", "qux_defaults"],
+ bazel_module: { bp2build_available: true },
+}
+`
+
+ runSoongConfigModuleTypeTest(t, bp2buildTestCase{
+ description: "soong config variables - defaults with multiple namespaces",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ blueprint: bp,
+ expectedBazelTargets: []string{`cc_library_static(
+ name = "lib",
+ copts = select({
+ "//build/bazel/product_variables:vendor_bar__feature__enabled": ["-DVENDOR_BAR_FEATURE"],
+ "//conditions:default": ["-DVENDOR_BAR_DEFAULT"],
+ }) + select({
+ "//build/bazel/product_variables:vendor_foo__feature__enabled": ["-DVENDOR_FOO_FEATURE"],
+ "//conditions:default": ["-DVENDOR_FOO_DEFAULT"],
+ }) + select({
+ "//build/bazel/product_variables:vendor_qux__feature__enabled": ["-DVENDOR_QUX_FEATURE"],
+ "//conditions:default": ["-DVENDOR_QUX_DEFAULT"],
+ }),
+ local_includes = ["."],
+)`}})
+}
+
+func TestSoongConfigModuleType_Defaults(t *testing.T) {
+ bp := `
+soong_config_string_variable {
+ name: "library_linking_strategy",
+ values: [
+ "prefer_static",
+ ],
+}
+
+soong_config_module_type {
+ name: "library_linking_strategy_cc_defaults",
+ module_type: "cc_defaults",
+ config_namespace: "ANDROID",
+ variables: ["library_linking_strategy"],
+ properties: [
+ "shared_libs",
+ "static_libs",
+ ],
+}
+
+library_linking_strategy_cc_defaults {
+ name: "library_linking_strategy_lib_a_defaults",
+ soong_config_variables: {
+ library_linking_strategy: {
+ prefer_static: {
+ static_libs: [
+ "lib_a",
+ ],
+ },
+ conditions_default: {
+ shared_libs: [
+ "lib_a",
+ ],
+ },
+ },
+ },
+}
+
+library_linking_strategy_cc_defaults {
+ name: "library_linking_strategy_merged_defaults",
+ defaults: ["library_linking_strategy_lib_a_defaults"],
+ soong_config_variables: {
+ library_linking_strategy: {
+ prefer_static: {
+ static_libs: [
+ "lib_b",
+ ],
+ },
+ conditions_default: {
+ shared_libs: [
+ "lib_b",
+ ],
+ },
+ },
+ },
+}
+
+cc_binary {
+ name: "library_linking_strategy_sample_binary",
+ srcs: ["library_linking_strategy.cc"],
+ defaults: ["library_linking_strategy_merged_defaults"],
+}`
+
+ otherDeps := `
+cc_library { name: "lib_a", bazel_module: { bp2build_available: false } }
+cc_library { name: "lib_b", bazel_module: { bp2build_available: false } }
+cc_library { name: "lib_default", bazel_module: { bp2build_available: false } }
+`
+
+ runSoongConfigModuleTypeTest(t, bp2buildTestCase{
+ description: "soong config variables - generates selects for library_linking_strategy",
+ moduleTypeUnderTest: "cc_binary",
+ moduleTypeUnderTestFactory: cc.BinaryFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.BinaryBp2build,
+ blueprint: bp,
+ filesystem: map[string]string{
+ "foo/bar/Android.bp": otherDeps,
+ },
+ expectedBazelTargets: []string{`cc_binary(
+ name = "library_linking_strategy_sample_binary",
+ deps = select({
+ "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": [
+ "//foo/bar:lib_b_bp2build_cc_library_static",
+ "//foo/bar:lib_a_bp2build_cc_library_static",
+ ],
+ "//conditions:default": [],
+ }),
+ dynamic_deps = select({
+ "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": [],
+ "//conditions:default": [
+ "//foo/bar:lib_b",
+ "//foo/bar:lib_a",
+ ],
+ }),
+ local_includes = ["."],
+ srcs = ["library_linking_strategy.cc"],
+)`}})
+}
+
+func TestSoongConfigModuleType_Defaults_Another(t *testing.T) {
+ bp := `
+soong_config_string_variable {
+ name: "library_linking_strategy",
+ values: [
+ "prefer_static",
+ ],
+}
+
+soong_config_module_type {
+ name: "library_linking_strategy_cc_defaults",
+ module_type: "cc_defaults",
+ config_namespace: "ANDROID",
+ variables: ["library_linking_strategy"],
+ properties: [
+ "shared_libs",
+ "static_libs",
+ ],
+}
+
+library_linking_strategy_cc_defaults {
+ name: "library_linking_strategy_sample_defaults",
+ soong_config_variables: {
+ library_linking_strategy: {
+ prefer_static: {
+ static_libs: [
+ "lib_a",
+ "lib_b",
+ ],
+ },
+ conditions_default: {
+ shared_libs: [
+ "lib_a",
+ "lib_b",
+ ],
+ },
+ },
+ },
+}
+
+cc_binary {
+ name: "library_linking_strategy_sample_binary",
+ srcs: ["library_linking_strategy.cc"],
+ defaults: ["library_linking_strategy_sample_defaults"],
+}`
+
+ otherDeps := `
+cc_library { name: "lib_a", bazel_module: { bp2build_available: false } }
+cc_library { name: "lib_b", bazel_module: { bp2build_available: false } }
+`
+
+ runSoongConfigModuleTypeTest(t, bp2buildTestCase{
+ description: "soong config variables - generates selects for library_linking_strategy",
+ moduleTypeUnderTest: "cc_binary",
+ moduleTypeUnderTestFactory: cc.BinaryFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.BinaryBp2build,
+ blueprint: bp,
+ filesystem: map[string]string{
+ "foo/bar/Android.bp": otherDeps,
+ },
+ expectedBazelTargets: []string{`cc_binary(
+ name = "library_linking_strategy_sample_binary",
+ deps = select({
+ "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": [
+ "//foo/bar:lib_a_bp2build_cc_library_static",
+ "//foo/bar:lib_b_bp2build_cc_library_static",
+ ],
+ "//conditions:default": [],
+ }),
+ dynamic_deps = select({
+ "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": [],
+ "//conditions:default": [
+ "//foo/bar:lib_a",
+ "//foo/bar:lib_b",
+ ],
+ }),
+ local_includes = ["."],
+ srcs = ["library_linking_strategy.cc"],
+)`}})
+}
+
+func TestSoongConfigModuleType_Defaults_UnusedProps(t *testing.T) {
+ bp := `
+soong_config_string_variable {
+ name: "alphabet",
+ values: [
+ "a",
+ "b",
+ "c", // unused
+ ],
+}
+
+soong_config_module_type {
+ name: "alphabet_cc_defaults",
+ module_type: "cc_defaults",
+ config_namespace: "ANDROID",
+ variables: ["alphabet"],
+ properties: [
+ "cflags", // unused
+ "shared_libs",
+ "static_libs",
+ ],
+}
+
+alphabet_cc_defaults {
+ name: "alphabet_sample_cc_defaults",
+ soong_config_variables: {
+ alphabet: {
+ a: {
+ shared_libs: [
+ "lib_a",
+ ],
+ },
+ b: {
+ shared_libs: [
+ "lib_b",
+ ],
+ },
+ conditions_default: {
+ static_libs: [
+ "lib_default",
+ ],
+ },
+ },
+ },
+}
+
+cc_binary {
+ name: "alphabet_binary",
+ srcs: ["main.cc"],
+ defaults: ["alphabet_sample_cc_defaults"],
+}`
+
+ otherDeps := `
+cc_library { name: "lib_a", bazel_module: { bp2build_available: false } }
+cc_library { name: "lib_b", bazel_module: { bp2build_available: false } }
+cc_library { name: "lib_default", bazel_module: { bp2build_available: false } }
+`
+
+ runSoongConfigModuleTypeTest(t, bp2buildTestCase{
+ description: "soong config variables - generates selects for library_linking_strategy",
+ moduleTypeUnderTest: "cc_binary",
+ moduleTypeUnderTestFactory: cc.BinaryFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.BinaryBp2build,
+ blueprint: bp,
+ filesystem: map[string]string{
+ "foo/bar/Android.bp": otherDeps,
+ },
+ expectedBazelTargets: []string{`cc_binary(
+ name = "alphabet_binary",
+ deps = select({
+ "//build/bazel/product_variables:android__alphabet__a": [],
+ "//build/bazel/product_variables:android__alphabet__b": [],
+ "//conditions:default": ["//foo/bar:lib_default_bp2build_cc_library_static"],
+ }),
+ dynamic_deps = select({
+ "//build/bazel/product_variables:android__alphabet__a": ["//foo/bar:lib_a"],
+ "//build/bazel/product_variables:android__alphabet__b": ["//foo/bar:lib_b"],
+ "//conditions:default": [],
+ }),
+ local_includes = ["."],
+ srcs = ["main.cc"],
+)`}})
+}
diff --git a/cc/bp2build.go b/cc/bp2build.go
index dde8dd4..d949436 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -611,6 +611,7 @@
ctx.ModuleErrorf("Could not convert product variable %s property", dep.excludesField)
}
+ dep.attribute.EmitEmptyList = productConfigProp.AlwaysEmit()
dep.attribute.SetSelectValue(
productConfigProp.ConfigurationAxis(),
productConfigProp.SelectKey(),
diff --git a/cc/config/global.go b/cc/config/global.go
index 7abd2fc..0b229be 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -270,8 +270,8 @@
// prebuilts/clang default settings.
ClangDefaultBase = "prebuilts/clang/host"
- ClangDefaultVersion = "clang-r433403b"
- ClangDefaultShortVersion = "13.0.3"
+ ClangDefaultVersion = "clang-r437112"
+ ClangDefaultShortVersion = "14.0.0"
// Directories with warnings from Android.bp files.
WarningAllowedProjects = []string{
diff --git a/cc/config/vndk.go b/cc/config/vndk.go
index 9577a8c..492cd98 100644
--- a/cc/config/vndk.go
+++ b/cc/config/vndk.go
@@ -101,6 +101,9 @@
"android.hardware.weaver-unstable-ndk_platform",
"android.system.suspend-V1-ndk",
"android.system.keystore2-V1-ndk",
+ "android.se.omapi-V1-ndk_platform",
+ "android.se.omapi-ndk_platform",
+ "android.se.omapi-unstable-ndk_platform",
"android.hardware.wifi.hostapd-V1-ndk",
"android.hardware.wifi.hostapd-V1-ndk_platform",
"android.hardware.wifi.supplicant-V1-ndk",
diff --git a/cmd/extract_apks/main.go b/cmd/extract_apks/main.go
index 6e51a28..1cf64de 100644
--- a/cmd/extract_apks/main.go
+++ b/cmd/extract_apks/main.go
@@ -356,7 +356,7 @@
// Writes out selected entries, renaming them as needed
func (apkSet *ApkSet) writeApks(selected SelectionResult, config TargetConfig,
- writer Zip2ZipWriter, partition string) ([]string, error) {
+ outFile io.Writer, zipWriter Zip2ZipWriter, partition string) ([]string, error) {
// Renaming rules:
// splits/MODULE-master.apk to STEM.apk
// else
@@ -406,8 +406,14 @@
origin, inName, outName)
}
entryOrigin[outName] = inName
- if err := writer.CopyFrom(apkFile, outName); err != nil {
- return nil, err
+ if outName == config.stem+".apk" {
+ if err := writeZipEntryToFile(outFile, apkFile); err != nil {
+ return nil, err
+ }
+ } else {
+ if err := zipWriter.CopyFrom(apkFile, outName); err != nil {
+ return nil, err
+ }
}
if partition != "" {
apkcerts = append(apkcerts, fmt.Sprintf(
@@ -426,14 +432,13 @@
if !ok {
return fmt.Errorf("Couldn't find apk path %s", selected.entries[0])
}
- inputReader, _ := apk.Open()
- _, err := io.Copy(outFile, inputReader)
- return err
+ return writeZipEntryToFile(outFile, apk)
}
// Arguments parsing
var (
- outputFile = flag.String("o", "", "output file containing extracted entries")
+ outputFile = flag.String("o", "", "output file for primary entry")
+ zipFile = flag.String("zip", "", "output file containing additional extracted entries")
targetConfig = TargetConfig{
screenDpi: map[android_bundle_proto.ScreenDensity_DensityAlias]bool{},
abis: map[android_bundle_proto.Abi_AbiAlias]int{},
@@ -494,7 +499,8 @@
func processArgs() {
flag.Usage = func() {
- fmt.Fprintln(os.Stderr, `usage: extract_apks -o <output-file> -sdk-version value -abis value `+
+ fmt.Fprintln(os.Stderr, `usage: extract_apks -o <output-file> [-zip <output-zip-file>] `+
+ `-sdk-version value -abis value `+
`-screen-densities value {-stem value | -extract-single} [-allow-prereleased] `+
`[-apkcerts <apkcerts output file> -partition <partition>] <APK set>`)
flag.PrintDefaults()
@@ -510,7 +516,8 @@
flag.StringVar(&targetConfig.stem, "stem", "", "output entries base name in the output zip file")
flag.Parse()
if (*outputFile == "") || len(flag.Args()) != 1 || *version == 0 ||
- (targetConfig.stem == "" && !*extractSingle) || (*apkcertsOutput != "" && *partition == "") {
+ ((targetConfig.stem == "" || *zipFile == "") && !*extractSingle) ||
+ (*apkcertsOutput != "" && *partition == "") {
flag.Usage()
}
targetConfig.sdkVersion = int32(*version)
@@ -542,13 +549,20 @@
if *extractSingle {
err = apkSet.extractAndCopySingle(sel, outFile)
} else {
- writer := zip.NewWriter(outFile)
+ zipOutputFile, err := os.Create(*zipFile)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer zipOutputFile.Close()
+
+ zipWriter := zip.NewWriter(zipOutputFile)
defer func() {
- if err := writer.Close(); err != nil {
+ if err := zipWriter.Close(); err != nil {
log.Fatal(err)
}
}()
- apkcerts, err := apkSet.writeApks(sel, targetConfig, writer, *partition)
+
+ apkcerts, err := apkSet.writeApks(sel, targetConfig, outFile, zipWriter, *partition)
if err == nil && *apkcertsOutput != "" {
apkcertsFile, err := os.Create(*apkcertsOutput)
if err != nil {
@@ -567,3 +581,13 @@
log.Fatal(err)
}
}
+
+func writeZipEntryToFile(outFile io.Writer, zipEntry *zip.File) error {
+ reader, err := zipEntry.Open()
+ if err != nil {
+ return err
+ }
+ defer reader.Close()
+ _, err = io.Copy(outFile, reader)
+ return err
+}
diff --git a/cmd/extract_apks/main_test.go b/cmd/extract_apks/main_test.go
index 9fcf324..f5e4046 100644
--- a/cmd/extract_apks/main_test.go
+++ b/cmd/extract_apks/main_test.go
@@ -15,6 +15,7 @@
package main
import (
+ "bytes"
"fmt"
"reflect"
"testing"
@@ -437,8 +438,8 @@
stem string
partition string
// what we write from what
- expectedZipEntries map[string]string
- expectedApkcerts []string
+ zipEntries map[string]string
+ expectedApkcerts []string
}
func TestWriteApks(t *testing.T) {
@@ -448,7 +449,7 @@
moduleName: "mybase",
stem: "Foo",
partition: "system",
- expectedZipEntries: map[string]string{
+ zipEntries: map[string]string{
"Foo.apk": "splits/mybase-master.apk",
"Foo-xhdpi.apk": "splits/mybase-xhdpi.apk",
},
@@ -462,7 +463,7 @@
moduleName: "base",
stem: "Bar",
partition: "product",
- expectedZipEntries: map[string]string{
+ zipEntries: map[string]string{
"Bar.apk": "universal.apk",
},
expectedApkcerts: []string{
@@ -471,23 +472,46 @@
},
}
for _, testCase := range testCases {
- apkSet := ApkSet{entries: make(map[string]*zip.File)}
- sel := SelectionResult{moduleName: testCase.moduleName}
- for _, in := range testCase.expectedZipEntries {
- apkSet.entries[in] = &zip.File{FileHeader: zip.FileHeader{Name: in}}
- sel.entries = append(sel.entries, in)
- }
- writer := testZip2ZipWriter{make(map[string]string)}
- config := TargetConfig{stem: testCase.stem}
- apkcerts, err := apkSet.writeApks(sel, config, writer, testCase.partition)
- if err != nil {
- t.Error(err)
- }
- if !reflect.DeepEqual(testCase.expectedZipEntries, writer.entries) {
- t.Errorf("expected zip entries %v, got %v", testCase.expectedZipEntries, writer.entries)
- }
- if !reflect.DeepEqual(testCase.expectedApkcerts, apkcerts) {
- t.Errorf("expected apkcerts %v, got %v", testCase.expectedApkcerts, apkcerts)
- }
+ t.Run(testCase.name, func(t *testing.T) {
+ testZipBuf := &bytes.Buffer{}
+ testZip := zip.NewWriter(testZipBuf)
+ for _, in := range testCase.zipEntries {
+ f, _ := testZip.Create(in)
+ f.Write([]byte(in))
+ }
+ testZip.Close()
+
+ zipReader, _ := zip.NewReader(bytes.NewReader(testZipBuf.Bytes()), int64(testZipBuf.Len()))
+
+ apkSet := ApkSet{entries: make(map[string]*zip.File)}
+ sel := SelectionResult{moduleName: testCase.moduleName}
+ for _, f := range zipReader.File {
+ apkSet.entries[f.Name] = f
+ sel.entries = append(sel.entries, f.Name)
+ }
+
+ zipWriter := testZip2ZipWriter{make(map[string]string)}
+ outWriter := &bytes.Buffer{}
+ config := TargetConfig{stem: testCase.stem}
+ apkcerts, err := apkSet.writeApks(sel, config, outWriter, zipWriter, testCase.partition)
+ if err != nil {
+ t.Error(err)
+ }
+ expectedZipEntries := make(map[string]string)
+ for k, v := range testCase.zipEntries {
+ if k != testCase.stem+".apk" {
+ expectedZipEntries[k] = v
+ }
+ }
+ if !reflect.DeepEqual(expectedZipEntries, zipWriter.entries) {
+ t.Errorf("expected zip entries %v, got %v", testCase.zipEntries, zipWriter.entries)
+ }
+ if !reflect.DeepEqual(testCase.expectedApkcerts, apkcerts) {
+ t.Errorf("expected apkcerts %v, got %v", testCase.expectedApkcerts, apkcerts)
+ }
+ if g, w := outWriter.String(), testCase.zipEntries[testCase.stem+".apk"]; !reflect.DeepEqual(g, w) {
+ t.Errorf("expected output file contents %q, got %q", testCase.stem+".apk", outWriter.String())
+ }
+ })
}
}
diff --git a/cmd/sbox/sbox.go b/cmd/sbox/sbox.go
index c7f3f6a..4fa7486 100644
--- a/cmd/sbox/sbox.go
+++ b/cmd/sbox/sbox.go
@@ -164,7 +164,7 @@
if useSubDir {
localTempDir = filepath.Join(localTempDir, strconv.Itoa(i))
}
- depFile, err := runCommand(command, localTempDir)
+ depFile, err := runCommand(command, localTempDir, i)
if err != nil {
// Running the command failed, keep the temporary output directory around in
// case a user wants to inspect it for debugging purposes. Soong will delete
@@ -194,6 +194,28 @@
return nil
}
+// createCommandScript will create and return an exec.Cmd that runs rawCommand.
+//
+// rawCommand is executed via a script in the sandbox.
+// tempDir is the temporary where the script is created.
+// toDirInSandBox is the path containing the script in the sbox environment.
+// toDirInSandBox is the path containing the script in the sbox environment.
+// seed is a unique integer used to distinguish different scripts that might be at location.
+//
+// returns an exec.Cmd that can be ran from within sbox context if no error, or nil if error.
+// caller must ensure script is cleaned up if function succeeds.
+//
+func createCommandScript(rawCommand string, tempDir, toDirInSandbox string, seed int) (*exec.Cmd, error) {
+ scriptName := fmt.Sprintf("sbox_command.%d.bash", seed)
+ scriptPathAndName := joinPath(tempDir, scriptName)
+ err := os.WriteFile(scriptPathAndName, []byte(rawCommand), 0644)
+ if err != nil {
+ return nil, fmt.Errorf("failed to write command %s... to %s",
+ rawCommand[0:40], scriptPathAndName)
+ }
+ return exec.Command("bash", joinPath(toDirInSandbox, filepath.Base(scriptName))), nil
+}
+
// readManifest reads an sbox manifest from a textproto file.
func readManifest(file string) (*sbox_proto.Manifest, error) {
manifestData, err := ioutil.ReadFile(file)
@@ -213,7 +235,7 @@
// runCommand runs a single command from a manifest. If the command references the
// __SBOX_DEPFILE__ placeholder it returns the name of the depfile that was used.
-func runCommand(command *sbox_proto.Command, tempDir string) (depFile string, err error) {
+func runCommand(command *sbox_proto.Command, tempDir string, commandIndex int) (depFile string, err error) {
rawCommand := command.GetCommand()
if rawCommand == "" {
return "", fmt.Errorf("command is required")
@@ -255,7 +277,11 @@
return "", err
}
- cmd := exec.Command("bash", "-c", rawCommand)
+ cmd, err := createCommandScript(rawCommand, tempDir, pathToTempDirInSbox, commandIndex)
+ if err != nil {
+ return "", err
+ }
+
buf := &bytes.Buffer{}
cmd.Stdin = os.Stdin
cmd.Stdout = buf
diff --git a/java/androidmk.go b/java/androidmk.go
index 4c115d5..272a4fd 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -696,12 +696,12 @@
return []android.AndroidMkEntries{
android.AndroidMkEntries{
Class: "APPS",
- OutputFile: android.OptionalPathForPath(apkSet.packedOutput),
+ OutputFile: android.OptionalPathForPath(apkSet.primaryOutput),
Include: "$(BUILD_SYSTEM)/soong_android_app_set.mk",
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
entries.SetBoolIfTrue("LOCAL_PRIVILEGED_MODULE", apkSet.Privileged())
- entries.SetString("LOCAL_APK_SET_INSTALL_FILE", apkSet.InstallFile())
+ entries.SetPath("LOCAL_APK_SET_INSTALL_FILE", apkSet.PackedAdditionalOutputs())
entries.SetPath("LOCAL_APKCERTS_FILE", apkSet.apkcertsFile)
entries.AddStrings("LOCAL_OVERRIDES_PACKAGES", apkSet.properties.Overrides...)
},
diff --git a/java/app_set.go b/java/app_set.go
index 6b25638..694b167 100644
--- a/java/app_set.go
+++ b/java/app_set.go
@@ -55,10 +55,10 @@
android.DefaultableModuleBase
prebuilt android.Prebuilt
- properties AndroidAppSetProperties
- packedOutput android.WritablePath
- installFile string
- apkcertsFile android.ModuleOutPath
+ properties AndroidAppSetProperties
+ packedOutput android.WritablePath
+ primaryOutput android.WritablePath
+ apkcertsFile android.ModuleOutPath
}
func (as *AndroidAppSet) Name() string {
@@ -78,11 +78,11 @@
}
func (as *AndroidAppSet) OutputFile() android.Path {
- return as.packedOutput
+ return as.primaryOutput
}
-func (as *AndroidAppSet) InstallFile() string {
- return as.installFile
+func (as *AndroidAppSet) PackedAdditionalOutputs() android.Path {
+ return as.packedOutput
}
func (as *AndroidAppSet) APKCertsFile() android.Path {
@@ -114,11 +114,11 @@
func (as *AndroidAppSet) GenerateAndroidBuildActions(ctx android.ModuleContext) {
as.packedOutput = android.PathForModuleOut(ctx, ctx.ModuleName()+".zip")
+ as.primaryOutput = android.PathForModuleOut(ctx, as.BaseModuleName()+".apk")
as.apkcertsFile = android.PathForModuleOut(ctx, "apkcerts.txt")
// We are assuming here that the install file in the APK
// set has `.apk` suffix. If it doesn't the build will fail.
// APK sets containing APEX files are handled elsewhere.
- as.installFile = as.BaseModuleName() + ".apk"
screenDensities := "all"
if dpis := ctx.Config().ProductAAPTPrebuiltDPI(); len(dpis) > 0 {
screenDensities = strings.ToUpper(strings.Join(dpis, ","))
@@ -127,11 +127,11 @@
// TODO(asmundak): do we support device features
ctx.Build(pctx,
android.BuildParams{
- Rule: extractMatchingApks,
- Description: "Extract APKs from APK set",
- Output: as.packedOutput,
- ImplicitOutput: as.apkcertsFile,
- Inputs: android.Paths{as.prebuilt.SingleSourcePath(ctx)},
+ Rule: extractMatchingApks,
+ Description: "Extract APKs from APK set",
+ Output: as.primaryOutput,
+ ImplicitOutputs: android.WritablePaths{as.packedOutput, as.apkcertsFile},
+ Inputs: android.Paths{as.prebuilt.SingleSourcePath(ctx)},
Args: map[string]string{
"abis": strings.Join(SupportedAbis(ctx), ","),
"allow-prereleased": strconv.FormatBool(proptools.Bool(as.properties.Prerelease)),
@@ -140,10 +140,21 @@
"stem": as.BaseModuleName(),
"apkcerts": as.apkcertsFile.String(),
"partition": as.PartitionTag(ctx.DeviceConfig()),
+ "zip": as.packedOutput.String(),
},
})
+
+ var installDir android.InstallPath
+ if as.Privileged() {
+ installDir = android.PathForModuleInstall(ctx, "priv-app", as.BaseModuleName())
+ } else {
+ installDir = android.PathForModuleInstall(ctx, "app", as.BaseModuleName())
+ }
+ ctx.InstallFileWithExtraFilesZip(installDir, as.BaseModuleName()+".apk", as.primaryOutput, as.packedOutput)
}
+func (as *AndroidAppSet) InstallBypassMake() bool { return true }
+
// android_app_set extracts a set of APKs based on the target device
// configuration and installs this set as "split APKs".
// The extracted set always contains an APK whose name is
diff --git a/java/app_set_test.go b/java/app_set_test.go
index adaf71b..03eb667 100644
--- a/java/app_set_test.go
+++ b/java/app_set_test.go
@@ -17,19 +17,20 @@
import (
"fmt"
"reflect"
+ "strings"
"testing"
"android/soong/android"
)
func TestAndroidAppSet(t *testing.T) {
- ctx, _ := testJava(t, `
+ result := PrepareForTestWithJavaDefaultModules.RunTestWithBp(t, `
android_app_set {
name: "foo",
set: "prebuilts/apks/app.apks",
prerelease: true,
}`)
- module := ctx.ModuleForTests("foo", "android_common")
+ module := result.ModuleForTests("foo", "android_common")
const packedSplitApks = "foo.zip"
params := module.Output(packedSplitApks)
if params.Rule == nil {
@@ -41,9 +42,22 @@
if s := params.Args["partition"]; s != "system" {
t.Errorf("wrong partition value: '%s', expected 'system'", s)
}
- mkEntries := android.AndroidMkEntriesForTest(t, ctx, module.Module())[0]
+
+ android.AssertPathRelativeToTopEquals(t, "incorrect output path",
+ "out/soong/.intermediates/foo/android_common/foo.apk", params.Output)
+
+ android.AssertPathsRelativeToTopEquals(t, "incorrect implicit output paths",
+ []string{
+ "out/soong/.intermediates/foo/android_common/foo.zip",
+ "out/soong/.intermediates/foo/android_common/apkcerts.txt",
+ },
+ params.ImplicitOutputs.Paths())
+
+ mkEntries := android.AndroidMkEntriesForTest(t, result.TestContext, module.Module())[0]
actualInstallFile := mkEntries.EntryMap["LOCAL_APK_SET_INSTALL_FILE"]
- expectedInstallFile := []string{"foo.apk"}
+ expectedInstallFile := []string{
+ strings.Replace(params.ImplicitOutputs[0].String(), android.OutSoongDir, result.Config.SoongOutDir(), 1),
+ }
if !reflect.DeepEqual(actualInstallFile, expectedInstallFile) {
t.Errorf("Unexpected LOCAL_APK_SET_INSTALL_FILE value: '%s', expected: '%s',",
actualInstallFile, expectedInstallFile)
diff --git a/java/base.go b/java/base.go
index 71b5ac8..d9b1260 100644
--- a/java/base.go
+++ b/java/base.go
@@ -1066,7 +1066,7 @@
j.compiledSrcJars = srcJars
enableSharding := false
- var headerJarFileWithoutJarjar android.Path
+ var headerJarFileWithoutDepsOrJarjar android.Path
if ctx.Device() && !ctx.Config().IsEnvFalse("TURBINE_ENABLED") && !deps.disableTurbine {
if j.properties.Javac_shard_size != nil && *(j.properties.Javac_shard_size) > 0 {
enableSharding = true
@@ -1076,7 +1076,7 @@
// allow for the use of annotation processors that do function correctly
// with sharding enabled. See: b/77284273.
}
- headerJarFileWithoutJarjar, j.headerJarFile =
+ headerJarFileWithoutDepsOrJarjar, j.headerJarFile =
j.compileJavaHeader(ctx, uniqueSrcFiles, srcJars, deps, flags, jarName, kotlinJars)
if ctx.Failed() {
return
@@ -1105,7 +1105,9 @@
}
if enableSharding {
- flags.classpath = append(flags.classpath, headerJarFileWithoutJarjar)
+ if headerJarFileWithoutDepsOrJarjar != nil {
+ flags.classpath = append(classpath{headerJarFileWithoutDepsOrJarjar}, flags.classpath...)
+ }
shardSize := int(*(j.properties.Javac_shard_size))
var shardSrcs []android.Paths
if len(uniqueSrcFiles) > 0 {
@@ -1508,7 +1510,7 @@
func (j *Module) compileJavaHeader(ctx android.ModuleContext, srcFiles, srcJars android.Paths,
deps deps, flags javaBuilderFlags, jarName string,
- extraJars android.Paths) (headerJar, jarjarHeaderJar android.Path) {
+ extraJars android.Paths) (headerJar, jarjarAndDepsHeaderJar android.Path) {
var jars android.Paths
if len(srcFiles) > 0 || len(srcJars) > 0 {
@@ -1519,6 +1521,7 @@
return nil, nil
}
jars = append(jars, turbineJar)
+ headerJar = turbineJar
}
jars = append(jars, extraJars...)
@@ -1532,20 +1535,19 @@
combinedJar := android.PathForModuleOut(ctx, "turbine-combined", jarName)
TransformJarsToJar(ctx, combinedJar, "for turbine", jars, android.OptionalPath{},
false, nil, []string{"META-INF/TRANSITIVE"})
- headerJar = combinedJar
- jarjarHeaderJar = combinedJar
+ jarjarAndDepsHeaderJar = combinedJar
if j.expandJarjarRules != nil {
// Transform classes.jar into classes-jarjar.jar
jarjarFile := android.PathForModuleOut(ctx, "turbine-jarjar", jarName)
- TransformJarJar(ctx, jarjarFile, headerJar, j.expandJarjarRules)
- jarjarHeaderJar = jarjarFile
+ TransformJarJar(ctx, jarjarFile, jarjarAndDepsHeaderJar, j.expandJarjarRules)
+ jarjarAndDepsHeaderJar = jarjarFile
if ctx.Failed() {
return nil, nil
}
}
- return headerJar, jarjarHeaderJar
+ return headerJar, jarjarAndDepsHeaderJar
}
func (j *Module) instrument(ctx android.ModuleContext, flags javaBuilderFlags,
diff --git a/java/builder.go b/java/builder.go
index ae124a3..e64a61f 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -120,14 +120,14 @@
"extractMatchingApks",
blueprint.RuleParams{
Command: `rm -rf "$out" && ` +
- `${config.ExtractApksCmd} -o "${out}" -allow-prereleased=${allow-prereleased} ` +
+ `${config.ExtractApksCmd} -o "${out}" -zip "${zip}" -allow-prereleased=${allow-prereleased} ` +
`-sdk-version=${sdk-version} -abis=${abis} ` +
`--screen-densities=${screen-densities} --stem=${stem} ` +
`-apkcerts=${apkcerts} -partition=${partition} ` +
`${in}`,
CommandDeps: []string{"${config.ExtractApksCmd}"},
},
- "abis", "allow-prereleased", "screen-densities", "sdk-version", "stem", "apkcerts", "partition")
+ "abis", "allow-prereleased", "screen-densities", "sdk-version", "stem", "apkcerts", "partition", "zip")
turbine, turbineRE = pctx.RemoteStaticRules("turbine",
blueprint.RuleParams{
diff --git a/java/java_test.go b/java/java_test.go
index c039f72..6e4e673 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -988,11 +988,11 @@
}
`)
- barHeaderJar := filepath.Join("out", "soong", ".intermediates", "bar", "android_common", "turbine-combined", "bar.jar")
+ barHeaderJar := filepath.Join("out", "soong", ".intermediates", "bar", "android_common", "turbine", "bar.jar")
for i := 0; i < 3; i++ {
barJavac := ctx.ModuleForTests("bar", "android_common").Description("javac" + strconv.Itoa(i))
- if !strings.Contains(barJavac.Args["classpath"], barHeaderJar) {
- t.Errorf("bar javac classpath %v does not contain %q", barJavac.Args["classpath"], barHeaderJar)
+ if !strings.HasPrefix(barJavac.Args["classpath"], "-classpath "+barHeaderJar+":") {
+ t.Errorf("bar javac classpath %v does start with %q", barJavac.Args["classpath"], barHeaderJar)
}
}
}
diff --git a/java/systemserver_classpath_fragment.go b/java/systemserver_classpath_fragment.go
index d75635c..e263cc4 100644
--- a/java/systemserver_classpath_fragment.go
+++ b/java/systemserver_classpath_fragment.go
@@ -125,6 +125,12 @@
// TODO(b/203233647): Add better mechanism to make it optional.
_, unknown = android.RemoveFromList("car-frameworks-service-module", unknown)
+ // This module is optional, so it is not present in all products.
+ // (See PRODUCT_ISOLATED_COMPILATION_ENABLED.)
+ // So ignore it even if it is not in PRODUCT_APEX_SYSTEM_SERVER_JARS.
+ // TODO(b/203233647): Add better mechanism to make it optional.
+ _, unknown = android.RemoveFromList("service-compos", unknown)
+
// TODO(satayev): for apex_test we want to include all contents unconditionally to classpaths
// config. However, any test specific jars would not be present in ApexSystemServerJars. Instead,
// we should check if we are creating a config for apex_test via ApexInfo and amend the values.
diff --git a/mk2rbc/cmd/mk2rbc.go b/mk2rbc/cmd/mk2rbc.go
index 7bb0246..bb5a680 100644
--- a/mk2rbc/cmd/mk2rbc.go
+++ b/mk2rbc/cmd/mk2rbc.go
@@ -46,8 +46,6 @@
dryRun = flag.Bool("dry_run", false, "dry run")
recurse = flag.Bool("convert_dependents", false, "convert all dependent files")
mode = flag.String("mode", "", `"backup" to back up existing files, "write" to overwrite them`)
- noWarn = flag.Bool("no_warnings", false, "don't warn about partially failed conversions")
- verbose = flag.Bool("v", false, "print summary")
errstat = flag.Bool("error_stat", false, "print error statistics")
traceVar = flag.String("trace", "", "comma-separated list of variables to trace")
// TODO(asmundak): this option is for debugging
@@ -75,7 +73,6 @@
flagAlias("root", "d")
flagAlias("dry_run", "n")
flagAlias("convert_dependents", "r")
- flagAlias("no_warnings", "w")
flagAlias("error_stat", "e")
}
@@ -207,9 +204,9 @@
}
}
- printStats()
if *errstat {
errorLogger.printStatistics()
+ printStats()
}
if !ok {
os.Exit(1)
@@ -329,17 +326,16 @@
}()
mk2starRequest := mk2rbc.Request{
- MkFile: mkFile,
- Reader: nil,
- RootDir: *rootDir,
- OutputDir: *outputTop,
- OutputSuffix: *suffix,
- TracedVariables: tracedVariables,
- TraceCalls: *traceCalls,
- WarnPartialSuccess: !*noWarn,
- SourceFS: os.DirFS(*rootDir),
- MakefileFinder: makefileFinder,
- ErrorLogger: errorLogger,
+ MkFile: mkFile,
+ Reader: nil,
+ RootDir: *rootDir,
+ OutputDir: *outputTop,
+ OutputSuffix: *suffix,
+ TracedVariables: tracedVariables,
+ TraceCalls: *traceCalls,
+ SourceFS: os.DirFS(*rootDir),
+ MakefileFinder: makefileFinder,
+ ErrorLogger: errorLogger,
}
ss, err := mk2rbc.Convert(mk2starRequest)
if err != nil {
@@ -417,9 +413,6 @@
func printStats() {
var sortedFiles []string
- if *noWarn && !*verbose {
- return
- }
for p := range converted {
sortedFiles = append(sortedFiles, p)
}
@@ -435,27 +428,22 @@
nOk++
}
}
- if !*noWarn {
- if nPartial > 0 {
- fmt.Fprintf(os.Stderr, "Conversion was partially successful for:\n")
- for _, f := range sortedFiles {
- if ss := converted[f]; ss != nil && ss.HasErrors() {
- fmt.Fprintln(os.Stderr, " ", f)
- }
- }
- }
-
- if nFailed > 0 {
- fmt.Fprintf(os.Stderr, "Conversion failed for files:\n")
- for _, f := range sortedFiles {
- if converted[f] == nil {
- fmt.Fprintln(os.Stderr, " ", f)
- }
+ if nPartial > 0 {
+ fmt.Fprintf(os.Stderr, "Conversion was partially successful for:\n")
+ for _, f := range sortedFiles {
+ if ss := converted[f]; ss != nil && ss.HasErrors() {
+ fmt.Fprintln(os.Stderr, " ", f)
}
}
}
- if *verbose && (nPartial > 0 || nFailed > 0) {
- fmt.Fprintln(os.Stderr, "Succeeded: ", nOk, " Partial: ", nPartial, " Failed: ", nFailed)
+
+ if nFailed > 0 {
+ fmt.Fprintf(os.Stderr, "Conversion failed for files:\n")
+ for _, f := range sortedFiles {
+ if converted[f] == nil {
+ fmt.Fprintln(os.Stderr, " ", f)
+ }
+ }
}
}
@@ -468,8 +456,8 @@
data map[string]datum
}
-func (ebt errorSink) NewError(sourceFile string, sourceLine int, node parser.Node, message string, args ...interface{}) {
- fmt.Fprintf(os.Stderr, "%s:%d ", sourceFile, sourceLine)
+func (ebt errorSink) NewError(el mk2rbc.ErrorLocation, node parser.Node, message string, args ...interface{}) {
+ fmt.Fprint(os.Stderr, el, ": ")
fmt.Fprintf(os.Stderr, message, args...)
fmt.Fprintln(os.Stderr)
if !*errstat {
diff --git a/mk2rbc/expr.go b/mk2rbc/expr.go
index 8279d2e..ec0b279 100644
--- a/mk2rbc/expr.go
+++ b/mk2rbc/expr.go
@@ -18,8 +18,6 @@
"fmt"
"strconv"
"strings"
-
- mkparser "android/soong/androidmk/parser"
)
// Represents an expression in the Starlark code. An expression has
@@ -106,7 +104,7 @@
format += "%s" + strings.ReplaceAll(chunk, "%", "%%")
}
gctx.writef("%q %% ", format)
- emitarg := func(arg starlarkExpr) {
+ emitArg := func(arg starlarkExpr) {
if arg.typ() == starlarkTypeList {
gctx.write(`" ".join(`)
arg.emit(gctx)
@@ -116,12 +114,12 @@
}
}
if len(xi.args) == 1 {
- emitarg(xi.args[0])
+ emitArg(xi.args[0])
} else {
sep := "("
for _, arg := range xi.args {
gctx.write(sep)
- emitarg(arg)
+ emitArg(arg)
sep = ", "
}
gctx.write(")")
@@ -224,9 +222,9 @@
s.expr.emit(ctx)
ctx.write("))")
case starlarkTypeBool:
- ctx.write("((")
+ ctx.write(`("true" if (`)
s.expr.emit(ctx)
- ctx.write(`) ? "true" : "")`)
+ ctx.write(`) else "")`)
case starlarkTypeVoid:
ctx.write(`""`)
default:
@@ -285,20 +283,33 @@
}
func (eq *eqExpr) emit(gctx *generationContext) {
- emitSimple := func(expr starlarkExpr) {
- if eq.isEq {
- gctx.write("not ")
- }
- expr.emit(gctx)
+ var stringOperand string
+ var otherOperand starlarkExpr
+ if s, ok := maybeString(eq.left); ok {
+ stringOperand = s
+ otherOperand = eq.right
+ } else if s, ok := maybeString(eq.right); ok {
+ stringOperand = s
+ otherOperand = eq.left
}
- // Are we checking that a variable is empty?
- if isEmptyString(eq.left) {
- emitSimple(eq.right)
- return
- } else if isEmptyString(eq.right) {
- emitSimple(eq.left)
- return
+ // If we've identified one of the operands as being a string literal, check
+ // for some special cases we can do to simplify the resulting expression.
+ if otherOperand != nil {
+ if stringOperand == "" {
+ if eq.isEq {
+ gctx.write("not ")
+ }
+ otherOperand.emit(gctx)
+ return
+ }
+ if stringOperand == "true" && otherOperand.typ() == starlarkTypeBool {
+ if !eq.isEq {
+ gctx.write("not ")
+ }
+ otherOperand.emit(gctx)
+ return
+ }
}
if eq.left.typ() != eq.right.typ() {
@@ -414,7 +425,7 @@
return &v
}
-// concatExpr generates epxr1 + expr2 + ... + exprN in Starlark.
+// concatExpr generates expr1 + expr2 + ... + exprN in Starlark.
type concatExpr struct {
items []starlarkExpr
}
@@ -607,8 +618,8 @@
}
type badExpr struct {
- node mkparser.Node
- message string
+ errorLocation ErrorLocation
+ message string
}
func (b *badExpr) eval(_ map[string]starlarkExpr) (res starlarkExpr, same bool) {
@@ -617,15 +628,15 @@
return
}
-func (b *badExpr) emit(_ *generationContext) {
- panic("implement me")
+func (b *badExpr) emit(gctx *generationContext) {
+ gctx.emitConversionError(b.errorLocation, b.message)
}
func (_ *badExpr) typ() starlarkType {
return starlarkTypeUnknown
}
-func (b *badExpr) emitListVarCopy(gctx *generationContext) {
+func (_ *badExpr) emitListVarCopy(_ *generationContext) {
panic("implement me")
}
diff --git a/mk2rbc/mk2rbc.go b/mk2rbc/mk2rbc.go
index 8d4626c..4b9779c 100644
--- a/mk2rbc/mk2rbc.go
+++ b/mk2rbc/mk2rbc.go
@@ -102,6 +102,7 @@
"addsuffix": {baseName + ".addsuffix", starlarkTypeList, hiddenArgNone},
"copy-files": {baseName + ".copy_files", starlarkTypeList, hiddenArgNone},
"dir": {baseName + ".dir", starlarkTypeList, hiddenArgNone},
+ "dist-for-goals": {baseName + ".mkdist_for_goals", starlarkTypeVoid, hiddenArgGlobal},
"enforce-product-packages-exist": {baseName + ".enforce_product_packages_exist", starlarkTypeVoid, hiddenArgNone},
"error": {baseName + ".mkerror", starlarkTypeVoid, hiddenArgNone},
"findstring": {"!findstring", starlarkTypeInt, hiddenArgNone},
@@ -156,23 +157,31 @@
// Conversion request parameters
type Request struct {
- MkFile string // file to convert
- Reader io.Reader // if set, read input from this stream instead
- RootDir string // root directory path used to resolve included files
- OutputSuffix string // generated Starlark files suffix
- OutputDir string // if set, root of the output hierarchy
- ErrorLogger ErrorLogger
- TracedVariables []string // trace assignment to these variables
- TraceCalls bool
- WarnPartialSuccess bool
- SourceFS fs.FS
- MakefileFinder MakefileFinder
+ MkFile string // file to convert
+ Reader io.Reader // if set, read input from this stream instead
+ RootDir string // root directory path used to resolve included files
+ OutputSuffix string // generated Starlark files suffix
+ OutputDir string // if set, root of the output hierarchy
+ ErrorLogger ErrorLogger
+ TracedVariables []string // trace assignment to these variables
+ TraceCalls bool
+ SourceFS fs.FS
+ MakefileFinder MakefileFinder
}
// ErrorLogger prints errors and gathers error statistics.
// Its NewError function is called on every error encountered during the conversion.
type ErrorLogger interface {
- NewError(sourceFile string, sourceLine int, node mkparser.Node, text string, args ...interface{})
+ NewError(el ErrorLocation, node mkparser.Node, text string, args ...interface{})
+}
+
+type ErrorLocation struct {
+ MkFile string
+ MkLine int
+}
+
+func (el ErrorLocation) String() string {
+ return fmt.Sprintf("%s:%d", el.MkFile, el.MkLine)
}
// Derives module name for a given file. It is base name
@@ -248,10 +257,6 @@
node.emit(gctx)
}
- if ss.hasErrors && ss.warnPartialSuccess {
- gctx.newLine()
- gctx.writef("%s(%q, %q)", cfnWarning, filepath.Base(ss.mkFile), "partially successful conversion")
- }
if gctx.starScript.traceCalls {
gctx.newLine()
gctx.writef(`print("<%s")`, gctx.starScript.mkFile)
@@ -306,6 +311,10 @@
gctx.writef("%*s", 2*gctx.indentLevel, "")
}
+func (gctx *generationContext) emitConversionError(el ErrorLocation, message string) {
+ gctx.writef(`rblf.mk2rbc_error("%s", %q)`, el, message)
+}
+
type knownVariable struct {
name string
class varClass
@@ -370,18 +379,17 @@
// Information about the generated Starlark script.
type StarlarkScript struct {
- mkFile string
- moduleName string
- mkPos scanner.Position
- nodes []starlarkNode
- inherited []*moduleInfo
- hasErrors bool
- topDir string
- traceCalls bool // print enter/exit each init function
- warnPartialSuccess bool
- sourceFS fs.FS
- makefileFinder MakefileFinder
- nodeLocator func(pos mkparser.Pos) int
+ mkFile string
+ moduleName string
+ mkPos scanner.Position
+ nodes []starlarkNode
+ inherited []*moduleInfo
+ hasErrors bool
+ topDir string
+ traceCalls bool // print enter/exit each init function
+ sourceFS fs.FS
+ makefileFinder MakefileFinder
+ nodeLocator func(pos mkparser.Pos) int
}
func (ss *StarlarkScript) newNode(node starlarkNode) {
@@ -560,7 +568,7 @@
return
}
_, isTraced := ctx.tracedVariables[name]
- asgn := &assignmentNode{lhs: lhs, mkValue: a.Value, isTraced: isTraced}
+ asgn := &assignmentNode{lhs: lhs, mkValue: a.Value, isTraced: isTraced, location: ctx.errorLocation(a)}
if lhs.valueType() == starlarkTypeUnknown {
// Try to divine variable type from the RHS
asgn.value = ctx.parseMakeString(a, a.Value)
@@ -1023,10 +1031,10 @@
func (ctx *parseContext) newBadExpr(node mkparser.Node, text string, args ...interface{}) starlarkExpr {
message := fmt.Sprintf(text, args...)
if ctx.errorLogger != nil {
- ctx.errorLogger.NewError(ctx.script.mkFile, ctx.script.nodeLocator(node.Pos()), node, text, args...)
+ ctx.errorLogger.NewError(ctx.errorLocation(node), node, text, args...)
}
ctx.script.hasErrors = true
- return &badExpr{node, message}
+ return &badExpr{errorLocation: ctx.errorLocation(node), message: message}
}
func (ctx *parseContext) parseCompare(cond *mkparser.Directive) starlarkExpr {
@@ -1544,18 +1552,14 @@
// records that the given node failed to be converted and includes an explanatory message
func (ctx *parseContext) errorf(failedNode mkparser.Node, message string, args ...interface{}) {
if ctx.errorLogger != nil {
- ctx.errorLogger.NewError(ctx.script.mkFile, ctx.script.nodeLocator(failedNode.Pos()), failedNode, message, args...)
+ ctx.errorLogger.NewError(ctx.errorLocation(failedNode), failedNode, message, args...)
}
- message = fmt.Sprintf(message, args...)
- ctx.insertComment(fmt.Sprintf("# MK2RBC TRANSLATION ERROR: %s", message))
- ctx.carryAsComment(failedNode)
-
+ ctx.receiver.newNode(&exprNode{ctx.newBadExpr(failedNode, message, args...)})
ctx.script.hasErrors = true
}
func (ctx *parseContext) wrapBadExpr(xBad *badExpr) {
- ctx.insertComment(fmt.Sprintf("# MK2RBC TRANSLATION ERROR: %s", xBad.message))
- ctx.carryAsComment(xBad.node)
+ ctx.receiver.newNode(&exprNode{xBad})
}
func (ctx *parseContext) loadedModulePath(path string) string {
@@ -1621,6 +1625,10 @@
return ok
}
+func (ctx *parseContext) errorLocation(node mkparser.Node) ErrorLocation {
+ return ErrorLocation{ctx.script.mkFile, ctx.script.nodeLocator(node.Pos())}
+}
+
func (ss *StarlarkScript) String() string {
return NewGenerateContext(ss).emit()
}
@@ -1659,14 +1667,13 @@
return nil, fmt.Errorf("bad makefile %s", req.MkFile)
}
starScript := &StarlarkScript{
- moduleName: moduleNameForFile(req.MkFile),
- mkFile: req.MkFile,
- topDir: req.RootDir,
- traceCalls: req.TraceCalls,
- warnPartialSuccess: req.WarnPartialSuccess,
- sourceFS: req.SourceFS,
- makefileFinder: req.MakefileFinder,
- nodeLocator: func(pos mkparser.Pos) int { return parser.Unpack(pos).Line },
+ moduleName: moduleNameForFile(req.MkFile),
+ mkFile: req.MkFile,
+ topDir: req.RootDir,
+ traceCalls: req.TraceCalls,
+ sourceFS: req.SourceFS,
+ makefileFinder: req.MakefileFinder,
+ nodeLocator: func(pos mkparser.Pos) int { return parser.Unpack(pos).Line },
}
ctx := newParseContext(starScript, nodes)
ctx.outputSuffix = req.OutputSuffix
diff --git a/mk2rbc/mk2rbc_test.go b/mk2rbc/mk2rbc_test.go
index c2c4654..dfdf274 100644
--- a/mk2rbc/mk2rbc_test.go
+++ b/mk2rbc/mk2rbc_test.go
@@ -105,15 +105,12 @@
PRODUCT_NAME := $(call foo1, bar)
PRODUCT_NAME := $(call foo0)
`,
- expected: `# MK2RBC TRANSLATION ERROR: cannot handle invoking foo1
-# PRODUCT_NAME := $(call foo1, bar)
-# MK2RBC TRANSLATION ERROR: cannot handle invoking foo0
-# PRODUCT_NAME := $(call foo0)
-load("//build/make/core:product_config.rbc", "rblf")
+ expected: `load("//build/make/core:product_config.rbc", "rblf")
def init(g, handle):
cfg = rblf.cfg(handle)
- rblf.warning("product.mk", "partially successful conversion")
+ rblf.mk2rbc_error("product.mk:2", "cannot handle invoking foo1")
+ rblf.mk2rbc_error("product.mk:3", "cannot handle invoking foo0")
`,
},
{
@@ -207,15 +204,11 @@
$(info foo)
endef
`,
- expected: `# MK2RBC TRANSLATION ERROR: define is not supported: some-macro
-# define some-macro
-# $(info foo)
-# endef
-load("//build/make/core:product_config.rbc", "rblf")
+ expected: `load("//build/make/core:product_config.rbc", "rblf")
def init(g, handle):
cfg = rblf.cfg(handle)
- rblf.warning("product.mk", "partially successful conversion")
+ rblf.mk2rbc_error("product.mk:2", "define is not supported: some-macro")
`,
},
{
@@ -282,9 +275,7 @@
# Comment
pass
else:
- # MK2RBC TRANSLATION ERROR: cannot set predefined variable TARGET_COPY_OUT_RECOVERY to "foo", its value should be "recovery"
- pass
- rblf.warning("product.mk", "partially successful conversion")
+ rblf.mk2rbc_error("product.mk:5", "cannot set predefined variable TARGET_COPY_OUT_RECOVERY to \"foo\", its value should be \"recovery\"")
`,
},
{
@@ -368,6 +359,21 @@
`,
},
{
+ desc: "ifeq with $(NATIVE_COVERAGE)",
+ mkname: "product.mk",
+ in: `
+ifeq ($(NATIVE_COVERAGE),true)
+endif
+`,
+ expected: `load("//build/make/core:product_config.rbc", "rblf")
+
+def init(g, handle):
+ cfg = rblf.cfg(handle)
+ if g.get("NATIVE_COVERAGE", False):
+ pass
+`,
+ },
+ {
desc: "Check filter result",
mkname: "product.mk",
in: `
@@ -689,6 +695,7 @@
$(call enforce-product-packages-exist, foo)
$(call require-artifacts-in-path, foo, bar)
$(call require-artifacts-in-path-relaxed, foo, bar)
+$(call dist-for-goals, goal, from:to)
`,
expected: `load("//build/make/core:product_config.rbc", "rblf")
@@ -698,6 +705,7 @@
rblf.enforce_product_packages_exist("foo")
rblf.require_artifacts_in_path("foo", "bar")
rblf.require_artifacts_in_path_relaxed("foo", "bar")
+ rblf.mkdist_for_goals(g, "goal", "from:to")
`,
},
{
@@ -857,9 +865,7 @@
rblf.soong_config_namespace(g, "cvd")
rblf.soong_config_set(g, "cvd", "launch_configs", "cvd_config_auto.json")
rblf.soong_config_append(g, "cvd", "grub_config", "grub.cfg")
- # MK2RBC TRANSLATION ERROR: SOONG_CONFIG_ variables cannot be referenced, use soong_config_get instead: SOONG_CONFIG_cvd_grub_config
- # x := $(SOONG_CONFIG_cvd_grub_config)
- rblf.warning("product.mk", "partially successful conversion")
+ rblf.mk2rbc_error("product.mk:7", "SOONG_CONFIG_ variables cannot be referenced, use soong_config_get instead: SOONG_CONFIG_cvd_grub_config")
`,
}, {
desc: "soong namespace accesses",
@@ -1046,15 +1052,11 @@
in: `
foo: foo.c
gcc -o $@ $*`,
- expected: `# MK2RBC TRANSLATION ERROR: unsupported line rule: foo: foo.c
-#gcc -o $@ $*
-# rule: foo: foo.c
-# gcc -o $@ $*
-load("//build/make/core:product_config.rbc", "rblf")
+ expected: `load("//build/make/core:product_config.rbc", "rblf")
def init(g, handle):
cfg = rblf.cfg(handle)
- rblf.warning("product.mk", "partially successful conversion")
+ rblf.mk2rbc_error("product.mk:2", "unsupported line rule: foo: foo.c\n#gcc -o $@ $*")
`,
},
{
@@ -1062,14 +1064,27 @@
mkname: "product.mk",
in: `
override FOO:=`,
- expected: `# MK2RBC TRANSLATION ERROR: cannot handle override directive
-# override FOO :=
-load("//build/make/core:product_config.rbc", "rblf")
+ expected: `load("//build/make/core:product_config.rbc", "rblf")
def init(g, handle):
cfg = rblf.cfg(handle)
+ rblf.mk2rbc_error("product.mk:2", "cannot handle override directive")
g["override FOO"] = ""
- rblf.warning("product.mk", "partially successful conversion")
+`,
+ },
+ {
+ desc: "Bad expression",
+ mkname: "build/product.mk",
+ in: `
+ifeq (,$(call foobar))
+endif
+`,
+ expected: `load("//build/make/core:product_config.rbc", "rblf")
+
+def init(g, handle):
+ cfg = rblf.cfg(handle)
+ if rblf.mk2rbc_error("build/product.mk:2", "cannot handle invoking foobar"):
+ pass
`,
},
}
@@ -1079,6 +1094,7 @@
class varClass
starlarkType
}{
+ {"NATIVE_COVERAGE", VarClassSoong, starlarkTypeBool},
{"PRODUCT_NAME", VarClassConfig, starlarkTypeString},
{"PRODUCT_MODEL", VarClassConfig, starlarkTypeString},
{"PRODUCT_PACKAGES", VarClassConfig, starlarkTypeList},
@@ -1140,13 +1156,12 @@
t.Run(test.desc,
func(t *testing.T) {
ss, err := Convert(Request{
- MkFile: test.mkname,
- Reader: bytes.NewBufferString(test.in),
- RootDir: ".",
- OutputSuffix: ".star",
- WarnPartialSuccess: true,
- SourceFS: fs,
- MakefileFinder: &testMakefileFinder{fs: fs},
+ MkFile: test.mkname,
+ Reader: bytes.NewBufferString(test.in),
+ RootDir: ".",
+ OutputSuffix: ".star",
+ SourceFS: fs,
+ MakefileFinder: &testMakefileFinder{fs: fs},
})
if err != nil {
t.Error(err)
diff --git a/mk2rbc/node.go b/mk2rbc/node.go
index 3fe1a17..d38299d 100644
--- a/mk2rbc/node.go
+++ b/mk2rbc/node.go
@@ -183,6 +183,7 @@
value starlarkExpr
mkValue *mkparser.MakeString
flavor assignmentFlavor
+ location ErrorLocation
isTraced bool
previous *assignmentNode
}
@@ -223,18 +224,6 @@
}
gctx.newLine()
- if bad, ok := in.expr.(*badExpr); ok {
- gctx.write("# MK2STAR ERROR converting:")
- gctx.newLine()
- gctx.writef("# %s", bad.node.Dump())
- gctx.newLine()
- gctx.writef("# %s", bad.message)
- gctx.newLine()
- // The init function emits a warning if the conversion was not
- // fullly successful, so here we (arbitrarily) take the false path.
- gctx.writef("%sFalse:", ifElif)
- return
- }
gctx.write(ifElif)
in.expr.emit(gctx)
gctx.write(":")
diff --git a/mk2rbc/variable.go b/mk2rbc/variable.go
index ded07fe..6b67a7c 100644
--- a/mk2rbc/variable.go
+++ b/mk2rbc/variable.go
@@ -228,10 +228,9 @@
if actualValue == expectedValue {
return
}
- gctx.writef("# MK2RBC TRANSLATION ERROR: cannot set predefined variable %s to %q, its value should be %q",
- pv.name(), actualValue, expectedValue)
- gctx.newLine()
- gctx.write("pass")
+ gctx.emitConversionError(asgn.location,
+ fmt.Sprintf("cannot set predefined variable %s to %q, its value should be %q",
+ pv.name(), actualValue, expectedValue))
gctx.starScript.hasErrors = true
return
}
diff --git a/rust/config/global.go b/rust/config/global.go
index ebddb75..d3826ac 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -24,7 +24,7 @@
var pctx = android.NewPackageContext("android/soong/rust/config")
var (
- RustDefaultVersion = "1.56.1"
+ RustDefaultVersion = "1.56.1p1"
RustDefaultBase = "prebuilts/rust/"
DefaultEdition = "2018"
Stdlibs = []string{
diff --git a/scripts/unpack-prebuilt-apex.sh b/scripts/unpack-prebuilt-apex.sh
index 1acdeb5..f34a480 100755
--- a/scripts/unpack-prebuilt-apex.sh
+++ b/scripts/unpack-prebuilt-apex.sh
@@ -29,8 +29,6 @@
shift 4
REQUIRED_PATHS=$@
-set -x 1
-
rm -fr $OUTPUT_DIR
mkdir -p $OUTPUT_DIR
diff --git a/scripts/update_out b/scripts/update_out
new file mode 100755
index 0000000..d3950cf
--- /dev/null
+++ b/scripts/update_out
@@ -0,0 +1,21 @@
+#! /bin/bash
+# Run given command application and update the contents of a given file.
+# Will not change the file if its contents has not changed.
+[[ $# -gt 1 ]] || { echo "Usage: ${0##*/} FILE COMMAND" >&2; exit 1; }
+set -u
+declare -r outfile="$1"
+shift
+if [[ ! -f $outfile ]]; then
+ $@ >$outfile
+ exit
+fi
+
+declare -r newout=${outfile}.new
+$@ >$newout
+rc=$?
+if cmp -s $newout $outfile; then
+ rm $newout
+else
+ mv -f $newout $outfile
+fi
+exit $rc