Merge "Improve apex build check explanation"
diff --git a/OWNERS b/OWNERS
index f0ccd82..937a243 100644
--- a/OWNERS
+++ b/OWNERS
@@ -7,12 +7,15 @@
asmundak@google.com
ccross@android.com
cparsons@google.com
+delmerico@google.com
dwillemsen@google.com
eakammer@google.com
jobredeaux@google.com
joeo@google.com
lamontjones@google.com
spandandas@google.com
+tradical@google.com
+usta@google.com
weiwli@google.com
yudiliu@google.com
yuntaoxu@google.com
diff --git a/README.md b/README.md
index b820fd1..127c52c 100644
--- a/README.md
+++ b/README.md
@@ -452,10 +452,9 @@
The values of the variables can be set from a product's `BoardConfig.mk` file:
```
-$(call add_soong_config_namespace, acme)
-$(call add_soong_config_var_value, acme, board, soc_a)
-$(call add_soong_config_var_value, acme, feature, true)
-$(call add_soong_config_var_value, acme, width, 200)
+$(call soong_config_set,acme,board,soc_a)
+$(call soong_config_set,acme,feature,true)
+$(call soong_config_set,acme,width,200)
```
The `acme_cc_defaults` module type can be used anywhere after the definition in
diff --git a/android/api_levels.go b/android/api_levels.go
index 1fbbc15..926d297 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -344,7 +344,7 @@
var apiLevelsMapKey = NewOnceKey("ApiLevelsMap")
-func getApiLevelsMap(config Config) map[string]int {
+func GetApiLevelsMap(config Config) map[string]int {
return config.Once(apiLevelsMapKey, func() interface{} {
apiLevelsMap := map[string]int{
"G": 9,
@@ -374,7 +374,7 @@
}
func (a *apiLevelsSingleton) GenerateBuildActions(ctx SingletonContext) {
- apiLevelsMap := getApiLevelsMap(ctx.Config())
+ apiLevelsMap := GetApiLevelsMap(ctx.Config())
apiLevelsJson := GetApiLevelsJson(ctx)
createApiLevelsJson(ctx, apiLevelsJson, apiLevelsMap)
}
diff --git a/android/arch.go b/android/arch.go
index e08fd5c..96a4cbf 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -993,8 +993,6 @@
base := m.base()
- // Store the original list of top level property structs
- base.generalProperties = m.GetProperties()
if len(base.archProperties) != 0 {
panic(fmt.Errorf("module %s already has archProperties", m.Name()))
}
@@ -1015,7 +1013,7 @@
return t
}
- for _, properties := range base.generalProperties {
+ for _, properties := range m.GetProperties() {
t := getStructType(properties)
// Get or create the arch-specific property struct types for this property struct type.
archPropTypes := archPropTypeMap.Once(NewCustomOnceKey(t), func() interface{} {
@@ -1036,9 +1034,6 @@
m.AddProperties(archProperties...)
}
- // Update the list of properties that can be set by a defaults module or a call to
- // AppendMatchingProperties or PrependMatchingProperties.
- base.customizableProperties = m.GetProperties()
}
func maybeBlueprintEmbed(src reflect.Value) reflect.Value {
@@ -1111,8 +1106,8 @@
func (m *ModuleBase) setOSProperties(ctx BottomUpMutatorContext) {
os := m.commonProperties.CompileOS
- for i := range m.generalProperties {
- genProps := m.generalProperties[i]
+ for i := range m.archProperties {
+ genProps := m.GetProperties()[i]
if m.archProperties[i] == nil {
continue
}
@@ -1439,8 +1434,8 @@
arch := m.Arch()
os := m.Os()
- for i := range m.generalProperties {
- genProps := m.generalProperties[i]
+ for i := range m.archProperties {
+ genProps := m.GetProperties()[i]
if m.archProperties[i] == nil {
continue
}
@@ -2018,8 +2013,8 @@
var archProperties []interface{}
// First find the property set in the module that corresponds to the requested
- // one. m.archProperties[i] corresponds to m.generalProperties[i].
- for i, generalProp := range m.generalProperties {
+ // one. m.archProperties[i] corresponds to m.GetProperties()[i].
+ for i, generalProp := range m.GetProperties() {
srcType := reflect.ValueOf(generalProp).Type()
if srcType == dstType {
archProperties = m.archProperties[i]
diff --git a/android/bazel.go b/android/bazel.go
index f4f9a72..7971451 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -226,6 +226,7 @@
"packages/apps/WallpaperPicker":/* recursive = */ false,
"prebuilts/gcc":/* recursive = */ true,
+ "prebuilts/build-tools":/* recursive = */ false,
"prebuilts/sdk":/* recursive = */ false,
"prebuilts/sdk/current/extras/app-toolkit":/* recursive = */ false,
"prebuilts/sdk/current/support":/* recursive = */ false,
@@ -236,6 +237,8 @@
// Configure modules in these directories to enable bp2build_available: true or false by default.
bp2buildDefaultConfig = Bp2BuildConfig{
"art/libdexfile": Bp2BuildDefaultTrueRecursively,
+ "art/runtime": Bp2BuildDefaultTrueRecursively,
+ "art/tools": Bp2BuildDefaultTrue,
"bionic": Bp2BuildDefaultTrueRecursively,
"bootable/recovery/tools/recovery_l10n": Bp2BuildDefaultTrue,
"build/bazel/examples/soong_config_variables": Bp2BuildDefaultTrueRecursively,
@@ -245,6 +248,7 @@
"build/soong/cc/libbuildversion": Bp2BuildDefaultTrue, // Skip tests subdir
"build/soong/cc/ndkstubgen": Bp2BuildDefaultTrue,
"build/soong/cc/symbolfile": Bp2BuildDefaultTrue,
+ "build/soong/linkerconfig": Bp2BuildDefaultTrueRecursively,
"build/soong/scripts": Bp2BuildDefaultTrueRecursively,
"cts/common/device-side/nativetesthelper/jni": Bp2BuildDefaultTrueRecursively,
"development/apps/DevelopmentSettings": Bp2BuildDefaultTrue,
@@ -323,6 +327,7 @@
"packages/apps/DevCamera": Bp2BuildDefaultTrue,
"packages/apps/HTMLViewer": Bp2BuildDefaultTrue,
"packages/apps/Protips": Bp2BuildDefaultTrue,
+ "packages/modules/StatsD/lib/libstatssocket": Bp2BuildDefaultTrueRecursively,
"packages/modules/adb": Bp2BuildDefaultTrue,
"packages/modules/adb/apex": Bp2BuildDefaultTrue,
"packages/modules/adb/crypto": Bp2BuildDefaultTrueRecursively,
@@ -336,6 +341,8 @@
"packages/services/Car/tests/SampleRearViewCamera": Bp2BuildDefaultTrue,
"prebuilts/clang/host/linux-x86": Bp2BuildDefaultTrueRecursively,
"system/apex": Bp2BuildDefaultFalse, // TODO(b/207466993): flaky failures
+ "system/apex/proto": Bp2BuildDefaultTrueRecursively,
+ "system/apex/libs": Bp2BuildDefaultTrueRecursively,
"system/core/debuggerd": Bp2BuildDefaultTrueRecursively,
"system/core/diagnose_usb": Bp2BuildDefaultTrueRecursively,
"system/core/libasyncio": Bp2BuildDefaultTrue,
@@ -364,16 +371,34 @@
// Per-module denylist to always opt modules out of both bp2build and mixed builds.
bp2buildModuleDoNotConvertList = []string{
+ "libnativehelper_compat_libc", // Broken compile: implicit declaration of function 'strerror_r' is invalid in C99
+
+ "libart", // depends on unconverted modules: art_operator_srcs, libodrstatslog, libelffile, art_cmdlineparser_headers, cpp-define-generator-definitions, libcpu_features, libdexfile, libartpalette, libbacktrace, libnativebridge, libnativeloader, libsigchain, libunwindstack, libartbase, libprofile, cpp-define-generator-asm-support, apex-info-list-tinyxml, libtinyxml2, libnativeloader-headers, libstatssocket, heapprofd_client_api
+ "libart-runtime-gtest", // depends on unconverted modules: libgtest_isolated, libart-compiler, libdexfile, libprofile, libartbase, libbacktrace, libartbase-art-gtest
+ "libart_headers", // depends on unconverted modules: art_libartbase_headers
+ "libartd", // depends on unconverted modules: apex-info-list-tinyxml, libtinyxml2, libnativeloader-headers, libstatssocket, heapprofd_client_api, art_operator_srcs, libodrstatslog, libelffiled, art_cmdlineparser_headers, cpp-define-generator-definitions, libcpu_features, libdexfiled, libartpalette, libbacktrace, libnativebridge, libnativeloader, libsigchain, libunwindstack, libartbased, libprofiled, cpp-define-generator-asm-support
+ "libartd-runtime-gtest", // depends on unconverted modules: libgtest_isolated, libartd-compiler, libdexfiled, libprofiled, libartbased, libbacktrace, libartbased-art-gtest
+ "libstatslog_art", // depends on unconverted modules: statslog_art.cpp, statslog_art.h
+ "statslog_art.h", "statslog_art.cpp", // depends on unconverted modules: stats-log-api-gen
+
"libandroid_runtime_lazy", // depends on unconverted modules: libbinder_headers
"libcmd", // depends on unconverted modules: libbinder
+ "libdexfile_support_static", // Depends on unconverted module: libdexfile_external_headers
+ "libunwindstack_local", "libunwindstack_utils", "libc_malloc_debug", "libfdtrack", // Depends on unconverted module: libunwindstack
+
+ "libdexfile_support", // TODO(b/210546943): Enabled based on product variables.
+ "libdexfile_external_headers", // TODO(b/210546943): Enabled based on product variables.
+
+ "libunwindstack", // Depends on unconverted module libdexfile_support.
+ "libnativehelper_compat_libc++", // Broken compile: implicit declaration of function 'strerror_r' is invalid in C99
+
"chkcon", "sefcontext_compile", // depends on unconverted modules: libsepol
"libsepol", // TODO(b/207408632): Unsupported case of .l sources in cc library rules
"gen-kotlin-build-file.py", // module has same name as source
- "libbinder", // TODO(b/188503688): Disabled for some archs,
"libactivitymanager_aidl", // TODO(b/207426160): Depends on activity_manager_procstate_aidl, which is an aidl filegroup.
"libnativehelper_lazy_mts_jni", "libnativehelper_mts_jni", // depends on unconverted modules: libgmock_ndk
@@ -395,22 +420,23 @@
"libdebuggerd", // depends on unconverted modules libdexfile_support, libunwindstack, gwp_asan_crash_handler, libtombstone_proto, libprotobuf-cpp-lite
"libdexfile_static", // depends on libartpalette, libartbase, libdexfile, which are of unsupported type: art_cc_library.
- "host_bionic_linker_asm", // depends on extract_linker, a go binary.
- "host_bionic_linker_script", // depends on extract_linker, a go binary.
- "static_crasher", // depends on unconverted modules: libdebuggerd_handler
+ "static_crasher", // depends on unconverted modules: libdebuggerd_handler
"pbtombstone", "crash_dump", // depends on libdebuggerd, libunwindstack
"libbase_ndk", // http://b/186826477, fails to link libctscamera2_jni for device (required for CtsCameraTestCases)
- "libprotobuf-python", // contains .proto sources
"libprotobuf-internal-protos", // b/210751803, we don't handle path property for filegroups
"libprotobuf-internal-python-srcs", // b/210751803, we don't handle path property for filegroups
"libprotobuf-java-full", // b/210751803, we don't handle path property for filegroups
"libprotobuf-java-util-full", // b/210751803, we don't handle path property for filegroups
"conscrypt", // b/210751803, we don't handle path property for filegroups
- "conv_linker_config", // depends on linker_config_proto, a python lib with proto sources
+ // python protos
+ "libprotobuf-python", // contains .proto sources
+ "conv_linker_config", // depends on linker_config_proto, a python lib with proto sources
+ "apex_build_info_proto", "apex_manifest_proto", // a python lib with proto sources
+ "linker_config_proto", // contains .proto sources
"brotli-fuzzer-corpus", // b/202015218: outputs are in location incompatible with bazel genrule handling.
@@ -427,6 +453,8 @@
"abb", // depends on unconverted modules: libcmd, libbinder
"adb", // depends on unconverted modules: AdbWinApi, libadb_host, libandroidfw, libapp_processes_protos_full, libfastdeploy_host, libopenscreen-discovery, libopenscreen-platform-impl, libusb, bin2c_fastdeployagent, AdbWinUsbApi
+ "libadb_host", // depends on unconverted modules: libopenscreen-discovery, libopenscreen-platform-impl, libusb, AdbWinApi
+ "libfastdeploy_host", // depends on unconverted modules: libandroidfw, libusb, AdbWinApi
"linker", // depends on unconverted modules: libdebuggerd_handler_fallback
"linker_reloc_bench_main", // depends on unconverted modules: liblinker_reloc_bench_*
"versioner", // depends on unconverted modules: libclang_cxx_host, libLLVM_host, of unsupported type llvm_host_prebuilt_library_shared
@@ -434,18 +462,20 @@
"linkerconfig", // http://b/202876379 has arch-variant static_executable
"mdnsd", // http://b/202876379 has arch-variant static_executable
- "acvp_modulewrapper", // disabled for android x86/x86_64
- "CarHTMLViewer", // depends on unconverted modules android.car-stubs, car-ui-lib
+ "CarHTMLViewer", // depends on unconverted modules android.car-stubs, car-ui-lib
"libdexfile", // depends on unconverted modules: dexfile_operator_srcs, libartbase, libartpalette,
"libdexfiled", // depends on unconverted modules: dexfile_operator_srcs, libartbased, libartpalette
+
+ // go deps:
+ "apex-protos", // depends on unconverted modules: soong_zip
+ "host_bionic_linker_asm", // depends on extract_linker, a go binary.
+ "host_bionic_linker_script", // depends on extract_linker, a go binary.
}
// Per-module denylist of cc_library modules to only generate the static
// variant if their shared variant isn't ready or buildable by Bazel.
- bp2buildCcLibraryStaticOnlyList = []string{
- "libjemalloc5", // http://b/188503688, cc_library, `target: { android: { enabled: false } }` for android targets.
- }
+ bp2buildCcLibraryStaticOnlyList = []string{}
// Per-module denylist to opt modules out of mixed builds. Such modules will
// still be generated via bp2build.
@@ -513,6 +543,9 @@
// Windows toolchains are not currently supported.
return false
}
+ if !ctx.Module().Enabled() {
+ return false
+ }
if !ctx.Config().BazelContext.BazelEnabled() {
return false
}
diff --git a/android/bazel_paths.go b/android/bazel_paths.go
index 62e6156..f353a9d 100644
--- a/android/bazel_paths.go
+++ b/android/bazel_paths.go
@@ -92,6 +92,7 @@
GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag)
ModuleFromName(name string) (blueprint.Module, bool)
AddUnconvertedBp2buildDep(string)
+ AddMissingBp2buildDep(dep string)
}
// BazelLabelForModuleDeps expects a list of reference to other modules, ("<module>"
@@ -129,8 +130,10 @@
}
if m, t := SrcIsModuleWithTag(module); m != "" {
l := getOtherModuleLabel(ctx, m, t, moduleToLabelFn)
- l.OriginalModuleName = bpText
- labels.Includes = append(labels.Includes, l)
+ if l != nil {
+ l.OriginalModuleName = bpText
+ labels.Includes = append(labels.Includes, *l)
+ }
} else {
ctx.ModuleErrorf("%q, is not a module reference", module)
}
@@ -157,11 +160,17 @@
}
func BazelLabelForModuleSrcSingle(ctx BazelConversionPathContext, path string) bazel.Label {
- return BazelLabelForModuleSrcExcludes(ctx, []string{path}, []string(nil)).Includes[0]
+ if srcs := BazelLabelForModuleSrcExcludes(ctx, []string{path}, []string(nil)).Includes; len(srcs) > 0 {
+ return srcs[0]
+ }
+ return bazel.Label{}
}
func BazelLabelForModuleDepSingle(ctx BazelConversionPathContext, path string) bazel.Label {
- return BazelLabelForModuleDepsExcludes(ctx, []string{path}, []string(nil)).Includes[0]
+ if srcs := BazelLabelForModuleDepsExcludes(ctx, []string{path}, []string(nil)).Includes; len(srcs) > 0 {
+ return srcs[0]
+ }
+ return bazel.Label{}
}
// BazelLabelForModuleSrc expects a list of path (relative to local module directory) and module
@@ -328,9 +337,9 @@
for _, p := range paths {
if m, tag := SrcIsModuleWithTag(p); m != "" {
l := getOtherModuleLabel(ctx, m, tag, BazelModuleLabel)
- if !InList(l.Label, expandedExcludes) {
+ if l != nil && !InList(l.Label, expandedExcludes) {
l.OriginalModuleName = fmt.Sprintf(":%s", m)
- labels.Includes = append(labels.Includes, l)
+ labels.Includes = append(labels.Includes, *l)
}
} else {
var expandedPaths []bazel.Label
@@ -354,10 +363,16 @@
// module. The label will be relative to the current directory if appropriate. The dependency must
// already be resolved by either deps mutator or path deps mutator.
func getOtherModuleLabel(ctx BazelConversionPathContext, dep, tag string,
- labelFromModule func(BazelConversionPathContext, blueprint.Module) string) bazel.Label {
+ labelFromModule func(BazelConversionPathContext, blueprint.Module) string) *bazel.Label {
m, _ := ctx.ModuleFromName(dep)
+ // The module was not found in an Android.bp file, this is often due to:
+ // * a limited manifest
+ // * a required module not being converted from Android.mk
if m == nil {
- panic(fmt.Errorf("No module named %q found, but was a direct dep of %q", dep, ctx.Module().Name()))
+ ctx.AddMissingBp2buildDep(dep)
+ return &bazel.Label{
+ Label: ":" + dep + "__BP2BUILD__MISSING__DEP",
+ }
}
if !convertedToBazel(ctx, m) {
ctx.AddUnconvertedBp2buildDep(dep)
@@ -371,7 +386,7 @@
otherLabel = bazelShortLabel(otherLabel)
}
- return bazel.Label{
+ return &bazel.Label{
Label: otherLabel,
}
}
diff --git a/android/config.go b/android/config.go
index 5c0e5ae..afc138b 100644
--- a/android/config.go
+++ b/android/config.go
@@ -1245,6 +1245,10 @@
return coverage
}
+func (c *deviceConfig) AfdoAdditionalProfileDirs() []string {
+ return c.config.productVariables.AfdoAdditionalProfileDirs
+}
+
func (c *deviceConfig) PgoAdditionalProfileDirs() []string {
return c.config.productVariables.PgoAdditionalProfileDirs
}
@@ -1465,6 +1469,10 @@
return String(c.config.productVariables.TotSepolicyVersion)
}
+func (c *deviceConfig) PlatformSepolicyCompatVersions() []string {
+ return c.config.productVariables.PlatformSepolicyCompatVersions
+}
+
func (c *deviceConfig) BoardSepolicyVers() string {
if ver := String(c.config.productVariables.BoardSepolicyVers); ver != "" {
return ver
diff --git a/android/defaults.go b/android/defaults.go
index 5677638..8b121f6 100644
--- a/android/defaults.go
+++ b/android/defaults.go
@@ -96,8 +96,6 @@
module.setProperties(module.GetProperties(), module.base().variableProperties)
module.AddProperties(module.defaults())
-
- module.base().customizableProperties = module.GetProperties()
}
// A restricted subset of context methods, similar to LoadHookContext.
diff --git a/android/hooks.go b/android/hooks.go
index 9eaa1ac..bded764 100644
--- a/android/hooks.go
+++ b/android/hooks.go
@@ -68,7 +68,7 @@
func (l *loadHookContext) appendPrependHelper(props []interface{},
extendFn func([]interface{}, interface{}, proptools.ExtendPropertyFilterFunc) error) {
for _, p := range props {
- err := extendFn(l.Module().base().customizableProperties, p, nil)
+ err := extendFn(l.Module().base().GetProperties(), p, nil)
if err != nil {
if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
l.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
diff --git a/android/license.go b/android/license.go
index 8bfd3ba..587cb36 100644
--- a/android/license.go
+++ b/android/license.go
@@ -80,9 +80,6 @@
base := module.base()
module.AddProperties(&base.nameProperties, &module.properties)
- base.generalProperties = module.GetProperties()
- base.customizableProperties = module.GetProperties()
-
// The visibility property needs to be checked and parsed by the visibility module.
setPrimaryVisibilityProperty(module, "visibility", &module.properties.Visibility)
diff --git a/android/license_kind.go b/android/license_kind.go
index ddecd77..838dedd 100644
--- a/android/license_kind.go
+++ b/android/license_kind.go
@@ -53,9 +53,6 @@
base := module.base()
module.AddProperties(&base.nameProperties, &module.properties)
- base.generalProperties = module.GetProperties()
- base.customizableProperties = module.GetProperties()
-
// The visibility property needs to be checked and parsed by the visibility module.
setPrimaryVisibilityProperty(module, "visibility", &module.properties.Visibility)
diff --git a/android/licenses_test.go b/android/licenses_test.go
index d05b0a3..70160fa 100644
--- a/android/licenses_test.go
+++ b/android/licenses_test.go
@@ -779,9 +779,6 @@
base := m.base()
m.AddProperties(&base.nameProperties, &m.properties)
- base.generalProperties = m.GetProperties()
- base.customizableProperties = m.GetProperties()
-
// The default_visibility property needs to be checked and parsed by the visibility module during
// its checking and parsing phases so make it the primary visibility property.
setPrimaryVisibilityProperty(m, "visibility", &m.properties.Visibility)
diff --git a/android/module.go b/android/module.go
index 6de4165..3c8c777 100644
--- a/android/module.go
+++ b/android/module.go
@@ -19,6 +19,7 @@
"os"
"path"
"path/filepath"
+ "reflect"
"regexp"
"strings"
"text/scanner"
@@ -320,6 +321,9 @@
// AddUnconvertedBp2buildDep stores module name of a direct dependency that was not converted via bp2build
AddUnconvertedBp2buildDep(dep string)
+ // AddMissingBp2buildDep stores the module name of a direct dependency that was not found.
+ AddMissingBp2buildDep(dep string)
+
Target() Target
TargetPrimary() bool
@@ -516,6 +520,7 @@
// Bp2buildTargets returns the target(s) generated for Bazel via bp2build for this module
Bp2buildTargets() []bp2buildInfo
GetUnconvertedBp2buildDeps() []string
+ GetMissingBp2buildDeps() []string
BuildParamsForTests() []BuildParams
RuleParamsForTests() map[blueprint.Rule]blueprint.RuleParams
@@ -857,6 +862,9 @@
// UnconvertedBp2buildDep stores the module names of direct dependency that were not converted to
// Bazel
UnconvertedBp2buildDeps []string `blueprint:"mutated"`
+
+ // MissingBp2buildDep stores the module names of direct dependency that were not found
+ MissingBp2buildDeps []string `blueprint:"mutated"`
}
// CommonAttributes represents the common Bazel attributes from which properties
@@ -869,6 +877,13 @@
Data bazel.LabelListAttribute
}
+// constraintAttributes represents Bazel attributes pertaining to build constraints,
+// which make restrict building a Bazel target for some set of platforms.
+type constraintAttributes struct {
+ // Constraint values this target can be built for.
+ Target_compatible_with bazel.LabelListAttribute
+}
+
type distProperties struct {
// configuration to distribute output files from this module to the distribution
// directory (default: $OUT/dist, configurable with $DIST_DIR)
@@ -1025,9 +1040,6 @@
initProductVariableModule(m)
- base.generalProperties = m.GetProperties()
- base.customizableProperties = m.GetProperties()
-
// The default_visibility property needs to be checked and parsed by the visibility module during
// its checking and parsing phases so make it the primary visibility property.
setPrimaryVisibilityProperty(m, "visibility", &base.commonProperties.Visibility)
@@ -1089,7 +1101,8 @@
m.base().commonProperties.CreateCommonOSVariant = true
}
-func (attrs *CommonAttributes) fillCommonBp2BuildModuleAttrs(ctx *topDownMutatorContext) {
+func (attrs *CommonAttributes) fillCommonBp2BuildModuleAttrs(ctx *topDownMutatorContext,
+ enabledPropertyOverrides bazel.BoolAttribute) constraintAttributes {
// Assert passed-in attributes include Name
name := attrs.Name
if len(name) == 0 {
@@ -1107,14 +1120,96 @@
required := depsToLabelList(props.Required)
archVariantProps := mod.GetArchVariantProperties(ctx, &commonProperties{})
+
+ var enabledProperty bazel.BoolAttribute
+ if props.Enabled != nil {
+ enabledProperty.Value = props.Enabled
+ }
+
for axis, configToProps := range archVariantProps {
for config, _props := range configToProps {
if archProps, ok := _props.(*commonProperties); ok {
required.SetSelectValue(axis, config, depsToLabelList(archProps.Required).Value)
+ if archProps.Enabled != nil {
+ enabledProperty.SetSelectValue(axis, config, archProps.Enabled)
+ }
}
}
}
+
+ if enabledPropertyOverrides.Value != nil {
+ enabledProperty.Value = enabledPropertyOverrides.Value
+ }
+ for _, axis := range enabledPropertyOverrides.SortedConfigurationAxes() {
+ configToBools := enabledPropertyOverrides.ConfigurableValues[axis]
+ for cfg, val := range configToBools {
+ enabledProperty.SetSelectValue(axis, cfg, &val)
+ }
+ }
+
+ productConfigEnabledLabels := []bazel.Label{}
+ if !proptools.BoolDefault(enabledProperty.Value, true) {
+ // If the module is not enabled by default, then we can check if a
+ // product variable enables it
+ productConfigEnabledLabels = productVariableConfigEnableLabels(ctx)
+
+ if len(productConfigEnabledLabels) > 0 {
+ // In this case, an existing product variable configuration overrides any
+ // module-level `enable: false` definition
+ newValue := true
+ enabledProperty.Value = &newValue
+ }
+ }
+
+ productConfigEnabledAttribute := bazel.MakeLabelListAttribute(bazel.LabelList{
+ productConfigEnabledLabels, nil,
+ })
+
+ platformEnabledAttribute, err := enabledProperty.ToLabelListAttribute(
+ bazel.LabelList{[]bazel.Label{bazel.Label{Label: "@platforms//:incompatible"}}, nil},
+ bazel.LabelList{[]bazel.Label{}, nil})
+ if err != nil {
+ ctx.ModuleErrorf("Error processing platform enabled attribute: %s", err)
+ }
+
data.Append(required)
+
+ constraints := constraintAttributes{}
+ moduleEnableConstraints := bazel.LabelListAttribute{}
+ moduleEnableConstraints.Append(platformEnabledAttribute)
+ moduleEnableConstraints.Append(productConfigEnabledAttribute)
+ constraints.Target_compatible_with = moduleEnableConstraints
+
+ return constraints
+}
+
+// Check product variables for `enabled: true` flag override.
+// Returns a list of the constraint_value targets who enable this override.
+func productVariableConfigEnableLabels(ctx *topDownMutatorContext) []bazel.Label {
+ productVariableProps := ProductVariableProperties(ctx)
+ productConfigEnablingTargets := []bazel.Label{}
+ const propName = "Enabled"
+ if productConfigProps, exists := productVariableProps[propName]; exists {
+ for productConfigProp, prop := range productConfigProps {
+ flag, ok := prop.(*bool)
+ if !ok {
+ ctx.ModuleErrorf("Could not convert product variable %s property", proptools.PropertyNameForField(propName))
+ }
+
+ if *flag {
+ axis := productConfigProp.ConfigurationAxis()
+ targetLabel := axis.SelectKey(productConfigProp.SelectKey())
+ productConfigEnablingTargets = append(productConfigEnablingTargets, bazel.Label{
+ Label: targetLabel,
+ })
+ } else {
+ // TODO(b/210546943): handle negative case where `enabled: false`
+ ctx.ModuleErrorf("`enabled: false` is not currently supported for configuration variables. See b/210546943", proptools.PropertyNameForField(propName))
+ }
+ }
+ }
+
+ return productConfigEnablingTargets
}
// A ModuleBase object contains the properties that are common to all Android
@@ -1169,17 +1264,14 @@
distProperties distProperties
variableProperties interface{}
hostAndDeviceProperties hostAndDeviceProperties
- generalProperties []interface{}
- // Arch specific versions of structs in generalProperties. The outer index
- // has the same order as generalProperties as initialized in
- // InitAndroidArchModule, and the inner index chooses the props specific to
- // the architecture. The interface{} value is an archPropRoot that is
- // filled with arch specific values by the arch mutator.
+ // Arch specific versions of structs in GetProperties() prior to
+ // initialization in InitAndroidArchModule, lets call it `generalProperties`.
+ // The outer index has the same order as generalProperties and the inner index
+ // chooses the props specific to the architecture. The interface{} value is an
+ // archPropRoot that is filled with arch specific values by the arch mutator.
archProperties [][]interface{}
- customizableProperties []interface{}
-
// Properties specific to the Blueprint to BUILD migration.
bazelTargetModuleProperties bazel.BazelTargetModuleProperties
@@ -1233,10 +1325,11 @@
// A struct containing all relevant information about a Bazel target converted via bp2build.
type bp2buildInfo struct {
- Dir string
- BazelProps bazel.BazelTargetModuleProperties
- CommonAttrs CommonAttributes
- Attrs interface{}
+ Dir string
+ BazelProps bazel.BazelTargetModuleProperties
+ CommonAttrs CommonAttributes
+ ConstraintAttrs constraintAttributes
+ Attrs interface{}
}
// TargetName returns the Bazel target name of a bp2build converted target.
@@ -1262,7 +1355,7 @@
// BazelAttributes returns the Bazel attributes of a bp2build converted target.
func (b bp2buildInfo) BazelAttributes() []interface{} {
- return []interface{}{&b.CommonAttrs, b.Attrs}
+ return []interface{}{&b.CommonAttrs, &b.ConstraintAttrs, b.Attrs}
}
func (m *ModuleBase) addBp2buildInfo(info bp2buildInfo) {
@@ -1285,14 +1378,82 @@
*unconvertedDeps = append(*unconvertedDeps, dep)
}
+// AddMissingBp2buildDep stores module name of a dependency that was not found in a Android.bp file.
+func (b *baseModuleContext) AddMissingBp2buildDep(dep string) {
+ missingDeps := &b.Module().base().commonProperties.MissingBp2buildDeps
+ *missingDeps = append(*missingDeps, dep)
+}
+
// GetUnconvertedBp2buildDeps returns the list of module names of this module's direct dependencies that
// were not converted to Bazel.
func (m *ModuleBase) GetUnconvertedBp2buildDeps() []string {
return FirstUniqueStrings(m.commonProperties.UnconvertedBp2buildDeps)
}
+// GetMissingBp2buildDeps eturns the list of module names that were not found in Android.bp files.
+func (m *ModuleBase) GetMissingBp2buildDeps() []string {
+ return FirstUniqueStrings(m.commonProperties.MissingBp2buildDeps)
+}
+
func (m *ModuleBase) AddJSONData(d *map[string]interface{}) {
- (*d)["Android"] = map[string]interface{}{}
+ (*d)["Android"] = map[string]interface{}{
+ // Properties set in Blueprint or in blueprint of a defaults modules
+ "SetProperties": m.propertiesWithValues(),
+ }
+}
+
+type propInfo struct {
+ Name string
+ Type string
+}
+
+func (m *ModuleBase) propertiesWithValues() []propInfo {
+ var info []propInfo
+ props := m.GetProperties()
+
+ var propsWithValues func(name string, v reflect.Value)
+ propsWithValues = func(name string, v reflect.Value) {
+ kind := v.Kind()
+ switch kind {
+ case reflect.Ptr, reflect.Interface:
+ if v.IsNil() {
+ return
+ }
+ propsWithValues(name, v.Elem())
+ case reflect.Struct:
+ if v.IsZero() {
+ return
+ }
+ for i := 0; i < v.NumField(); i++ {
+ namePrefix := name
+ sTyp := v.Type().Field(i)
+ if proptools.ShouldSkipProperty(sTyp) {
+ continue
+ }
+ if name != "" && !strings.HasSuffix(namePrefix, ".") {
+ namePrefix += "."
+ }
+ if !proptools.IsEmbedded(sTyp) {
+ namePrefix += sTyp.Name
+ }
+ sVal := v.Field(i)
+ propsWithValues(namePrefix, sVal)
+ }
+ case reflect.Array, reflect.Slice:
+ if v.IsNil() {
+ return
+ }
+ elKind := v.Type().Elem().Kind()
+ info = append(info, propInfo{name, elKind.String() + " " + kind.String()})
+ default:
+ info = append(info, propInfo{name, kind.String()})
+ }
+ }
+
+ for _, p := range props {
+ propsWithValues("", reflect.ValueOf(p).Elem())
+ }
+ return info
}
func (m *ModuleBase) ComponentDepsMutator(BottomUpMutatorContext) {}
@@ -1771,6 +1932,10 @@
return append(Paths{}, m.vintfFragmentsPaths...)
}
+func (m *ModuleBase) CompileMultilib() *string {
+ return m.base().commonProperties.Compile_multilib
+}
+
// SetLicenseInstallMap stores the set of dependency module:location mappings for files in an
// apex container for use when generation the license metadata file.
func (m *ModuleBase) SetLicenseInstallMap(installMap []string) {
diff --git a/android/module_test.go b/android/module_test.go
index d9e2c87..c35e66e 100644
--- a/android/module_test.go
+++ b/android/module_test.go
@@ -615,3 +615,204 @@
return rules
}
+
+type PropsTestModuleEmbedded struct {
+ Embedded_prop *string
+}
+
+type propsTestModule struct {
+ ModuleBase
+ DefaultableModuleBase
+ props struct {
+ A string `android:"arch_variant"`
+ B *bool
+ C []string
+ }
+ otherProps struct {
+ PropsTestModuleEmbedded
+
+ D *int64
+ Nested struct {
+ E *string
+ }
+ F *string `blueprint:"mutated"`
+ }
+}
+
+func propsTestModuleFactory() Module {
+ module := &propsTestModule{}
+ module.AddProperties(&module.props, &module.otherProps)
+ InitAndroidArchModule(module, HostAndDeviceSupported, MultilibBoth)
+ InitDefaultableModule(module)
+ return module
+}
+
+type propsTestModuleDefaults struct {
+ ModuleBase
+ DefaultsModuleBase
+}
+
+func propsTestModuleDefaultsFactory() Module {
+ defaults := &propsTestModuleDefaults{}
+ module := propsTestModule{}
+ defaults.AddProperties(&module.props, &module.otherProps)
+ InitDefaultsModule(defaults)
+ return defaults
+}
+
+func (p *propsTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
+ str := "abc"
+ p.otherProps.F = &str
+}
+
+func TestUsedProperties(t *testing.T) {
+ testCases := []struct {
+ desc string
+ bp string
+ expectedProps []propInfo
+ }{
+ {
+ desc: "only name",
+ bp: `test {
+ name: "foo",
+ }
+ `,
+ expectedProps: []propInfo{
+ propInfo{"Name", "string"},
+ },
+ },
+ {
+ desc: "some props",
+ bp: `test {
+ name: "foo",
+ a: "abc",
+ b: true,
+ d: 123,
+ }
+ `,
+ expectedProps: []propInfo{
+ propInfo{"A", "string"},
+ propInfo{"B", "bool"},
+ propInfo{"D", "int64"},
+ propInfo{"Name", "string"},
+ },
+ },
+ {
+ desc: "unused non-pointer prop",
+ bp: `test {
+ name: "foo",
+ b: true,
+ d: 123,
+ }
+ `,
+ expectedProps: []propInfo{
+ // for non-pointer cannot distinguish between unused and intentionally set to empty
+ propInfo{"A", "string"},
+ propInfo{"B", "bool"},
+ propInfo{"D", "int64"},
+ propInfo{"Name", "string"},
+ },
+ },
+ {
+ desc: "nested props",
+ bp: `test {
+ name: "foo",
+ nested: {
+ e: "abc",
+ }
+ }
+ `,
+ expectedProps: []propInfo{
+ propInfo{"Nested.E", "string"},
+ propInfo{"Name", "string"},
+ },
+ },
+ {
+ desc: "arch props",
+ bp: `test {
+ name: "foo",
+ arch: {
+ x86_64: {
+ a: "abc",
+ },
+ }
+ }
+ `,
+ expectedProps: []propInfo{
+ propInfo{"Name", "string"},
+ propInfo{"Arch.X86_64.A", "string"},
+ },
+ },
+ {
+ desc: "embedded props",
+ bp: `test {
+ name: "foo",
+ embedded_prop: "a",
+ }
+ `,
+ expectedProps: []propInfo{
+ propInfo{"Embedded_prop", "string"},
+ propInfo{"Name", "string"},
+ },
+ },
+ {
+ desc: "defaults",
+ bp: `
+test_defaults {
+ name: "foo_defaults",
+ a: "a",
+ b: true,
+ embedded_prop:"a",
+ arch: {
+ x86_64: {
+ a: "a",
+ },
+ },
+}
+test {
+ name: "foo",
+ defaults: ["foo_defaults"],
+ c: ["a"],
+ nested: {
+ e: "d",
+ },
+ target: {
+ linux: {
+ a: "a",
+ },
+ },
+}
+ `,
+ expectedProps: []propInfo{
+ propInfo{"A", "string"},
+ propInfo{"B", "bool"},
+ propInfo{"C", "string slice"},
+ propInfo{"Embedded_prop", "string"},
+ propInfo{"Nested.E", "string"},
+ propInfo{"Name", "string"},
+ propInfo{"Arch.X86_64.A", "string"},
+ propInfo{"Target.Linux.A", "string"},
+ propInfo{"Defaults", "string slice"},
+ },
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.desc, func(t *testing.T) {
+ result := GroupFixturePreparers(
+ PrepareForTestWithAllowMissingDependencies,
+ PrepareForTestWithDefaults,
+ FixtureRegisterWithContext(func(ctx RegistrationContext) {
+ ctx.RegisterModuleType("test", propsTestModuleFactory)
+ ctx.RegisterModuleType("test_defaults", propsTestModuleDefaultsFactory)
+ }),
+ FixtureWithRootAndroidBp(tc.bp),
+ ).RunTest(t)
+
+ foo := result.ModuleForTests("foo", "").Module().base()
+
+ AssertDeepEquals(t, "foo ", tc.expectedProps, foo.propertiesWithValues())
+
+ })
+ }
+}
diff --git a/android/mutator.go b/android/mutator.go
index dbd8c04..fa6f2be8 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -254,6 +254,14 @@
// BazelTargetModuleProperties containing additional metadata for the
// bp2build codegenerator.
CreateBazelTargetModule(bazel.BazelTargetModuleProperties, CommonAttributes, interface{})
+
+ // CreateBazelTargetModuleWithRestrictions creates a BazelTargetModule by calling the
+ // factory method, just like in CreateModule, but also requires
+ // BazelTargetModuleProperties containing additional metadata for the
+ // bp2build codegenerator. The generated target is restricted to only be buildable for certain
+ // platforms, as dictated by a given bool attribute: the target will not be buildable in
+ // any platform for which this bool attribute is false.
+ CreateBazelTargetModuleWithRestrictions(bazel.BazelTargetModuleProperties, CommonAttributes, interface{}, bazel.BoolAttribute)
}
type topDownMutatorContext struct {
@@ -502,13 +510,30 @@
bazelProps bazel.BazelTargetModuleProperties,
commonAttrs CommonAttributes,
attrs interface{}) {
- commonAttrs.fillCommonBp2BuildModuleAttrs(t)
+ t.createBazelTargetModule(bazelProps, commonAttrs, attrs, bazel.BoolAttribute{})
+}
+
+func (t *topDownMutatorContext) CreateBazelTargetModuleWithRestrictions(
+ bazelProps bazel.BazelTargetModuleProperties,
+ commonAttrs CommonAttributes,
+ attrs interface{},
+ enabledProperty bazel.BoolAttribute) {
+ t.createBazelTargetModule(bazelProps, commonAttrs, attrs, enabledProperty)
+}
+
+func (t *topDownMutatorContext) createBazelTargetModule(
+ bazelProps bazel.BazelTargetModuleProperties,
+ commonAttrs CommonAttributes,
+ attrs interface{},
+ enabledProperty bazel.BoolAttribute) {
+ constraintAttributes := commonAttrs.fillCommonBp2BuildModuleAttrs(t, enabledProperty)
mod := t.Module()
info := bp2buildInfo{
- Dir: t.OtherModuleDir(mod),
- BazelProps: bazelProps,
- CommonAttrs: commonAttrs,
- Attrs: attrs,
+ Dir: t.OtherModuleDir(mod),
+ BazelProps: bazelProps,
+ CommonAttrs: commonAttrs,
+ ConstraintAttrs: constraintAttributes,
+ Attrs: attrs,
}
mod.base().addBp2buildInfo(info)
}
diff --git a/android/neverallow.go b/android/neverallow.go
index 4bb3e57..6f9ae58 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -134,7 +134,6 @@
NeverAllow().
Without("name", "libhidlbase-combined-impl").
Without("name", "libhidlbase").
- Without("name", "libhidlbase_pgo").
With("product_variables.enforce_vintf_manifest.cflags", "*").
Because("manifest enforcement should be independent of ."),
@@ -215,11 +214,8 @@
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 and seapp contexts may be imported as a makefile goal."),
+ Because("Only boot images may be imported as a makefile goal."),
}
}
diff --git a/android/neverallow_test.go b/android/neverallow_test.go
index 58a90b3..59016d4 100644
--- a/android/neverallow_test.go
+++ b/android/neverallow_test.go
@@ -324,7 +324,7 @@
`),
},
expectedErrors: []string{
- "Only boot images and seapp contexts may be imported as a makefile goal.",
+ "Only boot images may be imported as a makefile goal.",
},
},
{
diff --git a/android/path_properties.go b/android/path_properties.go
index 3976880..fdc4d91 100644
--- a/android/path_properties.go
+++ b/android/path_properties.go
@@ -33,7 +33,7 @@
// The pathDepsMutator automatically adds dependencies on any module that is listed with the
// ":module" module reference syntax in a property that is tagged with `android:"path"`.
func pathDepsMutator(ctx BottomUpMutatorContext) {
- props := ctx.Module().base().generalProperties
+ props := ctx.Module().base().GetProperties()
addPathDepsForProps(ctx, props)
}
diff --git a/android/prebuilt.go b/android/prebuilt.go
index b0a4f43..5843487 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -183,7 +183,6 @@
func initPrebuiltModuleCommon(module PrebuiltInterface) *Prebuilt {
p := module.Prebuilt()
module.AddProperties(&p.properties)
- module.base().customizableProperties = module.GetProperties()
return p
}
@@ -310,6 +309,54 @@
return nil
}
+// PrebuiltGetPreferred returns the module that is preferred for the given
+// module. That is either the module itself or the prebuilt counterpart that has
+// taken its place. The given module must be a direct dependency of the current
+// context module, and it must be the source module if both source and prebuilt
+// exist.
+//
+// This function is for use on dependencies after PrebuiltPostDepsMutator has
+// run - any dependency that is registered before that will already reference
+// the right module. This function is only safe to call after all mutators that
+// may call CreateVariations, e.g. in GenerateAndroidBuildActions.
+func PrebuiltGetPreferred(ctx BaseModuleContext, module Module) Module {
+ if !module.IsReplacedByPrebuilt() {
+ return module
+ }
+ if IsModulePrebuilt(module) {
+ // If we're given a prebuilt then assume there's no source module around.
+ return module
+ }
+
+ sourceModDepFound := false
+ var prebuiltMod Module
+
+ ctx.WalkDeps(func(child, parent Module) bool {
+ if prebuiltMod != nil {
+ return false
+ }
+ if parent == ctx.Module() {
+ // First level: Only recurse if the module is found as a direct dependency.
+ sourceModDepFound = child == module
+ return sourceModDepFound
+ }
+ // Second level: Follow PrebuiltDepTag to the prebuilt.
+ if t := ctx.OtherModuleDependencyTag(child); t == PrebuiltDepTag {
+ prebuiltMod = child
+ }
+ return false
+ })
+
+ if prebuiltMod == nil {
+ if !sourceModDepFound {
+ panic(fmt.Errorf("Failed to find source module as a direct dependency: %s", module))
+ } else {
+ panic(fmt.Errorf("Failed to find prebuilt for source module: %s", module))
+ }
+ }
+ return prebuiltMod
+}
+
func RegisterPrebuiltsPreArchMutators(ctx RegisterMutatorsContext) {
ctx.BottomUp("prebuilt_rename", PrebuiltRenameMutator).Parallel()
}
diff --git a/android/variable.go b/android/variable.go
index bc93835..40dd2d8 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -124,6 +124,9 @@
Shared_libs []string
Cmdline []string
+
+ Srcs []string
+ Exclude_srcs []string
}
// eng is true for -eng builds, and can be used to turn on additionaly heavyweight debugging
@@ -327,7 +330,8 @@
NamespacesToExport []string `json:",omitempty"`
- PgoAdditionalProfileDirs []string `json:",omitempty"`
+ AfdoAdditionalProfileDirs []string `json:",omitempty"`
+ PgoAdditionalProfileDirs []string `json:",omitempty"`
VndkUseCoreVariant *bool `json:",omitempty"`
VndkSnapshotBuildArtifacts *bool `json:",omitempty"`
@@ -360,6 +364,8 @@
PlatformSepolicyVersion *string `json:",omitempty"`
TotSepolicyVersion *string `json:",omitempty"`
+ PlatformSepolicyCompatVersions []string `json:",omitempty"`
+
VendorVars map[string]map[string]string `json:",omitempty"`
Ndk_abis *bool `json:",omitempty"`
@@ -595,10 +601,16 @@
value := p.FullConfig
if value == p.Name {
- value = "enabled"
+ value = ""
}
- // e.g. acme__feature1__enabled, android__board__soc_a
- return strings.ToLower(strings.Join([]string{p.Namespace, p.Name, value}, "__"))
+
+ // e.g. acme__feature1, android__board__soc_a
+ selectKey := strings.ToLower(strings.Join([]string{p.Namespace, p.Name}, "__"))
+ if value != "" {
+ selectKey = strings.ToLower(strings.Join([]string{selectKey, value}, "__"))
+ }
+
+ return selectKey
}
// ProductConfigProperties is a map of maps to group property values according
@@ -1025,7 +1037,7 @@
printfIntoProperties(ctx, prefix, productVariablePropertyValue, variableValue)
- err := proptools.AppendMatchingProperties(m.generalProperties,
+ err := proptools.AppendMatchingProperties(m.GetProperties(),
productVariablePropertyValue.Addr().Interface(), nil)
if err != nil {
if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
diff --git a/apex/apex.go b/apex/apex.go
index 09e634e..3051553 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -1612,8 +1612,8 @@
return af
}
-func apexFileForBpfProgram(ctx android.BaseModuleContext, builtFile android.Path, bpfProgram bpf.BpfModule) apexFile {
- dirInApex := filepath.Join("etc", "bpf")
+func apexFileForBpfProgram(ctx android.BaseModuleContext, builtFile android.Path, apex_sub_dir string, bpfProgram bpf.BpfModule) apexFile {
+ dirInApex := filepath.Join("etc", "bpf", apex_sub_dir)
return newApexFile(ctx, builtFile, builtFile.Base(), dirInApex, etc, bpfProgram)
}
@@ -1765,13 +1765,17 @@
}
case bcpfTag:
{
- if _, ok := child.(*java.BootclasspathFragmentModule); !ok {
+ bcpfModule, ok := child.(*java.BootclasspathFragmentModule)
+ if !ok {
ctx.PropertyErrorf("bootclasspath_fragments", "%q is not a bootclasspath_fragment module", depName)
return false
}
filesToAdd := apexBootclasspathFragmentFiles(ctx, child)
filesInfo = append(filesInfo, filesToAdd...)
+ for _, makeModuleName := range bcpfModule.BootImageDeviceInstallMakeModules() {
+ a.requiredDeps = append(a.requiredDeps, makeModuleName)
+ }
return true
}
case sscpfTag:
@@ -1827,8 +1831,9 @@
case bpfTag:
if bpfProgram, ok := child.(bpf.BpfModule); ok {
filesToCopy, _ := bpfProgram.OutputFiles("")
+ apex_sub_dir := bpfProgram.SubDir()
for _, bpfFile := range filesToCopy {
- filesInfo = append(filesInfo, apexFileForBpfProgram(ctx, bpfFile, bpfProgram))
+ filesInfo = append(filesInfo, apexFileForBpfProgram(ctx, bpfFile, apex_sub_dir, bpfProgram))
}
} else {
ctx.PropertyErrorf("bpfs", "%q is not a bpf module", depName)
@@ -2175,13 +2180,15 @@
var filesToAdd []apexFile
// Add the boot image files, e.g. .art, .oat and .vdex files.
- for arch, files := range bootclasspathFragmentInfo.AndroidBootImageFilesByArchType() {
- dirInApex := filepath.Join("javalib", arch.String())
- for _, f := range files {
- androidMkModuleName := "javalib_" + arch.String() + "_" + filepath.Base(f.String())
- // TODO(b/177892522) - consider passing in the bootclasspath fragment module here instead of nil
- af := newApexFile(ctx, f, androidMkModuleName, dirInApex, etc, nil)
- filesToAdd = append(filesToAdd, af)
+ if bootclasspathFragmentInfo.ShouldInstallBootImageInApex() {
+ for arch, files := range bootclasspathFragmentInfo.AndroidBootImageFilesByArchType() {
+ dirInApex := filepath.Join("javalib", arch.String())
+ for _, f := range files {
+ androidMkModuleName := "javalib_" + arch.String() + "_" + filepath.Base(f.String())
+ // TODO(b/177892522) - consider passing in the bootclasspath fragment module here instead of nil
+ af := newApexFile(ctx, f, androidMkModuleName, dirInApex, etc, nil)
+ filesToAdd = append(filesToAdd, af)
+ }
}
}
@@ -3270,17 +3277,23 @@
// For Bazel / bp2build
type bazelApexBundleAttributes struct {
- Manifest bazel.LabelAttribute
- Android_manifest bazel.LabelAttribute
- File_contexts bazel.LabelAttribute
- Key bazel.LabelAttribute
- Certificate bazel.LabelAttribute
- Min_sdk_version *string
- Updatable bazel.BoolAttribute
- Installable bazel.BoolAttribute
- Native_shared_libs bazel.LabelListAttribute
- Binaries bazel.LabelListAttribute
- Prebuilts bazel.LabelListAttribute
+ Manifest bazel.LabelAttribute
+ Android_manifest bazel.LabelAttribute
+ File_contexts bazel.LabelAttribute
+ Key bazel.LabelAttribute
+ Certificate bazel.LabelAttribute
+ Min_sdk_version *string
+ Updatable bazel.BoolAttribute
+ Installable bazel.BoolAttribute
+ Binaries bazel.LabelListAttribute
+ Prebuilts bazel.LabelListAttribute
+ Native_shared_libs_32 bazel.LabelListAttribute
+ Native_shared_libs_64 bazel.LabelListAttribute
+}
+
+type convertedNativeSharedLibs struct {
+ Native_shared_libs_32 bazel.LabelListAttribute
+ Native_shared_libs_64 bazel.LabelListAttribute
}
// ConvertWithBp2build performs bp2build conversion of an apex
@@ -3320,9 +3333,21 @@
certificateLabelAttribute.SetValue(android.BazelLabelForModuleDepSingle(ctx, *a.overridableProperties.Certificate))
}
- nativeSharedLibs := a.properties.ApexNativeDependencies.Native_shared_libs
- nativeSharedLibsLabelList := android.BazelLabelForModuleDeps(ctx, nativeSharedLibs)
- nativeSharedLibsLabelListAttribute := bazel.MakeLabelListAttribute(nativeSharedLibsLabelList)
+ nativeSharedLibs := &convertedNativeSharedLibs{
+ Native_shared_libs_32: bazel.LabelListAttribute{},
+ Native_shared_libs_64: bazel.LabelListAttribute{},
+ }
+ compileMultilib := "both"
+ if a.CompileMultilib() != nil {
+ compileMultilib = *a.CompileMultilib()
+ }
+
+ // properties.Native_shared_libs is treated as "both"
+ convertBothLibs(ctx, compileMultilib, a.properties.Native_shared_libs, nativeSharedLibs)
+ convertBothLibs(ctx, compileMultilib, a.properties.Multilib.Both.Native_shared_libs, nativeSharedLibs)
+ convert32Libs(ctx, compileMultilib, a.properties.Multilib.Lib32.Native_shared_libs, nativeSharedLibs)
+ convert64Libs(ctx, compileMultilib, a.properties.Multilib.Lib64.Native_shared_libs, nativeSharedLibs)
+ convertFirstLibs(ctx, compileMultilib, a.properties.Multilib.First.Native_shared_libs, nativeSharedLibs)
prebuilts := a.overridableProperties.Prebuilts
prebuiltsLabelList := android.BazelLabelForModuleDeps(ctx, prebuilts)
@@ -3342,17 +3367,18 @@
}
attrs := &bazelApexBundleAttributes{
- Manifest: manifestLabelAttribute,
- Android_manifest: androidManifestLabelAttribute,
- File_contexts: fileContextsLabelAttribute,
- Min_sdk_version: minSdkVersion,
- Key: keyLabelAttribute,
- Certificate: certificateLabelAttribute,
- Updatable: updatableAttribute,
- Installable: installableAttribute,
- Native_shared_libs: nativeSharedLibsLabelListAttribute,
- Binaries: binariesLabelListAttribute,
- Prebuilts: prebuiltsLabelListAttribute,
+ Manifest: manifestLabelAttribute,
+ Android_manifest: androidManifestLabelAttribute,
+ File_contexts: fileContextsLabelAttribute,
+ Min_sdk_version: minSdkVersion,
+ Key: keyLabelAttribute,
+ Certificate: certificateLabelAttribute,
+ Updatable: updatableAttribute,
+ Installable: installableAttribute,
+ Native_shared_libs_32: nativeSharedLibs.Native_shared_libs_32,
+ Native_shared_libs_64: nativeSharedLibs.Native_shared_libs_64,
+ Binaries: binariesLabelListAttribute,
+ Prebuilts: prebuiltsLabelListAttribute,
}
props := bazel.BazelTargetModuleProperties{
@@ -3362,3 +3388,107 @@
ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: a.Name()}, attrs)
}
+
+// The following conversions are based on this table where the rows are the compile_multilib
+// values and the columns are the properties.Multilib.*.Native_shared_libs. Each cell
+// represents how the libs should be compiled for a 64-bit/32-bit device: 32 means it
+// should be compiled as 32-bit, 64 means it should be compiled as 64-bit, none means it
+// should not be compiled.
+// multib/compile_multilib, 32, 64, both, first
+// 32, 32/32, none/none, 32/32, none/32
+// 64, none/none, 64/none, 64/none, 64/none
+// both, 32/32, 64/none, 32&64/32, 64/32
+// first, 32/32, 64/none, 64/32, 64/32
+
+func convert32Libs(ctx android.TopDownMutatorContext, compileMultilb string,
+ libs []string, nativeSharedLibs *convertedNativeSharedLibs) {
+ libsLabelList := android.BazelLabelForModuleDeps(ctx, libs)
+ switch compileMultilb {
+ case "both", "32":
+ makeNoConfig32SharedLibsAttributes(libsLabelList, nativeSharedLibs)
+ case "first":
+ make32SharedLibsAttributes(libsLabelList, nativeSharedLibs)
+ case "64":
+ // Incompatible, ignore
+ default:
+ invalidCompileMultilib(ctx, compileMultilb)
+ }
+}
+
+func convert64Libs(ctx android.TopDownMutatorContext, compileMultilb string,
+ libs []string, nativeSharedLibs *convertedNativeSharedLibs) {
+ libsLabelList := android.BazelLabelForModuleDeps(ctx, libs)
+ switch compileMultilb {
+ case "both", "64", "first":
+ make64SharedLibsAttributes(libsLabelList, nativeSharedLibs)
+ case "32":
+ // Incompatible, ignore
+ default:
+ invalidCompileMultilib(ctx, compileMultilb)
+ }
+}
+
+func convertBothLibs(ctx android.TopDownMutatorContext, compileMultilb string,
+ libs []string, nativeSharedLibs *convertedNativeSharedLibs) {
+ libsLabelList := android.BazelLabelForModuleDeps(ctx, libs)
+ switch compileMultilb {
+ case "both":
+ makeNoConfig32SharedLibsAttributes(libsLabelList, nativeSharedLibs)
+ make64SharedLibsAttributes(libsLabelList, nativeSharedLibs)
+ case "first":
+ makeFirstSharedLibsAttributes(libsLabelList, nativeSharedLibs)
+ case "32":
+ makeNoConfig32SharedLibsAttributes(libsLabelList, nativeSharedLibs)
+ case "64":
+ make64SharedLibsAttributes(libsLabelList, nativeSharedLibs)
+ default:
+ invalidCompileMultilib(ctx, compileMultilb)
+ }
+}
+
+func convertFirstLibs(ctx android.TopDownMutatorContext, compileMultilb string,
+ libs []string, nativeSharedLibs *convertedNativeSharedLibs) {
+ libsLabelList := android.BazelLabelForModuleDeps(ctx, libs)
+ switch compileMultilb {
+ case "both", "first":
+ makeFirstSharedLibsAttributes(libsLabelList, nativeSharedLibs)
+ case "32":
+ make32SharedLibsAttributes(libsLabelList, nativeSharedLibs)
+ case "64":
+ make64SharedLibsAttributes(libsLabelList, nativeSharedLibs)
+ default:
+ invalidCompileMultilib(ctx, compileMultilb)
+ }
+}
+
+func makeFirstSharedLibsAttributes(libsLabelList bazel.LabelList, nativeSharedLibs *convertedNativeSharedLibs) {
+ make32SharedLibsAttributes(libsLabelList, nativeSharedLibs)
+ make64SharedLibsAttributes(libsLabelList, nativeSharedLibs)
+}
+
+func makeNoConfig32SharedLibsAttributes(libsLabelList bazel.LabelList, nativeSharedLibs *convertedNativeSharedLibs) {
+ list := bazel.LabelListAttribute{}
+ list.SetSelectValue(bazel.NoConfigAxis, "", libsLabelList)
+ nativeSharedLibs.Native_shared_libs_32.Append(list)
+}
+
+func make32SharedLibsAttributes(libsLabelList bazel.LabelList, nativeSharedLibs *convertedNativeSharedLibs) {
+ makeSharedLibsAttributes("x86", libsLabelList, &nativeSharedLibs.Native_shared_libs_32)
+ makeSharedLibsAttributes("arm", libsLabelList, &nativeSharedLibs.Native_shared_libs_32)
+}
+
+func make64SharedLibsAttributes(libsLabelList bazel.LabelList, nativeSharedLibs *convertedNativeSharedLibs) {
+ makeSharedLibsAttributes("x86_64", libsLabelList, &nativeSharedLibs.Native_shared_libs_64)
+ makeSharedLibsAttributes("arm64", libsLabelList, &nativeSharedLibs.Native_shared_libs_64)
+}
+
+func makeSharedLibsAttributes(config string, libsLabelList bazel.LabelList,
+ labelListAttr *bazel.LabelListAttribute) {
+ list := bazel.LabelListAttribute{}
+ list.SetSelectValue(bazel.ArchConfigurationAxis, config, libsLabelList)
+ labelListAttr.Append(list)
+}
+
+func invalidCompileMultilib(ctx android.TopDownMutatorContext, value string) {
+ ctx.PropertyErrorf("compile_multilib", "Invalid value: %s", value)
+}
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 9a6fae3..c546fa1 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -623,7 +623,7 @@
java_libs: ["myjar"],
apps: ["AppFoo"],
rros: ["rro"],
- bpfs: ["bpf"],
+ bpfs: ["bpf", "netd_test"],
updatable: false,
}
@@ -676,6 +676,12 @@
srcs: ["bpf.c", "bpf2.c"],
}
+ bpf {
+ name: "netd_test",
+ srcs: ["netd_test.c"],
+ sub_dir: "netd",
+ }
+
`)
ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
"etc/myetc",
@@ -685,6 +691,7 @@
"overlay/blue/rro.apk",
"etc/bpf/bpf.o",
"etc/bpf/bpf2.o",
+ "etc/bpf/netd/netd_test.o",
})
}
@@ -8739,6 +8746,22 @@
})
}
+// Verifies that the APEX depends on all the Make modules in the list.
+func ensureContainsRequiredDeps(t *testing.T, ctx *android.TestContext, moduleName, variant string, deps []string) {
+ a := ctx.ModuleForTests(moduleName, variant).Module().(*apexBundle)
+ for _, dep := range deps {
+ android.AssertStringListContains(t, "", a.requiredDeps, dep)
+ }
+}
+
+// Verifies that the APEX does not depend on any of the Make modules in the list.
+func ensureDoesNotContainRequiredDeps(t *testing.T, ctx *android.TestContext, moduleName, variant string, deps []string) {
+ a := ctx.ModuleForTests(moduleName, variant).Module().(*apexBundle)
+ for _, dep := range deps {
+ android.AssertStringListDoesNotContain(t, "", a.requiredDeps, dep)
+ }
+}
+
func TestMain(m *testing.M) {
os.Exit(m.Run())
}
diff --git a/apex/bootclasspath_fragment_test.go b/apex/bootclasspath_fragment_test.go
index ce828e1..8f44fc5 100644
--- a/apex/bootclasspath_fragment_test.go
+++ b/apex/bootclasspath_fragment_test.go
@@ -410,6 +410,7 @@
// bootclasspath_fragment's contents property.
java.FixtureConfigureBootJars("com.android.art:foo", "com.android.art:bar"),
addSource("foo", "bar"),
+ java.FixtureSetBootImageInstallDirOnDevice("art", "apex/com.android.art/javalib"),
).RunTest(t)
ensureExactContents(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{
@@ -437,12 +438,62 @@
`mybootclasspathfragment`,
})
+ // The boot images are installed in the APEX by Soong, so there shouldn't be any dexpreopt-related Make modules.
+ ensureDoesNotContainRequiredDeps(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{
+ "mybootclasspathfragment-dexpreopt-arm64-boot.art",
+ "mybootclasspathfragment-dexpreopt-arm64-boot.oat",
+ "mybootclasspathfragment-dexpreopt-arm64-boot.vdex",
+ "mybootclasspathfragment-dexpreopt-arm64-boot-bar.art",
+ "mybootclasspathfragment-dexpreopt-arm64-boot-bar.oat",
+ "mybootclasspathfragment-dexpreopt-arm64-boot-bar.vdex",
+ "mybootclasspathfragment-dexpreopt-arm-boot.art",
+ "mybootclasspathfragment-dexpreopt-arm-boot.oat",
+ "mybootclasspathfragment-dexpreopt-arm-boot.vdex",
+ "mybootclasspathfragment-dexpreopt-arm-boot-bar.art",
+ "mybootclasspathfragment-dexpreopt-arm-boot-bar.oat",
+ "mybootclasspathfragment-dexpreopt-arm-boot-bar.vdex",
+ })
+
// Make sure that the source bootclasspath_fragment copies its dex files to the predefined
// locations for the art image.
module := result.ModuleForTests("mybootclasspathfragment", "android_common_apex10000")
checkCopiesToPredefinedLocationForArt(t, result.Config, module, "bar", "foo")
})
+ t.Run("boot image files from source no boot image in apex", func(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ commonPreparer,
+
+ // Configure some libraries in the art bootclasspath_fragment that match the source
+ // bootclasspath_fragment's contents property.
+ java.FixtureConfigureBootJars("com.android.art:foo", "com.android.art:bar"),
+ addSource("foo", "bar"),
+ java.FixtureSetBootImageInstallDirOnDevice("art", "system/framework"),
+ ).RunTest(t)
+
+ ensureExactContents(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{
+ "etc/boot-image.prof",
+ "etc/classpaths/bootclasspath.pb",
+ "javalib/bar.jar",
+ "javalib/foo.jar",
+ })
+
+ ensureContainsRequiredDeps(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{
+ "mybootclasspathfragment-dexpreopt-arm64-boot.art",
+ "mybootclasspathfragment-dexpreopt-arm64-boot.oat",
+ "mybootclasspathfragment-dexpreopt-arm64-boot.vdex",
+ "mybootclasspathfragment-dexpreopt-arm64-boot-bar.art",
+ "mybootclasspathfragment-dexpreopt-arm64-boot-bar.oat",
+ "mybootclasspathfragment-dexpreopt-arm64-boot-bar.vdex",
+ "mybootclasspathfragment-dexpreopt-arm-boot.art",
+ "mybootclasspathfragment-dexpreopt-arm-boot.oat",
+ "mybootclasspathfragment-dexpreopt-arm-boot.vdex",
+ "mybootclasspathfragment-dexpreopt-arm-boot-bar.art",
+ "mybootclasspathfragment-dexpreopt-arm-boot-bar.oat",
+ "mybootclasspathfragment-dexpreopt-arm-boot-bar.vdex",
+ })
+ })
+
t.Run("boot image disable generate profile", func(t *testing.T) {
result := android.GroupFixturePreparers(
commonPreparer,
@@ -472,6 +523,8 @@
// Make sure that a preferred prebuilt with consistent contents doesn't affect the apex.
addPrebuilt(true, "foo", "bar"),
+
+ java.FixtureSetBootImageInstallDirOnDevice("art", "apex/com.android.art/javalib"),
).RunTest(t)
ensureExactContents(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{
diff --git a/bazel/configurability.go b/bazel/configurability.go
index 1993f76..7355ac7 100644
--- a/bazel/configurability.go
+++ b/bazel/configurability.go
@@ -109,6 +109,21 @@
osArchWindowsX86_64: "//build/bazel/platforms/os_arch:windows_x86_64",
ConditionsDefaultConfigKey: ConditionsDefaultSelectKey, // The default condition of an os select map.
}
+
+ // Map where keys are OsType names, and values are slices containing the archs
+ // that that OS supports.
+ // These definitions copied from arch.go.
+ // TODO(cparsons): Source from arch.go; this task is nontrivial, as it currently results
+ // in a cyclic dependency.
+ osToArchMap = map[string][]string{
+ osAndroid: {archArm, archArm64, archX86, archX86_64},
+ osLinux: {archX86, archX86_64},
+ osLinuxMusl: {archX86, archX86_64},
+ osDarwin: {archArm64, archX86_64},
+ osLinuxBionic: {archArm64, archX86_64},
+ // TODO(cparsons): According to arch.go, this should contain archArm, archArm64, as well.
+ osWindows: {archX86, archX86_64},
+ }
)
// basic configuration types
@@ -122,6 +137,10 @@
productVariables
)
+func osArchString(os string, arch string) string {
+ return fmt.Sprintf("%s_%s", os, arch)
+}
+
func (ct configurationType) String() string {
return map[configurationType]string{
noConfig: "no_config",
diff --git a/bazel/properties.go b/bazel/properties.go
index 76be058..1300a53 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -244,9 +244,69 @@
ConfigurableValues configurableLabels
}
+func (la *LabelAttribute) axisTypes() map[configurationType]bool {
+ types := map[configurationType]bool{}
+ for k := range la.ConfigurableValues {
+ if len(la.ConfigurableValues[k]) > 0 {
+ types[k.configurationType] = true
+ }
+ }
+ return types
+}
+
+// Collapse reduces the configurable axes of the label attribute to a single axis.
+// This is necessary for final writing to bp2build, as a configurable label
+// attribute can only be comprised by a single select.
+func (la *LabelAttribute) Collapse() error {
+ axisTypes := la.axisTypes()
+ _, containsOs := axisTypes[os]
+ _, containsArch := axisTypes[arch]
+ _, containsOsArch := axisTypes[osArch]
+ _, containsProductVariables := axisTypes[productVariables]
+ if containsProductVariables {
+ if containsOs || containsArch || containsOsArch {
+ return fmt.Errorf("label attribute could not be collapsed as it has two or more unrelated axes")
+ }
+ }
+ if (containsOs && containsArch) || (containsOsArch && (containsOs || containsArch)) {
+ // If a bool attribute has both os and arch configuration axes, the only
+ // way to successfully union their values is to increase the granularity
+ // of the configuration criteria to os_arch.
+ for osType, supportedArchs := range osToArchMap {
+ for _, supportedArch := range supportedArchs {
+ osArch := osArchString(osType, supportedArch)
+ if archOsVal := la.SelectValue(OsArchConfigurationAxis, osArch); archOsVal != nil {
+ // Do nothing, as the arch_os is explicitly defined already.
+ } else {
+ archVal := la.SelectValue(ArchConfigurationAxis, supportedArch)
+ osVal := la.SelectValue(OsConfigurationAxis, osType)
+ if osVal != nil && archVal != nil {
+ // In this case, arch takes precedence. (This fits legacy Soong behavior, as arch mutator
+ // runs after os mutator.
+ la.SetSelectValue(OsArchConfigurationAxis, osArch, *archVal)
+ } else if osVal != nil && archVal == nil {
+ la.SetSelectValue(OsArchConfigurationAxis, osArch, *osVal)
+ } else if osVal == nil && archVal != nil {
+ la.SetSelectValue(OsArchConfigurationAxis, osArch, *archVal)
+ }
+ }
+ }
+ }
+ // All os_arch values are now set. Clear os and arch axes.
+ delete(la.ConfigurableValues, ArchConfigurationAxis)
+ delete(la.ConfigurableValues, OsConfigurationAxis)
+ }
+ return nil
+}
+
// HasConfigurableValues returns whether there are configurable values set for this label.
func (la LabelAttribute) HasConfigurableValues() bool {
- return len(la.ConfigurableValues) > 0
+ for _, selectValues := range la.ConfigurableValues {
+ if len(selectValues) > 0 {
+ return true
+ }
+ }
+ return false
}
// SetValue sets the base, non-configured value for the Label
@@ -271,13 +331,13 @@
}
// SelectValue gets a value for a bazel select for the given axis and config.
-func (la *LabelAttribute) SelectValue(axis ConfigurationAxis, config string) Label {
+func (la *LabelAttribute) SelectValue(axis ConfigurationAxis, config string) *Label {
axis.validateConfig(config)
switch axis.configurationType {
case noConfig:
- return *la.Value
+ return la.Value
case arch, os, osArch, productVariables:
- return *la.ConfigurableValues[axis][config]
+ return la.ConfigurableValues[axis][config]
default:
panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
}
@@ -324,7 +384,12 @@
// HasConfigurableValues returns whether there are configurable values for this attribute.
func (ba BoolAttribute) HasConfigurableValues() bool {
- return len(ba.ConfigurableValues) > 0
+ for _, cfgToBools := range ba.ConfigurableValues {
+ if len(cfgToBools) > 0 {
+ return true
+ }
+ }
+ return false
}
// SetSelectValue sets value for the given axis/config.
@@ -343,6 +408,106 @@
}
}
+// ToLabelListAttribute creates and returns a LabelListAttribute from this
+// bool attribute, where each bool in this attribute corresponds to a
+// label list value in the resultant attribute.
+func (ba *BoolAttribute) ToLabelListAttribute(falseVal LabelList, trueVal LabelList) (LabelListAttribute, error) {
+ getLabelList := func(boolPtr *bool) LabelList {
+ if boolPtr == nil {
+ return LabelList{nil, nil}
+ } else if *boolPtr {
+ return trueVal
+ } else {
+ return falseVal
+ }
+ }
+
+ mainVal := getLabelList(ba.Value)
+ if !ba.HasConfigurableValues() {
+ return MakeLabelListAttribute(mainVal), nil
+ }
+
+ result := LabelListAttribute{}
+ if err := ba.Collapse(); err != nil {
+ return result, err
+ }
+
+ for axis, configToBools := range ba.ConfigurableValues {
+ if len(configToBools) < 1 {
+ continue
+ }
+ for config, boolPtr := range configToBools {
+ val := getLabelList(&boolPtr)
+ if !val.Equals(mainVal) {
+ result.SetSelectValue(axis, config, val)
+ }
+ }
+ result.SetSelectValue(axis, ConditionsDefaultConfigKey, mainVal)
+ }
+
+ return result, nil
+}
+
+// Collapse reduces the configurable axes of the boolean attribute to a single axis.
+// This is necessary for final writing to bp2build, as a configurable boolean
+// attribute can only be comprised by a single select.
+func (ba *BoolAttribute) Collapse() error {
+ axisTypes := ba.axisTypes()
+ _, containsOs := axisTypes[os]
+ _, containsArch := axisTypes[arch]
+ _, containsOsArch := axisTypes[osArch]
+ _, containsProductVariables := axisTypes[productVariables]
+ if containsProductVariables {
+ if containsOs || containsArch || containsOsArch {
+ return fmt.Errorf("boolean attribute could not be collapsed as it has two or more unrelated axes")
+ }
+ }
+ if (containsOs && containsArch) || (containsOsArch && (containsOs || containsArch)) {
+ // If a bool attribute has both os and arch configuration axes, the only
+ // way to successfully union their values is to increase the granularity
+ // of the configuration criteria to os_arch.
+ for osType, supportedArchs := range osToArchMap {
+ for _, supportedArch := range supportedArchs {
+ osArch := osArchString(osType, supportedArch)
+ if archOsVal := ba.SelectValue(OsArchConfigurationAxis, osArch); archOsVal != nil {
+ // Do nothing, as the arch_os is explicitly defined already.
+ } else {
+ archVal := ba.SelectValue(ArchConfigurationAxis, supportedArch)
+ osVal := ba.SelectValue(OsConfigurationAxis, osType)
+ if osVal != nil && archVal != nil {
+ // In this case, arch takes precedence. (This fits legacy Soong behavior, as arch mutator
+ // runs after os mutator.
+ ba.SetSelectValue(OsArchConfigurationAxis, osArch, archVal)
+ } else if osVal != nil && archVal == nil {
+ ba.SetSelectValue(OsArchConfigurationAxis, osArch, osVal)
+ } else if osVal == nil && archVal != nil {
+ ba.SetSelectValue(OsArchConfigurationAxis, osArch, archVal)
+ }
+ }
+ }
+ }
+ // All os_arch values are now set. Clear os and arch axes.
+ delete(ba.ConfigurableValues, ArchConfigurationAxis)
+ delete(ba.ConfigurableValues, OsConfigurationAxis)
+ // Verify post-condition; this should never fail, provided no additional
+ // axes are introduced.
+ if len(ba.ConfigurableValues) > 1 {
+ panic(fmt.Errorf("error in collapsing attribute: %#v", ba))
+ }
+ }
+ return nil
+}
+
+func (ba *BoolAttribute) axisTypes() map[configurationType]bool {
+ types := map[configurationType]bool{}
+ for k := range ba.ConfigurableValues {
+ if len(ba.ConfigurableValues[k]) > 0 {
+ types[k.configurationType] = true
+ }
+ }
+ return types
+}
+
// SelectValue gets the value for the given axis/config.
func (ba BoolAttribute) SelectValue(axis ConfigurationAxis, config string) *bool {
axis.validateConfig(config)
@@ -550,7 +715,12 @@
// HasConfigurableValues returns true if the attribute contains axis-specific label list values.
func (lla LabelListAttribute) HasConfigurableValues() bool {
- return len(lla.ConfigurableValues) > 0
+ for _, selectValues := range lla.ConfigurableValues {
+ if len(selectValues) > 0 {
+ return true
+ }
+ }
+ return false
}
// IsEmpty returns true if the attribute has no values under any configuration.
@@ -566,6 +736,24 @@
return true
}
+// IsNil returns true if the attribute has not been set for any configuration.
+func (lla LabelListAttribute) IsNil() bool {
+ if lla.Value.Includes != nil {
+ return false
+ }
+ return !lla.HasConfigurableValues()
+}
+
+// Exclude for the given axis, config, removes Includes in labelList from Includes and appends them
+// to Excludes. This is to special case any excludes that are not specified in a bp file but need to
+// be removed, e.g. if they could cause duplicate element failures.
+func (lla *LabelListAttribute) Exclude(axis ConfigurationAxis, config string, labelList LabelList) {
+ val := lla.SelectValue(axis, config)
+ newList := SubtractBazelLabelList(val, labelList)
+ newList.Excludes = append(newList.Excludes, labelList.Includes...)
+ lla.SetSelectValue(axis, config, newList)
+}
+
// ResolveExcludes handles excludes across the various axes, ensuring that items are removed from
// the base value and included in default values as appropriate.
func (lla *LabelListAttribute) ResolveExcludes() {
@@ -800,7 +988,12 @@
// HasConfigurableValues returns true if the attribute contains axis-specific string_list values.
func (sla StringListAttribute) HasConfigurableValues() bool {
- return len(sla.ConfigurableValues) > 0
+ for _, selectValues := range sla.ConfigurableValues {
+ if len(selectValues) > 0 {
+ return true
+ }
+ }
+ return false
}
// Append appends all values, including os and arch specific ones, from another
diff --git a/bp2build/apex_conversion_test.go b/bp2build/apex_conversion_test.go
index a3825e6..4b141c9 100644
--- a/bp2build/apex_conversion_test.go
+++ b/bp2build/apex_conversion_test.go
@@ -131,10 +131,21 @@
"key": `":com.android.apogee.key"`,
"manifest": `"apogee_manifest.json"`,
"min_sdk_version": `"29"`,
- "native_shared_libs": `[
+ "native_shared_libs_32": `[
":native_shared_lib_1",
":native_shared_lib_2",
]`,
+ "native_shared_libs_64": `select({
+ "//build/bazel/platforms/arch:arm64": [
+ ":native_shared_lib_1",
+ ":native_shared_lib_2",
+ ],
+ "//build/bazel/platforms/arch:x86_64": [
+ ":native_shared_lib_1",
+ ":native_shared_lib_2",
+ ],
+ "//conditions:default": [],
+ })`,
"prebuilts": `[
":pretend_prebuilt_1",
":pretend_prebuilt_2",
@@ -144,6 +155,126 @@
}})
}
+func TestApexBundleCompileMultilibBoth(t *testing.T) {
+ runApexTestCase(t, bp2buildTestCase{
+ description: "apex - example with compile_multilib=both",
+ moduleTypeUnderTest: "apex",
+ moduleTypeUnderTestFactory: apex.BundleFactory,
+ filesystem: map[string]string{},
+ blueprint: createMultilibBlueprint("both"),
+ expectedBazelTargets: []string{
+ makeBazelTarget("apex", "com.android.apogee", attrNameToString{
+ "native_shared_libs_32": `[
+ ":native_shared_lib_1",
+ ":native_shared_lib_3",
+ ] + select({
+ "//build/bazel/platforms/arch:arm": [":native_shared_lib_2"],
+ "//build/bazel/platforms/arch:x86": [":native_shared_lib_2"],
+ "//conditions:default": [],
+ })`,
+ "native_shared_libs_64": `select({
+ "//build/bazel/platforms/arch:arm64": [
+ ":native_shared_lib_1",
+ ":native_shared_lib_4",
+ ":native_shared_lib_2",
+ ],
+ "//build/bazel/platforms/arch:x86_64": [
+ ":native_shared_lib_1",
+ ":native_shared_lib_4",
+ ":native_shared_lib_2",
+ ],
+ "//conditions:default": [],
+ })`,
+ }),
+ }})
+}
+
+func TestApexBundleCompileMultilibFirst(t *testing.T) {
+ runApexTestCase(t, bp2buildTestCase{
+ description: "apex - example with compile_multilib=first",
+ moduleTypeUnderTest: "apex",
+ moduleTypeUnderTestFactory: apex.BundleFactory,
+ filesystem: map[string]string{},
+ blueprint: createMultilibBlueprint("first"),
+ expectedBazelTargets: []string{
+ makeBazelTarget("apex", "com.android.apogee", attrNameToString{
+ "native_shared_libs_32": `select({
+ "//build/bazel/platforms/arch:arm": [
+ ":native_shared_lib_1",
+ ":native_shared_lib_3",
+ ":native_shared_lib_2",
+ ],
+ "//build/bazel/platforms/arch:x86": [
+ ":native_shared_lib_1",
+ ":native_shared_lib_3",
+ ":native_shared_lib_2",
+ ],
+ "//conditions:default": [],
+ })`,
+ "native_shared_libs_64": `select({
+ "//build/bazel/platforms/arch:arm64": [
+ ":native_shared_lib_1",
+ ":native_shared_lib_4",
+ ":native_shared_lib_2",
+ ],
+ "//build/bazel/platforms/arch:x86_64": [
+ ":native_shared_lib_1",
+ ":native_shared_lib_4",
+ ":native_shared_lib_2",
+ ],
+ "//conditions:default": [],
+ })`,
+ }),
+ }})
+}
+
+func TestApexBundleCompileMultilib32(t *testing.T) {
+ runApexTestCase(t, bp2buildTestCase{
+ description: "apex - example with compile_multilib=32",
+ moduleTypeUnderTest: "apex",
+ moduleTypeUnderTestFactory: apex.BundleFactory,
+ filesystem: map[string]string{},
+ blueprint: createMultilibBlueprint("32"),
+ expectedBazelTargets: []string{
+ makeBazelTarget("apex", "com.android.apogee", attrNameToString{
+ "native_shared_libs_32": `[
+ ":native_shared_lib_1",
+ ":native_shared_lib_3",
+ ] + select({
+ "//build/bazel/platforms/arch:arm": [":native_shared_lib_2"],
+ "//build/bazel/platforms/arch:x86": [":native_shared_lib_2"],
+ "//conditions:default": [],
+ })`,
+ }),
+ }})
+}
+
+func TestApexBundleCompileMultilib64(t *testing.T) {
+ runApexTestCase(t, bp2buildTestCase{
+ description: "apex - example with compile_multilib=64",
+ moduleTypeUnderTest: "apex",
+ moduleTypeUnderTestFactory: apex.BundleFactory,
+ filesystem: map[string]string{},
+ blueprint: createMultilibBlueprint("64"),
+ expectedBazelTargets: []string{
+ makeBazelTarget("apex", "com.android.apogee", attrNameToString{
+ "native_shared_libs_64": `select({
+ "//build/bazel/platforms/arch:arm64": [
+ ":native_shared_lib_1",
+ ":native_shared_lib_4",
+ ":native_shared_lib_2",
+ ],
+ "//build/bazel/platforms/arch:x86_64": [
+ ":native_shared_lib_1",
+ ":native_shared_lib_4",
+ ":native_shared_lib_2",
+ ],
+ "//conditions:default": [],
+ })`,
+ }),
+ }})
+}
+
func TestApexBundleDefaultPropertyValues(t *testing.T) {
runApexTestCase(t, bp2buildTestCase{
description: "apex - default property values",
@@ -180,3 +311,53 @@
}),
}})
}
+
+func createMultilibBlueprint(compile_multilib string) string {
+ return `
+cc_library {
+ name: "native_shared_lib_1",
+ bazel_module: { bp2build_available: false },
+}
+
+cc_library {
+ name: "native_shared_lib_2",
+ bazel_module: { bp2build_available: false },
+}
+
+cc_library {
+ name: "native_shared_lib_3",
+ bazel_module: { bp2build_available: false },
+}
+
+cc_library {
+ name: "native_shared_lib_4",
+ bazel_module: { bp2build_available: false },
+}
+
+apex {
+ name: "com.android.apogee",
+ compile_multilib: "` + compile_multilib + `",
+ multilib: {
+ both: {
+ native_shared_libs: [
+ "native_shared_lib_1",
+ ],
+ },
+ first: {
+ native_shared_libs: [
+ "native_shared_lib_2",
+ ],
+ },
+ lib32: {
+ native_shared_libs: [
+ "native_shared_lib_3",
+ ],
+ },
+ lib64: {
+ native_shared_libs: [
+ "native_shared_lib_4",
+ ],
+ },
+ },
+}`
+}
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index 54b59af..5887d06 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -324,6 +324,15 @@
return
}
}
+ if unconvertedDeps := aModule.GetMissingBp2buildDeps(); len(unconvertedDeps) > 0 {
+ msg := fmt.Sprintf("%q depends on missing modules: %s", m.Name(), strings.Join(unconvertedDeps, ", "))
+ if ctx.unconvertedDepMode == warnUnconvertedDeps {
+ metrics.moduleWithMissingDepsMsgs = append(metrics.moduleWithMissingDepsMsgs, msg)
+ } else if ctx.unconvertedDepMode == errorModulesUnconvertedDeps {
+ errs = append(errs, fmt.Errorf(msg))
+ return
+ }
+ }
targets = generateBazelTargets(bpCtx, aModule)
for _, t := range targets {
// A module can potentially generate more than 1 Bazel
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index 1440b6f..b21a477 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -301,6 +301,19 @@
},
},
{
+ description: "non-existent dep",
+ blueprint: `custom {
+ name: "has_dep",
+ arch_paths: [":dep"],
+ bazel_module: { bp2build_available: true },
+}`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("custom", "has_dep", attrNameToString{
+ "arch_paths": `[":dep__BP2BUILD__MISSING__DEP"]`,
+ }),
+ },
+ },
+ {
description: "arch-variant srcs",
blueprint: `custom {
name: "arch_paths",
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index eaceea9..de4f437 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -1297,6 +1297,8 @@
"additional_linker_inputs": true,
"linkopts": true,
"strip": true,
+ "stubs_symbol_file": true,
+ "stubs_versions": true,
}
sharedAttrs := attrNameToString{}
staticAttrs := attrNameToString{}
@@ -1369,6 +1371,94 @@
})
}
+func TestCCLibraryNoLibCrtArchAndTargetVariant(t *testing.T) {
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ filesystem: map[string]string{
+ "impl.cpp": "",
+ },
+ blueprint: soongCcLibraryPreamble + `
+cc_library {
+ name: "foo-lib",
+ srcs: ["impl.cpp"],
+ arch: {
+ arm: {
+ no_libcrt: true,
+ },
+ x86: {
+ no_libcrt: true,
+ },
+ },
+ target: {
+ darwin: {
+ no_libcrt: true,
+ }
+ },
+ include_build_directory: false,
+}
+`,
+ expectedBazelTargets: makeCcLibraryTargets("foo-lib", attrNameToString{
+ "srcs": `["impl.cpp"]`,
+ "use_libcrt": `select({
+ "//build/bazel/platforms/os_arch:android_arm": False,
+ "//build/bazel/platforms/os_arch:android_x86": False,
+ "//build/bazel/platforms/os_arch:darwin_arm64": False,
+ "//build/bazel/platforms/os_arch:darwin_x86_64": False,
+ "//build/bazel/platforms/os_arch:linux_glibc_x86": False,
+ "//build/bazel/platforms/os_arch:linux_musl_x86": False,
+ "//build/bazel/platforms/os_arch:windows_x86": False,
+ "//conditions:default": None,
+ })`,
+ }),
+ })
+}
+
+func TestCCLibraryNoLibCrtArchAndTargetVariantConflict(t *testing.T) {
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ filesystem: map[string]string{
+ "impl.cpp": "",
+ },
+ blueprint: soongCcLibraryPreamble + `
+cc_library {
+ name: "foo-lib",
+ srcs: ["impl.cpp"],
+ arch: {
+ arm: {
+ no_libcrt: true,
+ },
+ // This is expected to override the value for darwin_x86_64.
+ x86_64: {
+ no_libcrt: true,
+ },
+ },
+ target: {
+ darwin: {
+ no_libcrt: false,
+ }
+ },
+ include_build_directory: false,
+}
+`,
+ expectedBazelTargets: makeCcLibraryTargets("foo-lib", attrNameToString{
+ "srcs": `["impl.cpp"]`,
+ "use_libcrt": `select({
+ "//build/bazel/platforms/os_arch:android_arm": False,
+ "//build/bazel/platforms/os_arch:android_x86_64": False,
+ "//build/bazel/platforms/os_arch:darwin_arm64": True,
+ "//build/bazel/platforms/os_arch:darwin_x86_64": False,
+ "//build/bazel/platforms/os_arch:linux_bionic_x86_64": False,
+ "//build/bazel/platforms/os_arch:linux_glibc_x86_64": False,
+ "//build/bazel/platforms/os_arch:linux_musl_x86_64": False,
+ "//build/bazel/platforms/os_arch:windows_x86_64": False,
+ "//conditions:default": None,
+ })`,
+ }),
+ })
+}
+
func TestCcLibraryStrip(t *testing.T) {
expectedTargets := []string{}
expectedTargets = append(expectedTargets, makeCcLibraryTargets("all", attrNameToString{
@@ -2159,3 +2249,175 @@
},
})
}
+
+func TestCcLibraryDisabledArchAndTarget(t *testing.T) {
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ blueprint: soongCcProtoPreamble + `cc_library {
+ name: "foo",
+ srcs: ["foo.cpp"],
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ windows: {
+ enabled: false,
+ },
+ linux_glibc_x86: {
+ enabled: false,
+ },
+ },
+ include_build_directory: false,
+}`,
+ expectedBazelTargets: makeCcLibraryTargets("foo", attrNameToString{
+ "srcs": `["foo.cpp"]`,
+ "target_compatible_with": `select({
+ "//build/bazel/platforms/os_arch:darwin_arm64": ["@platforms//:incompatible"],
+ "//build/bazel/platforms/os_arch:darwin_x86_64": ["@platforms//:incompatible"],
+ "//build/bazel/platforms/os_arch:linux_glibc_x86": ["@platforms//:incompatible"],
+ "//build/bazel/platforms/os_arch:windows_x86": ["@platforms//:incompatible"],
+ "//build/bazel/platforms/os_arch:windows_x86_64": ["@platforms//:incompatible"],
+ "//conditions:default": [],
+ })`,
+ }),
+ })
+}
+
+func TestCcLibraryDisabledArchAndTargetWithDefault(t *testing.T) {
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ blueprint: soongCcProtoPreamble + `cc_library {
+ name: "foo",
+ srcs: ["foo.cpp"],
+ enabled: false,
+ target: {
+ darwin: {
+ enabled: true,
+ },
+ windows: {
+ enabled: false,
+ },
+ linux_glibc_x86: {
+ enabled: false,
+ },
+ },
+ include_build_directory: false,
+}`,
+ expectedBazelTargets: makeCcLibraryTargets("foo", attrNameToString{
+ "srcs": `["foo.cpp"]`,
+ "target_compatible_with": `select({
+ "//build/bazel/platforms/os_arch:darwin_arm64": [],
+ "//build/bazel/platforms/os_arch:darwin_x86_64": [],
+ "//conditions:default": ["@platforms//:incompatible"],
+ })`,
+ }),
+ })
+}
+
+func TestCcLibrarySharedDisabled(t *testing.T) {
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ blueprint: soongCcProtoPreamble + `cc_library {
+ name: "foo",
+ srcs: ["foo.cpp"],
+ enabled: false,
+ shared: {
+ enabled: true,
+ },
+ target: {
+ android: {
+ shared: {
+ enabled: false,
+ },
+ }
+ },
+ include_build_directory: false,
+}`,
+ expectedBazelTargets: []string{makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", attrNameToString{
+ "srcs": `["foo.cpp"]`,
+ "target_compatible_with": `["@platforms//:incompatible"]`,
+ }), makeBazelTarget("cc_library_shared", "foo", attrNameToString{
+ "srcs": `["foo.cpp"]`,
+ "target_compatible_with": `select({
+ "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+ "//conditions:default": [],
+ })`,
+ }),
+ },
+ })
+}
+
+func TestCcLibraryStaticDisabledForSomeArch(t *testing.T) {
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ blueprint: soongCcProtoPreamble + `cc_library {
+ name: "foo",
+ srcs: ["foo.cpp"],
+ shared: {
+ enabled: false
+ },
+ target: {
+ darwin: {
+ enabled: true,
+ },
+ windows: {
+ enabled: false,
+ },
+ linux_glibc_x86: {
+ shared: {
+ enabled: true,
+ },
+ },
+ },
+ include_build_directory: false,
+}`,
+ expectedBazelTargets: []string{makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", attrNameToString{
+ "srcs": `["foo.cpp"]`,
+ "target_compatible_with": `select({
+ "//build/bazel/platforms/os:windows": ["@platforms//:incompatible"],
+ "//conditions:default": [],
+ })`,
+ }), makeBazelTarget("cc_library_shared", "foo", attrNameToString{
+ "srcs": `["foo.cpp"]`,
+ "target_compatible_with": `select({
+ "//build/bazel/platforms/os_arch:darwin_arm64": [],
+ "//build/bazel/platforms/os_arch:darwin_x86_64": [],
+ "//build/bazel/platforms/os_arch:linux_glibc_x86": [],
+ "//conditions:default": ["@platforms//:incompatible"],
+ })`,
+ }),
+ }})
+}
+
+func TestCcLibraryStubs(t *testing.T) {
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ description: "cc_library stubs",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ dir: "foo/bar",
+ filesystem: map[string]string{
+ "foo/bar/Android.bp": `
+cc_library {
+ name: "a",
+ stubs: { symbol_file: "a.map.txt", versions: ["28", "29", "current"] },
+ bazel_module: { bp2build_available: true },
+ include_build_directory: false,
+}
+`,
+ },
+ blueprint: soongCcLibraryPreamble,
+ expectedBazelTargets: makeCcLibraryTargets("a", attrNameToString{
+ "stubs_symbol_file": `"a.map.txt"`,
+ "stubs_versions": `[
+ "28",
+ "29",
+ "current",
+ ]`,
+ }),
+ },
+ )
+}
diff --git a/bp2build/cc_library_shared_conversion_test.go b/bp2build/cc_library_shared_conversion_test.go
index 97a600a..0f67653 100644
--- a/bp2build/cc_library_shared_conversion_test.go
+++ b/bp2build/cc_library_shared_conversion_test.go
@@ -464,3 +464,33 @@
},
})
}
+
+func TestCcLibrarySharedStubs(t *testing.T) {
+ runCcLibrarySharedTestCase(t, bp2buildTestCase{
+ description: "cc_library_shared stubs",
+ moduleTypeUnderTest: "cc_library_shared",
+ moduleTypeUnderTestFactory: cc.LibrarySharedFactory,
+ dir: "foo/bar",
+ filesystem: map[string]string{
+ "foo/bar/Android.bp": `
+cc_library_shared {
+ name: "a",
+ stubs: { symbol_file: "a.map.txt", versions: ["28", "29", "current"] },
+ bazel_module: { bp2build_available: true },
+ include_build_directory: false,
+}
+`,
+ },
+ blueprint: soongCcLibraryPreamble,
+ expectedBazelTargets: []string{makeBazelTarget("cc_library_shared", "a", attrNameToString{
+ "stubs_symbol_file": `"a.map.txt"`,
+ "stubs_versions": `[
+ "28",
+ "29",
+ "current",
+ ]`,
+ }),
+ },
+ },
+ )
+}
diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go
index e65a1fa..fac741c 100644
--- a/bp2build/cc_library_static_conversion_test.go
+++ b/bp2build/cc_library_static_conversion_test.go
@@ -65,7 +65,6 @@
t.Fatalf("Expected load statements to be %s, got %s", expected, actual)
}
}
-
}
func registerCcLibraryStaticModuleTypes(ctx android.RegistrationContext) {
@@ -1395,6 +1394,54 @@
})
}
+func TestCcLibrarystatic_SystemSharedLibUsedAsDep(t *testing.T) {
+ runCcLibraryStaticTestCase(t, bp2buildTestCase{
+ description: "cc_library_static system_shared_lib empty for linux_bionic variant",
+ blueprint: soongCcLibraryStaticPreamble +
+ simpleModuleDoNotConvertBp2build("cc_library", "libc") + `
+cc_library_static {
+ name: "used_in_bionic_oses",
+ target: {
+ android: {
+ shared_libs: ["libc"],
+ },
+ linux_bionic: {
+ shared_libs: ["libc"],
+ },
+ },
+ include_build_directory: false,
+}
+
+cc_library_static {
+ name: "all",
+ shared_libs: ["libc"],
+ include_build_directory: false,
+}
+
+cc_library_static {
+ name: "keep_for_empty_system_shared_libs",
+ shared_libs: ["libc"],
+ system_shared_libs: [],
+ include_build_directory: false,
+}
+`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "all", attrNameToString{
+ "implementation_dynamic_deps": `select({
+ "//build/bazel/platforms/os:android": [],
+ "//build/bazel/platforms/os:linux_bionic": [],
+ "//conditions:default": [":libc"],
+ })`,
+ }),
+ makeBazelTarget("cc_library_static", "keep_for_empty_system_shared_libs", attrNameToString{
+ "implementation_dynamic_deps": `[":libc"]`,
+ "system_dynamic_deps": `[]`,
+ }),
+ makeBazelTarget("cc_library_static", "used_in_bionic_oses", attrNameToString{}),
+ },
+ })
+}
+
func TestCcLibraryStaticProto(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
blueprint: soongCcProtoPreamble + `cc_library_static {
diff --git a/bp2build/configurability.go b/bp2build/configurability.go
index c953259..dfbb265 100644
--- a/bp2build/configurability.go
+++ b/bp2build/configurability.go
@@ -1,10 +1,11 @@
package bp2build
import (
- "android/soong/android"
- "android/soong/bazel"
"fmt"
"reflect"
+
+ "android/soong/android"
+ "android/soong/bazel"
)
// Configurability support for bp2build.
@@ -89,13 +90,15 @@
}
archSelects := map[string]reflect.Value{}
defaultVal := configToLabels[bazel.ConditionsDefaultConfigKey]
+ // Skip empty list values unless ether EmitEmptyList is true, or these values differ from the default.
+ emitEmptyList := list.EmitEmptyList || len(defaultVal.Includes) > 0
for config, labels := range configToLabels {
// Omit any entries in the map which match the default value, for brevity.
if config != bazel.ConditionsDefaultConfigKey && labels.Equals(defaultVal) {
continue
}
selectKey := axis.SelectKey(config)
- if use, value := labelListSelectValue(selectKey, labels, list.EmitEmptyList); use {
+ if use, value := labelListSelectValue(selectKey, labels, emitEmptyList); use {
archSelects[selectKey] = value
}
}
@@ -144,9 +147,15 @@
shouldPrintDefault = true
}
case bazel.LabelAttribute:
+ if err := list.Collapse(); err != nil {
+ return "", err
+ }
value, configurableAttrs = getLabelValue(list)
defaultSelectValue = &bazelNone
case bazel.BoolAttribute:
+ if err := list.Collapse(); err != nil {
+ return "", err
+ }
value, configurableAttrs = getBoolValue(list)
defaultSelectValue = &bazelNone
default:
@@ -204,11 +213,12 @@
continue
}
value := selectMap[selectKey]
- if isZero(value) && !emitZeroValues {
- // Ignore zero values to not generate empty lists.
+ if isZero(value) && !emitZeroValues && isZero(selectMap[bazel.ConditionsDefaultSelectKey]) {
+ // Ignore zero values to not generate empty lists. However, always note zero values if
+ // the default value is non-zero.
continue
}
- s, err := prettyPrintSelectEntry(value, selectKey, indent, emitZeroValues)
+ s, err := prettyPrintSelectEntry(value, selectKey, indent, true)
if err != nil {
return "", err
}
diff --git a/bp2build/conversion.go b/bp2build/conversion.go
index 81a4b26..96c12d3 100644
--- a/bp2build/conversion.go
+++ b/bp2build/conversion.go
@@ -1,6 +1,7 @@
package bp2build
import (
+ "encoding/json"
"fmt"
"reflect"
"strings"
@@ -27,6 +28,13 @@
files = append(files, newFile("product_config", "soong_config_variables.bzl", cfg.Bp2buildSoongConfigDefinitions.String()))
+ apiLevelsContent, err := json.Marshal(android.GetApiLevelsMap(cfg))
+ if err != nil {
+ panic(err)
+ }
+ files = append(files, newFile("api_levels", GeneratedBuildFileName, `exports_files(["api_levels.json"])`))
+ files = append(files, newFile("api_levels", "api_levels.json", string(apiLevelsContent)))
+
return files
}
diff --git a/bp2build/conversion_test.go b/bp2build/conversion_test.go
index 3e6d9e6..629ca9b 100644
--- a/bp2build/conversion_test.go
+++ b/bp2build/conversion_test.go
@@ -102,6 +102,14 @@
dir: "product_config",
basename: "soong_config_variables.bzl",
},
+ {
+ dir: "api_levels",
+ basename: GeneratedBuildFileName,
+ },
+ {
+ dir: "api_levels",
+ basename: "api_levels.json",
+ },
}
if len(files) != len(expectedFilePaths) {
diff --git a/bp2build/java_binary_host_conversion_test.go b/bp2build/java_binary_host_conversion_test.go
index 96b8958..c683b25 100644
--- a/bp2build/java_binary_host_conversion_test.go
+++ b/bp2build/java_binary_host_conversion_test.go
@@ -41,7 +41,7 @@
func TestJavaBinaryHost(t *testing.T) {
runJavaBinaryHostTestCase(t, bp2buildTestCase{
- description: "java_binary_host with srcs, exclude_srcs, jni_libs and manifest.",
+ description: "java_binary_host with srcs, exclude_srcs, jni_libs, javacflags, and manifest.",
filesystem: fs,
blueprint: `java_binary_host {
name: "java-binary-host-1",
@@ -49,6 +49,7 @@
exclude_srcs: ["b.java"],
manifest: "test.mf",
jni_libs: ["jni-lib-1"],
+ javacflags: ["-Xdoclint:all/protected"],
bazel_module: { bp2build_available: true },
}`,
expectedBazelTargets: []string{
@@ -57,6 +58,7 @@
"main_class": `"com.android.test.MainClass"`,
"deps": `["//other:jni-lib-1"]`,
"jvm_flags": `["-Djava.library.path=$${RUNPATH}other"]`,
+ "javacopts": `["-Xdoclint:all/protected"]`,
}),
},
})
diff --git a/bp2build/metrics.go b/bp2build/metrics.go
index 68ac544..557ea99 100644
--- a/bp2build/metrics.go
+++ b/bp2build/metrics.go
@@ -30,6 +30,10 @@
// NOTE: NOT in the .proto
moduleWithUnconvertedDepsMsgs []string
+ // List of modules with missing deps
+ // NOTE: NOT in the .proto
+ moduleWithMissingDepsMsgs []string
+
// List of converted modules
convertedModules []string
}
@@ -54,13 +58,21 @@
generatedTargetCount += count
}
fmt.Printf(
- "[bp2build] Converted %d Android.bp modules to %d total generated BUILD targets. Included %d handcrafted BUILD targets. There are %d total Android.bp modules.\n%d converted modules have unconverted deps: \n\t%s",
+ `[bp2build] Converted %d Android.bp modules to %d total generated BUILD targets. Included %d handcrafted BUILD targets. There are %d total Android.bp modules.
+%d converted modules have unconverted deps:
+ %s
+%d converted modules have missing deps:
+ %s
+`,
metrics.generatedModuleCount,
generatedTargetCount,
metrics.handCraftedModuleCount,
metrics.TotalModuleCount(),
len(metrics.moduleWithUnconvertedDepsMsgs),
- strings.Join(metrics.moduleWithUnconvertedDepsMsgs, "\n\t"))
+ strings.Join(metrics.moduleWithUnconvertedDepsMsgs, "\n\t"),
+ len(metrics.moduleWithMissingDepsMsgs),
+ strings.Join(metrics.moduleWithMissingDepsMsgs, "\n\t"),
+ )
}
const bp2buildMetricsFilename = "bp2build_metrics.pb"
diff --git a/bp2build/prebuilt_etc_conversion_test.go b/bp2build/prebuilt_etc_conversion_test.go
index 5065893..3a5d5bb 100644
--- a/bp2build/prebuilt_etc_conversion_test.go
+++ b/bp2build/prebuilt_etc_conversion_test.go
@@ -86,3 +86,45 @@
"sub_dir": `"tz"`,
})}})
}
+
+func TestPrebuiltEtcArchAndTargetVariant(t *testing.T) {
+ runPrebuiltEtcTestCase(t, bp2buildTestCase{
+ description: "prebuilt_etc - arch variant",
+ filesystem: map[string]string{},
+ blueprint: `
+prebuilt_etc {
+ name: "apex_tz_version",
+ src: "version/tz_version",
+ filename: "tz_version",
+ sub_dir: "tz",
+ installable: false,
+ arch: {
+ arm: {
+ src: "arm",
+ },
+ arm64: {
+ src: "darwin_or_arm64",
+ },
+ },
+ target: {
+ darwin: {
+ src: "darwin_or_arm64",
+ }
+ },
+}
+`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("prebuilt_etc", "apex_tz_version", attrNameToString{
+ "filename": `"tz_version"`,
+ "installable": `False`,
+ "src": `select({
+ "//build/bazel/platforms/os_arch:android_arm": "arm",
+ "//build/bazel/platforms/os_arch:android_arm64": "darwin_or_arm64",
+ "//build/bazel/platforms/os_arch:darwin_arm64": "darwin_or_arm64",
+ "//build/bazel/platforms/os_arch:darwin_x86_64": "darwin_or_arm64",
+ "//build/bazel/platforms/os_arch:linux_bionic_arm64": "darwin_or_arm64",
+ "//conditions:default": "version/tz_version",
+ })`,
+ "sub_dir": `"tz"`,
+ })}})
+}
diff --git a/bp2build/soong_config_module_type_conversion_test.go b/bp2build/soong_config_module_type_conversion_test.go
index f1489aa..b1e1fb2 100644
--- a/bp2build/soong_config_module_type_conversion_test.go
+++ b/bp2build/soong_config_module_type_conversion_test.go
@@ -68,7 +68,7 @@
expectedBazelTargets: []string{`cc_library_static(
name = "foo",
copts = select({
- "//build/bazel/product_variables:acme__feature1__enabled": ["-DFEATURE1"],
+ "//build/bazel/product_variables:acme__feature1": ["-DFEATURE1"],
"//conditions:default": ["-DDEFAULT1"],
}),
local_includes = ["."],
@@ -116,7 +116,7 @@
expectedBazelTargets: []string{`cc_library_static(
name = "foo",
copts = select({
- "//build/bazel/product_variables:acme__feature1__enabled": ["-DFEATURE1"],
+ "//build/bazel/product_variables:acme__feature1": ["-DFEATURE1"],
"//conditions:default": ["-DDEFAULT1"],
}),
local_includes = ["."],
@@ -240,10 +240,10 @@
"//build/bazel/product_variables:acme__board__soc_b": ["-DSOC_B"],
"//conditions:default": ["-DSOC_DEFAULT"],
}) + select({
- "//build/bazel/product_variables:acme__feature1__enabled": ["-DFEATURE1"],
+ "//build/bazel/product_variables:acme__feature1": ["-DFEATURE1"],
"//conditions:default": ["-DDEFAULT1"],
}) + select({
- "//build/bazel/product_variables:acme__feature2__enabled": ["-DFEATURE2"],
+ "//build/bazel/product_variables:acme__feature2": ["-DFEATURE2"],
"//conditions:default": ["-DDEFAULT2"],
}),
local_includes = ["."],
@@ -367,7 +367,7 @@
expectedBazelTargets: []string{`cc_library_static(
name = "lib",
copts = select({
- "//build/bazel/product_variables:vendor_foo__feature__enabled": [
+ "//build/bazel/product_variables:vendor_foo__feature": [
"-cflag_feature_2",
"-cflag_feature_1",
],
@@ -446,11 +446,11 @@
expectedBazelTargets: []string{`cc_library_static(
name = "lib",
asflags = select({
- "//build/bazel/product_variables:acme__feature__enabled": ["-asflag_bar"],
+ "//build/bazel/product_variables:acme__feature": ["-asflag_bar"],
"//conditions:default": ["-asflag_default_bar"],
}),
copts = select({
- "//build/bazel/product_variables:acme__feature__enabled": [
+ "//build/bazel/product_variables:acme__feature": [
"-cflag_foo",
"-cflag_bar",
],
@@ -465,11 +465,11 @@
`cc_library_static(
name = "lib2",
asflags = select({
- "//build/bazel/product_variables:acme__feature__enabled": ["-asflag_bar"],
+ "//build/bazel/product_variables:acme__feature": ["-asflag_bar"],
"//conditions:default": ["-asflag_default_bar"],
}),
copts = select({
- "//build/bazel/product_variables:acme__feature__enabled": [
+ "//build/bazel/product_variables:acme__feature": [
"-cflag_bar",
"-cflag_foo",
],
@@ -561,13 +561,13 @@
expectedBazelTargets: []string{`cc_library_static(
name = "lib",
copts = select({
- "//build/bazel/product_variables:vendor_bar__feature__enabled": ["-DVENDOR_BAR_FEATURE"],
+ "//build/bazel/product_variables:vendor_bar__feature": ["-DVENDOR_BAR_FEATURE"],
"//conditions:default": ["-DVENDOR_BAR_DEFAULT"],
}) + select({
- "//build/bazel/product_variables:vendor_foo__feature__enabled": ["-DVENDOR_FOO_FEATURE"],
+ "//build/bazel/product_variables:vendor_foo__feature": ["-DVENDOR_FOO_FEATURE"],
"//conditions:default": ["-DVENDOR_FOO_DEFAULT"],
}) + select({
- "//build/bazel/product_variables:vendor_qux__feature__enabled": ["-DVENDOR_QUX_FEATURE"],
+ "//build/bazel/product_variables:vendor_qux__feature": ["-DVENDOR_QUX_FEATURE"],
"//conditions:default": ["-DVENDOR_QUX_DEFAULT"],
}),
local_includes = ["."],
@@ -834,3 +834,152 @@
srcs = ["main.cc"],
)`}})
}
+
+func TestSoongConfigModuleType_ProductVariableConfigWithPlatformConfig(t *testing.T) {
+ bp := `
+soong_config_bool_variable {
+ name: "special_build",
+}
+
+soong_config_module_type {
+ name: "alphabet_cc_defaults",
+ module_type: "cc_defaults",
+ config_namespace: "alphabet_module",
+ bool_variables: ["special_build"],
+ properties: ["enabled"],
+}
+
+alphabet_cc_defaults {
+ name: "alphabet_sample_cc_defaults",
+ soong_config_variables: {
+ special_build: {
+ enabled: true,
+ },
+ },
+}
+
+cc_binary {
+ name: "alphabet_binary",
+ srcs: ["main.cc"],
+ defaults: ["alphabet_sample_cc_defaults"],
+ enabled: false,
+ arch: {
+ x86_64: {
+ enabled: false,
+ },
+ },
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+}`
+
+ runSoongConfigModuleTypeTest(t, bp2buildTestCase{
+ description: "soong config variables - generates selects for library_linking_strategy",
+ moduleTypeUnderTest: "cc_binary",
+ moduleTypeUnderTestFactory: cc.BinaryFactory,
+ blueprint: bp,
+ filesystem: map[string]string{},
+ expectedBazelTargets: []string{`cc_binary(
+ name = "alphabet_binary",
+ local_includes = ["."],
+ srcs = ["main.cc"],
+ target_compatible_with = ["//build/bazel/product_variables:alphabet_module__special_build"] + select({
+ "//build/bazel/platforms/os_arch:android_x86_64": ["@platforms//:incompatible"],
+ "//build/bazel/platforms/os_arch:darwin_arm64": ["@platforms//:incompatible"],
+ "//build/bazel/platforms/os_arch:darwin_x86_64": ["@platforms//:incompatible"],
+ "//build/bazel/platforms/os_arch:linux_bionic_x86_64": ["@platforms//:incompatible"],
+ "//build/bazel/platforms/os_arch:linux_glibc_x86_64": ["@platforms//:incompatible"],
+ "//build/bazel/platforms/os_arch:linux_musl_x86_64": ["@platforms//:incompatible"],
+ "//build/bazel/platforms/os_arch:windows_x86_64": ["@platforms//:incompatible"],
+ "//conditions:default": [],
+ }),
+)`}})
+}
+
+func TestSoongConfigModuleType_ProductVariableConfigOverridesEnable(t *testing.T) {
+ bp := `
+soong_config_bool_variable {
+ name: "special_build",
+}
+
+soong_config_module_type {
+ name: "alphabet_cc_defaults",
+ module_type: "cc_defaults",
+ config_namespace: "alphabet_module",
+ bool_variables: ["special_build"],
+ properties: ["enabled"],
+}
+
+alphabet_cc_defaults {
+ name: "alphabet_sample_cc_defaults",
+ soong_config_variables: {
+ special_build: {
+ enabled: true,
+ },
+ },
+}
+
+cc_binary {
+ name: "alphabet_binary",
+ srcs: ["main.cc"],
+ defaults: ["alphabet_sample_cc_defaults"],
+ enabled: false,
+}`
+
+ runSoongConfigModuleTypeTest(t, bp2buildTestCase{
+ description: "soong config variables - generates selects for library_linking_strategy",
+ moduleTypeUnderTest: "cc_binary",
+ moduleTypeUnderTestFactory: cc.BinaryFactory,
+ blueprint: bp,
+ filesystem: map[string]string{},
+ expectedBazelTargets: []string{`cc_binary(
+ name = "alphabet_binary",
+ local_includes = ["."],
+ srcs = ["main.cc"],
+ target_compatible_with = ["//build/bazel/product_variables:alphabet_module__special_build"],
+)`}})
+}
+
+func TestSoongConfigModuleType_ProductVariableIgnoredIfEnabledByDefault(t *testing.T) {
+ bp := `
+soong_config_bool_variable {
+ name: "special_build",
+}
+
+soong_config_module_type {
+ name: "alphabet_cc_defaults",
+ module_type: "cc_defaults",
+ config_namespace: "alphabet_module",
+ bool_variables: ["special_build"],
+ properties: ["enabled"],
+}
+
+alphabet_cc_defaults {
+ name: "alphabet_sample_cc_defaults",
+ soong_config_variables: {
+ special_build: {
+ enabled: true,
+ },
+ },
+}
+
+cc_binary {
+ name: "alphabet_binary",
+ srcs: ["main.cc"],
+ defaults: ["alphabet_sample_cc_defaults"],
+}`
+
+ runSoongConfigModuleTypeTest(t, bp2buildTestCase{
+ description: "soong config variables - generates selects for library_linking_strategy",
+ moduleTypeUnderTest: "cc_binary",
+ moduleTypeUnderTestFactory: cc.BinaryFactory,
+ blueprint: bp,
+ filesystem: map[string]string{},
+ expectedBazelTargets: []string{`cc_binary(
+ name = "alphabet_binary",
+ local_includes = ["."],
+ srcs = ["main.cc"],
+)`}})
+}
diff --git a/bp2build/testing.go b/bp2build/testing.go
index 8ae1a38..53b60fa 100644
--- a/bp2build/testing.go
+++ b/bp2build/testing.go
@@ -43,7 +43,7 @@
if len(errs) != 1 {
return false
}
- if errs[0].Error() == expectedErr.Error() {
+ if strings.Contains(errs[0].Error(), expectedErr.Error()) {
return true
}
@@ -127,8 +127,12 @@
codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
codegenCtx.unconvertedDepMode = tc.unconvertedDepsMode
bazelTargets, errs := generateBazelTargetsForDir(codegenCtx, checkDir)
- if tc.expectedErr != nil && checkError(t, errs, tc.expectedErr) {
- return
+ if tc.expectedErr != nil {
+ if checkError(t, errs, tc.expectedErr) {
+ return
+ } else {
+ t.Errorf("Expected error: %q, got: %q", tc.expectedErr, errs)
+ }
} else {
android.FailIfErrored(t, errs)
}
diff --git a/bpf/bpf.go b/bpf/bpf.go
index fa1a84d..187b4db 100644
--- a/bpf/bpf.go
+++ b/bpf/bpf.go
@@ -54,12 +54,16 @@
android.Module
OutputFiles(tag string) (android.Paths, error)
+
+ // Returns the sub install directory if the bpf module is included by apex.
+ SubDir() string
}
type BpfProperties struct {
Srcs []string `android:"path"`
Cflags []string
Include_dirs []string
+ Sub_dir string
}
type bpf struct {
@@ -83,9 +87,9 @@
// The architecture doesn't matter here, but asm/types.h is included by linux/types.h.
"-isystem bionic/libc/kernel/uapi/asm-arm64",
"-isystem bionic/libc/kernel/android/uapi",
+ "-I frameworks/libs/net/common/native/bpf_headers/include/bpf",
// TODO(b/149785767): only give access to specific file with AID_* constants
"-I system/core/libcutils/include",
- "-I system/bpf/progs/include",
"-I " + ctx.ModuleDir(),
}
@@ -121,6 +125,10 @@
fmt.Fprintln(w)
fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
fmt.Fprintln(w)
+ localModulePath := "LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/bpf"
+ if len(bpf.properties.Sub_dir) > 0 {
+ localModulePath += "/" + bpf.properties.Sub_dir
+ }
for _, obj := range bpf.objs {
objName := name + "_" + obj.Base()
names = append(names, objName)
@@ -130,7 +138,7 @@
fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", obj.String())
fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", obj.Base())
fmt.Fprintln(w, "LOCAL_MODULE_CLASS := ETC")
- fmt.Fprintln(w, "LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/bpf")
+ fmt.Fprintln(w, localModulePath)
fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
fmt.Fprintln(w)
}
@@ -154,6 +162,10 @@
}
}
+func (bpf *bpf) SubDir() string {
+ return bpf.properties.Sub_dir
+}
+
var _ android.OutputFileProducer = (*bpf)(nil)
func BpfFactory() android.Module {
diff --git a/bpfix/bpfix/bpfix.go b/bpfix/bpfix/bpfix.go
index c0925fe..b683472 100644
--- a/bpfix/bpfix/bpfix.go
+++ b/bpfix/bpfix/bpfix.go
@@ -641,7 +641,7 @@
// 'srcs' --> 'src' conversion
convertToSingleSource(mod, "src")
- renameProperty(mod, "sub_dir", "relative_install_dir")
+ renameProperty(mod, "sub_dir", "relative_install_path")
// The rewriter converts LOCAL_MODULE_PATH attribute into a struct attribute
// 'local_module_path'. Analyze its contents and create the correct sub_dir:,
@@ -1484,7 +1484,7 @@
ok := hasFile(relativePath+"/Android.mk", fs)
// some modules in the existing test cases in the androidmk_test.go do not have a valid path
if !ok && len(relativePath) > 0 {
- return fmt.Errorf("Cannot find an Android.mk file at path %s", relativePath)
+ return fmt.Errorf("Cannot find an Android.mk file at path %q", relativePath)
}
licenseKindsPropertyName := "android_license_kinds"
@@ -1661,9 +1661,12 @@
// if empty
return "", fmt.Errorf("Cannot find the value of the %s.%s property", mod.Type, property)
}
+ if relativePath == "" {
+ relativePath = "."
+ }
_, isDir, _ := fs.Exists(relativePath)
if !isDir {
- return "", fmt.Errorf("Cannot find the path %s", relativePath)
+ return "", fmt.Errorf("Cannot find the path %q", relativePath)
}
path := relativePath
for {
@@ -1675,7 +1678,7 @@
}
_, isDir, _ = fs.Exists(path)
if !isDir {
- return "", fmt.Errorf("Cannot find the path %s", path)
+ return "", fmt.Errorf("Cannot find the path %q", path)
}
return path, nil
}
diff --git a/bpfix/bpfix/bpfix_test.go b/bpfix/bpfix/bpfix_test.go
index 221df45..69f5967 100644
--- a/bpfix/bpfix/bpfix_test.go
+++ b/bpfix/bpfix/bpfix_test.go
@@ -824,7 +824,7 @@
out: `prebuilt_etc {
name: "foo",
src: "bar",
- relative_install_dir: "baz",
+ relative_install_path: "baz",
}
`,
},
@@ -1936,7 +1936,7 @@
fs: mockFs,
path: relativePathErr,
expectedErr: `
- Cannot find an Android.mk file at path a/b/c
+ Cannot find an Android.mk file at path "a/b/c"
`,
},
}
diff --git a/cc/Android.bp b/cc/Android.bp
index 07aa7cb..0bf0045 100644
--- a/cc/Android.bp
+++ b/cc/Android.bp
@@ -19,10 +19,11 @@
"soong-tradefed",
],
srcs: [
+ "afdo.go",
"androidmk.go",
"api_level.go",
- "builder.go",
"bp2build.go",
+ "builder.go",
"cc.go",
"ccdeps.go",
"check.go",
diff --git a/cc/afdo.go b/cc/afdo.go
new file mode 100644
index 0000000..022f283
--- /dev/null
+++ b/cc/afdo.go
@@ -0,0 +1,194 @@
+// Copyright 2021 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cc
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/google/blueprint/proptools"
+
+ "android/soong/android"
+)
+
+var (
+ globalAfdoProfileProjects = []string{
+ "vendor/google_data/pgo_profile/sampling/",
+ "toolchain/pgo-profiles/sampling/",
+ }
+)
+
+var afdoProfileProjectsConfigKey = android.NewOnceKey("AfdoProfileProjects")
+
+const afdoCFlagsFormat = "-fprofile-sample-accurate -fprofile-sample-use=%s"
+
+func getAfdoProfileProjects(config android.DeviceConfig) []string {
+ return config.OnceStringSlice(afdoProfileProjectsConfigKey, func() []string {
+ return append(globalAfdoProfileProjects, config.AfdoAdditionalProfileDirs()...)
+ })
+}
+
+func recordMissingAfdoProfileFile(ctx BaseModuleContext, missing string) {
+ getNamedMapForConfig(ctx.Config(), modulesMissingProfileFileKey).Store(missing, true)
+}
+
+type AfdoProperties struct {
+ Afdo bool
+
+ AfdoTarget *string `blueprint:"mutated"`
+ AfdoDeps []string `blueprint:"mutated"`
+}
+
+type afdo struct {
+ Properties AfdoProperties
+}
+
+func (afdo *afdo) props() []interface{} {
+ return []interface{}{&afdo.Properties}
+}
+
+func (afdo *afdo) AfdoEnabled() bool {
+ return afdo != nil && afdo.Properties.Afdo && afdo.Properties.AfdoTarget != nil
+}
+
+// Get list of profile file names, ordered by level of specialisation. For example:
+// 1. libfoo_arm64.afdo
+// 2. libfoo.afdo
+// Add more specialisation as needed.
+func getProfileFiles(ctx BaseModuleContext, moduleName string) []string {
+ var files []string
+ files = append(files, moduleName+"_"+ctx.Arch().ArchType.String()+".afdo")
+ files = append(files, moduleName+".afdo")
+ return files
+}
+
+func (props *AfdoProperties) getAfdoProfileFile(ctx BaseModuleContext, module string) android.OptionalPath {
+ // Test if the profile_file is present in any of the Afdo profile projects
+ for _, profileFile := range getProfileFiles(ctx, module) {
+ for _, profileProject := range getAfdoProfileProjects(ctx.DeviceConfig()) {
+ path := android.ExistentPathForSource(ctx, profileProject, profileFile)
+ if path.Valid() {
+ return path
+ }
+ }
+ }
+
+ // Record that this module's profile file is absent
+ missing := ctx.ModuleDir() + ":" + module
+ recordMissingAfdoProfileFile(ctx, missing)
+
+ return android.OptionalPathForPath(nil)
+}
+
+func (afdo *afdo) begin(ctx BaseModuleContext) {
+ if afdo.Properties.Afdo && !ctx.static() && !ctx.Host() {
+ module := ctx.ModuleName()
+ if afdo.Properties.getAfdoProfileFile(ctx, module).Valid() {
+ afdo.Properties.AfdoTarget = proptools.StringPtr(module)
+ }
+ }
+}
+
+func (afdo *afdo) flags(ctx ModuleContext, flags Flags) Flags {
+ if profile := afdo.Properties.AfdoTarget; profile != nil {
+ if profileFile := afdo.Properties.getAfdoProfileFile(ctx, *profile); profileFile.Valid() {
+ profileFilePath := profileFile.Path()
+
+ profileUseFlag := fmt.Sprintf(afdoCFlagsFormat, profileFile)
+ flags.Local.CFlags = append(flags.Local.CFlags, profileUseFlag)
+ flags.Local.LdFlags = append(flags.Local.LdFlags, profileUseFlag)
+ flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-mllvm,-no-warn-sample-unused=true")
+
+ // Update CFlagsDeps and LdFlagsDeps so the module is rebuilt
+ // if profileFile gets updated
+ flags.CFlagsDeps = append(flags.CFlagsDeps, profileFilePath)
+ flags.LdFlagsDeps = append(flags.LdFlagsDeps, profileFilePath)
+ }
+ }
+
+ return flags
+}
+
+// Propagate afdo requirements down from binaries
+func afdoDepsMutator(mctx android.TopDownMutatorContext) {
+ if m, ok := mctx.Module().(*Module); ok && m.afdo.AfdoEnabled() {
+ afdoTarget := *m.afdo.Properties.AfdoTarget
+ mctx.WalkDeps(func(dep android.Module, parent android.Module) bool {
+ tag := mctx.OtherModuleDependencyTag(dep)
+ libTag, isLibTag := tag.(libraryDependencyTag)
+
+ // Do not recurse down non-static dependencies
+ if isLibTag {
+ if !libTag.static() {
+ return false
+ }
+ } else {
+ if tag != objDepTag && tag != reuseObjTag {
+ return false
+ }
+ }
+
+ if dep, ok := dep.(*Module); ok {
+ dep.afdo.Properties.AfdoDeps = append(dep.afdo.Properties.AfdoDeps, afdoTarget)
+ }
+
+ return true
+ })
+ }
+}
+
+// Create afdo variants for modules that need them
+func afdoMutator(mctx android.BottomUpMutatorContext) {
+ if m, ok := mctx.Module().(*Module); ok && m.afdo != nil {
+ if m.afdo.AfdoEnabled() && !m.static() {
+ afdoTarget := *m.afdo.Properties.AfdoTarget
+ mctx.SetDependencyVariation(encodeTarget(afdoTarget))
+ }
+
+ variationNames := []string{""}
+ afdoDeps := android.FirstUniqueStrings(m.afdo.Properties.AfdoDeps)
+ for _, dep := range afdoDeps {
+ variationNames = append(variationNames, encodeTarget(dep))
+ }
+ if len(variationNames) > 1 {
+ modules := mctx.CreateVariations(variationNames...)
+ for i, name := range variationNames {
+ if name == "" {
+ continue
+ }
+ variation := modules[i].(*Module)
+ variation.Properties.PreventInstall = true
+ variation.Properties.HideFromMake = true
+ variation.afdo.Properties.AfdoTarget = proptools.StringPtr(decodeTarget(name))
+ }
+ }
+ }
+}
+
+// Encode target name to variation name.
+func encodeTarget(target string) string {
+ if target == "" {
+ return ""
+ }
+ return "afdo-" + target
+}
+
+// Decode target name from variation name.
+func decodeTarget(variation string) string {
+ if variation == "" {
+ return ""
+ }
+ return strings.TrimPrefix(variation, "afdo-")
+}
diff --git a/cc/binary.go b/cc/binary.go
index 50175d9..ee3de3f 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -427,7 +427,7 @@
linkerDeps = append(linkerDeps, ndkSharedLibDeps(ctx)...)
}
- validations = append(validations, objs.tidyFiles...)
+ validations = append(validations, objs.tidyDepFiles...)
linkerDeps = append(linkerDeps, flags.LdFlagsDeps...)
// Register link action.
@@ -558,13 +558,6 @@
}
func binaryBp2build(ctx android.TopDownMutatorContext, m *Module, typ string) {
- var compatibleWith bazel.StringListAttribute
- if typ == "cc_binary_host" {
- //incompatible with android OS
- compatibleWith.SetSelectValue(bazel.OsConfigurationAxis, android.Android.Name, []string{"@platforms//:incompatible"})
- compatibleWith.SetSelectValue(bazel.OsConfigurationAxis, bazel.ConditionsDefaultConfigKey, []string{})
- }
-
baseAttrs := bp2BuildParseBaseProps(ctx, m)
binaryLinkerAttrs := bp2buildBinaryLinkerProps(ctx, m)
@@ -610,16 +603,22 @@
None: baseAttrs.stripNone,
},
- Target_compatible_with: compatibleWith,
- Features: baseAttrs.features,
+ Features: baseAttrs.features,
}
- ctx.CreateBazelTargetModule(bazel.BazelTargetModuleProperties{
+ var enabledProperty bazel.BoolAttribute
+ if typ == "cc_binary_host" {
+ falseVal := false
+ enabledProperty.SetSelectValue(bazel.OsConfigurationAxis, android.Android.Name, &falseVal)
+ }
+
+ ctx.CreateBazelTargetModuleWithRestrictions(bazel.BazelTargetModuleProperties{
Rule_class: "cc_binary",
Bzl_load_location: "//build/bazel/rules:cc_binary.bzl",
},
android.CommonAttributes{Name: m.Name()},
- attrs)
+ attrs,
+ enabledProperty)
}
// binaryAttributes contains Bazel attributes corresponding to a cc binary
@@ -655,6 +654,4 @@
Strip stripAttributes
Features bazel.StringListAttribute
-
- Target_compatible_with bazel.StringListAttribute
}
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 2119ee4..c5eab06 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -57,6 +57,8 @@
Implementation_whole_archive_deps bazel.LabelListAttribute
System_dynamic_deps bazel.LabelListAttribute
+
+ Enabled bazel.BoolAttribute
}
func groupSrcsByExtension(ctx android.BazelConversionPathContext, srcs bazel.LabelListAttribute) bazel.PartitionToLabelListAttribute {
@@ -175,6 +177,7 @@
attrs.Implementation_dynamic_deps.SetSelectValue(axis, config, sharedDeps.implementation)
attrs.Whole_archive_deps.SetSelectValue(axis, config, bazelLabelForWholeDeps(ctx, props.Whole_static_libs))
+ attrs.Enabled.SetSelectValue(axis, config, props.Enabled)
}
// system_dynamic_deps distinguishes between nil/empty list behavior:
// nil -> use default values
@@ -277,6 +280,9 @@
includes BazelIncludes
protoSrcs bazel.LabelListAttribute
+
+ stubsSymbolFile *string
+ stubsVersions bazel.StringListAttribute
}
type filterOutFn func(string) bool
@@ -461,10 +467,11 @@
return relative, absolute
}
-// bp2BuildParseCompilerProps returns copts, srcs and hdrs and other attributes.
+// bp2BuildParseBaseProps returns all compiler, linker, library attributes of a cc module..
func bp2BuildParseBaseProps(ctx android.Bp2buildMutatorContext, module *Module) baseAttributes {
archVariantCompilerProps := module.GetArchVariantProperties(ctx, &BaseCompilerProperties{})
archVariantLinkerProps := module.GetArchVariantProperties(ctx, &BaseLinkerProperties{})
+ archVariantLibraryProperties := module.GetArchVariantProperties(ctx, &LibraryProperties{})
var implementationHdrs bazel.LabelListAttribute
@@ -481,6 +488,7 @@
}
allAxesAndConfigs(archVariantCompilerProps)
allAxesAndConfigs(archVariantLinkerProps)
+ allAxesAndConfigs(archVariantLibraryProperties)
compilerAttrs := compilerAttributes{}
linkerAttrs := linkerAttributes{}
@@ -516,6 +524,13 @@
currIncludes := compilerAttrs.localIncludes.SelectValue(axis, config)
currIncludes = android.FirstUniqueStrings(append(currIncludes, includes...))
compilerAttrs.localIncludes.SetSelectValue(axis, config, currIncludes)
+
+ if libraryProps, ok := archVariantLibraryProperties[axis][config].(*LibraryProperties); ok {
+ if axis == bazel.NoConfigAxis {
+ compilerAttrs.stubsSymbolFile = libraryProps.Stubs.Symbol_file
+ compilerAttrs.stubsVersions.SetSelectValue(axis, config, libraryProps.Stubs.Versions)
+ }
+ }
}
}
@@ -528,7 +543,7 @@
(&linkerAttrs).convertProductVariables(ctx, productVariableProps)
(&compilerAttrs).finalize(ctx, implementationHdrs)
- (&linkerAttrs).finalize()
+ (&linkerAttrs).finalize(ctx)
protoDep := bp2buildProto(ctx, module, compilerAttrs.protoSrcs)
@@ -547,13 +562,14 @@
// Convenience struct to hold all attributes parsed from linker properties.
type linkerAttributes struct {
- deps bazel.LabelListAttribute
- implementationDeps bazel.LabelListAttribute
- dynamicDeps bazel.LabelListAttribute
- implementationDynamicDeps bazel.LabelListAttribute
- wholeArchiveDeps bazel.LabelListAttribute
- implementationWholeArchiveDeps bazel.LabelListAttribute
- systemDynamicDeps bazel.LabelListAttribute
+ deps bazel.LabelListAttribute
+ implementationDeps bazel.LabelListAttribute
+ dynamicDeps bazel.LabelListAttribute
+ implementationDynamicDeps bazel.LabelListAttribute
+ wholeArchiveDeps bazel.LabelListAttribute
+ implementationWholeArchiveDeps bazel.LabelListAttribute
+ systemDynamicDeps bazel.LabelListAttribute
+ usedSystemDynamicDepAsDynamicDep map[string]bool
linkCrt bazel.BoolAttribute
useLibcrt bazel.BoolAttribute
@@ -568,6 +584,10 @@
features bazel.StringListAttribute
}
+var (
+ soongSystemSharedLibs = []string{"libc", "libm", "libdl"}
+)
+
func (la *linkerAttributes) bp2buildForAxisAndConfig(ctx android.BazelConversionPathContext, isBinary bool, axis bazel.ConfigurationAxis, config string, props *BaseLinkerProperties) {
// Use a single variable to capture usage of nocrt in arch variants, so there's only 1 error message for this module
var axisFeatures []string
@@ -599,6 +619,17 @@
la.systemDynamicDeps.SetSelectValue(axis, config, bazelLabelForSharedDeps(ctx, systemSharedLibs))
sharedLibs := android.FirstUniqueStrings(props.Shared_libs)
+ excludeSharedLibs := props.Exclude_shared_libs
+ usedSystem := android.FilterListPred(sharedLibs, func(s string) bool {
+ return android.InList(s, soongSystemSharedLibs) && !android.InList(s, excludeSharedLibs)
+ })
+ for _, el := range usedSystem {
+ if la.usedSystemDynamicDepAsDynamicDep == nil {
+ la.usedSystemDynamicDepAsDynamicDep = map[string]bool{}
+ }
+ la.usedSystemDynamicDepAsDynamicDep[el] = true
+ }
+
sharedDeps := maybePartitionExportedAndImplementationsDepsExcludes(ctx, !isBinary, sharedLibs, props.Exclude_shared_libs, props.Export_shared_lib_headers, bazelLabelForSharedDepsExcludes)
la.dynamicDeps.SetSelectValue(axis, config, sharedDeps.export)
la.implementationDynamicDeps.SetSelectValue(axis, config, sharedDeps.implementation)
@@ -718,13 +749,25 @@
}
}
-func (la *linkerAttributes) finalize() {
+func (la *linkerAttributes) finalize(ctx android.BazelConversionPathContext) {
+ // if system dynamic deps have the default value, any use of a system dynamic library used will
+ // result in duplicate library errors for bionic OSes. Here, we explicitly exclude those libraries
+ // from bionic OSes.
+ if la.systemDynamicDeps.IsNil() && len(la.usedSystemDynamicDepAsDynamicDep) > 0 {
+ toRemove := bazelLabelForSharedDeps(ctx, android.SortedStringKeys(la.usedSystemDynamicDepAsDynamicDep))
+ la.dynamicDeps.Exclude(bazel.OsConfigurationAxis, "android", toRemove)
+ la.dynamicDeps.Exclude(bazel.OsConfigurationAxis, "linux_bionic", toRemove)
+ la.implementationDynamicDeps.Exclude(bazel.OsConfigurationAxis, "android", toRemove)
+ la.implementationDynamicDeps.Exclude(bazel.OsConfigurationAxis, "linux_bionic", toRemove)
+ }
+
la.deps.ResolveExcludes()
la.implementationDeps.ResolveExcludes()
la.dynamicDeps.ResolveExcludes()
la.implementationDynamicDeps.ResolveExcludes()
la.wholeArchiveDeps.ResolveExcludes()
la.systemDynamicDeps.ForceSpecifyEmptyList = true
+
}
// Relativize a list of root-relative paths with respect to the module's
diff --git a/cc/builder.go b/cc/builder.go
index fa7f7a3..512f838 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -387,10 +387,11 @@
toolchain config.Toolchain
// True if these extra features are enabled.
- tidy bool
- gcovCoverage bool
- sAbiDump bool
- emitXrefs bool
+ tidy bool
+ needTidyFiles bool
+ gcovCoverage bool
+ sAbiDump bool
+ emitXrefs bool
assemblerWithCpp bool // True if .s files should be processed with the c preprocessor.
@@ -420,6 +421,7 @@
type Objects struct {
objFiles android.Paths
tidyFiles android.Paths
+ tidyDepFiles android.Paths // link dependent .tidy files
coverageFiles android.Paths
sAbiDumpFiles android.Paths
kytheFiles android.Paths
@@ -429,6 +431,7 @@
return Objects{
objFiles: append(android.Paths{}, a.objFiles...),
tidyFiles: append(android.Paths{}, a.tidyFiles...),
+ tidyDepFiles: append(android.Paths{}, a.tidyDepFiles...),
coverageFiles: append(android.Paths{}, a.coverageFiles...),
sAbiDumpFiles: append(android.Paths{}, a.sAbiDumpFiles...),
kytheFiles: append(android.Paths{}, a.kytheFiles...),
@@ -439,6 +442,7 @@
return Objects{
objFiles: append(a.objFiles, b.objFiles...),
tidyFiles: append(a.tidyFiles, b.tidyFiles...),
+ tidyDepFiles: append(a.tidyDepFiles, b.tidyDepFiles...),
coverageFiles: append(a.coverageFiles, b.coverageFiles...),
sAbiDumpFiles: append(a.sAbiDumpFiles, b.sAbiDumpFiles...),
kytheFiles: append(a.kytheFiles, b.kytheFiles...),
@@ -452,9 +456,8 @@
}
// Generate rules for compiling multiple .c, .cpp, or .S files to individual .o files
-func transformSourceToObj(ctx android.ModuleContext, subdir string, srcFiles, noTidySrcs android.Paths,
+func transformSourceToObj(ctx ModuleContext, subdir string, srcFiles, noTidySrcs android.Paths,
flags builderFlags, pathDeps android.Paths, cFlagsDeps android.Paths) Objects {
-
// Source files are one-to-one with tidy, coverage, or kythe files, if enabled.
objFiles := make(android.Paths, len(srcFiles))
var tidyFiles android.Paths
@@ -540,8 +543,7 @@
// Multiple source files have build rules usually share the same cFlags or tidyFlags.
// Define only one version in this module and share it in multiple build rules.
// To simplify the code, the shared variables are all named as $flags<nnn>.
- numSharedFlags := 0
- flagsMap := make(map[string]string)
+ shared := ctx.getSharedFlags()
// Share flags only when there are multiple files or tidy rules.
var hasMultipleRules = len(srcFiles) > 1 || flags.tidy
@@ -553,11 +555,11 @@
return flags
}
mapKey := kind + flags
- n, ok := flagsMap[mapKey]
+ n, ok := shared.flagsMap[mapKey]
if !ok {
- numSharedFlags += 1
- n = strconv.Itoa(numSharedFlags)
- flagsMap[mapKey] = n
+ shared.numSharedFlags += 1
+ n = strconv.Itoa(shared.numSharedFlags)
+ shared.flagsMap[mapKey] = n
ctx.Variable(pctx, kind+n, flags)
}
return "$" + kind + n
@@ -720,9 +722,14 @@
}
+ var tidyDepFiles android.Paths
+ if flags.needTidyFiles {
+ tidyDepFiles = tidyFiles
+ }
return Objects{
objFiles: objFiles,
tidyFiles: tidyFiles,
+ tidyDepFiles: tidyDepFiles,
coverageFiles: coverageFiles,
sAbiDumpFiles: sAbiDumpFiles,
kytheFiles: kytheFiles,
diff --git a/cc/cc.go b/cc/cc.go
index 22baf30..9c35348 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -64,6 +64,9 @@
ctx.BottomUp("coverage", coverageMutator).Parallel()
+ ctx.TopDown("afdo_deps", afdoDepsMutator)
+ ctx.BottomUp("afdo", afdoMutator).Parallel()
+
ctx.TopDown("lto_deps", ltoDepsMutator)
ctx.BottomUp("lto", ltoMutator).Parallel()
@@ -207,11 +210,12 @@
// These must be after any module include flags, which will be in CommonFlags.
SystemIncludeFlags []string
- Toolchain config.Toolchain
- Tidy bool // True if clang-tidy is enabled.
- GcovCoverage bool // True if coverage files should be generated.
- SAbiDump bool // True if header abi dumps should be generated.
- EmitXrefs bool // If true, generate Ninja rules to generate emitXrefs input files for Kythe
+ Toolchain config.Toolchain
+ Tidy bool // True if ninja .tidy rules should be generated.
+ NeedTidyFiles bool // True if module link should depend on .tidy files
+ GcovCoverage bool // True if coverage files should be generated.
+ SAbiDump bool // True if header abi dumps should be generated.
+ EmitXrefs bool // If true, generate Ninja rules to generate emitXrefs input files for Kythe
// The instruction set required for clang ("arm" or "thumb").
RequiredInstructionSet string
@@ -513,6 +517,12 @@
directlyInAnyApex() bool
isPreventInstall() bool
isCfiAssemblySupportEnabled() bool
+ getSharedFlags() *SharedFlags
+}
+
+type SharedFlags struct {
+ numSharedFlags int
+ flagsMap map[string]string
}
type ModuleContext interface {
@@ -810,6 +820,7 @@
sabi *sabi
vndkdep *vndkdep
lto *lto
+ afdo *afdo
pgo *pgo
library libraryInterface
@@ -823,6 +834,9 @@
// Flags used to compile this module
flags Flags
+ // Shared flags among build rules of this module
+ sharedFlags SharedFlags
+
// only non-nil when this is a shared library that reuses the objects of a static library
staticAnalogue *StaticLibraryInfo
@@ -1143,6 +1157,9 @@
if c.lto != nil {
c.AddProperties(c.lto.props()...)
}
+ if c.afdo != nil {
+ c.AddProperties(c.afdo.props()...)
+ }
if c.pgo != nil {
c.AddProperties(c.pgo.props()...)
}
@@ -1598,6 +1615,15 @@
return ctx.mod.Properties.PreventInstall
}
+func (ctx *moduleContextImpl) getSharedFlags() *SharedFlags {
+ shared := &ctx.mod.sharedFlags
+ if shared.flagsMap == nil {
+ shared.numSharedFlags = 0
+ shared.flagsMap = make(map[string]string)
+ }
+ return shared
+}
+
func (ctx *moduleContextImpl) isCfiAssemblySupportEnabled() bool {
return ctx.mod.isCfiAssemblySupportEnabled()
}
@@ -1620,6 +1646,7 @@
module.sabi = &sabi{}
module.vndkdep = &vndkdep{}
module.lto = <o{}
+ module.afdo = &afdo{}
module.pgo = &pgo{}
return module
}
@@ -1815,6 +1842,9 @@
if c.lto != nil {
flags = c.lto.flags(ctx, flags)
}
+ if c.afdo != nil {
+ flags = c.afdo.flags(ctx, flags)
+ }
if c.pgo != nil {
flags = c.pgo.flags(ctx, flags)
}
@@ -1942,6 +1972,9 @@
if c.lto != nil {
c.lto.begin(ctx)
}
+ if c.afdo != nil {
+ c.afdo.begin(ctx)
+ }
if c.pgo != nil {
c.pgo.begin(ctx)
}
@@ -3461,17 +3494,22 @@
objectBp2Build(ctx, c)
}
} else if c.CcLibrary() {
- static := c.BuildStaticVariant()
- shared := c.BuildSharedVariant()
+ static := false
+ shared := false
+ if library, ok := c.linker.(*libraryDecorator); ok {
+ static = library.MutatedProperties.BuildStatic
+ shared = library.MutatedProperties.BuildShared
+ } else if library, ok := c.linker.(*prebuiltLibraryLinker); ok {
+ static = library.MutatedProperties.BuildStatic
+ shared = library.MutatedProperties.BuildShared
+ }
if static && shared {
if !prebuilt {
libraryBp2Build(ctx, c)
}
} else if !static && !shared {
- if !prebuilt {
- libraryHeadersBp2Build(ctx, c)
- }
+ libraryHeadersBp2Build(ctx, c)
} else if static {
if prebuilt {
prebuiltLibraryStaticBp2Build(ctx, c)
@@ -3534,6 +3572,7 @@
&SAbiProperties{},
&VndkProperties{},
<OProperties{},
+ &AfdoProperties{},
&PgoProperties{},
&android.ProtoProperties{},
// RustBindgenProperties is included here so that cc_defaults can be used for rust_bindgen modules.
diff --git a/cc/compiler.go b/cc/compiler.go
index 8adc3ab..9dbf2d1 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -675,7 +675,7 @@
}
// Compile a list of source files into objects a specified subdirectory
-func compileObjs(ctx android.ModuleContext, flags builderFlags, subdir string,
+func compileObjs(ctx ModuleContext, flags builderFlags, subdir string,
srcFiles, noTidySrcs, pathDeps android.Paths, cFlagsDeps android.Paths) Objects {
return transformSourceToObj(ctx, subdir, srcFiles, noTidySrcs, flags, pathDeps, cFlagsDeps)
diff --git a/cc/config/global.go b/cc/config/global.go
index 7f2c23e..e46ac96 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -279,8 +279,8 @@
// prebuilts/clang default settings.
ClangDefaultBase = "prebuilts/clang/host"
- ClangDefaultVersion = "clang-r437112"
- ClangDefaultShortVersion = "14.0.0"
+ ClangDefaultVersion = "clang-r437112b"
+ ClangDefaultShortVersion = "14.0.1"
// Directories with warnings from Android.bp files.
WarningAllowedProjects = []string{
diff --git a/cc/library.go b/cc/library.go
index 216c124..cefbf6c 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -381,6 +381,9 @@
None: linkerAttrs.stripNone,
},
Features: linkerAttrs.features,
+
+ Stubs_symbol_file: compilerAttrs.stubsSymbolFile,
+ Stubs_versions: compilerAttrs.stubsVersions,
}
staticProps := bazel.BazelTargetModuleProperties{
@@ -392,8 +395,12 @@
Bzl_load_location: "//build/bazel/rules:cc_library_shared.bzl",
}
- ctx.CreateBazelTargetModule(staticProps, android.CommonAttributes{Name: m.Name() + "_bp2build_cc_library_static"}, staticTargetAttrs)
- ctx.CreateBazelTargetModule(sharedProps, android.CommonAttributes{Name: m.Name()}, sharedTargetAttrs)
+ ctx.CreateBazelTargetModuleWithRestrictions(staticProps,
+ android.CommonAttributes{Name: m.Name() + "_bp2build_cc_library_static"},
+ staticTargetAttrs, staticAttrs.Enabled)
+ ctx.CreateBazelTargetModuleWithRestrictions(sharedProps,
+ android.CommonAttributes{Name: m.Name()},
+ sharedTargetAttrs, sharedAttrs.Enabled)
}
// cc_library creates both static and/or shared libraries for a device and/or
@@ -439,6 +446,8 @@
module, library := NewLibrary(android.HostSupported)
library.BuildOnlyStatic()
module.sdkMemberTypes = []android.SdkMemberType{staticLibrarySdkMemberType}
+ module.bazelable = true
+ module.bazelHandler = &ccLibraryBazelHandler{module: module}
return module.Init()
}
@@ -1334,7 +1343,7 @@
}
}
- transformObjToStaticLib(ctx, library.objects.objFiles, deps.WholeStaticLibsFromPrebuilts, builderFlags, outputFile, nil, objs.tidyFiles)
+ transformObjToStaticLib(ctx, library.objects.objFiles, deps.WholeStaticLibsFromPrebuilts, builderFlags, outputFile, nil, objs.tidyDepFiles)
library.coverageOutputFile = transformCoverageFilesToZip(ctx, library.objects, ctx.ModuleName())
@@ -1481,7 +1490,7 @@
linkerDeps = append(linkerDeps, deps.LateSharedLibsDeps...)
transformObjToDynamicBinary(ctx, objs.objFiles, sharedLibs,
deps.StaticLibs, deps.LateStaticLibs, deps.WholeStaticLibs,
- linkerDeps, deps.CrtBegin, deps.CrtEnd, false, builderFlags, outputFile, implicitOutputs, objs.tidyFiles)
+ linkerDeps, deps.CrtBegin, deps.CrtEnd, false, builderFlags, outputFile, implicitOutputs, objs.tidyDepFiles)
objs.coverageFiles = append(objs.coverageFiles, deps.StaticLibObjs.coverageFiles...)
objs.coverageFiles = append(objs.coverageFiles, deps.WholeStaticLibObjs.coverageFiles...)
@@ -2512,6 +2521,9 @@
},
Features: linkerAttrs.features,
+
+ Stubs_symbol_file: compilerAttrs.stubsSymbolFile,
+ Stubs_versions: compilerAttrs.stubsVersions,
}
}
@@ -2585,4 +2597,7 @@
Asflags bazel.StringListAttribute
Features bazel.StringListAttribute
+
+ Stubs_symbol_file *string
+ Stubs_versions bazel.StringListAttribute
}
diff --git a/cc/library_headers.go b/cc/library_headers.go
index 70e4715..064e2b8 100644
--- a/cc/library_headers.go
+++ b/cc/library_headers.go
@@ -104,6 +104,8 @@
func prebuiltLibraryHeaderFactory() android.Module {
module, library := NewPrebuiltLibrary(android.HostAndDeviceSupported, "")
library.HeaderOnly()
+ module.bazelable = true
+ module.bazelHandler = &ccLibraryBazelHandler{module: module}
return module.Init()
}
diff --git a/cc/object.go b/cc/object.go
index bd43e36..24f6ed4 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -155,7 +155,8 @@
for config, props := range configToProps {
if objectLinkerProps, ok := props.(*ObjectLinkerProperties); ok {
if objectLinkerProps.Linker_script != nil {
- linkerScript.SetSelectValue(axis, config, android.BazelLabelForModuleSrcSingle(ctx, *objectLinkerProps.Linker_script))
+ label := android.BazelLabelForModuleSrcSingle(ctx, *objectLinkerProps.Linker_script)
+ linkerScript.SetSelectValue(axis, config, label)
}
deps.SetSelectValue(axis, config, android.BazelLabelForModuleDeps(ctx, objectLinkerProps.Objs))
systemSharedLibs := objectLinkerProps.System_shared_libs
diff --git a/cc/sanitize.go b/cc/sanitize.go
index d7b1ade..6c68822 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -539,11 +539,6 @@
if Bool(s.Hwaddress) {
s.Address = nil
s.Thread = nil
- // Disable ubsan diagnosic as a workaround for a compiler bug.
- // TODO(b/191808836): re-enable.
- s.Diag.Undefined = nil
- s.Diag.Integer_overflow = nil
- s.Diag.Misc_undefined = nil
}
// TODO(b/131771163): CFI transiently depends on LTO, and thus Fuzzer is
diff --git a/cc/tidy.go b/cc/tidy.go
index 78a791f..97418fe 100644
--- a/cc/tidy.go
+++ b/cc/tidy.go
@@ -71,13 +71,17 @@
return flags
}
- // If not explicitly set, check the global tidy flag
- if tidy.Properties.Tidy == nil && !ctx.Config().ClangTidy() {
- return flags
- }
-
+ // If not explicitly disabled, set flags.Tidy to generate .tidy rules.
+ // Note that libraries and binaries will depend on .tidy files ONLY if
+ // the global WITH_TIDY or module 'tidy' property is true.
flags.Tidy = true
+ // If explicitly enabled, by global default or local tidy property,
+ // set flags.NeedTidyFiles to make this module depend on .tidy files.
+ if ctx.Config().ClangTidy() || Bool(tidy.Properties.Tidy) {
+ flags.NeedTidyFiles = true
+ }
+
// Add global WITH_TIDY_FLAGS and local tidy_flags.
withTidyFlags := ctx.Config().Getenv("WITH_TIDY_FLAGS")
if len(withTidyFlags) > 0 {
diff --git a/cc/util.go b/cc/util.go
index 88b0aba..b256b9a 100644
--- a/cc/util.go
+++ b/cc/util.go
@@ -85,6 +85,7 @@
toolchain: in.Toolchain,
gcovCoverage: in.GcovCoverage,
tidy: in.Tidy,
+ needTidyFiles: in.NeedTidyFiles,
sAbiDump: in.SAbiDump,
emitXrefs: in.EmitXrefs,
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index 9ee373e..d8cb47a 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -117,12 +117,23 @@
return indexList(s, list) != -1
}
-func loadEnvConfig() error {
+func loadEnvConfig(config build.Config) error {
bc := os.Getenv("ANDROID_BUILD_ENVIRONMENT_CONFIG")
if bc == "" {
return nil
}
- cfgFile := filepath.Join(os.Getenv("TOP"), configDir, fmt.Sprintf("%s.%s", bc, jsonSuffix))
+ configDirs := []string{
+ os.Getenv("ANDROID_BUILD_ENVIRONMENT_CONFIG_DIR"),
+ config.OutDir(),
+ configDir,
+ }
+ var cfgFile string
+ for _, dir := range configDirs {
+ cfgFile = filepath.Join(os.Getenv("TOP"), dir, fmt.Sprintf("%s.%s", bc, jsonSuffix))
+ if _, err := os.Stat(cfgFile); err == nil {
+ break
+ }
+ }
envVarsJSON, err := ioutil.ReadFile(cfgFile)
if err != nil {
@@ -138,9 +149,7 @@
if os.Getenv(k) != "" {
continue
}
- if err := os.Setenv(k, v); err != nil {
- return err
- }
+ config.Environment().Set(k, v)
}
return nil
}
@@ -207,13 +216,13 @@
Status: stat,
}}
- if err := loadEnvConfig(); err != nil {
+ config := c.config(buildCtx, args...)
+
+ if err := loadEnvConfig(config); err != nil {
fmt.Fprintf(os.Stderr, "failed to parse env config files: %v", err)
os.Exit(1)
}
- config := c.config(buildCtx, args...)
-
build.SetupOutDir(buildCtx, config)
if config.UseBazel() && config.Dist() {
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index c2866ab..377a566 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -439,6 +439,7 @@
// This module is host-only
android.InitAndroidArchModule(module, android.HostSupported, android.MultilibCommon)
android.InitDefaultableModule(module)
+ android.InitBazelModule(module)
return module
}
@@ -665,7 +666,7 @@
// ConvertWithBp2build performs bp2build conversion of PrebuiltEtc
func (p *PrebuiltEtc) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
// All prebuilt_* modules are PrebuiltEtc, but at this time, we only convert prebuilt_etc modules.
- if ctx.ModuleType() != "prebuilt_etc" {
+ if p.installDirBase != "etc" {
return
}
@@ -681,7 +682,8 @@
continue
}
if props.Src != nil {
- srcLabelAttribute.SetSelectValue(axis, config, android.BazelLabelForModuleSrcSingle(ctx, *props.Src))
+ label := android.BazelLabelForModuleSrcSingle(ctx, *props.Src)
+ srcLabelAttribute.SetSelectValue(axis, config, label)
}
}
}
diff --git a/filesystem/bootimg.go b/filesystem/bootimg.go
index fc973a4..33beb37 100644
--- a/filesystem/bootimg.go
+++ b/filesystem/bootimg.go
@@ -145,12 +145,10 @@
}
dtbName := proptools.String(b.properties.Dtb_prebuilt)
- if dtbName == "" {
- ctx.PropertyErrorf("dtb_prebuilt", "must be set")
- return output
+ if dtbName != "" {
+ dtb := android.PathForModuleSrc(ctx, dtbName)
+ cmd.FlagWithInput("--dtb ", dtb)
}
- dtb := android.PathForModuleSrc(ctx, dtbName)
- cmd.FlagWithInput("--dtb ", dtb)
cmdline := strings.Join(b.properties.Cmdline, " ")
if cmdline != "" {
@@ -178,20 +176,18 @@
cmd.FlagWithArg("--header_version ", headerVersion)
ramdiskName := proptools.String(b.properties.Ramdisk_module)
- if ramdiskName == "" {
- ctx.PropertyErrorf("ramdisk_module", "must be set")
- return output
- }
- ramdisk := ctx.GetDirectDepWithTag(ramdiskName, bootimgRamdiskDep)
- if filesystem, ok := ramdisk.(*filesystem); ok {
- flag := "--ramdisk "
- if vendor {
- flag = "--vendor_ramdisk "
+ if ramdiskName != "" {
+ ramdisk := ctx.GetDirectDepWithTag(ramdiskName, bootimgRamdiskDep)
+ if filesystem, ok := ramdisk.(*filesystem); ok {
+ flag := "--ramdisk "
+ if vendor {
+ flag = "--vendor_ramdisk "
+ }
+ cmd.FlagWithInput(flag, filesystem.OutputPath())
+ } else {
+ ctx.PropertyErrorf("ramdisk", "%q is not android_filesystem module", ramdisk.Name())
+ return output
}
- cmd.FlagWithInput(flag, filesystem.OutputPath())
- } else {
- ctx.PropertyErrorf("ramdisk", "%q is not android_filesystem module", ramdisk.Name())
- return output
}
bootconfig := proptools.String(b.properties.Bootconfig)
diff --git a/fuzz/fuzz_common.go b/fuzz/fuzz_common.go
index 8861d1b..89f8187 100644
--- a/fuzz/fuzz_common.go
+++ b/fuzz/fuzz_common.go
@@ -31,6 +31,7 @@
const (
Cc Lang = ""
Rust Lang = "rust"
+ Java Lang = "java"
)
var BoolDefault = proptools.BoolDefault
@@ -220,6 +221,9 @@
if lang == Rust {
zipFileName = "fuzz-rust-" + hostOrTarget + "-" + arch + ".zip"
}
+ if lang == Java {
+ zipFileName = "fuzz-java-" + hostOrTarget + "-" + arch + ".zip"
+ }
outputFile := android.PathForOutput(ctx, zipFileName)
s.Packages = append(s.Packages, outputFile)
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 6a91e01..c3e3ba5 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -106,6 +106,16 @@
android.LicenseAnnotationToolchainDependencyTag
label string
}
+
+func (t hostToolDependencyTag) AllowDisabledModuleDependency(target android.Module) bool {
+ // Allow depending on a disabled module if it's replaced by a prebuilt
+ // counterpart. We get the prebuilt through android.PrebuiltGetPreferred in
+ // GenerateAndroidBuildActions.
+ return target.IsReplacedByPrebuilt()
+}
+
+var _ android.AllowDisabledModuleDependency = (*hostToolDependencyTag)(nil)
+
type generatorProperties struct {
// The command to run on one or more input files. Cmd supports substitution of a few variables.
//
@@ -298,6 +308,12 @@
switch tag := ctx.OtherModuleDependencyTag(module).(type) {
case hostToolDependencyTag:
tool := ctx.OtherModuleName(module)
+ if m, ok := module.(android.Module); ok {
+ // Necessary to retrieve any prebuilt replacement for the tool, since
+ // toolDepsMutator runs too late for the prebuilt mutators to have
+ // replaced the dependency.
+ module = android.PrebuiltGetPreferred(ctx, m)
+ }
switch t := module.(type) {
case android.HostToolProvider:
diff --git a/genrule/genrule_test.go b/genrule/genrule_test.go
index 714d2f8..04c97fd 100644
--- a/genrule/genrule_test.go
+++ b/genrule/genrule_test.go
@@ -34,7 +34,9 @@
android.PrepareForTestWithFilegroup,
PrepareForTestWithGenRuleBuildComponents,
android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
+ android.RegisterPrebuiltMutators(ctx)
ctx.RegisterModuleType("tool", toolFactory)
+ ctx.RegisterModuleType("prebuilt_tool", prebuiltToolFactory)
ctx.RegisterModuleType("output", outputProducerFactory)
ctx.RegisterModuleType("use_source", useSourceFactory)
}),
@@ -720,6 +722,69 @@
result.ModuleForTests("gen_all", "").Module().(*useSource).srcs)
}
+func TestPrebuiltTool(t *testing.T) {
+ testcases := []struct {
+ name string
+ bp string
+ expectedToolName string
+ }{
+ {
+ name: "source only",
+ bp: `
+ tool { name: "tool" }
+ `,
+ expectedToolName: "bin/tool",
+ },
+ {
+ name: "prebuilt only",
+ bp: `
+ prebuilt_tool { name: "tool" }
+ `,
+ expectedToolName: "prebuilt_bin/tool",
+ },
+ {
+ name: "source preferred",
+ bp: `
+ tool { name: "tool" }
+ prebuilt_tool { name: "tool" }
+ `,
+ expectedToolName: "bin/tool",
+ },
+ {
+ name: "prebuilt preferred",
+ bp: `
+ tool { name: "tool" }
+ prebuilt_tool { name: "tool", prefer: true }
+ `,
+ expectedToolName: "prebuilt_bin/prebuilt_tool",
+ },
+ {
+ name: "source disabled",
+ bp: `
+ tool { name: "tool", enabled: false }
+ prebuilt_tool { name: "tool" }
+ `,
+ expectedToolName: "prebuilt_bin/prebuilt_tool",
+ },
+ }
+
+ for _, test := range testcases {
+ t.Run(test.name, func(t *testing.T) {
+ result := prepareForGenRuleTest.RunTestWithBp(t, test.bp+`
+ genrule {
+ name: "gen",
+ tools: ["tool"],
+ out: ["foo"],
+ cmd: "$(location tool)",
+ }
+ `)
+ gen := result.Module("gen", "").(*Module)
+ expectedCmd := "__SBOX_SANDBOX_DIR__/tools/out/" + test.expectedToolName
+ android.AssertStringEquals(t, "command", expectedCmd, gen.rawCommands[0])
+ })
+ }
+}
+
func TestGenruleWithBazel(t *testing.T) {
bp := `
genrule {
@@ -764,7 +829,33 @@
return android.OptionalPathForPath(t.outputFile)
}
+type prebuiltTestTool struct {
+ android.ModuleBase
+ prebuilt android.Prebuilt
+ testTool
+}
+
+func (p *prebuiltTestTool) Name() string {
+ return p.prebuilt.Name(p.ModuleBase.Name())
+}
+
+func (p *prebuiltTestTool) Prebuilt() *android.Prebuilt {
+ return &p.prebuilt
+}
+
+func (t *prebuiltTestTool) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ t.outputFile = ctx.InstallFile(android.PathForModuleInstall(ctx, "prebuilt_bin"), ctx.ModuleName(), android.PathForOutput(ctx, ctx.ModuleName()))
+}
+
+func prebuiltToolFactory() android.Module {
+ module := &prebuiltTestTool{}
+ android.InitPrebuiltModuleWithoutSrcs(module)
+ android.InitAndroidArchModule(module, android.HostSupported, android.MultilibFirst)
+ return module
+}
+
var _ android.HostToolProvider = (*testTool)(nil)
+var _ android.HostToolProvider = (*prebuiltTestTool)(nil)
type testOutputProducer struct {
android.ModuleBase
diff --git a/java/Android.bp b/java/Android.bp
index 8835b44..c062941 100644
--- a/java/Android.bp
+++ b/java/Android.bp
@@ -44,6 +44,7 @@
"dexpreopt_config.go",
"droiddoc.go",
"droidstubs.go",
+ "fuzz.go",
"gen.go",
"genrule.go",
"hiddenapi.go",
diff --git a/java/aar.go b/java/aar.go
index 13390db..aabbec6 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -616,6 +616,7 @@
exportPackage android.WritablePath
extraAaptPackagesFile android.WritablePath
manifest android.WritablePath
+ assetsPackage android.WritablePath
exportedStaticPackages android.Paths
@@ -686,9 +687,8 @@
return android.Paths{a.manifest}
}
-// TODO(jungjw): Decide whether we want to implement this.
func (a *AARImport) ExportedAssets() android.OptionalPath {
- return android.OptionalPath{}
+ return android.OptionalPathForPath(a.assetsPackage)
}
// RRO enforcement is not available on aar_import since its RRO dirs are not
@@ -732,10 +732,11 @@
blueprint.RuleParams{
Command: `rm -rf $outDir && mkdir -p $outDir && ` +
`unzip -qoDD -d $outDir $in && rm -rf $outDir/res && touch $out && ` +
+ `${config.Zip2ZipCmd} -i $in -o $assetsPackage 'assets/**/*' && ` +
`${config.MergeZipsCmd} $combinedClassesJar $$(ls $outDir/classes.jar 2> /dev/null) $$(ls $outDir/libs/*.jar 2> /dev/null)`,
- CommandDeps: []string{"${config.MergeZipsCmd}"},
+ CommandDeps: []string{"${config.MergeZipsCmd}", "${config.Zip2ZipCmd}"},
},
- "outDir", "combinedClassesJar")
+ "outDir", "combinedClassesJar", "assetsPackage")
func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
if len(a.properties.Aars) != 1 {
@@ -761,15 +762,17 @@
a.classpathFile = extractedAARDir.Join(ctx, "classes-combined.jar")
a.proguardFlags = extractedAARDir.Join(ctx, "proguard.txt")
a.manifest = extractedAARDir.Join(ctx, "AndroidManifest.xml")
+ a.assetsPackage = android.PathForModuleOut(ctx, "assets.zip")
ctx.Build(pctx, android.BuildParams{
Rule: unzipAAR,
Input: a.aarPath,
- Outputs: android.WritablePaths{a.classpathFile, a.proguardFlags, a.manifest},
+ Outputs: android.WritablePaths{a.classpathFile, a.proguardFlags, a.manifest, a.assetsPackage},
Description: "unzip AAR",
Args: map[string]string{
"outDir": extractedAARDir.String(),
"combinedClassesJar": a.classpathFile.String(),
+ "assetsPackage": a.assetsPackage.String(),
},
})
@@ -812,6 +815,19 @@
aapt2Link(ctx, a.exportPackage, srcJar, proguardOptionsFile, rTxt, a.extraAaptPackagesFile,
linkFlags, linkDeps, nil, overlayRes, transitiveAssets, nil)
+ // Merge this import's assets with its dependencies' assets (if there are any).
+ if len(transitiveAssets) > 0 {
+ mergedAssets := android.PathForModuleOut(ctx, "merged-assets.zip")
+ inputZips := append(android.Paths{a.assetsPackage}, transitiveAssets...)
+ ctx.Build(pctx, android.BuildParams{
+ Rule: mergeAssetsRule,
+ Inputs: inputZips,
+ Output: mergedAssets,
+ Description: "merge assets from dependencies and self",
+ })
+ a.assetsPackage = mergedAssets
+ }
+
ctx.SetProvider(JavaInfoProvider, JavaInfo{
HeaderJars: android.PathsIfNonNil(a.classpathFile),
ImplementationAndResourcesJars: android.PathsIfNonNil(a.classpathFile),
diff --git a/java/androidmk.go b/java/androidmk.go
index 19fe7e2..b930441 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -433,8 +433,10 @@
if len(a.appProperties.Overrides) > 0 {
overridden = append(overridden, a.appProperties.Overrides...)
}
- if a.Name() != a.installApkName {
- overridden = append(overridden, a.Name())
+ // When APK name is overridden via PRODUCT_PACKAGE_NAME_OVERRIDES
+ // ensure that the original name is overridden.
+ if a.Stem() != a.installApkName {
+ overridden = append(overridden, a.Stem())
}
return overridden
}
diff --git a/java/app.go b/java/app.go
index 1c69aeb..f574599 100755
--- a/java/app.go
+++ b/java/app.go
@@ -621,7 +621,7 @@
a.aapt.useEmbeddedDex = Bool(a.appProperties.Use_embedded_dex)
// Check if the install APK name needs to be overridden.
- a.installApkName = ctx.DeviceConfig().OverridePackageNameFor(a.Name())
+ a.installApkName = ctx.DeviceConfig().OverridePackageNameFor(a.Stem())
if ctx.ModuleName() == "framework-res" {
// framework-res.apk is installed as system/framework/framework-res.apk
@@ -1006,6 +1006,7 @@
command := rule.Command().BuiltTool("test_config_fixer").Input(testConfig).Output(fixedConfig)
fixNeeded := false
+ // Auto-generated test config uses `ModuleName` as the APK name. So fix it if it is not the case.
if ctx.ModuleName() != a.installApkName {
fixNeeded = true
command.FlagWithArg("--test-file-name ", a.installApkName+".apk")
@@ -1162,7 +1163,10 @@
// some of its properties.
func OverrideAndroidAppModuleFactory() android.Module {
m := &OverrideAndroidApp{}
- m.AddProperties(&overridableAppProperties{})
+ m.AddProperties(
+ &OverridableDeviceProperties{},
+ &overridableAppProperties{},
+ )
android.InitAndroidMultiTargetsArchModule(m, android.DeviceSupported, android.MultilibCommon)
android.InitOverrideModule(m)
diff --git a/java/app_test.go b/java/app_test.go
index 4da7c3d..2322ef4 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -1707,7 +1707,7 @@
},
},
{
- name: "overridden",
+ name: "overridden via PRODUCT_PACKAGE_NAME_OVERRIDES",
bp: `
android_app {
name: "foo",
@@ -1722,6 +1722,22 @@
"out/soong/target/product/test_device/system/app/bar/bar.apk",
},
},
+ {
+ name: "overridden via stem",
+ bp: `
+ android_app {
+ name: "foo",
+ srcs: ["a.java"],
+ sdk_version: "current",
+ stem: "bar",
+ }
+ `,
+ packageNameOverride: "",
+ expected: []string{
+ "out/soong/.intermediates/foo/android_common/bar.apk",
+ "out/soong/target/product/test_device/system/app/bar/bar.apk",
+ },
+ },
}
for _, test := range testCases {
@@ -1965,6 +1981,80 @@
}
}
+func TestOverrideAndroidAppStem(t *testing.T) {
+ ctx, _ := testJava(t, `
+ android_app {
+ name: "foo",
+ srcs: ["a.java"],
+ sdk_version: "current",
+ }
+ override_android_app {
+ name: "bar",
+ base: "foo",
+ }
+ override_android_app {
+ name: "baz",
+ base: "foo",
+ stem: "baz_stem",
+ }
+ android_app {
+ name: "foo2",
+ srcs: ["a.java"],
+ sdk_version: "current",
+ stem: "foo2_stem",
+ }
+ override_android_app {
+ name: "bar2",
+ base: "foo2",
+ }
+ override_android_app {
+ name: "baz2",
+ base: "foo2",
+ stem: "baz2_stem",
+ }
+ `)
+ for _, expected := range []struct {
+ moduleName string
+ variantName string
+ apkPath string
+ }{
+ {
+ moduleName: "foo",
+ variantName: "android_common",
+ apkPath: "out/soong/target/product/test_device/system/app/foo/foo.apk",
+ },
+ {
+ moduleName: "foo",
+ variantName: "android_common_bar",
+ apkPath: "out/soong/target/product/test_device/system/app/bar/bar.apk",
+ },
+ {
+ moduleName: "foo",
+ variantName: "android_common_baz",
+ apkPath: "out/soong/target/product/test_device/system/app/baz_stem/baz_stem.apk",
+ },
+ {
+ moduleName: "foo2",
+ variantName: "android_common",
+ apkPath: "out/soong/target/product/test_device/system/app/foo2_stem/foo2_stem.apk",
+ },
+ {
+ moduleName: "foo2",
+ variantName: "android_common_bar2",
+ // Note that this may cause the duplicate output error.
+ apkPath: "out/soong/target/product/test_device/system/app/foo2_stem/foo2_stem.apk",
+ },
+ {
+ moduleName: "foo2",
+ variantName: "android_common_baz2",
+ apkPath: "out/soong/target/product/test_device/system/app/baz2_stem/baz2_stem.apk",
+ },
+ } {
+ variant := ctx.ModuleForTests(expected.moduleName, expected.variantName)
+ variant.Output(expected.apkPath)
+ }
+}
+
func TestOverrideAndroidAppDependency(t *testing.T) {
ctx, _ := testJava(t, `
android_app {
@@ -2168,10 +2258,33 @@
t.Errorf("test_config_fixer was not expected to run, but did: %q", params.RuleParams.Command)
}
}
-
}
}
+func TestInstrumentationTargetPrebuilt(t *testing.T) {
+ bp := `
+ android_app_import {
+ name: "foo",
+ apk: "foo.apk",
+ presigned: true,
+ }
+
+ android_test {
+ name: "bar",
+ srcs: ["a.java"],
+ instrumentation_for: "foo",
+ sdk_version: "current",
+ }
+ `
+
+ android.GroupFixturePreparers(
+ PrepareForTestWithJavaDefaultModules,
+ ).ExtendWithErrorHandler(
+ android.FixtureExpectsAtLeastOneErrorMatchingPattern(
+ "instrumentation_for: dependency \"foo\" of type \"android_app_import\" does not provide JavaInfo so is unsuitable for use with this property")).
+ RunTestWithBp(t, bp)
+}
+
func TestStl(t *testing.T) {
ctx, _ := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
cc_library {
diff --git a/java/base.go b/java/base.go
index 7cd71a2..63328c8 100644
--- a/java/base.go
+++ b/java/base.go
@@ -253,9 +253,6 @@
// otherwise provides defaults libraries to add to the bootclasspath.
System_modules *string
- // set the name of the output
- Stem *string
-
IsSDKLibrary bool `blueprint:"mutated"`
// If true, generate the signature file of APK Signing Scheme V4, along side the signed APK file.
@@ -267,6 +264,15 @@
SyspropPublicStub string `blueprint:"mutated"`
}
+// Device properties that can be overridden by overriding module (e.g. override_android_app)
+type OverridableDeviceProperties struct {
+ // set the name of the output. If not set, `name` is used.
+ // To override a module with this property set, overriding module might need to set this as well.
+ // Otherwise, both the overridden and the overriding modules will have the same output name, which
+ // can cause the duplicate output error.
+ Stem *string
+}
+
// Functionality common to Module and Import
//
// It is embedded in Module so its functionality can be used by methods in Module
@@ -389,6 +395,8 @@
protoProperties android.ProtoProperties
deviceProperties DeviceProperties
+ overridableDeviceProperties OverridableDeviceProperties
+
// jar file containing header classes including static library dependencies, suitable for
// inserting into the bootclasspath/classpath of another compile
headerJarFile android.Path
@@ -544,6 +552,7 @@
j.addHostProperties()
j.AddProperties(
&j.deviceProperties,
+ &j.overridableDeviceProperties,
&j.dexer.dexProperties,
&j.dexpreoptProperties,
&j.linter.properties,
@@ -1671,7 +1680,7 @@
}
func (j *Module) Stem() string {
- return proptools.StringDefault(j.deviceProperties.Stem, j.Name())
+ return proptools.StringDefault(j.overridableDeviceProperties.Stem, j.Name())
}
func (j *Module) JacocoReportClassesFile() android.Path {
@@ -1936,6 +1945,9 @@
sm := module.(SystemModulesProvider)
outputDir, outputDeps := sm.OutputDirAndDeps()
deps.systemModules = &systemModules{outputDir, outputDeps}
+
+ case instrumentationForTag:
+ ctx.PropertyErrorf("instrumentation_for", "dependency %q of type %q does not provide JavaInfo so is unsuitable for use with this property", ctx.OtherModuleName(module), ctx.OtherModuleType(module))
}
}
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index bfe895c..fee51d7 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -219,6 +219,11 @@
// Collect the module directory for IDE info in java/jdeps.go.
modulePaths []string
+
+ // Installs for on-device boot image files. This list has entries only if the installs should be
+ // handled by Make (e.g., the boot image should be installed on the system partition, rather than
+ // in the APEX).
+ bootImageDeviceInstalls []dexpreopterInstall
}
// commonBootclasspathFragment defines the methods that are implemented by both source and prebuilt
@@ -387,6 +392,9 @@
// Map from arch type to the boot image files.
bootImageFilesByArch bootImageFilesByArch
+ // True if the boot image should be installed in the APEX.
+ shouldInstallBootImageInApex bool
+
// Map from the base module name (without prebuilt_ prefix) of a fragment's contents module to the
// hidden API encoded dex jar path.
contentModuleDexJarPaths bootDexJarByModule
@@ -410,6 +418,11 @@
return i.bootImageFilesByArch
}
+// Return true if the boot image should be installed in the APEX.
+func (i *BootclasspathFragmentApexContentInfo) ShouldInstallBootImageInApex() bool {
+ return i.shouldInstallBootImageInApex
+}
+
// DexBootJarPathForContentModule returns the path to the dex boot jar for specified module.
//
// The dex boot jar is one which has had hidden API encoding performed on it.
@@ -550,6 +563,24 @@
// Copy the dex jars of this fragment's content modules to their predefined locations.
copyBootJarsToPredefinedLocations(ctx, hiddenAPIOutput.EncodedBootDexFilesByModule, imageConfig.dexPathsByModule)
}
+
+ for _, variant := range imageConfig.apexVariants() {
+ arch := variant.target.Arch.ArchType.String()
+ for _, install := range variant.deviceInstalls {
+ // Remove the "/" prefix because the path should be relative to $ANDROID_PRODUCT_OUT.
+ installDir := strings.TrimPrefix(filepath.Dir(install.To), "/")
+ installBase := filepath.Base(install.To)
+ installPath := android.PathForModuleInPartitionInstall(ctx, "", installDir)
+
+ b.bootImageDeviceInstalls = append(b.bootImageDeviceInstalls, dexpreopterInstall{
+ name: arch + "-" + installBase,
+ moduleName: b.Name(),
+ outputPathOnHost: install.From,
+ installDirOnDevice: installPath,
+ installFileOnDevice: installBase,
+ })
+ }
+ }
}
// A prebuilt fragment cannot contribute to an apex.
@@ -599,6 +630,8 @@
info.profilePathOnHost = imageConfig.profilePathOnHost
info.profileInstallPathInApex = imageConfig.profileInstallPathInApex
}
+
+ info.shouldInstallBootImageInApex = imageConfig.shouldInstallInApex()
}
info.bootImageFilesByArch = bootImageFilesByArch
@@ -813,6 +846,23 @@
return androidBootImageFilesByArch
}
+func (b *BootclasspathFragmentModule) AndroidMkEntries() []android.AndroidMkEntries {
+ var entriesList []android.AndroidMkEntries
+ for _, install := range b.bootImageDeviceInstalls {
+ entriesList = append(entriesList, install.ToMakeEntries())
+ }
+ return entriesList
+}
+
+// Returns the names of all Make modules that handle the installation of the boot image.
+func (b *BootclasspathFragmentModule) BootImageDeviceInstallMakeModules() []string {
+ var makeModules []string
+ for _, install := range b.bootImageDeviceInstalls {
+ makeModules = append(makeModules, install.FullModuleName())
+ }
+ return makeModules
+}
+
// Collect information for opening IDE project files in java/jdeps.go.
func (b *BootclasspathFragmentModule) IDEInfo(dpInfo *android.IdeInfo) {
dpInfo.Deps = append(dpInfo.Deps, b.properties.Contents...)
diff --git a/java/dex.go b/java/dex.go
index 8045b5c..474694a 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -72,6 +72,9 @@
// This defaults to reasonable value based on module and should not be set.
// It exists only to support ART tests.
Uncompress_dex *bool
+
+ // Exclude kotlinc generate files: *.kotlin_module, *.kotlin_builtins. Defaults to false.
+ Exclude_kotlinc_generated_files *bool
}
type dexer struct {
@@ -94,7 +97,7 @@
`${config.Zip2ZipCmd} -i $in -o $tmpJar -x '**/*.dex' && ` +
`$d8Template${config.D8Cmd} ${config.DexFlags} --output $outDir $d8Flags $tmpJar && ` +
`$zipTemplate${config.SoongZipCmd} $zipFlags -o $outDir/classes.dex.jar -C $outDir -f "$outDir/classes*.dex" && ` +
- `${config.MergeZipsCmd} -D -stripFile "**/*.class" $out $outDir/classes.dex.jar $in`,
+ `${config.MergeZipsCmd} -D -stripFile "**/*.class" $mergeZipsFlags $out $outDir/classes.dex.jar $in`,
CommandDeps: []string{
"${config.D8Cmd}",
"${config.Zip2ZipCmd}",
@@ -116,7 +119,7 @@
ExecStrategy: "${config.RED8ExecStrategy}",
Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
},
- }, []string{"outDir", "d8Flags", "zipFlags", "tmpJar"}, nil)
+ }, []string{"outDir", "d8Flags", "zipFlags", "tmpJar", "mergeZipsFlags"}, nil)
var r8, r8RE = pctx.MultiCommandRemoteStaticRules("r8",
blueprint.RuleParams{
@@ -134,7 +137,7 @@
`${config.SoongZipCmd} -o ${outUsageZip} -C ${outUsageDir} -f ${outUsage} && ` +
`rm -rf ${outUsageDir} && ` +
`$zipTemplate${config.SoongZipCmd} $zipFlags -o $outDir/classes.dex.jar -C $outDir -f "$outDir/classes*.dex" && ` +
- `${config.MergeZipsCmd} -D -stripFile "**/*.class" $out $outDir/classes.dex.jar $in`,
+ `${config.MergeZipsCmd} -D -stripFile "**/*.class" $mergeZipsFlags $out $outDir/classes.dex.jar $in`,
CommandDeps: []string{
"${config.R8Cmd}",
"${config.Zip2ZipCmd}",
@@ -165,7 +168,7 @@
Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
},
}, []string{"outDir", "outDict", "outUsage", "outUsageZip", "outUsageDir",
- "r8Flags", "zipFlags", "tmpJar"}, []string{"implicits"})
+ "r8Flags", "zipFlags", "tmpJar", "mergeZipsFlags"}, []string{"implicits"})
func (d *dexer) dexCommonFlags(ctx android.ModuleContext,
minSdkVersion android.SdkSpec) (flags []string, deps android.Paths) {
@@ -254,6 +257,15 @@
if BoolDefault(opt.Proguard_compatibility, true) {
r8Flags = append(r8Flags, "--force-proguard-compatibility")
+ } else {
+ // TODO(b/213833843): Allow configuration of the prefix via a build variable.
+ var sourceFilePrefix = "go/retraceme "
+ var sourceFileTemplate = "\"" + sourceFilePrefix + "%MAP_ID\""
+ // TODO(b/200967150): Also tag the source file in compat builds.
+ if Bool(opt.Optimize) || Bool(opt.Obfuscate) {
+ r8Flags = append(r8Flags, "--map-id-template", "%MAP_HASH")
+ r8Flags = append(r8Flags, "--source-file-template", sourceFileTemplate)
+ }
}
// TODO(ccross): Don't shrink app instrumentation tests by default.
@@ -298,6 +310,12 @@
commonFlags, commonDeps := d.dexCommonFlags(ctx, minSdkVersion)
+ // Exclude kotlinc generated files when "exclude_kotlinc_generated_files" is set to true.
+ mergeZipsFlags := ""
+ if proptools.BoolDefault(d.dexProperties.Exclude_kotlinc_generated_files, false) {
+ mergeZipsFlags = "-stripFile META-INF/*.kotlin_module -stripFile **/*.kotlin_builtins"
+ }
+
useR8 := d.effectiveOptimizeEnabled()
if useR8 {
proguardDictionary := android.PathForModuleOut(ctx, "proguard_dictionary")
@@ -311,14 +329,15 @@
r8Deps = append(r8Deps, commonDeps...)
rule := r8
args := map[string]string{
- "r8Flags": strings.Join(append(commonFlags, r8Flags...), " "),
- "zipFlags": zipFlags,
- "outDict": proguardDictionary.String(),
- "outUsageDir": proguardUsageDir.String(),
- "outUsage": proguardUsage.String(),
- "outUsageZip": proguardUsageZip.String(),
- "outDir": outDir.String(),
- "tmpJar": tmpJar.String(),
+ "r8Flags": strings.Join(append(commonFlags, r8Flags...), " "),
+ "zipFlags": zipFlags,
+ "outDict": proguardDictionary.String(),
+ "outUsageDir": proguardUsageDir.String(),
+ "outUsage": proguardUsage.String(),
+ "outUsageZip": proguardUsageZip.String(),
+ "outDir": outDir.String(),
+ "tmpJar": tmpJar.String(),
+ "mergeZipsFlags": mergeZipsFlags,
}
if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_R8") {
rule = r8RE
@@ -347,10 +366,11 @@
Input: classesJar,
Implicits: d8Deps,
Args: map[string]string{
- "d8Flags": strings.Join(append(commonFlags, d8Flags...), " "),
- "zipFlags": zipFlags,
- "outDir": outDir.String(),
- "tmpJar": tmpJar.String(),
+ "d8Flags": strings.Join(append(commonFlags, d8Flags...), " "),
+ "zipFlags": zipFlags,
+ "outDir": outDir.String(),
+ "tmpJar": tmpJar.String(),
+ "mergeZipsFlags": mergeZipsFlags,
},
})
}
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index e9bc518..7c5f055 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -57,6 +57,25 @@
return "-dexpreopt-" + install.name
}
+// Returns Make entries for installing the file.
+//
+// This function uses a value receiver rather than a pointer receiver to ensure that the object is
+// safe to use in `android.AndroidMkExtraEntriesFunc`.
+func (install dexpreopterInstall) ToMakeEntries() android.AndroidMkEntries {
+ return android.AndroidMkEntries{
+ Class: "ETC",
+ SubName: install.SubModuleName(),
+ OutputFile: android.OptionalPathForPath(install.outputPathOnHost),
+ ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+ func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+ entries.SetString("LOCAL_MODULE_PATH", install.installDirOnDevice.String())
+ entries.SetString("LOCAL_INSTALLED_MODULE_STEM", install.installFileOnDevice)
+ entries.SetString("LOCAL_NOT_AVAILABLE_FOR_PLATFORM", "false")
+ },
+ },
+ }
+}
+
type dexpreopter struct {
dexpreoptProperties DexpreoptProperties
@@ -383,19 +402,7 @@
func (d *dexpreopter) AndroidMkEntriesForApex() []android.AndroidMkEntries {
var entries []android.AndroidMkEntries
for _, install := range d.builtInstalledForApex {
- install := install
- entries = append(entries, android.AndroidMkEntries{
- Class: "ETC",
- SubName: install.SubModuleName(),
- OutputFile: android.OptionalPathForPath(install.outputPathOnHost),
- ExtraEntries: []android.AndroidMkExtraEntriesFunc{
- func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- entries.SetString("LOCAL_MODULE_PATH", install.installDirOnDevice.String())
- entries.SetString("LOCAL_INSTALLED_MODULE_STEM", install.installFileOnDevice)
- entries.SetString("LOCAL_NOT_AVAILABLE_FOR_PLATFORM", "false")
- },
- },
- })
+ entries = append(entries, install.ToMakeEntries())
}
return entries
}
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index c599c4d..cad9c33 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -313,10 +313,13 @@
// This is only set for a variant of an image that extends another image.
primaryImagesDeps android.Paths
- // Rules which should be used in make to install the outputs.
+ // Rules which should be used in make to install the outputs on host.
installs android.RuleBuilderInstalls
vdexInstalls android.RuleBuilderInstalls
unstrippedInstalls android.RuleBuilderInstalls
+
+ // Rules which should be used in make to install the outputs on device.
+ deviceInstalls android.RuleBuilderInstalls
}
// Get target-specific boot image variant for the given boot image config and target.
@@ -388,6 +391,11 @@
return variants
}
+// Returns true if the boot image should be installed in the APEX.
+func (image *bootImageConfig) shouldInstallInApex() bool {
+ return strings.HasPrefix(image.installDirOnDevice, "apex/")
+}
+
// Return boot image locations (as a list of symbolic paths).
//
// The image "location" is a symbolic path that, with multiarchitecture support, doesn't really
@@ -710,6 +718,7 @@
var vdexInstalls android.RuleBuilderInstalls
var unstrippedInstalls android.RuleBuilderInstalls
+ var deviceInstalls android.RuleBuilderInstalls
for _, artOrOat := range image.moduleFiles(ctx, outputDir, ".art", ".oat") {
cmd.ImplicitOutput(artOrOat)
@@ -735,12 +744,21 @@
android.RuleBuilderInstall{unstrippedOat, filepath.Join(installDir, unstrippedOat.Base())})
}
+ if image.installDirOnHost != image.installDirOnDevice && !image.shouldInstallInApex() && !ctx.Config().UnbundledBuild() {
+ installDirOnDevice := filepath.Join("/", image.installDirOnDevice, arch.String())
+ for _, file := range image.moduleFiles(ctx, outputDir, ".art", ".oat", ".vdex") {
+ deviceInstalls = append(deviceInstalls,
+ android.RuleBuilderInstall{file, filepath.Join(installDirOnDevice, file.Base())})
+ }
+ }
+
rule.Build(image.name+"JarsDexpreopt_"+image.target.String(), "dexpreopt "+image.name+" jars "+arch.String())
// save output and installed files for makevars
image.installs = rule.Installs()
image.vdexInstalls = vdexInstalls
image.unstrippedInstalls = unstrippedInstalls
+ image.deviceInstalls = deviceInstalls
}
const failureMessage = `ERROR: Dex2oat failed to compile a boot image.
diff --git a/java/dexpreopt_check.go b/java/dexpreopt_check.go
index 149cbb7..83c088c 100644
--- a/java/dexpreopt_check.go
+++ b/java/dexpreopt_check.go
@@ -72,8 +72,7 @@
return
}
- // TODO(b/203198541): Check all system server jars.
- systemServerJars := global.AllSystemServerClasspathJars(ctx)
+ systemServerJars := global.AllSystemServerJars(ctx)
for _, jar := range systemServerJars.CopyOfJars() {
dexLocation := dexpreopt.GetSystemServerDexLocation(ctx, global, jar)
odexLocation := dexpreopt.ToOdexPath(dexLocation, targets[0].Arch.ArchType)
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index 26c1105..df8d8c8 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -41,17 +41,14 @@
var (
bootImageConfigKey = android.NewOnceKey("bootImageConfig")
+ bootImageConfigRawKey = android.NewOnceKey("bootImageConfigRaw")
artBootImageName = "art"
frameworkBootImageName = "boot"
)
-// Construct the global boot image configs.
-func genBootImageConfigs(ctx android.PathContext) map[string]*bootImageConfig {
- return ctx.Config().Once(bootImageConfigKey, func() interface{} {
-
+func genBootImageConfigRaw(ctx android.PathContext) map[string]*bootImageConfig {
+ return ctx.Config().Once(bootImageConfigRawKey, func() interface{} {
global := dexpreopt.GetGlobalConfig(ctx)
- targets := dexpreoptTargets(ctx)
- deviceDir := android.PathForOutput(ctx, ctx.Config().DeviceName())
artModules := global.ArtApexJars
frameworkModules := global.BootJars.RemoveList(artModules)
@@ -79,10 +76,22 @@
modules: frameworkModules,
}
- configs := map[string]*bootImageConfig{
+ return map[string]*bootImageConfig{
artBootImageName: &artCfg,
frameworkBootImageName: &frameworkCfg,
}
+ }).(map[string]*bootImageConfig)
+}
+
+// Construct the global boot image configs.
+func genBootImageConfigs(ctx android.PathContext) map[string]*bootImageConfig {
+ return ctx.Config().Once(bootImageConfigKey, func() interface{} {
+ targets := dexpreoptTargets(ctx)
+ deviceDir := android.PathForOutput(ctx, ctx.Config().DeviceName())
+
+ configs := genBootImageConfigRaw(ctx)
+ artCfg := configs[artBootImageName]
+ frameworkCfg := configs[frameworkBootImageName]
// common to all configs
for _, c := range configs {
diff --git a/java/droidstubs.go b/java/droidstubs.go
index 7ad316f..5a84e05 100644
--- a/java/droidstubs.go
+++ b/java/droidstubs.go
@@ -19,6 +19,7 @@
"path/filepath"
"strings"
+ "github.com/google/blueprint"
"github.com/google/blueprint/proptools"
"android/soong/android"
@@ -806,7 +807,8 @@
properties PrebuiltStubsSourcesProperties
- stubsSrcJar android.Path
+ stubsSrcJar android.Path
+ jsonDataActions []blueprint.JSONDataAction
}
func (p *PrebuiltStubsSources) OutputFiles(tag string) (android.Paths, error) {
@@ -822,6 +824,13 @@
return d.stubsSrcJar
}
+// AddJSONData is a temporary solution for droidstubs module to put action
+// related data into the module json graph.
+func (p *PrebuiltStubsSources) AddJSONData(d *map[string]interface{}) {
+ p.ModuleBase.AddJSONData(d)
+ (*d)["Actions"] = blueprint.FormatJSONDataActions(p.jsonDataActions)
+}
+
func (p *PrebuiltStubsSources) GenerateAndroidBuildActions(ctx android.ModuleContext) {
if len(p.properties.Srcs) != 1 {
ctx.PropertyErrorf("srcs", "must only specify one directory path or srcjar, contains %d paths", len(p.properties.Srcs))
@@ -829,9 +838,12 @@
}
src := p.properties.Srcs[0]
+ var jsonDataAction blueprint.JSONDataAction
if filepath.Ext(src) == ".srcjar" {
// This is a srcjar. We can use it directly.
p.stubsSrcJar = android.PathForModuleSrc(ctx, src)
+ jsonDataAction.Inputs = []string{src}
+ jsonDataAction.Outputs = []string{src}
} else {
outPath := android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar")
@@ -855,7 +867,10 @@
rule.Restat()
rule.Build("zip src", "Create srcjar from prebuilt source")
p.stubsSrcJar = outPath
+ jsonDataAction.Inputs = srcPaths.Strings()
+ jsonDataAction.Outputs = []string{outPath.String()}
}
+ p.jsonDataActions = []blueprint.JSONDataAction{jsonDataAction}
}
func (p *PrebuiltStubsSources) Prebuilt() *android.Prebuilt {
diff --git a/java/droidstubs_test.go b/java/droidstubs_test.go
index 10d99f3..82ebba7 100644
--- a/java/droidstubs_test.go
+++ b/java/droidstubs_test.go
@@ -21,6 +21,8 @@
"strings"
"testing"
+ "github.com/google/blueprint"
+
"android/soong/android"
)
@@ -232,6 +234,27 @@
checkSystemModulesUseByDroidstubs(t, ctx, "stubs-prebuilt-system-modules", "prebuilt-jar.jar")
}
+func TestAddJSONData(t *testing.T) {
+ prebuiltStubsSources := PrebuiltStubsSources{}
+ prebuiltStubsSources.jsonDataActions = []blueprint.JSONDataAction{
+ blueprint.JSONDataAction{
+ Inputs: []string{},
+ Outputs: []string{},
+ },
+ }
+ jsonData := map[string]interface{}{}
+ prebuiltStubsSources.AddJSONData(&jsonData)
+ expectedOut := []map[string]interface{}{
+ map[string]interface{}{
+ "Inputs": []string{},
+ "Outputs": []string{},
+ },
+ }
+ if !reflect.DeepEqual(jsonData["Actions"], expectedOut) {
+ t.Errorf("The JSON action data %#v isn't as expected %#v.", jsonData["Actions"], expectedOut)
+ }
+}
+
func checkSystemModulesUseByDroidstubs(t *testing.T, ctx *android.TestContext, moduleName string, systemJar string) {
metalavaRule := ctx.ModuleForTests(moduleName, "android_common").Rule("metalava")
var systemJars []string
diff --git a/java/fuzz.go b/java/fuzz.go
new file mode 100644
index 0000000..257f343
--- /dev/null
+++ b/java/fuzz.go
@@ -0,0 +1,159 @@
+// Copyright 2021 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package java
+
+import (
+ "github.com/google/blueprint/proptools"
+ "sort"
+ "strings"
+
+ "android/soong/android"
+ "android/soong/fuzz"
+)
+
+func init() {
+ RegisterJavaFuzzBuildComponents(android.InitRegistrationContext)
+}
+
+func RegisterJavaFuzzBuildComponents(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("java_fuzz_host", FuzzFactory)
+ ctx.RegisterSingletonType("java_fuzz_packaging", javaFuzzPackagingFactory)
+}
+
+type JavaFuzzLibrary struct {
+ Library
+ fuzzPackagedModule fuzz.FuzzPackagedModule
+}
+
+func (j *JavaFuzzLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ j.Library.GenerateAndroidBuildActions(ctx)
+
+ if j.fuzzPackagedModule.FuzzProperties.Corpus != nil {
+ j.fuzzPackagedModule.Corpus = android.PathsForModuleSrc(ctx, j.fuzzPackagedModule.FuzzProperties.Corpus)
+ }
+ if j.fuzzPackagedModule.FuzzProperties.Data != nil {
+ j.fuzzPackagedModule.Data = android.PathsForModuleSrc(ctx, j.fuzzPackagedModule.FuzzProperties.Data)
+ }
+ if j.fuzzPackagedModule.FuzzProperties.Dictionary != nil {
+ j.fuzzPackagedModule.Dictionary = android.PathForModuleSrc(ctx, *j.fuzzPackagedModule.FuzzProperties.Dictionary)
+ }
+
+ if j.fuzzPackagedModule.FuzzProperties.Fuzz_config != nil {
+ configPath := android.PathForModuleOut(ctx, "config").Join(ctx, "config.json")
+ android.WriteFileRule(ctx, configPath, j.fuzzPackagedModule.FuzzProperties.Fuzz_config.String())
+ j.fuzzPackagedModule.Config = configPath
+ }
+}
+
+// java_fuzz builds and links sources into a `.jar` file for the host.
+//
+// By default, a java_fuzz produces a `.jar` file containing `.class` files.
+// This jar is not suitable for installing on a device.
+func FuzzFactory() android.Module {
+ module := &JavaFuzzLibrary{}
+
+ module.addHostProperties()
+ module.Module.properties.Installable = proptools.BoolPtr(false)
+ module.AddProperties(&module.fuzzPackagedModule.FuzzProperties)
+
+ // java_fuzz packaging rules collide when both linux_glibc and linux_bionic are enabled, disable the linux_bionic variants.
+ android.AddLoadHook(module, func(ctx android.LoadHookContext) {
+ disableLinuxBionic := struct {
+ Target struct {
+ Linux_bionic struct {
+ Enabled *bool
+ }
+ }
+ }{}
+ disableLinuxBionic.Target.Linux_bionic.Enabled = proptools.BoolPtr(false)
+ ctx.AppendProperties(&disableLinuxBionic)
+ })
+
+ module.initModuleAndImport(module)
+ android.InitSdkAwareModule(module)
+ InitJavaModule(module, android.HostSupported)
+ return module
+}
+
+// Responsible for generating rules that package fuzz targets into
+// their architecture & target/host specific zip file.
+type javaFuzzPackager struct {
+ fuzz.FuzzPackager
+}
+
+func javaFuzzPackagingFactory() android.Singleton {
+ return &javaFuzzPackager{}
+}
+
+func (s *javaFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) {
+ // Map between each architecture + host/device combination.
+ archDirs := make(map[fuzz.ArchOs][]fuzz.FileToZip)
+
+ // List of individual fuzz targets.
+ s.FuzzTargets = make(map[string]bool)
+
+ ctx.VisitAllModules(func(module android.Module) {
+ // Discard non-fuzz targets.
+ javaModule, ok := module.(*JavaFuzzLibrary)
+ if !ok {
+ return
+ }
+
+ fuzzModuleValidator := fuzz.FuzzModule{
+ javaModule.ModuleBase,
+ javaModule.DefaultableModuleBase,
+ javaModule.ApexModuleBase,
+ }
+
+ if ok := fuzz.IsValid(fuzzModuleValidator); !ok || *javaModule.Module.properties.Installable {
+ return
+ }
+
+ hostOrTargetString := "target"
+ if javaModule.Host() {
+ hostOrTargetString = "host"
+ }
+ archString := javaModule.Arch().ArchType.String()
+
+ archDir := android.PathForIntermediates(ctx, "fuzz", hostOrTargetString, archString)
+ archOs := fuzz.ArchOs{HostOrTarget: hostOrTargetString, Arch: archString, Dir: archDir.String()}
+
+ var files []fuzz.FileToZip
+ builder := android.NewRuleBuilder(pctx, ctx)
+
+ // Package the artifacts (data, corpus, config and dictionary into a zipfile.
+ files = s.PackageArtifacts(ctx, module, javaModule.fuzzPackagedModule, archDir, builder)
+
+ // Add .jar
+ files = append(files, fuzz.FileToZip{javaModule.outputFile, ""})
+
+ archDirs[archOs], ok = s.BuildZipFile(ctx, module, javaModule.fuzzPackagedModule, files, builder, archDir, archString, "host", archOs, archDirs)
+ if !ok {
+ return
+ }
+
+ })
+ s.CreateFuzzPackage(ctx, archDirs, fuzz.Java, pctx)
+}
+
+func (s *javaFuzzPackager) MakeVars(ctx android.MakeVarsContext) {
+ packages := s.Packages.Strings()
+ sort.Strings(packages)
+
+ ctx.Strict("SOONG_JAVA_FUZZ_PACKAGING_ARCH_MODULES", strings.Join(packages, " "))
+
+ // Preallocate the slice of fuzz targets to minimize memory allocations.
+ s.PreallocateSlice(ctx, "ALL_JAVA_FUZZ_TARGETS")
+}
diff --git a/java/fuzz_test.go b/java/fuzz_test.go
new file mode 100644
index 0000000..cf063eb
--- /dev/null
+++ b/java/fuzz_test.go
@@ -0,0 +1,65 @@
+// Copyright 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package java
+
+import (
+ "android/soong/android"
+ "path/filepath"
+ "testing"
+)
+
+var prepForJavaFuzzTest = android.GroupFixturePreparers(
+ PrepareForTestWithJavaDefaultModules,
+ android.FixtureRegisterWithContext(RegisterJavaFuzzBuildComponents),
+)
+
+func TestJavaFuzz(t *testing.T) {
+ result := prepForJavaFuzzTest.RunTestWithBp(t, `
+ java_fuzz_host {
+ name: "foo",
+ srcs: ["a.java"],
+ libs: ["bar"],
+ static_libs: ["baz"],
+ }
+
+ java_library_host {
+ name: "bar",
+ srcs: ["b.java"],
+ }
+
+ java_library_host {
+ name: "baz",
+ srcs: ["c.java"],
+ }`)
+
+ osCommonTarget := result.Config.BuildOSCommonTarget.String()
+ javac := result.ModuleForTests("foo", osCommonTarget).Rule("javac")
+ combineJar := result.ModuleForTests("foo", osCommonTarget).Description("for javac")
+
+ if len(javac.Inputs) != 1 || javac.Inputs[0].String() != "a.java" {
+ t.Errorf(`foo inputs %v != ["a.java"]`, javac.Inputs)
+ }
+
+ baz := result.ModuleForTests("baz", osCommonTarget).Rule("javac").Output.String()
+ barOut := filepath.Join("out", "soong", ".intermediates", "bar", osCommonTarget, "javac", "bar.jar")
+ bazOut := filepath.Join("out", "soong", ".intermediates", "baz", osCommonTarget, "javac", "baz.jar")
+
+ android.AssertStringDoesContain(t, "foo classpath", javac.Args["classpath"], barOut)
+ android.AssertStringDoesContain(t, "foo classpath", javac.Args["classpath"], bazOut)
+
+ if len(combineJar.Inputs) != 2 || combineJar.Inputs[1].String() != baz {
+ t.Errorf("foo combineJar inputs %v does not contain %q", combineJar.Inputs, baz)
+ }
+}
diff --git a/java/java.go b/java/java.go
index 9b4a005..bb7c32b 100644
--- a/java/java.go
+++ b/java/java.go
@@ -24,6 +24,7 @@
"strings"
"android/soong/bazel"
+
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
@@ -1866,6 +1867,7 @@
module.AddProperties(
&CommonProperties{},
&DeviceProperties{},
+ &OverridableDeviceProperties{},
&DexProperties{},
&DexpreoptProperties{},
&android.ProtoProperties{},
@@ -2000,6 +2002,7 @@
Deps bazel.LabelListAttribute
Main_class string
Jvm_flags bazel.StringListAttribute
+ Javacopts bazel.StringListAttribute
}
// JavaBinaryHostBp2Build is for java_binary_host bp2build.
@@ -2021,6 +2024,10 @@
Main_class: mainClass,
}
+ if m.properties.Javacflags != nil {
+ attrs.Javacopts = bazel.MakeStringListAttribute(m.properties.Javacflags)
+ }
+
// Attribute deps
deps := []string{}
if m.properties.Static_libs != nil {
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 0bc8895..7849f96 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -2579,11 +2579,11 @@
implicitUntilAttr := formattedOptionalSdkLevelAttribute(ctx, "on-bootclasspath-before", module.properties.On_bootclasspath_before)
minSdkAttr := formattedOptionalSdkLevelAttribute(ctx, "min-device-sdk", module.properties.Min_device_sdk)
maxSdkAttr := formattedOptionalSdkLevelAttribute(ctx, "max-device-sdk", module.properties.Max_device_sdk)
- // <library> is understood in all android versions whereas <updatable-library> is only understood from API T (and ignored before that).
- // similarly, min_device_sdk is only understood from T. So if a library is using that, we need to use the updatable-library to make sure this library is not loaded before T
+ // <library> is understood in all android versions whereas <apex-library> is only understood from API T (and ignored before that).
+ // similarly, min_device_sdk is only understood from T. So if a library is using that, we need to use the apex-library to make sure this library is not loaded before T
var libraryTag string
if module.properties.Min_device_sdk != nil {
- libraryTag = ` <updatable-library\n`
+ libraryTag = ` <apex-library\n`
} else {
libraryTag = ` <library\n`
}
diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go
index f3a19e9..e0e5b56 100644
--- a/java/sdk_library_test.go
+++ b/java/sdk_library_test.go
@@ -48,6 +48,7 @@
name: "bar",
srcs: ["a.java", "b.java"],
api_packages: ["bar"],
+ exclude_kotlinc_generated_files: true,
}
java_library {
name: "baz",
@@ -161,6 +162,14 @@
android.AssertDeepEquals(t, "qux exports (required)", []string{"fred", "quuz", "foo", "bar"}, requiredSdkLibs)
android.AssertDeepEquals(t, "qux exports (optional)", []string{}, optionalSdkLibs)
}
+
+ fooDexJar := result.ModuleForTests("foo", "android_common").Rule("d8")
+ // tests if kotlinc generated files are NOT excluded from output of foo.
+ android.AssertStringDoesNotContain(t, "foo dex", fooDexJar.BuildParams.Args["mergeZipsFlags"], "-stripFile META-INF/*.kotlin_module")
+
+ barDexJar := result.ModuleForTests("bar", "android_common").Rule("d8")
+ // tests if kotlinc generated files are excluded from output of bar.
+ android.AssertStringDoesContain(t, "bar dex", barDexJar.BuildParams.Args["mergeZipsFlags"], "-stripFile META-INF/*.kotlin_module")
}
func TestJavaSdkLibrary_UpdatableLibrary(t *testing.T) {
@@ -338,7 +347,7 @@
`)
// test that updatability attributes are passed on correctly
fooUpdatable := result.ModuleForTests("foo.xml", "android_common").Rule("java_sdk_xml")
- android.AssertStringDoesContain(t, "foo.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `<updatable-library`)
+ android.AssertStringDoesContain(t, "foo.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `<apex-library`)
android.AssertStringDoesNotContain(t, "foo.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `<library`)
}
diff --git a/java/testing.go b/java/testing.go
index 7441e44..6c49bc8 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -506,3 +506,19 @@
}
}
}
+
+// Applies the given modifier on the boot image config with the given name.
+func FixtureModifyBootImageConfig(name string, configModifier func(*bootImageConfig)) android.FixturePreparer {
+ return android.FixtureModifyConfig(func(androidConfig android.Config) {
+ pathCtx := android.PathContextForTesting(androidConfig)
+ config := genBootImageConfigRaw(pathCtx)
+ configModifier(config[name])
+ })
+}
+
+// Sets the value of `installDirOnDevice` of the boot image config with the given name.
+func FixtureSetBootImageInstallDirOnDevice(name string, installDir string) android.FixturePreparer {
+ return FixtureModifyBootImageConfig(name, func(config *bootImageConfig) {
+ config.installDirOnDevice = installDir
+ })
+}
diff --git a/licenses/LICENSE b/licenses/LICENSE
index dae0406..d645695 100644
--- a/licenses/LICENSE
+++ b/licenses/LICENSE
@@ -1,16 +1,4 @@
- Copyright (c) The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
-
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
diff --git a/mk2rbc/expr.go b/mk2rbc/expr.go
index 7cd4899..3f355ac 100644
--- a/mk2rbc/expr.go
+++ b/mk2rbc/expr.go
@@ -119,6 +119,29 @@
}
}
+type globalsExpr struct {
+}
+
+func (g *globalsExpr) emit(gctx *generationContext) {
+ gctx.write("g")
+}
+
+func (g *globalsExpr) typ() starlarkType {
+ return starlarkTypeUnknown
+}
+
+func (g *globalsExpr) emitListVarCopy(gctx *generationContext) {
+ g.emit(gctx)
+}
+
+func (g *globalsExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
+ if replacement := transformer(g); replacement != nil {
+ return replacement
+ } else {
+ return g
+ }
+}
+
// interpolateExpr represents Starlark's interpolation operator <string> % list
// we break <string> into a list of chunks, i.e., "first%second%third" % (X, Y)
// will have chunks = ["first", "second", "third"] and args = [X, Y]
@@ -322,35 +345,6 @@
}
func (eq *eqExpr) emit(gctx *generationContext) {
- 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
- }
-
- // 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() {
eq.left = &toStringExpr{expr: eq.left}
eq.right = &toStringExpr{expr: eq.right}
@@ -594,29 +588,15 @@
}
func (cx *callExpr) emit(gctx *generationContext) {
- sep := ""
if cx.object != nil {
gctx.write("(")
cx.object.emit(gctx)
gctx.write(")")
gctx.write(".", cx.name, "(")
} else {
- kf, found := knownFunctions[cx.name]
- if !found {
- panic(fmt.Errorf("callExpr with unknown function %q", cx.name))
- }
- if kf.runtimeName[0] == '!' {
- panic(fmt.Errorf("callExpr for %q should not be there", cx.name))
- }
- gctx.write(kf.runtimeName, "(")
- if kf.hiddenArg == hiddenArgGlobal {
- gctx.write("g")
- sep = ", "
- } else if kf.hiddenArg == hiddenArgConfig {
- gctx.write("cfg")
- sep = ", "
- }
+ gctx.write(cx.name, "(")
}
+ sep := ""
for _, arg := range cx.args {
gctx.write(sep)
arg.emit(gctx)
@@ -748,6 +728,36 @@
}
}
+type binaryOpExpr struct {
+ left, right starlarkExpr
+ op string
+ returnType starlarkType
+}
+
+func (b *binaryOpExpr) emit(gctx *generationContext) {
+ b.left.emit(gctx)
+ gctx.write(" " + b.op + " ")
+ b.right.emit(gctx)
+}
+
+func (b *binaryOpExpr) typ() starlarkType {
+ return b.returnType
+}
+
+func (b *binaryOpExpr) emitListVarCopy(gctx *generationContext) {
+ b.emit(gctx)
+}
+
+func (b *binaryOpExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
+ b.left = b.left.transform(transformer)
+ b.right = b.right.transform(transformer)
+ if replacement := transformer(b); replacement != nil {
+ return replacement
+ } else {
+ return b
+ }
+}
+
type badExpr struct {
errorLocation ErrorLocation
message string
diff --git a/mk2rbc/mk2rbc.go b/mk2rbc/mk2rbc.go
index 024311e..e317cad 100644
--- a/mk2rbc/mk2rbc.go
+++ b/mk2rbc/mk2rbc.go
@@ -54,7 +54,6 @@
cfnMain = baseName + ".product_configuration"
cfnBoardMain = baseName + ".board_configuration"
cfnPrintVars = baseName + ".printvars"
- cfnPrintGlobals = baseName + ".printglobals"
cfnWarning = baseName + ".warning"
cfnLocalAppend = baseName + ".local_append"
cfnLocalSetDefault = baseName + ".local_set_default"
@@ -63,92 +62,78 @@
)
const (
- // Phony makefile functions, they are eventually rewritten
- // according to knownFunctions map
- fileExistsPhony = "$file_exists"
- // The following two macros are obsolete, and will we deleted once
- // there are deleted from the makefiles:
- soongConfigNamespaceOld = "add_soong_config_namespace"
- soongConfigVarSetOld = "add_soong_config_var_value"
- soongConfigAppend = "soong_config_append"
- soongConfigAssign = "soong_config_set"
- soongConfigGet = "soong_config_get"
- wildcardExistsPhony = "$wildcard_exists"
+ soongConfigAppend = "soong_config_append"
+ soongConfigAssign = "soong_config_set"
)
-const (
- callLoadAlways = "inherit-product"
- callLoadIf = "inherit-product-if-exists"
-)
-
-var knownFunctions = map[string]struct {
- // The name of the runtime function this function call in makefiles maps to.
- // If it starts with !, then this makefile function call is rewritten to
- // something else.
- runtimeName string
- returnType starlarkType
- hiddenArg hiddenArgType
+var knownFunctions = map[string]interface {
+ parse(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString) starlarkExpr
}{
- "abspath": {baseName + ".abspath", starlarkTypeString, hiddenArgNone},
- fileExistsPhony: {baseName + ".file_exists", starlarkTypeBool, hiddenArgNone},
- wildcardExistsPhony: {baseName + ".file_wildcard_exists", starlarkTypeBool, hiddenArgNone},
- soongConfigNamespaceOld: {baseName + ".soong_config_namespace", starlarkTypeVoid, hiddenArgGlobal},
- soongConfigVarSetOld: {baseName + ".soong_config_set", starlarkTypeVoid, hiddenArgGlobal},
- soongConfigAssign: {baseName + ".soong_config_set", starlarkTypeVoid, hiddenArgGlobal},
- soongConfigAppend: {baseName + ".soong_config_append", starlarkTypeVoid, hiddenArgGlobal},
- soongConfigGet: {baseName + ".soong_config_get", starlarkTypeString, hiddenArgGlobal},
- "add-to-product-copy-files-if-exists": {baseName + ".copy_if_exists", starlarkTypeList, hiddenArgNone},
- "addprefix": {baseName + ".addprefix", starlarkTypeList, hiddenArgNone},
- "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": {baseName + ".findstring", starlarkTypeString, hiddenArgNone},
- "find-copy-subdir-files": {baseName + ".find_and_copy", starlarkTypeList, hiddenArgNone},
- "find-word-in-list": {"!find-word-in-list", starlarkTypeUnknown, hiddenArgNone}, // internal macro
- "filter": {baseName + ".filter", starlarkTypeList, hiddenArgNone},
- "filter-out": {baseName + ".filter_out", starlarkTypeList, hiddenArgNone},
- "firstword": {"!firstword", starlarkTypeString, hiddenArgNone},
- "foreach": {"!foreach", starlarkTypeList, hiddenArgNone},
- "get-vendor-board-platforms": {"!get-vendor-board-platforms", starlarkTypeList, hiddenArgNone}, // internal macro, used by is-board-platform, etc.
- "if": {"!if", starlarkTypeUnknown, hiddenArgNone},
- "info": {baseName + ".mkinfo", starlarkTypeVoid, hiddenArgNone},
- "is-android-codename": {"!is-android-codename", starlarkTypeBool, hiddenArgNone}, // unused by product config
- "is-android-codename-in-list": {"!is-android-codename-in-list", starlarkTypeBool, hiddenArgNone}, // unused by product config
- "is-board-platform": {"!is-board-platform", starlarkTypeBool, hiddenArgNone},
- "is-board-platform2": {baseName + ".board_platform_is", starlarkTypeBool, hiddenArgGlobal},
- "is-board-platform-in-list": {"!is-board-platform-in-list", starlarkTypeBool, hiddenArgNone},
- "is-board-platform-in-list2": {baseName + ".board_platform_in", starlarkTypeBool, hiddenArgGlobal},
- "is-chipset-in-board-platform": {"!is-chipset-in-board-platform", starlarkTypeUnknown, hiddenArgNone}, // unused by product config
- "is-chipset-prefix-in-board-platform": {"!is-chipset-prefix-in-board-platform", starlarkTypeBool, hiddenArgNone}, // unused by product config
- "is-not-board-platform": {"!is-not-board-platform", starlarkTypeBool, hiddenArgNone}, // defined but never used
- "is-platform-sdk-version-at-least": {"!is-platform-sdk-version-at-least", starlarkTypeBool, hiddenArgNone}, // unused by product config
- "is-product-in-list": {"!is-product-in-list", starlarkTypeBool, hiddenArgNone},
- "is-vendor-board-platform": {"!is-vendor-board-platform", starlarkTypeBool, hiddenArgNone},
- "is-vendor-board-qcom": {"!is-vendor-board-qcom", starlarkTypeBool, hiddenArgNone},
- callLoadAlways: {"!inherit-product", starlarkTypeVoid, hiddenArgNone},
- callLoadIf: {"!inherit-product-if-exists", starlarkTypeVoid, hiddenArgNone},
- "lastword": {"!lastword", starlarkTypeString, hiddenArgNone},
- "match-prefix": {"!match-prefix", starlarkTypeUnknown, hiddenArgNone}, // internal macro
- "match-word": {"!match-word", starlarkTypeUnknown, hiddenArgNone}, // internal macro
- "match-word-in-list": {"!match-word-in-list", starlarkTypeUnknown, hiddenArgNone}, // internal macro
- "notdir": {baseName + ".notdir", starlarkTypeString, hiddenArgNone},
- "my-dir": {"!my-dir", starlarkTypeString, hiddenArgNone},
- "patsubst": {baseName + ".mkpatsubst", starlarkTypeString, hiddenArgNone},
- "product-copy-files-by-pattern": {baseName + ".product_copy_files_by_pattern", starlarkTypeList, hiddenArgNone},
- "require-artifacts-in-path": {baseName + ".require_artifacts_in_path", starlarkTypeVoid, hiddenArgNone},
- "require-artifacts-in-path-relaxed": {baseName + ".require_artifacts_in_path_relaxed", starlarkTypeVoid, hiddenArgNone},
+ "abspath": &simpleCallParser{name: baseName + ".abspath", returnType: starlarkTypeString, addGlobals: false},
+ "add_soong_config_namespace": &simpleCallParser{name: baseName + ".soong_config_namespace", returnType: starlarkTypeVoid, addGlobals: true},
+ "add_soong_config_var_value": &simpleCallParser{name: baseName + ".soong_config_set", returnType: starlarkTypeVoid, addGlobals: true},
+ soongConfigAssign: &simpleCallParser{name: baseName + ".soong_config_set", returnType: starlarkTypeVoid, addGlobals: true},
+ soongConfigAppend: &simpleCallParser{name: baseName + ".soong_config_append", returnType: starlarkTypeVoid, addGlobals: true},
+ "soong_config_get": &simpleCallParser{name: baseName + ".soong_config_get", returnType: starlarkTypeString, addGlobals: true},
+ "add-to-product-copy-files-if-exists": &simpleCallParser{name: baseName + ".copy_if_exists", returnType: starlarkTypeList, addGlobals: false},
+ "addprefix": &simpleCallParser{name: baseName + ".addprefix", returnType: starlarkTypeList, addGlobals: false},
+ "addsuffix": &simpleCallParser{name: baseName + ".addsuffix", returnType: starlarkTypeList, addGlobals: false},
+ "copy-files": &simpleCallParser{name: baseName + ".copy_files", returnType: starlarkTypeList, addGlobals: false},
+ "dir": &simpleCallParser{name: baseName + ".dir", returnType: starlarkTypeList, addGlobals: false},
+ "dist-for-goals": &simpleCallParser{name: baseName + ".mkdist_for_goals", returnType: starlarkTypeVoid, addGlobals: true},
+ "enforce-product-packages-exist": &simpleCallParser{name: baseName + ".enforce_product_packages_exist", returnType: starlarkTypeVoid, addGlobals: false},
+ "error": &makeControlFuncParser{name: baseName + ".mkerror"},
+ "findstring": &simpleCallParser{name: baseName + ".findstring", returnType: starlarkTypeInt, addGlobals: false},
+ "find-copy-subdir-files": &simpleCallParser{name: baseName + ".find_and_copy", returnType: starlarkTypeList, addGlobals: false},
+ "filter": &simpleCallParser{name: baseName + ".filter", returnType: starlarkTypeList, addGlobals: false},
+ "filter-out": &simpleCallParser{name: baseName + ".filter_out", returnType: starlarkTypeList, addGlobals: false},
+ "firstword": &firstOrLastwordCallParser{isLastWord: false},
+ "foreach": &foreachCallPaser{},
+ "if": &ifCallParser{},
+ "info": &makeControlFuncParser{name: baseName + ".mkinfo"},
+ "is-board-platform": &simpleCallParser{name: baseName + ".board_platform_is", returnType: starlarkTypeBool, addGlobals: true},
+ "is-board-platform2": &simpleCallParser{name: baseName + ".board_platform_is", returnType: starlarkTypeBool, addGlobals: true},
+ "is-board-platform-in-list": &simpleCallParser{name: baseName + ".board_platform_in", returnType: starlarkTypeBool, addGlobals: true},
+ "is-board-platform-in-list2": &simpleCallParser{name: baseName + ".board_platform_in", returnType: starlarkTypeBool, addGlobals: true},
+ "is-product-in-list": &isProductInListCallParser{},
+ "is-vendor-board-platform": &isVendorBoardPlatformCallParser{},
+ "is-vendor-board-qcom": &isVendorBoardQcomCallParser{},
+ "lastword": &firstOrLastwordCallParser{isLastWord: true},
+ "notdir": &simpleCallParser{name: baseName + ".notdir", returnType: starlarkTypeString, addGlobals: false},
+ "math_max": &mathMaxOrMinCallParser{function: "max"},
+ "math_min": &mathMaxOrMinCallParser{function: "min"},
+ "math_gt_or_eq": &mathComparisonCallParser{op: ">="},
+ "math_gt": &mathComparisonCallParser{op: ">"},
+ "math_lt": &mathComparisonCallParser{op: "<"},
+ "my-dir": &myDirCallParser{},
+ "patsubst": &substCallParser{fname: "patsubst"},
+ "product-copy-files-by-pattern": &simpleCallParser{name: baseName + ".product_copy_files_by_pattern", returnType: starlarkTypeList, addGlobals: false},
+ "require-artifacts-in-path": &simpleCallParser{name: baseName + ".require_artifacts_in_path", returnType: starlarkTypeVoid, addGlobals: false},
+ "require-artifacts-in-path-relaxed": &simpleCallParser{name: baseName + ".require_artifacts_in_path_relaxed", returnType: starlarkTypeVoid, addGlobals: false},
// TODO(asmundak): remove it once all calls are removed from configuration makefiles. see b/183161002
- "shell": {baseName + ".shell", starlarkTypeString, hiddenArgNone},
- "strip": {baseName + ".mkstrip", starlarkTypeString, hiddenArgNone},
- "tb-modules": {"!tb-modules", starlarkTypeUnknown, hiddenArgNone}, // defined in hardware/amlogic/tb_modules/tb_detect.mk, unused
- "subst": {baseName + ".mksubst", starlarkTypeString, hiddenArgNone},
- "warning": {baseName + ".mkwarning", starlarkTypeVoid, hiddenArgNone},
- "word": {baseName + "!word", starlarkTypeString, hiddenArgNone},
- "wildcard": {baseName + ".expand_wildcard", starlarkTypeList, hiddenArgNone},
- "words": {baseName + ".words", starlarkTypeList, hiddenArgNone},
+ "shell": &shellCallParser{},
+ "strip": &simpleCallParser{name: baseName + ".mkstrip", returnType: starlarkTypeString, addGlobals: false},
+ "subst": &substCallParser{fname: "subst"},
+ "warning": &makeControlFuncParser{name: baseName + ".mkwarning"},
+ "word": &wordCallParser{},
+ "wildcard": &simpleCallParser{name: baseName + ".expand_wildcard", returnType: starlarkTypeList, addGlobals: false},
+}
+
+// These are functions that we don't implement conversions for, but
+// we allow seeing their definitions in the product config files.
+var ignoredDefines = map[string]bool{
+ "find-word-in-list": true, // internal macro
+ "get-vendor-board-platforms": true, // internal macro, used by is-board-platform, etc.
+ "is-android-codename": true, // unused by product config
+ "is-android-codename-in-list": true, // unused by product config
+ "is-chipset-in-board-platform": true, // unused by product config
+ "is-chipset-prefix-in-board-platform": true, // unused by product config
+ "is-not-board-platform": true, // defined but never used
+ "is-platform-sdk-version-at-least": true, // unused by product config
+ "match-prefix": true, // internal macro
+ "match-word": true, // internal macro
+ "match-word-in-list": true, // internal macro
+ "tb-modules": true, // defined in hardware/amlogic/tb_modules/tb_detect.mk, unused
}
var identifierFullMatchRegex = regexp.MustCompile("^[a-zA-Z_][a-zA-Z0-9_]*$")
@@ -269,19 +254,19 @@
gctx.writef("load(%q, %q)", baseUri, baseName)
// Emit exactly one load statement for each URI.
loadedSubConfigs := make(map[string]string)
- for _, sc := range gctx.starScript.inherited {
- uri := sc.path
+ for _, mi := range gctx.starScript.inherited {
+ uri := mi.path
if m, ok := loadedSubConfigs[uri]; ok {
// No need to emit load statement, but fix module name.
- sc.moduleLocalName = m
+ mi.moduleLocalName = m
continue
}
- if sc.optional {
+ if mi.optional || mi.missing {
uri += "|init"
}
gctx.newLine()
- gctx.writef("load(%q, %s = \"init\")", uri, sc.entryName())
- loadedSubConfigs[uri] = sc.moduleLocalName
+ gctx.writef("load(%q, %s = \"init\")", uri, mi.entryName())
+ loadedSubConfigs[uri] = mi.moduleLocalName
}
gctx.write("\n")
}
@@ -313,6 +298,20 @@
gctx.writef(`rblf.mk2rbc_error("%s", %q)`, el, message)
}
+func (gctx *generationContext) emitLoadCheck(im inheritedModule) {
+ if !im.needsLoadCheck() {
+ return
+ }
+ gctx.newLine()
+ gctx.writef("if not %s:", im.entryName())
+ gctx.indentLevel++
+ gctx.newLine()
+ gctx.write(`rblf.mkerror("`, gctx.starScript.mkFile, `", "Cannot find %s" % (`)
+ im.pathExpr().emit(gctx)
+ gctx.write("))")
+ gctx.indentLevel--
+}
+
type knownVariable struct {
name string
class varClass
@@ -466,7 +465,7 @@
variables: make(map[string]variable),
dependentModules: make(map[string]*moduleInfo),
soongNamespaces: make(map[string]map[string]bool),
- includeTops: []string{"vendor/google-devices"},
+ includeTops: []string{},
}
ctx.pushVarAssignments()
for _, item := range predefined {
@@ -641,8 +640,8 @@
for _, ns := range strings.Fields(s) {
ctx.addSoongNamespace(ns)
ctx.receiver.newNode(&exprNode{&callExpr{
- name: soongConfigNamespaceOld,
- args: []starlarkExpr{&stringLiteralExpr{ns}},
+ name: baseName + ".soong_config_namespace",
+ args: []starlarkExpr{&globalsExpr{}, &stringLiteralExpr{ns}},
returnType: starlarkTypeVoid,
}})
}
@@ -691,13 +690,13 @@
ctx.errorf(asgn, "no %s variable in %s namespace, please use add_soong_config_var_value instead", varName, namespaceName)
return
}
- fname := soongConfigAssign
+ fname := baseName + "." + soongConfigAssign
if asgn.Type == "+=" {
- fname = soongConfigAppend
+ fname = baseName + "." + soongConfigAppend
}
ctx.receiver.newNode(&exprNode{&callExpr{
name: fname,
- args: []starlarkExpr{&stringLiteralExpr{namespaceName}, &stringLiteralExpr{varName}, val},
+ args: []starlarkExpr{&globalsExpr{}, &stringLiteralExpr{namespaceName}, &stringLiteralExpr{varName}, val},
returnType: starlarkTypeVoid,
}})
}
@@ -766,11 +765,13 @@
moduleLocalName += fmt.Sprintf("%d", n)
}
ctx.moduleNameCount[moduleName] = n + 1
+ _, err := fs.Stat(ctx.script.sourceFS, path)
mi := &moduleInfo{
path: modulePath,
originalPath: path,
moduleLocalName: moduleLocalName,
optional: optional,
+ missing: err != nil,
}
ctx.dependentModules[modulePath] = mi
ctx.script.inherited = append(ctx.script.inherited, mi)
@@ -829,6 +830,10 @@
}
}
if pathPattern[0] == "" {
+ if len(ctx.includeTops) == 0 {
+ ctx.errorf(v, "inherit-product/include statements must not be prefixed with a variable, or must include a #RBC# include_top comment beforehand giving a root directory to search.")
+ return
+ }
// If pattern starts from the top. restrict it to the directories where
// we know inherit-product uses dynamically calculated path.
for _, p := range ctx.includeTops {
@@ -878,7 +883,13 @@
return res
}
-func (ctx *parseContext) handleInheritModule(v mkparser.Node, pathExpr starlarkExpr, loadAlways bool) {
+func (ctx *parseContext) handleInheritModule(v mkparser.Node, args *mkparser.MakeString, loadAlways bool) {
+ args.TrimLeftSpaces()
+ args.TrimRightSpaces()
+ pathExpr := ctx.parseMakeString(v, args)
+ if _, ok := pathExpr.(*badExpr); ok {
+ ctx.errorf(v, "Unable to parse argument to inherit")
+ }
ctx.handleSubConfig(v, pathExpr, loadAlways, func(im inheritedModule) {
ctx.receiver.newNode(&inheritNode{im, loadAlways})
})
@@ -897,36 +908,40 @@
// $(info xxx)
// $(warning xxx)
// $(error xxx)
+ // $(call other-custom-functions,...)
+
+ // inherit-product(-if-exists) gets converted to a series of statements,
+ // not just a single expression like parseReference returns. So handle it
+ // separately at the beginning here.
+ if strings.HasPrefix(v.Name.Dump(), "call inherit-product,") {
+ args := v.Name.Clone()
+ args.ReplaceLiteral("call inherit-product,", "")
+ ctx.handleInheritModule(v, args, true)
+ return
+ }
+ if strings.HasPrefix(v.Name.Dump(), "call inherit-product-if-exists,") {
+ args := v.Name.Clone()
+ args.ReplaceLiteral("call inherit-product-if-exists,", "")
+ ctx.handleInheritModule(v, args, false)
+ return
+ }
expr := ctx.parseReference(v, v.Name)
switch x := expr.(type) {
case *callExpr:
- if x.name == callLoadAlways || x.name == callLoadIf {
- ctx.handleInheritModule(v, x.args[0], x.name == callLoadAlways)
- } else if isMakeControlFunc(x.name) {
- // File name is the first argument
- args := []starlarkExpr{
- &stringLiteralExpr{ctx.script.mkFile},
- x.args[0],
- }
- ctx.receiver.newNode(&exprNode{
- &callExpr{name: x.name, args: args, returnType: starlarkTypeUnknown},
- })
- } else {
- ctx.receiver.newNode(&exprNode{expr})
- }
+ ctx.receiver.newNode(&exprNode{expr})
case *badExpr:
ctx.wrapBadExpr(x)
- return
default:
ctx.errorf(v, "cannot handle %s", v.Dump())
- return
}
}
func (ctx *parseContext) handleDefine(directive *mkparser.Directive) {
macro_name := strings.Fields(directive.Args.Strings[0])[0]
// Ignore the macros that we handle
- if _, ok := knownFunctions[macro_name]; !ok {
+ _, ignored := ignoredDefines[macro_name]
+ _, known := knownFunctions[macro_name]
+ if !ignored && !known {
ctx.errorf(directive, "define is not supported: %s", macro_name)
}
}
@@ -1056,6 +1071,72 @@
return expr
}
+ var stringOperand string
+ var otherOperand starlarkExpr
+ if s, ok := maybeString(xLeft); ok {
+ stringOperand = s
+ otherOperand = xRight
+ } else if s, ok := maybeString(xRight); ok {
+ stringOperand = s
+ otherOperand = xLeft
+ }
+
+ not := func(expr starlarkExpr) starlarkExpr {
+ switch typedExpr := expr.(type) {
+ case *inExpr:
+ typedExpr.isNot = !typedExpr.isNot
+ return typedExpr
+ case *eqExpr:
+ typedExpr.isEq = !typedExpr.isEq
+ return typedExpr
+ case *binaryOpExpr:
+ switch typedExpr.op {
+ case ">":
+ typedExpr.op = "<="
+ return typedExpr
+ case "<":
+ typedExpr.op = ">="
+ return typedExpr
+ case ">=":
+ typedExpr.op = "<"
+ return typedExpr
+ case "<=":
+ typedExpr.op = ">"
+ return typedExpr
+ default:
+ return ¬Expr{expr: expr}
+ }
+ default:
+ return ¬Expr{expr: expr}
+ }
+ }
+
+ // 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 isEq {
+ return not(otherOperand)
+ } else {
+ return otherOperand
+ }
+ }
+ if stringOperand == "true" && otherOperand.typ() == starlarkTypeBool {
+ if !isEq {
+ return not(otherOperand)
+ } else {
+ return otherOperand
+ }
+ }
+ if intOperand, err := strconv.Atoi(strings.TrimSpace(stringOperand)); err == nil && otherOperand.typ() == starlarkTypeInt {
+ return &eqExpr{
+ left: otherOperand,
+ right: &intLiteralExpr{literal: intOperand},
+ isEq: isEq,
+ }
+ }
+ }
+
return &eqExpr{left: xLeft, right: xRight, isEq: isEq}
}
@@ -1089,97 +1170,15 @@
return nil, false
}
- checkIsSomethingFunction := func(xCall *callExpr) starlarkExpr {
- s, ok := maybeString(value)
- if !ok || s != "true" {
- return ctx.newBadExpr(directive,
- fmt.Sprintf("the result of %s can be compared only to 'true'", xCall.name))
- }
- if len(xCall.args) < 1 {
- return ctx.newBadExpr(directive, "%s requires an argument", xCall.name)
- }
- return nil
- }
-
switch call.name {
- case "filter", "filter-out":
+ case baseName + ".filter", baseName + ".filter-out":
return ctx.parseCompareFilterFuncResult(directive, call, value, isEq), true
- case "wildcard":
+ case baseName + ".expand_wildcard":
return ctx.parseCompareWildcardFuncResult(directive, call, value, !isEq), true
- case "findstring":
+ case baseName + ".findstring":
return ctx.parseCheckFindstringFuncResult(directive, call, value, !isEq), true
- case "strip":
+ case baseName + ".strip":
return ctx.parseCompareStripFuncResult(directive, call, value, !isEq), true
- case "is-board-platform":
- if xBad := checkIsSomethingFunction(call); xBad != nil {
- return xBad, true
- }
- return &eqExpr{
- left: NewVariableRefExpr(ctx.addVariable("TARGET_BOARD_PLATFORM"), false),
- right: call.args[0],
- isEq: isEq,
- }, true
- case "is-board-platform-in-list":
- if xBad := checkIsSomethingFunction(call); xBad != nil {
- return xBad, true
- }
- return &inExpr{
- expr: NewVariableRefExpr(ctx.addVariable("TARGET_BOARD_PLATFORM"), false),
- list: maybeConvertToStringList(call.args[0]),
- isNot: !isEq,
- }, true
- case "is-product-in-list":
- if xBad := checkIsSomethingFunction(call); xBad != nil {
- return xBad, true
- }
- return &inExpr{
- expr: NewVariableRefExpr(ctx.addVariable("TARGET_PRODUCT"), true),
- list: maybeConvertToStringList(call.args[0]),
- isNot: !isEq,
- }, true
- case "is-vendor-board-platform":
- if xBad := checkIsSomethingFunction(call); xBad != nil {
- return xBad, true
- }
- s, ok := maybeString(call.args[0])
- if !ok {
- return ctx.newBadExpr(directive, "cannot handle non-constant argument to is-vendor-board-platform"), true
- }
- return &inExpr{
- expr: NewVariableRefExpr(ctx.addVariable("TARGET_BOARD_PLATFORM"), false),
- list: NewVariableRefExpr(ctx.addVariable(s+"_BOARD_PLATFORMS"), true),
- isNot: !isEq,
- }, true
-
- case "is-board-platform2", "is-board-platform-in-list2":
- if s, ok := maybeString(value); !ok || s != "" {
- return ctx.newBadExpr(directive,
- fmt.Sprintf("the result of %s can be compared only to empty", call.name)), true
- }
- if len(call.args) != 1 {
- return ctx.newBadExpr(directive, "%s requires an argument", call.name), true
- }
- cc := &callExpr{
- name: call.name,
- args: []starlarkExpr{call.args[0]},
- returnType: starlarkTypeBool,
- }
- if isEq {
- return ¬Expr{cc}, true
- }
- return cc, true
- case "is-vendor-board-qcom":
- if s, ok := maybeString(value); !ok || s != "" {
- return ctx.newBadExpr(directive,
- fmt.Sprintf("the result of %s can be compared only to empty", call.name)), true
- }
- // if the expression is ifneq (,$(call is-vendor-board-platform,...)), negate==true,
- // so we should set inExpr.isNot to false
- return &inExpr{
- expr: NewVariableRefExpr(ctx.addVariable("TARGET_BOARD_PLATFORM"), false),
- list: NewVariableRefExpr(ctx.addVariable("QCOM_BOARD_PLATFORMS"), true),
- isNot: isEq,
- }, true
}
return nil, false
}
@@ -1254,9 +1253,9 @@
if !isEmptyString(xValue) {
return ctx.newBadExpr(directive, "wildcard result can be compared only to empty: %s", xValue)
}
- callFunc := wildcardExistsPhony
+ callFunc := baseName + ".file_wildcard_exists"
if s, ok := xCall.args[0].(*stringLiteralExpr); ok && !strings.ContainsAny(s.literal, "*?{[") {
- callFunc = fileExistsPhony
+ callFunc = baseName + ".file_exists"
}
var cc starlarkExpr = &callExpr{name: callFunc, args: xCall.args, returnType: starlarkTypeBool}
if !negate {
@@ -1323,14 +1322,7 @@
// If it is a single word, it can be a simple variable
// reference or a function call
- if len(words) == 1 {
- if isMakeControlFunc(refDump) || refDump == "shell" {
- return &callExpr{
- name: refDump,
- args: []starlarkExpr{&stringLiteralExpr{""}},
- returnType: starlarkTypeUnknown,
- }
- }
+ if len(words) == 1 && !isMakeControlFunc(refDump) && refDump != "shell" {
if strings.HasPrefix(refDump, soongNsPrefix) {
// TODO (asmundak): if we find many, maybe handle them.
return ctx.newBadExpr(node, "SOONG_CONFIG_ variables cannot be referenced, use soong_config_get instead: %s", refDump)
@@ -1354,8 +1346,8 @@
return ctx.newBadExpr(node, "unknown variable %s", refDump)
}
return &callExpr{
- name: "patsubst",
- returnType: knownFunctions["patsubst"].returnType,
+ name: baseName + ".mkpatsubst",
+ returnType: starlarkTypeString,
args: []starlarkExpr{
&stringLiteralExpr{literal: substParts[0]},
&stringLiteralExpr{literal: substParts[1]},
@@ -1370,18 +1362,11 @@
}
expr := &callExpr{name: words[0].Dump(), returnType: starlarkTypeUnknown}
- args := words[1]
- args.TrimLeftSpaces()
- // Make control functions and shell need special treatment as everything
- // after the name is a single text argument
- if isMakeControlFunc(expr.name) || expr.name == "shell" {
- x := ctx.parseMakeString(node, args)
- if xBad, ok := x.(*badExpr); ok {
- return xBad
- }
- expr.args = []starlarkExpr{x}
- return expr
+ args := mkparser.SimpleMakeString("", words[0].Pos())
+ if len(words) >= 2 {
+ args = words[1]
}
+ args.TrimLeftSpaces()
if expr.name == "call" {
words = args.SplitN(",", 2)
if words[0].Empty() || !words[0].Const() {
@@ -1395,41 +1380,128 @@
}
}
if kf, found := knownFunctions[expr.name]; found {
- expr.returnType = kf.returnType
+ return kf.parse(ctx, node, args)
} else {
return ctx.newBadExpr(node, "cannot handle invoking %s", expr.name)
}
- switch expr.name {
- case "if":
- return ctx.parseIfFunc(node, args)
- case "foreach":
- return ctx.parseForeachFunc(node, args)
- case "word":
- return ctx.parseWordFunc(node, args)
- case "firstword", "lastword":
- return ctx.parseFirstOrLastwordFunc(node, expr.name, args)
- case "my-dir":
- return NewVariableRefExpr(ctx.addVariable("LOCAL_PATH"), true)
- case "subst", "patsubst":
- return ctx.parseSubstFunc(node, expr.name, args)
- default:
- for _, arg := range args.Split(",") {
- arg.TrimLeftSpaces()
- arg.TrimRightSpaces()
- x := ctx.parseMakeString(node, arg)
- if xBad, ok := x.(*badExpr); ok {
- return xBad
- }
- expr.args = append(expr.args, x)
+}
+
+type simpleCallParser struct {
+ name string
+ returnType starlarkType
+ addGlobals bool
+}
+
+func (p *simpleCallParser) parse(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString) starlarkExpr {
+ expr := &callExpr{name: p.name, returnType: p.returnType}
+ if p.addGlobals {
+ expr.args = append(expr.args, &globalsExpr{})
+ }
+ for _, arg := range args.Split(",") {
+ arg.TrimLeftSpaces()
+ arg.TrimRightSpaces()
+ x := ctx.parseMakeString(node, arg)
+ if xBad, ok := x.(*badExpr); ok {
+ return xBad
}
+ expr.args = append(expr.args, x)
}
return expr
}
-func (ctx *parseContext) parseSubstFunc(node mkparser.Node, fname string, args *mkparser.MakeString) starlarkExpr {
+type makeControlFuncParser struct {
+ name string
+}
+
+func (p *makeControlFuncParser) parse(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString) starlarkExpr {
+ // Make control functions need special treatment as everything
+ // after the name is a single text argument
+ x := ctx.parseMakeString(node, args)
+ if xBad, ok := x.(*badExpr); ok {
+ return xBad
+ }
+ return &callExpr{
+ name: p.name,
+ args: []starlarkExpr{
+ &stringLiteralExpr{ctx.script.mkFile},
+ x,
+ },
+ returnType: starlarkTypeUnknown,
+ }
+}
+
+type shellCallParser struct{}
+
+func (p *shellCallParser) parse(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString) starlarkExpr {
+ // Shell functions need special treatment as everything
+ // after the name is a single text argument
+ x := ctx.parseMakeString(node, args)
+ if xBad, ok := x.(*badExpr); ok {
+ return xBad
+ }
+ return &callExpr{
+ name: baseName + ".shell",
+ args: []starlarkExpr{x},
+ returnType: starlarkTypeUnknown,
+ }
+}
+
+type myDirCallParser struct{}
+
+func (p *myDirCallParser) parse(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString) starlarkExpr {
+ if !args.Empty() {
+ return ctx.newBadExpr(node, "my-dir function cannot have any arguments passed to it.")
+ }
+ return &variableRefExpr{ctx.addVariable("LOCAL_PATH"), true}
+}
+
+type isProductInListCallParser struct{}
+
+func (p *isProductInListCallParser) parse(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString) starlarkExpr {
+ if args.Empty() {
+ return ctx.newBadExpr(node, "is-product-in-list requires an argument")
+ }
+ return &inExpr{
+ expr: &variableRefExpr{ctx.addVariable("TARGET_PRODUCT"), true},
+ list: maybeConvertToStringList(ctx.parseMakeString(node, args)),
+ isNot: false,
+ }
+}
+
+type isVendorBoardPlatformCallParser struct{}
+
+func (p *isVendorBoardPlatformCallParser) parse(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString) starlarkExpr {
+ if args.Empty() || !identifierFullMatchRegex.MatchString(args.Dump()) {
+ return ctx.newBadExpr(node, "cannot handle non-constant argument to is-vendor-board-platform")
+ }
+ return &inExpr{
+ expr: &variableRefExpr{ctx.addVariable("TARGET_BOARD_PLATFORM"), false},
+ list: &variableRefExpr{ctx.addVariable(args.Dump() + "_BOARD_PLATFORMS"), true},
+ isNot: false,
+ }
+}
+
+type isVendorBoardQcomCallParser struct{}
+
+func (p *isVendorBoardQcomCallParser) parse(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString) starlarkExpr {
+ if !args.Empty() {
+ return ctx.newBadExpr(node, "is-vendor-board-qcom does not accept any arguments")
+ }
+ return &inExpr{
+ expr: &variableRefExpr{ctx.addVariable("TARGET_BOARD_PLATFORM"), false},
+ list: &variableRefExpr{ctx.addVariable("QCOM_BOARD_PLATFORMS"), true},
+ isNot: false,
+ }
+}
+
+type substCallParser struct {
+ fname string
+}
+
+func (p *substCallParser) parse(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString) starlarkExpr {
words := args.Split(",")
if len(words) != 3 {
- return ctx.newBadExpr(node, "%s function should have 3 arguments", fname)
+ return ctx.newBadExpr(node, "%s function should have 3 arguments", p.fname)
}
from := ctx.parseMakeString(node, words[0])
if xBad, ok := from.(*badExpr); ok {
@@ -1443,7 +1515,7 @@
words[2].TrimRightSpaces()
obj := ctx.parseMakeString(node, words[2])
typ := obj.typ()
- if typ == starlarkTypeString && fname == "subst" {
+ if typ == starlarkTypeString && p.fname == "subst" {
// Optimization: if it's $(subst from, to, string), emit string.replace(from, to)
return &callExpr{
object: obj,
@@ -1453,13 +1525,15 @@
}
}
return &callExpr{
- name: fname,
+ name: baseName + ".mk" + p.fname,
args: []starlarkExpr{from, to, obj},
returnType: obj.typ(),
}
}
-func (ctx *parseContext) parseIfFunc(node mkparser.Node, args *mkparser.MakeString) starlarkExpr {
+type ifCallParser struct{}
+
+func (p *ifCallParser) parse(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString) starlarkExpr {
words := args.Split(",")
if len(words) != 2 && len(words) != 3 {
return ctx.newBadExpr(node, "if function should have 2 or 3 arguments, found "+strconv.Itoa(len(words)))
@@ -1488,7 +1562,9 @@
}
}
-func (ctx *parseContext) parseForeachFunc(node mkparser.Node, args *mkparser.MakeString) starlarkExpr {
+type foreachCallPaser struct{}
+
+func (p *foreachCallPaser) parse(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString) starlarkExpr {
words := args.Split(",")
if len(words) != 3 {
return ctx.newBadExpr(node, "foreach function should have 3 arguments, found "+strconv.Itoa(len(words)))
@@ -1507,8 +1583,8 @@
if list.typ() != starlarkTypeList {
list = &callExpr{
- name: "words",
- returnType: knownFunctions["words"].returnType,
+ name: baseName + ".words",
+ returnType: starlarkTypeList,
args: []starlarkExpr{list},
}
}
@@ -1520,7 +1596,9 @@
}
}
-func (ctx *parseContext) parseWordFunc(node mkparser.Node, args *mkparser.MakeString) starlarkExpr {
+type wordCallParser struct{}
+
+func (p *wordCallParser) parse(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString) starlarkExpr {
words := args.Split(",")
if len(words) != 2 {
return ctx.newBadExpr(node, "word function should have 2 arguments")
@@ -1544,13 +1622,17 @@
return &indexExpr{array, &intLiteralExpr{int(index - 1)}}
}
-func (ctx *parseContext) parseFirstOrLastwordFunc(node mkparser.Node, name string, args *mkparser.MakeString) starlarkExpr {
+type firstOrLastwordCallParser struct {
+ isLastWord bool
+}
+
+func (p *firstOrLastwordCallParser) parse(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString) starlarkExpr {
arg := ctx.parseMakeString(node, args)
if bad, ok := arg.(*badExpr); ok {
return bad
}
index := &intLiteralExpr{0}
- if name == "lastword" {
+ if p.isLastWord {
if v, ok := arg.(*variableRefExpr); ok && v.ref.name() == "MAKEFILE_LIST" {
return &stringLiteralExpr{ctx.script.mkFile}
}
@@ -1562,6 +1644,68 @@
return &indexExpr{&callExpr{object: arg, name: "split", returnType: starlarkTypeList}, index}
}
+func parseIntegerArguments(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString, expectedArgs int) ([]starlarkExpr, error) {
+ parsedArgs := make([]starlarkExpr, 0)
+ for _, arg := range args.Split(",") {
+ expr := ctx.parseMakeString(node, arg)
+ if expr.typ() == starlarkTypeList {
+ return nil, fmt.Errorf("argument to math argument has type list, which cannot be converted to int")
+ }
+ if s, ok := maybeString(expr); ok {
+ intVal, err := strconv.Atoi(strings.TrimSpace(s))
+ if err != nil {
+ return nil, err
+ }
+ expr = &intLiteralExpr{literal: intVal}
+ } else if expr.typ() != starlarkTypeInt {
+ expr = &callExpr{
+ name: "int",
+ args: []starlarkExpr{expr},
+ returnType: starlarkTypeInt,
+ }
+ }
+ parsedArgs = append(parsedArgs, expr)
+ }
+ if len(parsedArgs) != expectedArgs {
+ return nil, fmt.Errorf("function should have %d arguments", expectedArgs)
+ }
+ return parsedArgs, nil
+}
+
+type mathComparisonCallParser struct {
+ op string
+}
+
+func (p *mathComparisonCallParser) parse(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString) starlarkExpr {
+ parsedArgs, err := parseIntegerArguments(ctx, node, args, 2)
+ if err != nil {
+ return ctx.newBadExpr(node, err.Error())
+ }
+ return &binaryOpExpr{
+ left: parsedArgs[0],
+ right: parsedArgs[1],
+ op: p.op,
+ returnType: starlarkTypeBool,
+ }
+}
+
+type mathMaxOrMinCallParser struct {
+ function string
+}
+
+func (p *mathMaxOrMinCallParser) parse(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString) starlarkExpr {
+ parsedArgs, err := parseIntegerArguments(ctx, node, args, 2)
+ if err != nil {
+ return ctx.newBadExpr(node, err.Error())
+ }
+ return &callExpr{
+ object: nil,
+ name: p.function,
+ args: parsedArgs,
+ returnType: starlarkTypeInt,
+ }
+}
+
func (ctx *parseContext) parseMakeString(node mkparser.Node, mk *mkparser.MakeString) starlarkExpr {
if mk.Const() {
return &stringLiteralExpr{mk.Dump()}
@@ -1612,6 +1756,13 @@
default:
ctx.errorf(x, "unsupported line %s", strings.ReplaceAll(x.Dump(), "\n", "\n#"))
}
+
+ // Clear the includeTops after each non-comment statement
+ // so that include annotations placed on certain statements don't apply
+ // globally for the rest of the makefile was well.
+ if _, wasComment := node.(*mkparser.Comment); !wasComment && len(ctx.includeTops) > 0 {
+ ctx.includeTops = []string{}
+ }
}
// Processes annotation. An annotation is a comment that starts with #RBC# and provides
@@ -1629,6 +1780,13 @@
return
}
if p, ok := maybeTrim(annotation, "include_top"); ok {
+ // Don't allow duplicate include tops, because then we will generate
+ // invalid starlark code. (duplicate keys in the _entry dictionary)
+ for _, top := range ctx.includeTops {
+ if top == p {
+ return
+ }
+ }
ctx.includeTops = append(ctx.includeTops, p)
return
}
diff --git a/mk2rbc/mk2rbc_test.go b/mk2rbc/mk2rbc_test.go
index 94c4fe6..d62882d 100644
--- a/mk2rbc/mk2rbc_test.go
+++ b/mk2rbc/mk2rbc_test.go
@@ -121,7 +121,7 @@
ifdef PRODUCT_NAME
$(call inherit-product, part1.mk)
else # Comment
-$(call inherit-product, $(LOCAL_PATH)/part1.mk)
+$(call inherit-product, $(LOCAL_PATH)/part.mk)
endif
`,
expected: `load("//build/make/core:product_config.rbc", "rblf")
@@ -132,10 +132,12 @@
cfg = rblf.cfg(handle)
rblf.inherit(handle, "part", _part_init)
if g.get("PRODUCT_NAME") != None:
+ if not _part1_init:
+ rblf.mkerror("product.mk", "Cannot find %s" % (":part1.star"))
rblf.inherit(handle, "part1", _part1_init)
else:
# Comment
- rblf.inherit(handle, "part1", _part1_init)
+ rblf.inherit(handle, "part", _part_init)
`,
},
{
@@ -173,6 +175,8 @@
cfg = rblf.cfg(handle)
_part_init(g, handle)
if g.get("PRODUCT_NAME") != None:
+ if not _part1_init:
+ rblf.mkerror("product.mk", "Cannot find %s" % (":part1.star"))
_part1_init(g, handle)
else:
if _part1_init != None:
@@ -598,9 +602,9 @@
def init(g, handle):
cfg = rblf.cfg(handle)
- if g.get("TARGET_BOARD_PLATFORM", "") in ["msm8998"]:
+ if rblf.board_platform_in(g, "msm8998"):
pass
- elif g.get("TARGET_BOARD_PLATFORM", "") != "copper":
+ elif not rblf.board_platform_is(g, "copper"):
pass
elif g.get("TARGET_BOARD_PLATFORM", "") not in g["QCOM_BOARD_PLATFORMS"]:
pass
@@ -1049,7 +1053,7 @@
}.get("vendor/%s/cfg.mk" % g["MY_PATH"])
(_varmod, _varmod_init) = _entry if _entry else (None, None)
if not _varmod_init:
- rblf.mkerror("cannot")
+ rblf.mkerror("product.mk", "Cannot find %s" % ("vendor/%s/cfg.mk" % g["MY_PATH"]))
rblf.inherit(handle, _varmod, _varmod_init)
`,
},
@@ -1073,11 +1077,85 @@
}.get("%s/cfg.mk" % g["MY_PATH"])
(_varmod, _varmod_init) = _entry if _entry else (None, None)
if not _varmod_init:
- rblf.mkerror("cannot")
+ rblf.mkerror("product.mk", "Cannot find %s" % ("%s/cfg.mk" % g["MY_PATH"]))
rblf.inherit(handle, _varmod, _varmod_init)
`,
},
{
+ desc: "Dynamic inherit with duplicated hint",
+ mkname: "product.mk",
+ in: `
+MY_PATH:=foo
+#RBC# include_top vendor/foo1
+$(call inherit-product,$(MY_PATH)/cfg.mk)
+#RBC# include_top vendor/foo1
+$(call inherit-product,$(MY_PATH)/cfg.mk)
+`,
+ expected: `load("//build/make/core:product_config.rbc", "rblf")
+load("//vendor/foo1:cfg.star|init", _cfg_init = "init")
+
+def init(g, handle):
+ cfg = rblf.cfg(handle)
+ g["MY_PATH"] = "foo"
+ #RBC# include_top vendor/foo1
+ _entry = {
+ "vendor/foo1/cfg.mk": ("_cfg", _cfg_init),
+ }.get("%s/cfg.mk" % g["MY_PATH"])
+ (_varmod, _varmod_init) = _entry if _entry else (None, None)
+ if not _varmod_init:
+ rblf.mkerror("product.mk", "Cannot find %s" % ("%s/cfg.mk" % g["MY_PATH"]))
+ rblf.inherit(handle, _varmod, _varmod_init)
+ #RBC# include_top vendor/foo1
+ _entry = {
+ "vendor/foo1/cfg.mk": ("_cfg", _cfg_init),
+ }.get("%s/cfg.mk" % g["MY_PATH"])
+ (_varmod, _varmod_init) = _entry if _entry else (None, None)
+ if not _varmod_init:
+ rblf.mkerror("product.mk", "Cannot find %s" % ("%s/cfg.mk" % g["MY_PATH"]))
+ rblf.inherit(handle, _varmod, _varmod_init)
+`,
+ },
+ {
+ desc: "Dynamic inherit path that lacks necessary hint",
+ mkname: "product.mk",
+ in: `
+#RBC# include_top foo
+$(call inherit-product,$(MY_VAR)/font.mk)
+
+#RBC# include_top foo
+
+# There's some space and even this comment between the include_top and the inherit-product
+
+$(call inherit-product,$(MY_VAR)/font.mk)
+
+$(call inherit-product,$(MY_VAR)/font.mk)
+`,
+ expected: `#RBC# include_top foo
+load("//build/make/core:product_config.rbc", "rblf")
+load("//foo:font.star|init", _font_init = "init")
+
+def init(g, handle):
+ cfg = rblf.cfg(handle)
+ _entry = {
+ "foo/font.mk": ("_font", _font_init),
+ }.get("%s/font.mk" % g.get("MY_VAR", ""))
+ (_varmod, _varmod_init) = _entry if _entry else (None, None)
+ if not _varmod_init:
+ rblf.mkerror("product.mk", "Cannot find %s" % ("%s/font.mk" % g.get("MY_VAR", "")))
+ rblf.inherit(handle, _varmod, _varmod_init)
+ #RBC# include_top foo
+ # There's some space and even this comment between the include_top and the inherit-product
+ _entry = {
+ "foo/font.mk": ("_font", _font_init),
+ }.get("%s/font.mk" % g.get("MY_VAR", ""))
+ (_varmod, _varmod_init) = _entry if _entry else (None, None)
+ if not _varmod_init:
+ rblf.mkerror("product.mk", "Cannot find %s" % ("%s/font.mk" % g.get("MY_VAR", "")))
+ rblf.inherit(handle, _varmod, _varmod_init)
+ rblf.mk2rbc_error("product.mk:11", "inherit-product/include statements must not be prefixed with a variable, or must include a #RBC# include_top comment beforehand giving a root directory to search.")
+`,
+ },
+ {
desc: "Ignore make rules",
mkname: "product.mk",
in: `
@@ -1180,6 +1258,90 @@
g["BOOT_KERNEL_MODULES_FILTER_2"] = ["%%/%s" % m for m in g["BOOT_KERNEL_MODULES_LIST"]]
`,
},
+ {
+ desc: "List appended to string",
+ mkname: "product.mk",
+ in: `
+NATIVE_BRIDGE_PRODUCT_PACKAGES := \
+ libnative_bridge_vdso.native_bridge \
+ native_bridge_guest_app_process.native_bridge \
+ native_bridge_guest_linker.native_bridge
+
+NATIVE_BRIDGE_MODIFIED_GUEST_LIBS := \
+ libaaudio \
+ libamidi \
+ libandroid \
+ libandroid_runtime
+
+NATIVE_BRIDGE_PRODUCT_PACKAGES += \
+ $(addsuffix .native_bridge,$(NATIVE_BRIDGE_ORIG_GUEST_LIBS))
+`,
+ expected: `load("//build/make/core:product_config.rbc", "rblf")
+
+def init(g, handle):
+ cfg = rblf.cfg(handle)
+ g["NATIVE_BRIDGE_PRODUCT_PACKAGES"] = "libnative_bridge_vdso.native_bridge native_bridge_guest_app_process.native_bridge native_bridge_guest_linker.native_bridge"
+ g["NATIVE_BRIDGE_MODIFIED_GUEST_LIBS"] = "libaaudio libamidi libandroid libandroid_runtime"
+ g["NATIVE_BRIDGE_PRODUCT_PACKAGES"] += " " + " ".join(rblf.addsuffix(".native_bridge", g.get("NATIVE_BRIDGE_ORIG_GUEST_LIBS", "")))
+`,
+ },
+ {
+ desc: "Math functions",
+ mkname: "product.mk",
+ in: `
+# Test the math functions defined in build/make/common/math.mk
+ifeq ($(call math_max,2,5),5)
+endif
+ifeq ($(call math_min,2,5),2)
+endif
+ifeq ($(call math_gt_or_eq,2,5),true)
+endif
+ifeq ($(call math_gt,2,5),true)
+endif
+ifeq ($(call math_lt,2,5),true)
+endif
+ifeq ($(call math_gt_or_eq,2,5),)
+endif
+ifeq ($(call math_gt,2,5),)
+endif
+ifeq ($(call math_lt,2,5),)
+endif
+ifeq ($(call math_gt_or_eq,$(MY_VAR), 5),true)
+endif
+ifeq ($(call math_gt_or_eq,$(MY_VAR),$(MY_OTHER_VAR)),true)
+endif
+ifeq ($(call math_gt_or_eq,100$(MY_VAR),10),true)
+endif
+`,
+ expected: `# Test the math functions defined in build/make/common/math.mk
+load("//build/make/core:product_config.rbc", "rblf")
+
+def init(g, handle):
+ cfg = rblf.cfg(handle)
+ if max(2, 5) == 5:
+ pass
+ if min(2, 5) == 2:
+ pass
+ if 2 >= 5:
+ pass
+ if 2 > 5:
+ pass
+ if 2 < 5:
+ pass
+ if 2 < 5:
+ pass
+ if 2 <= 5:
+ pass
+ if 2 >= 5:
+ pass
+ if int(g.get("MY_VAR", "")) >= 5:
+ pass
+ if int(g.get("MY_VAR", "")) >= int(g.get("MY_OTHER_VAR", "")):
+ pass
+ if int("100%s" % g.get("MY_VAR", "")) >= 10:
+ pass
+`,
+ },
}
var known_variables = []struct {
diff --git a/mk2rbc/node.go b/mk2rbc/node.go
index d38299d..333a8da 100644
--- a/mk2rbc/node.go
+++ b/mk2rbc/node.go
@@ -47,6 +47,7 @@
originalPath string // Makefile file path
moduleLocalName string
optional bool
+ missing bool // a module may not exist if a module that depends on it is loaded dynamically
}
func (im moduleInfo) entryName() string {
@@ -57,7 +58,8 @@
name() string
entryName() string
emitSelect(gctx *generationContext)
- shouldExist() bool
+ pathExpr() starlarkExpr
+ needsLoadCheck() bool
}
type inheritedStaticModule struct {
@@ -72,8 +74,12 @@
func (im inheritedStaticModule) emitSelect(_ *generationContext) {
}
-func (im inheritedStaticModule) shouldExist() bool {
- return im.loadAlways
+func (im inheritedStaticModule) pathExpr() starlarkExpr {
+ return &stringLiteralExpr{im.path}
+}
+
+func (im inheritedStaticModule) needsLoadCheck() bool {
+ return im.missing
}
type inheritedDynamicModule struct {
@@ -105,18 +111,14 @@
gctx.write(")")
gctx.newLine()
gctx.writef("(%s, %s) = _entry if _entry else (None, None)", i.name(), i.entryName())
- if i.loadAlways {
- gctx.newLine()
- gctx.writef("if not %s:", i.entryName())
- gctx.indentLevel++
- gctx.newLine()
- gctx.write(`rblf.mkerror("cannot")`)
- gctx.indentLevel--
- }
}
-func (i inheritedDynamicModule) shouldExist() bool {
- return i.loadAlways
+func (i inheritedDynamicModule) pathExpr() starlarkExpr {
+ return &i.path
+}
+
+func (i inheritedDynamicModule) needsLoadCheck() bool {
+ return true
}
type inheritNode struct {
@@ -126,20 +128,22 @@
func (inn *inheritNode) emit(gctx *generationContext) {
// Unconditional case:
+ // maybe check that loaded
// rblf.inherit(handle, <module>, module_init)
// Conditional case:
// if <module>_init != None:
// same as above
inn.module.emitSelect(gctx)
-
name := inn.module.name()
entry := inn.module.entryName()
- gctx.newLine()
if inn.loadAlways {
+ gctx.emitLoadCheck(inn.module)
+ gctx.newLine()
gctx.writef("%s(handle, %s, %s)", cfnInherit, name, entry)
return
}
+ gctx.newLine()
gctx.writef("if %s:", entry)
gctx.indentLevel++
gctx.newLine()
@@ -155,12 +159,14 @@
func (inn *includeNode) emit(gctx *generationContext) {
inn.module.emitSelect(gctx)
entry := inn.module.entryName()
- gctx.newLine()
if inn.loadAlways {
+ gctx.emitLoadCheck(inn.module)
+ gctx.newLine()
gctx.writef("%s(g, handle)", entry)
return
}
+ gctx.newLine()
gctx.writef("if %s != None:", entry)
gctx.indentLevel++
gctx.newLine()
diff --git a/mk2rbc/variable.go b/mk2rbc/variable.go
index 6b67a7c..f7adca5 100644
--- a/mk2rbc/variable.go
+++ b/mk2rbc/variable.go
@@ -81,10 +81,12 @@
emitAppend := func() {
pcv.emitGet(gctx, true)
gctx.write(" += ")
+ value := asgn.value
if pcv.valueType() == starlarkTypeString {
gctx.writef(`" " + `)
+ value = &toStringExpr{expr: value}
}
- asgn.value.emit(gctx)
+ value.emit(gctx)
}
switch asgn.flavor {
@@ -136,10 +138,12 @@
emitAppend := func() {
scv.emitGet(gctx, true)
gctx.write(" += ")
+ value := asgn.value
if scv.valueType() == starlarkTypeString {
gctx.writef(`" " + `)
+ value = &toStringExpr{expr: value}
}
- asgn.value.emit(gctx)
+ value.emit(gctx)
}
switch asgn.flavor {
@@ -193,10 +197,12 @@
case asgnAppend:
lv.emitGet(gctx, false)
gctx.write(" += ")
+ value := asgn.value
if lv.valueType() == starlarkTypeString {
gctx.writef(`" " + `)
+ value = &toStringExpr{expr: value}
}
- asgn.value.emit(gctx)
+ value.emit(gctx)
case asgnMaybeAppend:
gctx.writef("%s(%q, ", cfnLocalAppend, lv)
asgn.value.emit(gctx)
diff --git a/rust/OWNERS b/rust/OWNERS
index b5b795c..d07ef7e 100644
--- a/rust/OWNERS
+++ b/rust/OWNERS
@@ -2,4 +2,4 @@
per-file * = chh@google.com, ivanlozano@google.com, jeffv@google.com, mmaurer@google.com, srhines@google.com
# Limited owners/reviewers of the allowed list.
-per-file allowed_list.go = chh@google.com, ivanlozano@google.com, jeffv@google.com, jgalenson@google.com, mmaurer@google.com, srhines@google.com
+per-file allowed_list.go = chh@google.com, ivanlozano@google.com, jeffv@google.com, mmaurer@google.com, srhines@google.com
diff --git a/rust/bindgen.go b/rust/bindgen.go
index 5e1b4b7..ef5702b 100644
--- a/rust/bindgen.go
+++ b/rust/bindgen.go
@@ -30,7 +30,7 @@
defaultBindgenFlags = []string{""}
// bindgen should specify its own Clang revision so updating Clang isn't potentially blocked on bindgen failures.
- bindgenClangVersion = "clang-r437112"
+ bindgenClangVersion = "clang-r437112b"
_ = pctx.VariableFunc("bindgenClangVersion", func(ctx android.PackageVarContext) string {
if override := ctx.Config().Getenv("LLVM_BINDGEN_PREBUILTS_VERSION"); override != "" {
diff --git a/rust/config/allowed_list.go b/rust/config/allowed_list.go
index 0d0b712..f318507 100644
--- a/rust/config/allowed_list.go
+++ b/rust/config/allowed_list.go
@@ -36,6 +36,7 @@
"system/tools/aidl",
"tools/security/fuzzing/example_rust_fuzzer",
"tools/security/fuzzing/orphans",
+ "tools/vendor",
"vendor/",
}
diff --git a/rust/config/global.go b/rust/config/global.go
index bfb2d1f..bae1dc8 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.57.0"
+ RustDefaultVersion = "1.58.0"
RustDefaultBase = "prebuilts/rust/"
DefaultEdition = "2021"
Stdlibs = []string{
diff --git a/rust/config/lints.go b/rust/config/lints.go
index ef6b315..fe195c4 100644
--- a/rust/config/lints.go
+++ b/rust/config/lints.go
@@ -51,6 +51,7 @@
// It should be assumed that any warning lint will be promoted to a
// deny.
defaultClippyLints = []string{
+ "-A clippy::non-send-fields-in-send-ty",
"-A clippy::type-complexity",
"-A clippy::unnecessary-wraps",
"-A clippy::unusual-byte-groupings",
diff --git a/rust/protobuf.go b/rust/protobuf.go
index b91fea8..9fe27c4c 100644
--- a/rust/protobuf.go
+++ b/rust/protobuf.go
@@ -188,6 +188,12 @@
lines,
"pub mod empty {",
" pub use protobuf::well_known_types::Empty;",
+ "}",
+ "pub mod wrappers {",
+ " pub use protobuf::well_known_types::{",
+ " DoubleValue, FloatValue, Int64Value, UInt64Value, Int32Value, UInt32Value,",
+ " BoolValue, StringValue, BytesValue",
+ " };",
"}")
}
diff --git a/rust/rust.go b/rust/rust.go
index c2585f2..cba92c3 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -366,10 +366,6 @@
return ""
}
-func (mod *Module) MinSdkVersion() string {
- return ""
-}
-
func (mod *Module) AlwaysSdk() bool {
return false
}
@@ -901,6 +897,9 @@
bloaty.MeasureSizeForPaths(ctx, mod.compiler.strippedOutputFilePath(), android.OptionalPathForPath(mod.compiler.unstrippedOutputFilePath()))
mod.docTimestampFile = mod.compiler.rustdoc(ctx, flags, deps)
+ if mod.docTimestampFile.Valid() {
+ ctx.CheckbuildFile(mod.docTimestampFile.Path())
+ }
// glob exported headers for snapshot, if BOARD_VNDK_VERSION is current or
// RECOVERY_SNAPSHOT_VERSION is current.
@@ -1494,15 +1493,13 @@
var _ android.ApexModule = (*Module)(nil)
-func (mod *Module) minSdkVersion() string {
+func (mod *Module) MinSdkVersion() string {
return String(mod.Properties.Min_sdk_version)
}
-var _ android.ApexModule = (*Module)(nil)
-
// Implements android.ApexModule
func (mod *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion android.ApiLevel) error {
- minSdkVersion := mod.minSdkVersion()
+ minSdkVersion := mod.MinSdkVersion()
if minSdkVersion == "apex_inherit" {
return nil
}
diff --git a/sh/sh_binary.go b/sh/sh_binary.go
index b1d1bb2..2ab784d 100644
--- a/sh/sh_binary.go
+++ b/sh/sh_binary.go
@@ -268,6 +268,9 @@
func (s *ShBinary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
s.generateAndroidBuildActions(ctx)
installDir := android.PathForModuleInstall(ctx, "bin", proptools.String(s.properties.Sub_dir))
+ if !s.Installable() {
+ s.SkipInstall()
+ }
s.installedFile = ctx.InstallExecutable(installDir, s.outputFilePath.Base(), s.outputFilePath)
for _, symlink := range s.Symlinks() {
ctx.InstallSymlink(installDir, symlink, s.installedFile)
@@ -283,6 +286,7 @@
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
s.customAndroidMkEntries(entries)
entries.SetString("LOCAL_MODULE_RELATIVE_PATH", proptools.String(s.properties.Sub_dir))
+ entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", !s.Installable())
},
},
}}
diff --git a/ui/build/rbe.go b/ui/build/rbe.go
index d74f262..8f9a699 100644
--- a/ui/build/rbe.go
+++ b/ui/build/rbe.go
@@ -19,6 +19,7 @@
"math/rand"
"os"
"path/filepath"
+ "runtime"
"syscall"
"time"
@@ -87,6 +88,13 @@
}
vars["RBE_server_address"] = fmt.Sprintf("unix://%v", name)
}
+
+ rf := 1.0
+ if config.Parallel() < runtime.NumCPU() {
+ rf = float64(config.Parallel()) / float64(runtime.NumCPU())
+ }
+ vars["RBE_local_resource_fraction"] = fmt.Sprintf("%.2f", rf)
+
k, v := config.rbeAuth()
vars[k] = v
return vars
diff --git a/ui/build/soong.go b/ui/build/soong.go
index 5360342..8133762 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -166,10 +166,22 @@
}
commonArgs = append(commonArgs, "-l", filepath.Join(config.FileListDir(), "Android.bp.list"))
+ invocationEnv := make(map[string]string)
+ debugMode := os.Getenv("SOONG_DELVE") != ""
- if os.Getenv("SOONG_DELVE") != "" {
+ if debugMode {
commonArgs = append(commonArgs, "--delve_listen", os.Getenv("SOONG_DELVE"))
commonArgs = append(commonArgs, "--delve_path", shared.ResolveDelveBinary())
+ // GODEBUG=asyncpreemptoff=1 disables the preemption of goroutines. This
+ // is useful because the preemption happens by sending SIGURG to the OS
+ // thread hosting the goroutine in question and each signal results in
+ // work that needs to be done by Delve; it uses ptrace to debug the Go
+ // process and the tracer process must deal with every signal (it is not
+ // possible to selectively ignore SIGURG). This makes debugging slower,
+ // sometimes by an order of magnitude depending on luck.
+ // The original reason for adding async preemption to Go is here:
+ // https://github.com/golang/proposal/blob/master/design/24543-non-cooperative-preemption.md
+ invocationEnv["GODEBUG"] = "asyncpreemptoff=1"
}
allArgs := make([]string, 0, 0)
@@ -187,6 +199,12 @@
Outputs: []string{output},
Args: allArgs,
Description: description,
+ // NB: Changing the value of this environment variable will not result in a
+ // rebuild. The bootstrap Ninja file will change, but apparently Ninja does
+ // not consider changing the pool specified in a statement a change that's
+ // worth rebuilding for.
+ Console: os.Getenv("SOONG_UNBUFFERED_OUTPUT") == "1",
+ Env: invocationEnv,
}
}