Merge "Revert^3 "Add seapp_contexts to allowlist of makefile goal""
diff --git a/android/Android.bp b/android/Android.bp
index 6450a06..da36959 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -19,6 +19,9 @@
"soong-ui-metrics_proto",
"golang-protobuf-proto",
"golang-protobuf-encoding-prototext",
+
+ // Only used for tests.
+ "androidmk-parser",
],
srcs: [
"androidmk.go",
@@ -44,6 +47,7 @@
"image.go",
"license.go",
"license_kind.go",
+ "license_metadata.go",
"license_sdk_member.go",
"licenses.go",
"makefile_goal.go",
@@ -110,6 +114,7 @@
"paths_test.go",
"prebuilt_test.go",
"rule_builder_test.go",
+ "sdk_version_test.go",
"sdk_test.go",
"singleton_module_test.go",
"soong_config_modules_test.go",
diff --git a/android/androidmk.go b/android/androidmk.go
index b6b04a6..72b6584 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -25,7 +25,6 @@
"bytes"
"fmt"
"io"
- "io/ioutil"
"os"
"path/filepath"
"reflect"
@@ -35,6 +34,7 @@
"github.com/google/blueprint"
"github.com/google/blueprint/bootstrap"
+ "github.com/google/blueprint/pathtools"
)
func init() {
@@ -114,7 +114,7 @@
// If true, the module is skipped and does not appear on the final Android-<product name>.mk
// file. Useful when a module needs to be skipped conditionally.
Disabled bool
- // The postprocessing mk file to include, e.g. $(BUILD_SYSTEM)/soong_cc_prebuilt.mk
+ // The postprocessing mk file to include, e.g. $(BUILD_SYSTEM)/soong_cc_rust_prebuilt.mk
// If not set, $(BUILD_SYSTEM)/prebuilt.mk is used.
Include string
// Required modules that need to be built and included in the final build output when building
@@ -474,6 +474,7 @@
ModuleDir(module blueprint.Module) string
Config() Config
ModuleProvider(module blueprint.Module, provider blueprint.ProviderKey) interface{}
+ ModuleHasProvider(module blueprint.Module, provider blueprint.ProviderKey) bool
}
func (a *AndroidMkEntries) fillInEntries(ctx fillInEntriesContext, mod blueprint.Module) {
@@ -517,7 +518,7 @@
a.AddStrings("LOCAL_TARGET_REQUIRED_MODULES", a.Target_required...)
// If the install rule was generated by Soong tell Make about it.
- if amod.InstallBypassMake() && len(base.katiInstalls) > 0 {
+ if len(base.katiInstalls) > 0 {
// Assume the primary install file is last since it probably needs to depend on any other
// installed files. If that is not the case we can add a method to specify the primary
// installed file.
@@ -609,6 +610,11 @@
}
}
+ if ctx.ModuleHasProvider(mod, LicenseMetadataProvider) {
+ licenseMetadata := ctx.ModuleProvider(mod, LicenseMetadataProvider).(*LicenseMetadataInfo)
+ a.SetPath("LOCAL_SOONG_LICENSE_METADATA", licenseMetadata.LicenseMetadataPath)
+ }
+
extraCtx := &androidMkExtraEntriesContext{
ctx: ctx,
mod: mod,
@@ -690,7 +696,7 @@
})
}
-func translateAndroidMk(ctx SingletonContext, mkFile string, mods []blueprint.Module) error {
+func translateAndroidMk(ctx SingletonContext, absMkFile string, mods []blueprint.Module) error {
buf := &bytes.Buffer{}
fmt.Fprintln(buf, "LOCAL_MODULE_MAKEFILE := $(lastword $(MAKEFILE_LIST))")
@@ -699,7 +705,7 @@
for _, mod := range mods {
err := translateAndroidMkModule(ctx, buf, mod)
if err != nil {
- os.Remove(mkFile)
+ os.Remove(absMkFile)
return err
}
@@ -719,27 +725,7 @@
fmt.Fprintf(buf, "STATS.SOONG_MODULE_TYPE.%s := %d\n", mod_type, typeStats[mod_type])
}
- // Don't write to the file if it hasn't changed
- if _, err := os.Stat(absolutePath(mkFile)); !os.IsNotExist(err) {
- if data, err := ioutil.ReadFile(absolutePath(mkFile)); err == nil {
- matches := buf.Len() == len(data)
-
- if matches {
- for i, value := range buf.Bytes() {
- if value != data[i] {
- matches = false
- break
- }
- }
- }
-
- if matches {
- return nil
- }
- }
- }
-
- return ioutil.WriteFile(absolutePath(mkFile), buf.Bytes(), 0666)
+ return pathtools.WriteFileIfChanged(absMkFile, buf.Bytes(), 0666)
}
func translateAndroidMkModule(ctx SingletonContext, w io.Writer, mod blueprint.Module) error {
@@ -907,6 +893,10 @@
return nil
}
+func ShouldSkipAndroidMkProcessing(module Module) bool {
+ return shouldSkipAndroidMkProcessing(module.base())
+}
+
func shouldSkipAndroidMkProcessing(module *ModuleBase) bool {
if !module.commonProperties.NamespaceExportedToMake {
// TODO(jeffrygaston) do we want to validate that there are no modules being
diff --git a/android/apex.go b/android/apex.go
index b9efe4e..cf1bcfe 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -854,7 +854,6 @@
}
return list
}(map[string]int{
- "adbd": 30,
"android.net.ipsec.ike": 30,
"androidx.annotation_annotation-nodeps": 29,
"androidx.arch.core_core-common-nodeps": 29,
@@ -879,24 +878,8 @@
"kotlinx-coroutines-android-nodeps": 30,
"kotlinx-coroutines-core": 28,
"kotlinx-coroutines-core-nodeps": 30,
- "libadb_crypto": 30,
- "libadb_pairing_auth": 30,
- "libadb_pairing_connection": 30,
- "libadb_pairing_server": 30,
- "libadb_protos": 30,
- "libadb_tls_connection": 30,
- "libadbconnection_client": 30,
- "libadbconnection_server": 30,
- "libadbd_core": 30,
- "libadbd_services": 30,
- "libadbd": 30,
- "libapp_processes_protos_lite": 30,
- "libasyncio": 30,
"libbrotli": 30,
- "libbuildversion": 30,
"libcrypto_static": 30,
- "libcrypto_utils": 30,
- "libdiagnose_usb": 30,
"libeigen": 30,
"liblz4": 30,
"libmdnssd": 30,
@@ -906,7 +889,6 @@
"libprocpartition": 30,
"libprotobuf-java-lite": 30,
"libprotoutil": 30,
- "libsync": 30,
"libtextclassifier_hash_headers": 30,
"libtextclassifier_hash_static": 30,
"libtflite_kernel_utils": 30,
@@ -926,16 +908,18 @@
//
// Return true if the `to` module should be visited, false otherwise.
type PayloadDepsCallback func(ctx ModuleContext, from blueprint.Module, to ApexModule, externalDep bool) bool
+type WalkPayloadDepsFunc func(ctx ModuleContext, do PayloadDepsCallback)
-// UpdatableModule represents updatable APEX/APK
-type UpdatableModule interface {
+// ModuleWithMinSdkVersionCheck represents a module that implements min_sdk_version checks
+type ModuleWithMinSdkVersionCheck interface {
Module
- WalkPayloadDeps(ctx ModuleContext, do PayloadDepsCallback)
+ MinSdkVersion(ctx EarlyModuleContext) SdkSpec
+ CheckMinSdkVersion(ctx ModuleContext)
}
// CheckMinSdkVersion checks if every dependency of an updatable module sets min_sdk_version
// accordingly
-func CheckMinSdkVersion(m UpdatableModule, ctx ModuleContext, minSdkVersion ApiLevel) {
+func CheckMinSdkVersion(ctx ModuleContext, minSdkVersion ApiLevel, walk WalkPayloadDepsFunc) {
// do not enforce min_sdk_version for host
if ctx.Host() {
return
@@ -951,7 +935,7 @@
return
}
- m.WalkPayloadDeps(ctx, func(ctx ModuleContext, from blueprint.Module, to ApexModule, externalDep bool) bool {
+ walk(ctx, func(ctx ModuleContext, from blueprint.Module, to ApexModule, externalDep bool) bool {
if externalDep {
// external deps are outside the payload boundary, which is "stable"
// interface. We don't have to check min_sdk_version for external
@@ -961,6 +945,14 @@
if am, ok := from.(DepIsInSameApex); ok && !am.DepIsInSameApex(ctx, to) {
return false
}
+ if m, ok := to.(ModuleWithMinSdkVersionCheck); ok {
+ // This dependency performs its own min_sdk_version check, just make sure it sets min_sdk_version
+ // to trigger the check.
+ if !m.MinSdkVersion(ctx).Specified() {
+ ctx.OtherModuleErrorf(m, "must set min_sdk_version")
+ }
+ return false
+ }
if err := to.ShouldSupportSdkVersion(ctx, minSdkVersion); err != nil {
toName := ctx.OtherModuleName(to)
if ver, ok := minSdkVersionAllowlist[toName]; !ok || ver.GreaterThan(minSdkVersion) {
diff --git a/android/api_levels.go b/android/api_levels.go
index c1b3ba2..1fbbc15 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -192,8 +192,8 @@
// * "30" -> "30"
// * "R" -> "30"
// * "S" -> "S"
-func ReplaceFinalizedCodenames(ctx PathContext, raw string) string {
- num, ok := getFinalCodenamesMap(ctx.Config())[raw]
+func ReplaceFinalizedCodenames(config Config, raw string) string {
+ num, ok := getFinalCodenamesMap(config)[raw]
if !ok {
return raw
}
@@ -201,7 +201,7 @@
return strconv.Itoa(num)
}
-// Converts the given string `raw` to an ApiLevel, possibly returning an error.
+// ApiLevelFromUser converts the given string `raw` to an ApiLevel, possibly returning an error.
//
// `raw` must be non-empty. Passing an empty string results in a panic.
//
@@ -216,6 +216,12 @@
// Inputs that are not "current", known previews, or convertible to an integer
// will return an error.
func ApiLevelFromUser(ctx PathContext, raw string) (ApiLevel, error) {
+ return ApiLevelFromUserWithConfig(ctx.Config(), raw)
+}
+
+// ApiLevelFromUserWithConfig implements ApiLevelFromUser, see comments for
+// ApiLevelFromUser for more details.
+func ApiLevelFromUserWithConfig(config Config, raw string) (ApiLevel, error) {
if raw == "" {
panic("API level string must be non-empty")
}
@@ -224,13 +230,13 @@
return FutureApiLevel, nil
}
- for _, preview := range ctx.Config().PreviewApiLevels() {
+ for _, preview := range config.PreviewApiLevels() {
if raw == preview.String() {
return preview, nil
}
}
- canonical := ReplaceFinalizedCodenames(ctx, raw)
+ canonical := ReplaceFinalizedCodenames(config, raw)
asInt, err := strconv.Atoi(canonical)
if err != nil {
return NoneApiLevel, fmt.Errorf("%q could not be parsed as an integer and is not a recognized codename", canonical)
diff --git a/android/arch.go b/android/arch.go
index 3bf54b7..96a4cbf 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -168,7 +168,7 @@
return archType
}
-// ArchTypeList returns the a slice copy of the 4 supported ArchTypes for arm,
+// ArchTypeList returns a slice copy of the 4 supported ArchTypes for arm,
// arm64, x86 and x86_64.
func ArchTypeList() []ArchType {
return append([]ArchType(nil), archTypeList...)
@@ -408,7 +408,7 @@
// addPathDepsForProps does not descend into sub structs, so we need to descend into the
// arch-specific properties ourselves
- properties := []interface{}{}
+ var properties []interface{}
for _, archProperties := range m.archProperties {
for _, archProps := range archProperties {
archPropValues := reflect.ValueOf(archProps).Elem()
@@ -566,6 +566,8 @@
return variants
}
+var DarwinUniversalVariantTag = archDepTag{name: "darwin universal binary"}
+
// archMutator splits a module into a variant for each Target requested by the module. Target selection
// for a module is in three levels, OsClass, multilib, and then Target.
// OsClass selection is determined by:
@@ -652,7 +654,7 @@
prefer32 := os == Windows
// Determine the multilib selection for this module.
- multilib, extraMultilib := decodeMultilib(base, os.Class)
+ multilib, extraMultilib := decodeMultilib(base, os)
// Convert the multilib selection into a list of Targets.
targets, err := decodeMultilibTargets(multilib, osTargets, prefer32)
@@ -702,6 +704,16 @@
m.base().commonProperties.SkipInstall = true
}
}
+
+ // Create a dependency for Darwin Universal binaries from the primary to secondary
+ // architecture. The module itself will be responsible for calling lipo to merge the outputs.
+ if os == Darwin {
+ if multilib == "darwin_universal" && len(modules) == 2 {
+ mctx.AddInterVariantDependency(DarwinUniversalVariantTag, modules[1], modules[0])
+ } else if multilib == "darwin_universal_common_first" && len(modules) == 3 {
+ mctx.AddInterVariantDependency(DarwinUniversalVariantTag, modules[2], modules[1])
+ }
+ }
}
// addTargetProperties annotates a variant with the Target is is being compiled for, the list
@@ -717,9 +729,9 @@
// multilib from the factory's call to InitAndroidArchModule if none was set. For modules that
// called InitAndroidMultiTargetsArchModule it always returns "common" for multilib, and returns
// the actual multilib in extraMultilib.
-func decodeMultilib(base *ModuleBase, class OsClass) (multilib, extraMultilib string) {
+func decodeMultilib(base *ModuleBase, os OsType) (multilib, extraMultilib string) {
// First check the "android.compile_multilib" or "host.compile_multilib" properties.
- switch class {
+ switch os.Class {
case Device:
multilib = String(base.commonProperties.Target.Android.Compile_multilib)
case Host:
@@ -737,6 +749,26 @@
}
if base.commonProperties.UseTargetVariants {
+ // Darwin has the concept of "universal binaries" which is implemented in Soong by
+ // building both x86_64 and arm64 variants, and having select module types know how to
+ // merge the outputs of their corresponding variants together into a final binary. Most
+ // module types don't need to understand this logic, as we only build a small portion
+ // of the tree for Darwin, and only module types writing macho files need to do the
+ // merging.
+ //
+ // This logic is not enabled for:
+ // "common", as it's not an arch-specific variant
+ // "32", as Darwin never has a 32-bit variant
+ // !UseTargetVariants, as the module has opted into handling the arch-specific logic on
+ // its own.
+ if os == Darwin && multilib != "common" && multilib != "32" {
+ if multilib == "common_first" {
+ multilib = "darwin_universal_common_first"
+ } else {
+ multilib = "darwin_universal"
+ }
+ }
+
return multilib, ""
} else {
// For app modules a single arch variant will be created per OS class which is expected to handle all the
@@ -961,10 +993,11 @@
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()))
+ }
- for _, properties := range base.generalProperties {
+ getStructType := func(properties interface{}) reflect.Type {
propertiesValue := reflect.ValueOf(properties)
t := propertiesValue.Type()
if propertiesValue.Kind() != reflect.Ptr {
@@ -974,10 +1007,14 @@
propertiesValue = propertiesValue.Elem()
if propertiesValue.Kind() != reflect.Struct {
- panic(fmt.Errorf("properties must be a pointer to a struct, got %T",
+ panic(fmt.Errorf("properties must be a pointer to a struct, got a pointer to %T",
propertiesValue.Interface()))
}
+ return t
+ }
+ 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{} {
return createArchPropTypeDesc(t)
@@ -997,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 {
@@ -1072,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
}
@@ -1400,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
}
@@ -1793,6 +1827,15 @@
if len(buildTargets) == 0 {
buildTargets = filterMultilibTargets(targets, "lib64")
}
+ case "darwin_universal":
+ buildTargets = filterMultilibTargets(targets, "lib64")
+ // Reverse the targets so that the first architecture can depend on the second
+ // architecture module in order to merge the outputs.
+ reverseSliceInPlace(buildTargets)
+ case "darwin_universal_common_first":
+ archTargets := filterMultilibTargets(targets, "lib64")
+ reverseSliceInPlace(archTargets)
+ buildTargets = append(getCommonTargets(targets), archTargets...)
default:
return nil, fmt.Errorf(`compile_multilib must be "both", "first", "32", "64", "prefer32" or "first_prefer32" found %q`,
multilib)
@@ -1970,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 cf27cb4..9f38c3b 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -15,6 +15,8 @@
package android
import (
+ "bufio"
+ "errors"
"fmt"
"io/ioutil"
"path/filepath"
@@ -39,6 +41,10 @@
// To opt-out a module, set bazel_module: { bp2build_available: false }
// To defer the default setting for the directory, do not set the value.
Bp2build_available *bool
+
+ // CanConvertToBazel is set via InitBazelModule to indicate that a module type can be converted to
+ // Bazel with Bp2build.
+ CanConvertToBazel bool `blueprint:"mutated"`
}
// Properties contains common module properties for Bazel migration purposes.
@@ -48,10 +54,30 @@
Bazel_module bazelModuleProperties
}
+// namespacedVariableProperties is a map from a string representing a Soong
+// config variable namespace, like "android" or "vendor_name" to a slice of
+// pointer to a struct containing a single field called Soong_config_variables
+// whose value mirrors the structure in the Blueprint file.
+type namespacedVariableProperties map[string][]interface{}
+
// BazelModuleBase contains the property structs with metadata for modules which can be converted to
// Bazel.
type BazelModuleBase struct {
bazelProperties properties
+
+ // namespacedVariableProperties is used for soong_config_module_type support
+ // in bp2build. Soong config modules allow users to set module properties
+ // based on custom product variables defined in Android.bp files. These
+ // variables are namespaced to prevent clobbering, especially when set from
+ // Makefiles.
+ namespacedVariableProperties namespacedVariableProperties
+
+ // baseModuleType is set when this module was created from a module type
+ // defined by a soong_config_module_type. Every soong_config_module_type
+ // "wraps" another module type, e.g. a soong_config_module_type can wrap a
+ // cc_defaults to a custom_cc_defaults, or cc_binary to a custom_cc_binary.
+ // This baseModuleType is set to the wrapped module type.
+ baseModuleType string
}
// Bazelable is specifies the interface for modules that can be converted to Bazel.
@@ -60,9 +86,24 @@
HasHandcraftedLabel() bool
HandcraftedLabel() string
GetBazelLabel(ctx BazelConversionPathContext, module blueprint.Module) string
- ConvertWithBp2build(ctx BazelConversionContext) bool
- convertWithBp2build(ctx BazelConversionContext, module blueprint.Module) bool
+ ShouldConvertWithBp2build(ctx BazelConversionContext) bool
+ shouldConvertWithBp2build(ctx BazelConversionContext, module blueprint.Module) bool
GetBazelBuildFileContents(c Config, path, name string) (string, error)
+ ConvertWithBp2build(ctx TopDownMutatorContext)
+
+ // namespacedVariableProps is a map from a soong config variable namespace
+ // (e.g. acme, android) to a map of interfaces{}, which are really
+ // reflect.Struct pointers, representing the value of the
+ // soong_config_variables property of a module. The struct pointer is the
+ // one with the single member called Soong_config_variables, which itself is
+ // a struct containing fields for each supported feature in that namespace.
+ //
+ // The reason for using an slice of interface{} is to support defaults
+ // propagation of the struct pointers.
+ namespacedVariableProps() namespacedVariableProperties
+ setNamespacedVariableProps(props namespacedVariableProperties)
+ BaseModuleType() string
+ SetBaseModuleType(baseModuleType string)
}
// BazelModule is a lightweight wrapper interface around Module for Bazel-convertible modules.
@@ -75,6 +116,7 @@
// properties.
func InitBazelModule(module BazelModule) {
module.AddProperties(module.bazelProps())
+ module.bazelProps().Bazel_module.CanConvertToBazel = true
}
// bazelProps returns the Bazel properties for the given BazelModuleBase.
@@ -82,6 +124,22 @@
return &b.bazelProperties
}
+func (b *BazelModuleBase) namespacedVariableProps() namespacedVariableProperties {
+ return b.namespacedVariableProperties
+}
+
+func (b *BazelModuleBase) setNamespacedVariableProps(props namespacedVariableProperties) {
+ b.namespacedVariableProperties = props
+}
+
+func (b *BazelModuleBase) BaseModuleType() string {
+ return b.baseModuleType
+}
+
+func (b *BazelModuleBase) SetBaseModuleType(baseModuleType string) {
+ b.baseModuleType = baseModuleType
+}
+
// HasHandcraftedLabel returns whether this module has a handcrafted Bazel label.
func (b *BazelModuleBase) HasHandcraftedLabel() bool {
return b.bazelProperties.Bazel_module.Label != nil
@@ -97,7 +155,7 @@
if b.HasHandcraftedLabel() {
return b.HandcraftedLabel()
}
- if b.ConvertWithBp2build(ctx) {
+ if b.ShouldConvertWithBp2build(ctx) {
return bp2buildModuleLabel(ctx, module)
}
return "" // no label for unconverted module
@@ -150,7 +208,8 @@
"build/bazel/platforms":/* recursive = */ true,
"build/bazel/product_variables":/* recursive = */ true,
"build/bazel_common_rules":/* recursive = */ true,
- "build/make/tools":/* recursive = */ true,
+ // build/make/tools/signapk BUILD file is generated, so build/make/tools is not recursive.
+ "build/make/tools":/* recursive = */ false,
"build/pesto":/* recursive = */ true,
// external/bazelbuild-rules_android/... is needed by mixed builds, otherwise mixed builds analysis fails
@@ -166,6 +225,7 @@
"packages/apps/QuickSearchBox":/* recursive = */ true,
"packages/apps/WallpaperPicker":/* recursive = */ false,
+ "prebuilts/gcc":/* recursive = */ true,
"prebuilts/sdk":/* recursive = */ false,
"prebuilts/sdk/current/extras/app-toolkit":/* recursive = */ false,
"prebuilts/sdk/current/support":/* recursive = */ false,
@@ -175,22 +235,71 @@
// Configure modules in these directories to enable bp2build_available: true or false by default.
bp2buildDefaultConfig = Bp2BuildConfig{
- "bionic": Bp2BuildDefaultTrueRecursively,
+ "art/libdexfile": Bp2BuildDefaultTrueRecursively,
+ "bionic": Bp2BuildDefaultTrueRecursively,
+ "bootable/recovery/tools/recovery_l10n": Bp2BuildDefaultTrue,
+ "build/bazel/examples/soong_config_variables": Bp2BuildDefaultTrueRecursively,
"build/bazel/examples/apex/minimal": Bp2BuildDefaultTrueRecursively,
+ "build/make/tools/signapk": Bp2BuildDefaultTrue,
+ "build/soong": Bp2BuildDefaultTrue,
+ "build/soong/cc/libbuildversion": Bp2BuildDefaultTrue, // Skip tests subdir
+ "build/soong/cc/ndkstubgen": Bp2BuildDefaultTrue,
+ "build/soong/cc/symbolfile": Bp2BuildDefaultTrue,
+ "build/soong/scripts": Bp2BuildDefaultTrueRecursively,
+ "cts/common/device-side/nativetesthelper/jni": Bp2BuildDefaultTrueRecursively,
+ "development/apps/DevelopmentSettings": Bp2BuildDefaultTrue,
+ "development/apps/Fallback": Bp2BuildDefaultTrue,
+ "development/apps/WidgetPreview": Bp2BuildDefaultTrue,
+ "development/samples/BasicGLSurfaceView": Bp2BuildDefaultTrue,
+ "development/samples/BluetoothChat": Bp2BuildDefaultTrue,
+ "development/samples/BrokenKeyDerivation": Bp2BuildDefaultTrue,
+ "development/samples/Compass": Bp2BuildDefaultTrue,
+ "development/samples/ContactManager": Bp2BuildDefaultTrue,
+ "development/samples/FixedGridLayout": Bp2BuildDefaultTrue,
+ "development/samples/HelloEffects": Bp2BuildDefaultTrue,
+ "development/samples/Home": Bp2BuildDefaultTrue,
+ "development/samples/HoneycombGallery": Bp2BuildDefaultTrue,
+ "development/samples/JetBoy": Bp2BuildDefaultTrue,
+ "development/samples/KeyChainDemo": Bp2BuildDefaultTrue,
+ "development/samples/LceDemo": Bp2BuildDefaultTrue,
+ "development/samples/LunarLander": Bp2BuildDefaultTrue,
+ "development/samples/MultiResolution": Bp2BuildDefaultTrue,
+ "development/samples/MultiWindow": Bp2BuildDefaultTrue,
+ "development/samples/NotePad": Bp2BuildDefaultTrue,
+ "development/samples/Obb": Bp2BuildDefaultTrue,
+ "development/samples/RSSReader": Bp2BuildDefaultTrue,
+ "development/samples/ReceiveShareDemo": Bp2BuildDefaultTrue,
+ "development/samples/SearchableDictionary": Bp2BuildDefaultTrue,
+ "development/samples/SipDemo": Bp2BuildDefaultTrue,
+ "development/samples/SkeletonApp": Bp2BuildDefaultTrue,
+ "development/samples/Snake": Bp2BuildDefaultTrue,
+ "development/samples/SpellChecker/": Bp2BuildDefaultTrueRecursively,
+ "development/samples/ThemedNavBarKeyboard": Bp2BuildDefaultTrue,
+ "development/samples/ToyVpn": Bp2BuildDefaultTrue,
+ "development/samples/TtsEngine": Bp2BuildDefaultTrue,
+ "development/samples/USB/AdbTest": Bp2BuildDefaultTrue,
+ "development/samples/USB/MissileLauncher": Bp2BuildDefaultTrue,
+ "development/samples/VoiceRecognitionService": Bp2BuildDefaultTrue,
+ "development/samples/VoicemailProviderDemo": Bp2BuildDefaultTrue,
"development/sdk": Bp2BuildDefaultTrueRecursively,
"external/arm-optimized-routines": Bp2BuildDefaultTrueRecursively,
"external/boringssl": Bp2BuildDefaultTrueRecursively,
+ "external/bouncycastle": Bp2BuildDefaultTrue,
"external/brotli": Bp2BuildDefaultTrue,
+ "external/conscrypt": Bp2BuildDefaultTrue,
"external/fmtlib": Bp2BuildDefaultTrueRecursively,
"external/google-benchmark": Bp2BuildDefaultTrueRecursively,
- "external/googletest/googletest": Bp2BuildDefaultTrueRecursively,
+ "external/googletest": Bp2BuildDefaultTrueRecursively,
"external/gwp_asan": Bp2BuildDefaultTrueRecursively,
"external/jemalloc_new": Bp2BuildDefaultTrueRecursively,
"external/jsoncpp": Bp2BuildDefaultTrueRecursively,
"external/libcap": Bp2BuildDefaultTrueRecursively,
"external/libcxx": Bp2BuildDefaultTrueRecursively,
"external/libcxxabi": Bp2BuildDefaultTrueRecursively,
+ "external/libevent": Bp2BuildDefaultTrueRecursively,
+ "external/libpng": Bp2BuildDefaultTrueRecursively,
"external/lz4/lib": Bp2BuildDefaultTrue,
+ "external/lzma/C": Bp2BuildDefaultTrueRecursively,
"external/mdnsresponder": Bp2BuildDefaultTrueRecursively,
"external/minijail": Bp2BuildDefaultTrueRecursively,
"external/pcre": Bp2BuildDefaultTrueRecursively,
@@ -198,17 +307,36 @@
"external/python/six": Bp2BuildDefaultTrueRecursively,
"external/scudo": Bp2BuildDefaultTrueRecursively,
"external/selinux/libselinux": Bp2BuildDefaultTrueRecursively,
+ "external/selinux/libsepol": Bp2BuildDefaultTrueRecursively,
"external/zlib": Bp2BuildDefaultTrueRecursively,
"external/zstd": Bp2BuildDefaultTrueRecursively,
+ "frameworks/base/media/tests/MediaDump": Bp2BuildDefaultTrue,
+ "frameworks/base/startop/apps/test": Bp2BuildDefaultTrue,
"frameworks/native/libs/adbd_auth": Bp2BuildDefaultTrueRecursively,
+ "frameworks/native/opengl/tests/gl2_cameraeye": Bp2BuildDefaultTrue,
+ "frameworks/native/opengl/tests/gl2_java": Bp2BuildDefaultTrue,
+ "frameworks/native/opengl/tests/testLatency": Bp2BuildDefaultTrue,
+ "frameworks/native/opengl/tests/testPauseResume": Bp2BuildDefaultTrue,
+ "frameworks/native/opengl/tests/testViewport": Bp2BuildDefaultTrue,
+ "frameworks/proto_logging/stats/stats_log_api_gen": Bp2BuildDefaultTrueRecursively,
+ "libnativehelper": Bp2BuildDefaultTrueRecursively,
+ "packages/apps/DevCamera": Bp2BuildDefaultTrue,
+ "packages/apps/HTMLViewer": Bp2BuildDefaultTrue,
+ "packages/apps/Protips": Bp2BuildDefaultTrue,
"packages/modules/adb": Bp2BuildDefaultTrue,
+ "packages/modules/adb/apex": Bp2BuildDefaultTrue,
"packages/modules/adb/crypto": Bp2BuildDefaultTrueRecursively,
"packages/modules/adb/libs": Bp2BuildDefaultTrueRecursively,
"packages/modules/adb/pairing_auth": Bp2BuildDefaultTrueRecursively,
"packages/modules/adb/pairing_connection": Bp2BuildDefaultTrueRecursively,
"packages/modules/adb/proto": Bp2BuildDefaultTrueRecursively,
"packages/modules/adb/tls": Bp2BuildDefaultTrueRecursively,
+ "packages/providers/MediaProvider/tools/dialogs": Bp2BuildDefaultTrue,
+ "packages/screensavers/Basic": Bp2BuildDefaultTrue,
+ "packages/services/Car/tests/SampleRearViewCamera": Bp2BuildDefaultTrue,
"prebuilts/clang/host/linux-x86": Bp2BuildDefaultTrueRecursively,
+ "system/apex": Bp2BuildDefaultFalse, // TODO(b/207466993): flaky failures
+ "system/core/debuggerd": Bp2BuildDefaultTrueRecursively,
"system/core/diagnose_usb": Bp2BuildDefaultTrueRecursively,
"system/core/libasyncio": Bp2BuildDefaultTrue,
"system/core/libcrypto_utils": Bp2BuildDefaultTrueRecursively,
@@ -217,29 +345,80 @@
"system/core/libprocessgroup": Bp2BuildDefaultTrue,
"system/core/libprocessgroup/cgrouprc": Bp2BuildDefaultTrue,
"system/core/libprocessgroup/cgrouprc_format": Bp2BuildDefaultTrue,
+ "system/core/libsystem": Bp2BuildDefaultTrueRecursively,
+ "system/core/libutils": Bp2BuildDefaultTrueRecursively,
+ "system/core/libvndksupport": Bp2BuildDefaultTrueRecursively,
"system/core/property_service/libpropertyinfoparser": Bp2BuildDefaultTrueRecursively,
"system/libbase": Bp2BuildDefaultTrueRecursively,
+ "system/libprocinfo": Bp2BuildDefaultTrue,
"system/libziparchive": Bp2BuildDefaultTrueRecursively,
"system/logging/liblog": Bp2BuildDefaultTrueRecursively,
"system/sepolicy/apex": Bp2BuildDefaultTrueRecursively,
"system/timezone/apex": Bp2BuildDefaultTrueRecursively,
"system/timezone/output_data": Bp2BuildDefaultTrueRecursively,
+ "system/unwinding/libbacktrace": Bp2BuildDefaultTrueRecursively,
+ "system/unwinding/libunwindstack": Bp2BuildDefaultTrueRecursively,
+ "tools/apksig": Bp2BuildDefaultTrue,
+ "tools/platform-compat/java/android/compat": Bp2BuildDefaultTrueRecursively,
}
// Per-module denylist to always opt modules out of both bp2build and mixed builds.
bp2buildModuleDoNotConvertList = []string{
- "libc_malloc_debug", // depends on libunwindstack, which depends on unsupported module art_cc_library_statics
+ "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
+
+ "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
+ "libnativetesthelper_jni", "libgmock_main_ndk", "libgmock_ndk", // depends on unconverted module: libgtest_ndk_c++
+
+ "statslog-framework-java-gen", "statslog.cpp", "statslog.h", "statslog.rs", "statslog_header.rs", // depends on unconverted modules: stats-log-api-gen
+
+ "stats-log-api-gen", // depends on unconverted modules: libstats_proto_host, libprotobuf-cpp-full
+
+ "libstatslog", // depends on unconverted modules: statslog.cpp, statslog.h, ...
+
+ "cmd", // depends on unconverted module packagemanager_aidl-cpp, of unsupported type aidl_interface
+ "servicedispatcher", // depends on unconverted module android.debug_aidl, of unsupported type aidl_interface
+ "libutilscallstack", // depends on unconverted module libbacktrace
+ "libbacktrace", // depends on unconverted module libunwindstack
+ "libdebuggerd_handler", // depends on unconverted module libdebuggerd_handler_core
+ "libdebuggerd_handler_core", "libdebuggerd_handler_fallback", // depends on unconverted module libdebuggerd
+ "unwind_for_offline", // depends on unconverted module libunwindstack_utils
+ "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
+
+ "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", // we don't handle path property for fileegroups
- "libprotobuf-internal-python-srcs", // we don't handle path property for fileegroups
+ "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
- "libseccomp_policy", // b/201094425: depends on func_to_syscall_nrs, which depends on py_binary, which is unsupported in mixed builds.
- "libfdtrack", // depends on libunwindstack, which depends on unsupported module art_cc_library_statics
-
- "gwp_asan_crash_handler", // cc_library, ld.lld: error: undefined symbol: memset
+ "conv_linker_config", // depends on linker_config_proto, a python lib with proto sources
"brotli-fuzzer-corpus", // b/202015218: outputs are in location incompatible with bazel genrule handling.
@@ -248,72 +427,49 @@
"platform_tools_properties",
"build_tools_source_properties",
- // //external/libcap/...
- "cap_names.h", // http://b/196105070 host toolchain misconfigurations for mixed builds
- "libcap", // http://b/196105070 host toolchain misconfigurations for mixed builds
-
- "libminijail", // depends on unconverted modules: libcap
- "getcap", // depends on unconverted modules: libcap
- "setcap", // depends on unconverted modules: libcap
- "minijail0", // depends on unconverted modules: libcap, libminijail
- "drop_privs", // depends on unconverted modules: libminijail
-
- // Tests. Handle later.
- "libbionic_tests_headers_posix", // http://b/186024507, cc_library_static, sched.h, time.h not found
- "libjemalloc5_integrationtest",
- "libjemalloc5_stresstestlib",
- "libjemalloc5_unittest",
-
// APEX support
- "com.android.runtime", // http://b/194746715, apex, depends on 'libc_malloc_debug'
-
- "libadb_crypto", // Depends on libadb_protos
- "libadb_crypto_static", // Depends on libadb_protos_static
- "libadb_pairing_connection", // Depends on libadb_protos
- "libadb_pairing_connection_static", // Depends on libadb_protos_static
- "libadb_pairing_server", // Depends on libadb_protos
- "libadb_pairing_server_static", // Depends on libadb_protos_static
- "libadbd", // Depends on libadbd_core
- "libadbd_core", // Depends on libadb_protos
- "libadbd_services", // Depends on libadb_protos
-
- "libadb_protos_static", // b/200601772: Requires cc_library proto support
- "libadb_protos", // b/200601772: Requires cc_library proto support
- "libapp_processes_protos_lite", // b/200601772: Requires cc_library proto support
+ "com.android.runtime", // depends on unconverted modules: bionic-linker-config, linkerconfig
"libgtest_ndk_c++", // b/201816222: Requires sdk_version support.
"libgtest_main_ndk_c++", // b/201816222: Requires sdk_version support.
- "abb", // depends on unconverted modules: libadbd_core, libadbd_services, libcmd, libbinder, libutils, libselinux
- "adb", // depends on unconverted modules: bin2c_fastdeployagent, libadb_crypto, libadb_host, libadb_pairing_connection, libadb_protos, libandroidfw, libapp_processes_protos_full, libfastdeploy_host, libmdnssd, libopenscreen-discovery, libopenscreen-platform-impl, libusb, libutils, libziparchive, libzstd, AdbWinApi
- "adbd", // depends on unconverted modules: libadb_crypto, libadb_pairing_connection, libadb_protos, libadbd, libadbd_core, libapp_processes_protos_lite, libmdnssd, libzstd, libadbd_services, libcap, libminijail, libselinux
- "bionic_tests_zipalign", // depends on unconverted modules: libziparchive, libutils
- "linker", // depends on unconverted modules: liblinker_debuggerd_stub, libdebuggerd_handler_fallback, libziparchive, liblinker_main, liblinker_malloc
+ "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_*
- "sefcontext_compile", // depends on unconverted modules: libsepol
- "versioner", // depends on unconverted modules: libclang_cxx_host, libLLVM_host
+ "versioner", // depends on unconverted modules: libclang_cxx_host, libLLVM_host, of unsupported type llvm_host_prebuilt_library_shared
"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
+
+ "libdexfile", // depends on unconverted modules: dexfile_operator_srcs, libartbase, libartpalette,
+ "libdexfiled", // depends on unconverted modules: dexfile_operator_srcs, libartbased, libartpalette
}
// 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.
mixedBuildsDisabledList = []string{
- "libbrotli", // http://b/198585397, ld.lld: error: bionic/libc/arch-arm64/generic/bionic/memmove.S:95:(.text+0x10): relocation R_AARCH64_CONDBR19 out of range: -1404176 is not in [-1048576, 1048575]; references __memcpy
- "func_to_syscall_nrs", // http://b/200899432, bazel-built cc_genrule does not work in mixed build when it is a dependency of another soong module.
- "libseccomp_policy_app_zygote_sources", // http://b/200899432, bazel-built cc_genrule does not work in mixed build when it is a dependency of another soong module.
- "libseccomp_policy_app_sources", // http://b/200899432, bazel-built cc_genrule does not work in mixed build when it is a dependency of another soong module.
- "libseccomp_policy_system_sources", // http://b/200899432, bazel-built cc_genrule does not work in mixed build when it is a dependency of another soong module.
- "minijail_constants_json", // http://b/200899432, bazel-built cc_genrule does not work in mixed build when it is a dependency of another soong module.
+ "art_libdexfile_dex_instruction_list_header", // breaks libart_mterp.armng, header not found
+
+ "libbrotli", // http://b/198585397, ld.lld: error: bionic/libc/arch-arm64/generic/bionic/memmove.S:95:(.text+0x10): relocation R_AARCH64_CONDBR19 out of range: -1404176 is not in [-1048576, 1048575]; references __memcpy
+ "minijail_constants_json", // http://b/200899432, bazel-built cc_genrule does not work in mixed build when it is a dependency of another soong module.
+
+ "cap_names.h", // TODO(b/204913827) runfiles need to be handled in mixed builds
+ "libcap", // TODO(b/204913827) runfiles need to be handled in mixed builds
+ "libprotobuf-cpp-full", "libprotobuf-cpp-lite", // Unsupported product&vendor suffix. b/204811222 and b/204810610.
+
+ // Depends on libprotobuf-cpp-*
+ "libadb_pairing_connection",
+ "libadb_pairing_connection_static",
+ "libadb_pairing_server", "libadb_pairing_server_static",
}
// Used for quicker lookups
@@ -359,7 +515,14 @@
// MixedBuildsEnabled checks that a module is ready to be replaced by a
// converted or handcrafted Bazel target.
-func (b *BazelModuleBase) MixedBuildsEnabled(ctx BazelConversionPathContext) bool {
+func (b *BazelModuleBase) MixedBuildsEnabled(ctx ModuleContext) bool {
+ if ctx.Os() == Windows {
+ // Windows toolchains are not currently supported.
+ return false
+ }
+ if !ctx.Module().Enabled() {
+ return false
+ }
if !ctx.Config().BazelContext.BazelEnabled() {
return false
}
@@ -382,23 +545,20 @@
if !ok {
return false
}
- return b.convertWithBp2build(ctx, module) || b.HasHandcraftedLabel()
+ return b.shouldConvertWithBp2build(ctx, module) || b.HasHandcraftedLabel()
}
-// ConvertWithBp2build returns whether the given BazelModuleBase should be converted with bp2build.
-func (b *BazelModuleBase) ConvertWithBp2build(ctx BazelConversionContext) bool {
- return b.convertWithBp2build(ctx, ctx.Module())
+// ShouldConvertWithBp2build returns whether the given BazelModuleBase should be converted with bp2build.
+func (b *BazelModuleBase) ShouldConvertWithBp2build(ctx BazelConversionContext) bool {
+ return b.shouldConvertWithBp2build(ctx, ctx.Module())
}
-func (b *BazelModuleBase) convertWithBp2build(ctx BazelConversionContext, module blueprint.Module) bool {
+func (b *BazelModuleBase) shouldConvertWithBp2build(ctx BazelConversionContext, module blueprint.Module) bool {
if bp2buildModuleDoNotConvert[module.Name()] {
return false
}
- // Ensure that the module type of this module has a bp2build converter. This
- // prevents mixed builds from using auto-converted modules just by matching
- // the package dir; it also has to have a bp2build mutator as well.
- if ctx.Config().bp2buildModuleTypeConfig[ctx.OtherModuleType(module)] == false {
+ if !b.bazelProps().Bazel_module.CanConvertToBazel {
return false
}
@@ -473,3 +633,35 @@
}
return string(data[:]), nil
}
+
+func registerBp2buildConversionMutator(ctx RegisterMutatorsContext) {
+ ctx.TopDown("bp2build_conversion", convertWithBp2build).Parallel()
+}
+
+func convertWithBp2build(ctx TopDownMutatorContext) {
+ bModule, ok := ctx.Module().(Bazelable)
+ if !ok || !bModule.shouldConvertWithBp2build(ctx, ctx.Module()) {
+ return
+ }
+
+ bModule.ConvertWithBp2build(ctx)
+}
+
+// GetMainClassInManifest scans the manifest file specified in filepath and returns
+// the value of attribute Main-Class in the manifest file if it exists, or returns error.
+// WARNING: this is for bp2build converters of java_* modules only.
+func GetMainClassInManifest(c Config, filepath string) (string, error) {
+ file, err := c.fs.Open(filepath)
+ if err != nil {
+ return "", err
+ }
+ scanner := bufio.NewScanner(file)
+ for scanner.Scan() {
+ line := scanner.Text()
+ if strings.HasPrefix(line, "Main-Class:") {
+ return strings.TrimSpace(line[len("Main-Class:"):]), nil
+ }
+ }
+
+ return "", errors.New("Main-Class is not found.")
+}
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 3c6212e..0052551 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -602,8 +602,6 @@
platform_name = build_options(target)["//command_line_option:platforms"][0].name
if platform_name == "host":
return "HOST"
- elif platform_name.startswith("linux_glibc_"):
- return platform_name[len("linux_glibc_"):] + "|" + platform_name[:len("linux_glibc_")-1]
elif platform_name.startswith("android_"):
return platform_name[len("android_"):] + "|" + platform_name[:len("android_")-1]
elif platform_name.startswith("linux_"):
@@ -865,7 +863,7 @@
arch = "x86_64"
}
os := key.configKey.osType.Name
- if len(os) == 0 || os == "common_os" {
+ if len(os) == 0 || os == "common_os" || os == "linux_glibc" {
// Use host OS, which is currently hardcoded to be linux.
os = "linux"
}
diff --git a/android/bazel_paths.go b/android/bazel_paths.go
index 729c73c..62e6156 100644
--- a/android/bazel_paths.go
+++ b/android/bazel_paths.go
@@ -279,6 +279,16 @@
return newPaths
}
+// Converts root-relative Paths to a list of bazel.Label relative to the module in ctx.
+func RootToModuleRelativePaths(ctx BazelConversionPathContext, paths Paths) []bazel.Label {
+ var newPaths []bazel.Label
+ for _, path := range PathsWithModuleSrcSubDir(ctx, paths, "") {
+ s := path.Rel()
+ newPaths = append(newPaths, bazel.Label{Label: s})
+ }
+ return newPaths
+}
+
// expandSrcsForBazel returns bazel.LabelList with paths rooted from the module's local source
// directory and Bazel target labels, excluding those included in the excludes argument (which
// should already be expanded to resolve references to Soong-modules). Valid elements of paths
@@ -328,12 +338,7 @@
// e.g. turn "math/*.c" in
// external/arm-optimized-routines to external/arm-optimized-routines/math/*.c
rootRelativeGlobPath := pathForModuleSrc(ctx, p).String()
- globbedPaths := GlobFiles(ctx, rootRelativeGlobPath, rootRelativeExpandedExcludes)
- globbedPaths = PathsWithModuleSrcSubDir(ctx, globbedPaths, "")
- for _, path := range globbedPaths {
- s := path.Rel()
- expandedPaths = append(expandedPaths, bazel.Label{Label: s})
- }
+ expandedPaths = RootToModuleRelativePaths(ctx, GlobFiles(ctx, rootRelativeGlobPath, rootRelativeExpandedExcludes))
} else {
if !InList(p, expandedExcludes) {
expandedPaths = append(expandedPaths, bazel.Label{Label: p})
diff --git a/android/config.go b/android/config.go
index 78d43c6..afc138b 100644
--- a/android/config.go
+++ b/android/config.go
@@ -155,8 +155,9 @@
fs pathtools.FileSystem
mockBpList string
- bp2buildPackageConfig Bp2BuildConfig
- bp2buildModuleTypeConfig map[string]bool
+ runningAsBp2Build bool
+ bp2buildPackageConfig Bp2BuildConfig
+ Bp2buildSoongConfigDefinitions soongconfig.Bp2BuildSoongConfigDefinitions
// If testAllowNonExistentPaths is true then PathForSource and PathForModuleSrc won't error
// in tests when a path doesn't exist.
@@ -322,7 +323,7 @@
DeviceName: stringPtr("test_device"),
Platform_sdk_version: intPtr(30),
Platform_sdk_codename: stringPtr("S"),
- Platform_version_active_codenames: []string{"S"},
+ Platform_version_active_codenames: []string{"S", "Tiramisu"},
DeviceSystemSdkVersions: []string{"14", "15"},
Platform_systemsdk_versions: []string{"29", "30"},
AAPTConfig: []string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"},
@@ -333,10 +334,8 @@
ShippingApiLevel: stringPtr("30"),
},
- outDir: buildDir,
- // soongOutDir is inconsistent with production (it should be buildDir + "/soong")
- // but a lot of tests assume this :(
- soongOutDir: buildDir,
+ outDir: buildDir,
+ soongOutDir: filepath.Join(buildDir, "soong"),
captureBuild: true,
env: envCopy,
@@ -353,8 +352,6 @@
config.mockFileSystem(bp, fs)
- config.bp2buildModuleTypeConfig = map[string]bool{}
-
determineBuildOS(config)
return Config{config}
@@ -522,7 +519,6 @@
config.BazelContext, err = NewBazelContext(config)
config.bp2buildPackageConfig = bp2buildDefaultConfig
- config.bp2buildModuleTypeConfig = make(map[string]bool)
return Config{config}, err
}
@@ -564,7 +560,11 @@
// BlueprintToolLocation returns the directory containing build system tools
// from Blueprint, like soong_zip and merge_zips.
func (c *config) HostToolDir() string {
- return filepath.Join(c.soongOutDir, "host", c.PrebuiltOS(), "bin")
+ if c.KatiEnabled() {
+ return filepath.Join(c.outDir, "host", c.PrebuiltOS(), "bin")
+ } else {
+ return filepath.Join(c.soongOutDir, "host", c.PrebuiltOS(), "bin")
+ }
}
func (c *config) HostToolPath(ctx PathContext, tool string) Path {
@@ -581,8 +581,9 @@
return path
}
-func (c *config) HostJavaToolPath(ctx PathContext, path string) Path {
- return PathForOutput(ctx, "host", c.PrebuiltOS(), "framework", path)
+func (c *config) HostJavaToolPath(ctx PathContext, tool string) Path {
+ path := pathForInstall(ctx, ctx.Config().BuildOS, ctx.Config().BuildArch, "framework", false, tool)
+ return path
}
// PrebuiltOS returns the name of the host OS used in prebuilts directories.
@@ -657,6 +658,10 @@
return value == "0" || value == "n" || value == "no" || value == "off" || value == "false"
}
+func (c *config) TargetsJava11() bool {
+ return c.IsEnvTrue("EXPERIMENTAL_TARGET_JAVA_VERSION_11")
+}
+
// EnvDeps returns the environment variables this build depends on. The first
// call to this function blocks future reads from the environment.
func (c *config) EnvDeps() map[string]string {
@@ -751,6 +756,16 @@
return levels
}
+func (c *config) LatestPreviewApiLevel() ApiLevel {
+ level := NoneApiLevel
+ for _, l := range c.PreviewApiLevels() {
+ if l.GreaterThan(level) {
+ level = l
+ }
+ }
+ return level
+}
+
func (c *config) AllSupportedApiLevels() []ApiLevel {
var levels []ApiLevel
levels = append(levels, c.FinalApiLevels()...)
@@ -842,7 +857,7 @@
// Returns true if building apps that aren't bundled with the platform.
// UnbundledBuild() is always true when this is true.
func (c *config) UnbundledBuildApps() bool {
- return Bool(c.productVariables.Unbundled_build_apps)
+ return len(c.productVariables.Unbundled_build_apps) > 0
}
// Returns true if building image that aren't bundled with the platform.
@@ -868,8 +883,13 @@
return Bool(c.productVariables.Eng)
}
+// DevicePrimaryArchType returns the ArchType for the first configured device architecture, or
+// Common if there are no device architectures.
func (c *config) DevicePrimaryArchType() ArchType {
- return c.Targets[Android][0].Arch.ArchType
+ if androidTargets := c.Targets[Android]; len(androidTargets) > 0 {
+ return androidTargets[0].Arch.ArchType
+ }
+ return Common
}
func (c *config) SanitizeHost() []string {
@@ -1170,10 +1190,6 @@
return c.config.productVariables.DeviceKernelHeaders
}
-func (c *deviceConfig) SamplingPGO() bool {
- return Bool(c.config.productVariables.SamplingPGO)
-}
-
// JavaCoverageEnabledForPath returns whether Java code coverage is enabled for
// path. Coverage is enabled by default when the product variable
// JavaCoveragePaths is empty. If JavaCoveragePaths is not empty, coverage is
@@ -1229,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
}
@@ -1449,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
@@ -1456,10 +1480,30 @@
return c.PlatformSepolicyVersion()
}
+func (c *deviceConfig) BoardPlatVendorPolicy() []string {
+ return c.config.productVariables.BoardPlatVendorPolicy
+}
+
func (c *deviceConfig) BoardReqdMaskPolicy() []string {
return c.config.productVariables.BoardReqdMaskPolicy
}
+func (c *deviceConfig) BoardSystemExtPublicPrebuiltDirs() []string {
+ return c.config.productVariables.BoardSystemExtPublicPrebuiltDirs
+}
+
+func (c *deviceConfig) BoardSystemExtPrivatePrebuiltDirs() []string {
+ return c.config.productVariables.BoardSystemExtPrivatePrebuiltDirs
+}
+
+func (c *deviceConfig) BoardProductPublicPrebuiltDirs() []string {
+ return c.config.productVariables.BoardProductPublicPrebuiltDirs
+}
+
+func (c *deviceConfig) BoardProductPrivatePrebuiltDirs() []string {
+ return c.config.productVariables.BoardProductPrivatePrebuiltDirs
+}
+
func (c *deviceConfig) DirectedVendorSnapshot() bool {
return c.config.productVariables.DirectedVendorSnapshot
}
@@ -1673,7 +1717,7 @@
}
// Append a list of (apex, jar) pairs to the list.
-func (l *ConfiguredJarList) AppendList(other ConfiguredJarList) ConfiguredJarList {
+func (l *ConfiguredJarList) AppendList(other *ConfiguredJarList) ConfiguredJarList {
apexes := make([]string, 0, l.Len()+other.Len())
jars := make([]string, 0, l.Len()+other.Len())
diff --git a/android/deapexer.go b/android/deapexer.go
index bed6574..265f531 100644
--- a/android/deapexer.go
+++ b/android/deapexer.go
@@ -143,12 +143,16 @@
}
// FindDeapexerProviderForModule searches through the direct dependencies of the current context
-// module for a DeapexerTag dependency and returns its DeapexerInfo. If there is an error then it is
-// reported with ctx.ModuleErrorf and nil is returned.
+// module for a DeapexerTag dependency and returns its DeapexerInfo. If a single nonambiguous
+// deapexer module isn't found then errors are reported with ctx.ModuleErrorf and nil is returned.
func FindDeapexerProviderForModule(ctx ModuleContext) *DeapexerInfo {
var di *DeapexerInfo
ctx.VisitDirectDepsWithTag(DeapexerTag, func(m Module) {
p := ctx.OtherModuleProvider(m, DeapexerProvider).(DeapexerInfo)
+ if di != nil {
+ ctx.ModuleErrorf("Multiple installable prebuilt APEXes provide ambiguous deapexers: %s and %s",
+ di.ApexModuleName(), p.ApexModuleName())
+ }
di = &p
})
if di != nil {
diff --git a/android/defaults.go b/android/defaults.go
index be80cf1..8b121f6 100644
--- a/android/defaults.go
+++ b/android/defaults.go
@@ -89,14 +89,13 @@
var _ Defaultable = (*DefaultableModuleBase)(nil)
func InitDefaultableModule(module DefaultableModule) {
- if module.(Module).base().module == nil {
+ if module.base().module == nil {
panic("InitAndroidModule must be called before InitDefaultableModule")
}
- module.setProperties(module.(Module).GetProperties(), module.(Module).base().variableProperties)
+
+ 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.
@@ -118,6 +117,11 @@
type DefaultsModuleBase struct {
DefaultableModuleBase
+
+ // Included to support setting bazel_module.label for multiple Soong modules to the same Bazel
+ // target. This is primarily useful for modules that were architecture specific and instead are
+ // handled in Bazel as a select().
+ BazelModuleBase
}
// The common pattern for defaults modules is to register separate instances of
@@ -160,6 +164,7 @@
type DefaultsModule interface {
Module
Defaults
+ Bazelable
}
func (d *DefaultsModuleBase) properties() []interface{} {
@@ -170,8 +175,11 @@
return d.defaultableVariableProperties
}
-func (d *DefaultsModuleBase) GenerateAndroidBuildActions(ctx ModuleContext) {
-}
+func (d *DefaultsModuleBase) GenerateAndroidBuildActions(ctx ModuleContext) {}
+
+// ConvertWithBp2build to fulfill Bazelable interface; however, at this time defaults module are
+// *NOT* converted with bp2build
+func (defaultable *DefaultsModuleBase) ConvertWithBp2build(ctx TopDownMutatorContext) {}
func InitDefaultsModule(module DefaultsModule) {
commonProperties := &commonProperties{}
@@ -182,6 +190,8 @@
&ApexProperties{},
&distProperties{})
+ // Bazel module must be initialized _before_ Defaults to be included in cc_defaults module.
+ InitBazelModule(module)
initAndroidModuleBase(module)
initProductVariableModule(module)
initArchModule(module)
@@ -208,15 +218,64 @@
// The applicable licenses property for defaults is 'licenses'.
setPrimaryLicensesProperty(module, "licenses", &commonProperties.Licenses)
- base.module = module
}
var _ Defaults = (*DefaultsModuleBase)(nil)
+// applyNamespacedVariableDefaults only runs in bp2build mode for
+// defaultable/defaults modules. Its purpose is to merge namespaced product
+// variable props from defaults deps, even if those defaults are custom module
+// types created from soong_config_module_type, e.g. one that's wrapping a
+// cc_defaults or java_defaults.
+func applyNamespacedVariableDefaults(defaultDep Defaults, ctx TopDownMutatorContext) {
+ var dep, b Bazelable
+
+ dep, ok := defaultDep.(Bazelable)
+ if !ok {
+ if depMod, ok := defaultDep.(Module); ok {
+ // Track that this dependency hasn't been converted to bp2build yet.
+ ctx.AddUnconvertedBp2buildDep(depMod.Name())
+ return
+ } else {
+ panic("Expected default dep to be a Module.")
+ }
+ }
+
+ b, ok = ctx.Module().(Bazelable)
+ if !ok {
+ return
+ }
+
+ // namespacedVariableProps is a map from namespaces (e.g. acme, android,
+ // vendor_foo) to a slice of soong_config_variable struct pointers,
+ // containing properties for that particular module.
+ src := dep.namespacedVariableProps()
+ dst := b.namespacedVariableProps()
+ if dst == nil {
+ dst = make(namespacedVariableProperties)
+ }
+
+ // Propagate all soong_config_variable structs from the dep. We'll merge the
+ // actual property values later in variable.go.
+ for namespace := range src {
+ if dst[namespace] == nil {
+ dst[namespace] = []interface{}{}
+ }
+ for _, i := range src[namespace] {
+ dst[namespace] = append(dst[namespace], i)
+ }
+ }
+
+ b.setNamespacedVariableProps(dst)
+}
+
func (defaultable *DefaultableModuleBase) applyDefaults(ctx TopDownMutatorContext,
defaultsList []Defaults) {
for _, defaults := range defaultsList {
+ if ctx.Config().runningAsBp2Build {
+ applyNamespacedVariableDefaults(defaults, ctx)
+ }
for _, prop := range defaultable.defaultableProperties {
if prop == defaultable.defaultableVariableProperties {
defaultable.applyDefaultVariableProperties(ctx, defaults, prop)
diff --git a/android/defs.go b/android/defs.go
index c8e2e9b..362b382 100644
--- a/android/defs.go
+++ b/android/defs.go
@@ -52,10 +52,10 @@
// A copy rule.
Cp = pctx.AndroidStaticRule("Cp",
blueprint.RuleParams{
- Command: "rm -f $out && cp $cpPreserveSymlinks $cpFlags $in $out",
+ Command: "rm -f $out && cp $cpPreserveSymlinks $cpFlags $in $out$extraCmds",
Description: "cp $out",
},
- "cpFlags")
+ "cpFlags", "extraCmds")
// A copy rule that only updates the output if it changed.
CpIfChanged = pctx.AndroidStaticRule("CpIfChanged",
@@ -68,10 +68,10 @@
CpExecutable = pctx.AndroidStaticRule("CpExecutable",
blueprint.RuleParams{
- Command: "rm -f $out && cp $cpPreserveSymlinks $cpFlags $in $out && chmod +x $out",
+ Command: "rm -f $out && cp $cpPreserveSymlinks $cpFlags $in $out && chmod +x $out$extraCmds",
Description: "cp $out",
},
- "cpFlags")
+ "cpFlags", "extraCmds")
// A timestamp touch rule.
Touch = pctx.AndroidStaticRule("Touch",
diff --git a/android/filegroup.go b/android/filegroup.go
index a79374d..c932ffa 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -22,7 +22,6 @@
func init() {
RegisterModuleType("filegroup", FileGroupFactory)
- RegisterBp2BuildMutator("filegroup", FilegroupBp2Build)
}
var PrepareForTestWithFilegroup = FixtureRegisterWithContext(func(ctx RegistrationContext) {
@@ -34,12 +33,8 @@
Srcs bazel.LabelListAttribute
}
-func FilegroupBp2Build(ctx TopDownMutatorContext) {
- fg, ok := ctx.Module().(*fileGroup)
- if !ok || !fg.ConvertWithBp2build(ctx) {
- return
- }
-
+// ConvertWithBp2build performs bp2build conversion of filegroup
+func (fg *fileGroup) ConvertWithBp2build(ctx TopDownMutatorContext) {
srcs := bazel.MakeLabelListAttribute(
BazelLabelForModuleSrcExcludes(ctx, fg.properties.Srcs, fg.properties.Exclude_srcs))
diff --git a/android/hooks.go b/android/hooks.go
index 85fc081..bded764 100644
--- a/android/hooks.go
+++ b/android/hooks.go
@@ -65,10 +65,10 @@
return l.bp.ModuleFactories()
}
-func (l *loadHookContext) AppendProperties(props ...interface{}) {
+func (l *loadHookContext) appendPrependHelper(props []interface{},
+ extendFn func([]interface{}, interface{}, proptools.ExtendPropertyFilterFunc) error) {
for _, p := range props {
- err := proptools.AppendMatchingProperties(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())
@@ -78,19 +78,12 @@
}
}
}
+func (l *loadHookContext) AppendProperties(props ...interface{}) {
+ l.appendPrependHelper(props, proptools.AppendMatchingProperties)
+}
func (l *loadHookContext) PrependProperties(props ...interface{}) {
- for _, p := range props {
- err := proptools.PrependMatchingProperties(l.Module().base().customizableProperties,
- p, nil)
- if err != nil {
- if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
- l.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
- } else {
- panic(err)
- }
- }
- }
+ l.appendPrependHelper(props, proptools.PrependMatchingProperties)
}
func (l *loadHookContext) CreateModule(factory ModuleFactory, props ...interface{}) Module {
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/license_metadata.go b/android/license_metadata.go
new file mode 100644
index 0000000..3bc53d6
--- /dev/null
+++ b/android/license_metadata.go
@@ -0,0 +1,231 @@
+// 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 android
+
+import (
+ "fmt"
+ "sort"
+ "strings"
+
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
+)
+
+var (
+ _ = pctx.HostBinToolVariable("licenseMetadataCmd", "build_license_metadata")
+
+ licenseMetadataRule = pctx.AndroidStaticRule("licenseMetadataRule", blueprint.RuleParams{
+ Command: "${licenseMetadataCmd} -o $out @${out}.rsp",
+ CommandDeps: []string{"${licenseMetadataCmd}"},
+ Rspfile: "${out}.rsp",
+ RspfileContent: "${args}",
+ }, "args")
+)
+
+func buildLicenseMetadata(ctx ModuleContext) {
+ base := ctx.Module().base()
+
+ if !base.Enabled() {
+ return
+ }
+
+ if exemptFromRequiredApplicableLicensesProperty(ctx.Module()) {
+ return
+ }
+
+ var allDepMetadataFiles Paths
+ var allDepMetadataArgs []string
+ var allDepOutputFiles Paths
+
+ ctx.VisitDirectDepsBlueprint(func(bpdep blueprint.Module) {
+ dep, _ := bpdep.(Module)
+ if dep == nil {
+ return
+ }
+ if !dep.Enabled() {
+ return
+ }
+
+ if ctx.OtherModuleHasProvider(dep, LicenseMetadataProvider) {
+ info := ctx.OtherModuleProvider(dep, LicenseMetadataProvider).(*LicenseMetadataInfo)
+ allDepMetadataFiles = append(allDepMetadataFiles, info.LicenseMetadataPath)
+
+ depAnnotations := licenseAnnotationsFromTag(ctx.OtherModuleDependencyTag(dep))
+
+ allDepMetadataArgs = append(allDepMetadataArgs, info.LicenseMetadataPath.String()+depAnnotations)
+
+ if depInstallFiles := dep.base().installFiles; len(depInstallFiles) > 0 {
+ allDepOutputFiles = append(allDepOutputFiles, depInstallFiles.Paths()...)
+ } else if depOutputFiles, err := outputFilesForModule(ctx, dep, ""); err == nil {
+ depOutputFiles = PathsIfNonNil(depOutputFiles...)
+ allDepOutputFiles = append(allDepOutputFiles, depOutputFiles...)
+ }
+ }
+ })
+
+ allDepMetadataFiles = SortedUniquePaths(allDepMetadataFiles)
+ sort.Strings(allDepMetadataArgs)
+ allDepOutputFiles = SortedUniquePaths(allDepOutputFiles)
+
+ var orderOnlyDeps Paths
+ var args []string
+
+ if t := ctx.ModuleType(); t != "" {
+ args = append(args,
+ "-mt "+proptools.NinjaAndShellEscape(t))
+ }
+
+ args = append(args,
+ "-r "+proptools.NinjaAndShellEscape(ctx.ModuleDir()),
+ "-mc UNKNOWN")
+
+ if p := base.commonProperties.Effective_package_name; p != nil {
+ args = append(args,
+ "-p "+proptools.NinjaAndShellEscape(*p))
+ }
+
+ args = append(args,
+ JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(base.commonProperties.Effective_license_kinds), "-k "))
+
+ args = append(args,
+ JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(base.commonProperties.Effective_license_conditions), "-c "))
+
+ args = append(args,
+ JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(base.commonProperties.Effective_license_text.Strings()), "-n "))
+
+ args = append(args,
+ JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(allDepMetadataArgs), "-d "))
+ orderOnlyDeps = append(orderOnlyDeps, allDepMetadataFiles...)
+
+ args = append(args,
+ JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(allDepOutputFiles.Strings()), "-s "))
+
+ // Install map
+ args = append(args,
+ JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(base.licenseInstallMap), "-m "))
+
+ // Built files
+ var outputFiles Paths
+ if outputFileProducer, ok := ctx.Module().(OutputFileProducer); ok {
+ outputFiles, _ = outputFileProducer.OutputFiles("")
+ outputFiles = PathsIfNonNil(outputFiles...)
+ }
+
+ if len(outputFiles) > 0 {
+ args = append(args,
+ JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(outputFiles.Strings()), "-t "))
+ } else {
+ args = append(args, fmt.Sprintf("-t //%s:%s", ctx.ModuleDir(), ctx.ModuleName()))
+ }
+
+ // Installed files
+ args = append(args,
+ JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(base.installFiles.Strings()), "-i "))
+
+ isContainer := isContainerFromFileExtensions(base.installFiles, outputFiles)
+ if isContainer {
+ args = append(args, "--is_container")
+ }
+
+ licenseMetadataFile := PathForModuleOut(ctx, "meta_lic")
+
+ ctx.Build(pctx, BuildParams{
+ Rule: licenseMetadataRule,
+ Output: licenseMetadataFile,
+ OrderOnly: orderOnlyDeps,
+ Description: "license metadata",
+ Args: map[string]string{
+ "args": strings.Join(args, " "),
+ },
+ })
+
+ ctx.SetProvider(LicenseMetadataProvider, &LicenseMetadataInfo{
+ LicenseMetadataPath: licenseMetadataFile,
+ })
+}
+
+func isContainerFromFileExtensions(installPaths InstallPaths, builtPaths Paths) bool {
+ var paths Paths
+ if len(installPaths) > 0 {
+ paths = installPaths.Paths()
+ } else {
+ paths = builtPaths
+ }
+
+ for _, path := range paths {
+ switch path.Ext() {
+ case ".zip", ".tar", ".tgz", ".tar.gz", ".img", ".srcszip", ".apex":
+ return true
+ }
+ }
+
+ return false
+}
+
+// LicenseMetadataProvider is used to propagate license metadata paths between modules.
+var LicenseMetadataProvider = blueprint.NewProvider(&LicenseMetadataInfo{})
+
+// LicenseMetadataInfo stores the license metadata path for a module.
+type LicenseMetadataInfo struct {
+ LicenseMetadataPath Path
+}
+
+// licenseAnnotationsFromTag returns the LicenseAnnotations for a tag (if any) converted into
+// a string, or an empty string if there are none.
+func licenseAnnotationsFromTag(tag blueprint.DependencyTag) string {
+ if annoTag, ok := tag.(LicenseAnnotationsDependencyTag); ok {
+ annos := annoTag.LicenseAnnotations()
+ if len(annos) > 0 {
+ annoStrings := make([]string, len(annos))
+ for i, s := range annos {
+ annoStrings[i] = string(s)
+ }
+ return ":" + strings.Join(annoStrings, ",")
+ }
+ }
+ return ""
+}
+
+// LicenseAnnotationsDependencyTag is implemented by dependency tags in order to provide a
+// list of license dependency annotations.
+type LicenseAnnotationsDependencyTag interface {
+ LicenseAnnotations() []LicenseAnnotation
+}
+
+// LicenseAnnotation is an enum of annotations that can be applied to dependencies for propagating
+// license information.
+type LicenseAnnotation string
+
+const (
+ // LicenseAnnotationSharedDependency should be returned by LicenseAnnotations implementations
+ // of dependency tags when the usage of the dependency is dynamic, for example a shared library
+ // linkage for native modules or as a classpath library for java modules.
+ LicenseAnnotationSharedDependency LicenseAnnotation = "dynamic"
+
+ // LicenseAnnotationToolchain should be returned by LicenseAnnotations implementations of
+ // dependency tags when the dependency is used as a toolchain.
+ //
+ // Dependency tags that need to always return LicenseAnnotationToolchain
+ // can embed LicenseAnnotationToolchainDependencyTag to implement LicenseAnnotations.
+ LicenseAnnotationToolchain LicenseAnnotation = "toolchain"
+)
+
+// LicenseAnnotationToolchainDependencyTag can be embedded in a dependency tag to implement
+// LicenseAnnotations that always returns LicenseAnnotationToolchain.
+type LicenseAnnotationToolchainDependencyTag struct{}
+
+func (LicenseAnnotationToolchainDependencyTag) LicenseAnnotations() []LicenseAnnotation {
+ return []LicenseAnnotation{LicenseAnnotationToolchain}
+}
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/makevars.go b/android/makevars.go
index 20db65a..ece7091 100644
--- a/android/makevars.go
+++ b/android/makevars.go
@@ -142,15 +142,19 @@
var singletonMakeVarsProvidersKey = NewOnceKey("singletonMakeVarsProvidersKey")
+func getSingletonMakevarsProviders(config Config) *[]makeVarsProvider {
+ return config.Once(singletonMakeVarsProvidersKey, func() interface{} {
+ return &[]makeVarsProvider{}
+ }).(*[]makeVarsProvider)
+}
+
// registerSingletonMakeVarsProvider adds a singleton that implements SingletonMakeVarsProvider to
// the list of MakeVarsProviders to run.
func registerSingletonMakeVarsProvider(config Config, singleton SingletonMakeVarsProvider) {
// Singletons are registered on the Context and may be different between different Contexts,
// for example when running multiple tests. Store the SingletonMakeVarsProviders in the
// Config so they are attached to the Context.
- singletonMakeVarsProviders := config.Once(singletonMakeVarsProvidersKey, func() interface{} {
- return &[]makeVarsProvider{}
- }).(*[]makeVarsProvider)
+ singletonMakeVarsProviders := getSingletonMakevarsProviders(config)
*singletonMakeVarsProviders = append(*singletonMakeVarsProviders,
makeVarsProvider{pctx, singletonMakeVarsProviderAdapter(singleton)})
@@ -175,7 +179,9 @@
return &makeVarsSingleton{}
}
-type makeVarsSingleton struct{}
+type makeVarsSingleton struct {
+ installsForTesting []byte
+}
type makeVarsProvider struct {
pctx PackageContext
@@ -238,7 +244,7 @@
var katiSymlinks []katiInstall
providers := append([]makeVarsProvider(nil), makeVarsInitProviders...)
- providers = append(providers, *ctx.Config().Get(singletonMakeVarsProvidersKey).(*[]makeVarsProvider)...)
+ providers = append(providers, *getSingletonMakevarsProviders(ctx.Config())...)
for _, provider := range providers {
mctx := &makeVarsContext{
@@ -313,6 +319,8 @@
if err := pathtools.WriteFileIfChanged(installsFile, installsBytes, 0666); err != nil {
ctx.Errorf(err.Error())
}
+
+ s.installsForTesting = installsBytes
}
func (s *makeVarsSingleton) writeVars(vars []makeVarsVariable) []byte {
@@ -414,6 +422,7 @@
fmt.Fprintln(buf)
for _, dist := range dists {
+ fmt.Fprintf(buf, ".PHONY: %s\n", strings.Join(dist.goals, " "))
fmt.Fprintf(buf, "$(call dist-for-goals,%s,%s)\n",
strings.Join(dist.goals, " "), strings.Join(dist.paths, " "))
}
@@ -447,6 +456,9 @@
for _, dep := range install.implicitDeps {
fmt.Fprintf(buf, " %s", dep.String())
}
+ if extraFiles := install.extraFiles; extraFiles != nil {
+ fmt.Fprintf(buf, " %s", extraFiles.zip.String())
+ }
if len(install.orderOnlyDeps) > 0 {
fmt.Fprintf(buf, " |")
}
@@ -454,26 +466,32 @@
fmt.Fprintf(buf, " %s", dep.String())
}
fmt.Fprintln(buf)
-
- fmt.Fprintf(buf, "\trm -f $@ && cp -f %s $< $@", preserveSymlinksFlag)
+ fmt.Fprintln(buf, "\t@echo \"Install $@\"")
+ fmt.Fprintf(buf, "\trm -f $@ && cp -f %s $< $@\n", preserveSymlinksFlag)
if install.executable {
- fmt.Fprintf(buf, " && chmod +x $@")
+ fmt.Fprintf(buf, "\tchmod +x $@\n")
}
- fmt.Fprintln(buf)
+ if extraFiles := install.extraFiles; extraFiles != nil {
+ fmt.Fprintf(buf, "\tunzip -qDD -d '%s' '%s'\n", extraFiles.dir.String(), extraFiles.zip.String())
+ }
fmt.Fprintln(buf)
}
for _, symlink := range symlinks {
fmt.Fprintf(buf, "%s:", symlink.to.String())
+ if symlink.from != nil {
+ // The symlink doesn't need updating when the target is modified, but we sometimes
+ // have a dependency on a symlink to a binary instead of to the binary directly, and
+ // the mtime of the symlink must be updated when the binary is modified, so use a
+ // normal dependency here instead of an order-only dependency.
+ fmt.Fprintf(buf, " %s", symlink.from.String())
+ }
for _, dep := range symlink.implicitDeps {
fmt.Fprintf(buf, " %s", dep.String())
}
- if symlink.from != nil || len(symlink.orderOnlyDeps) > 0 {
+ if len(symlink.orderOnlyDeps) > 0 {
fmt.Fprintf(buf, " |")
}
- if symlink.from != nil {
- fmt.Fprintf(buf, " %s", symlink.from.String())
- }
for _, dep := range symlink.orderOnlyDeps {
fmt.Fprintf(buf, " %s", dep.String())
}
@@ -491,6 +509,7 @@
fromStr = symlink.absFrom
}
+ fmt.Fprintln(buf, "\t@echo \"Symlink $@\"")
fmt.Fprintf(buf, "\trm -f $@ && ln -sfn %s $@", fromStr)
fmt.Fprintln(buf)
fmt.Fprintln(buf)
diff --git a/android/module.go b/android/module.go
index 3447f2b..c2fa848 100644
--- a/android/module.go
+++ b/android/module.go
@@ -381,6 +381,16 @@
// for which IsInstallDepNeeded returns true.
InstallFile(installPath InstallPath, name string, srcPath Path, deps ...Path) InstallPath
+ // InstallFileWithExtraFilesZip creates a rule to copy srcPath to name in the installPath
+ // directory, and also unzip a zip file containing extra files to install into the same
+ // directory.
+ //
+ // The installed file will be returned by FilesToInstall(), and the PackagingSpec for the
+ // installed file will be returned by PackagingSpecs() on this module or by
+ // TransitivePackagingSpecs() on modules that depend on this module through dependency tags
+ // for which IsInstallDepNeeded returns true.
+ InstallFileWithExtraFilesZip(installPath InstallPath, name string, srcPath Path, extraZip Path, deps ...Path) InstallPath
+
// InstallSymlink creates a rule to create a symlink from src srcPath to name in the installPath
// directory.
//
@@ -409,7 +419,6 @@
PackageFile(installPath InstallPath, name string, srcPath Path) PackagingSpec
CheckbuildFile(srcPath Path)
- TidyFile(srcPath WritablePath)
InstallInData() bool
InstallInTestcases() bool
@@ -420,7 +429,6 @@
InstallInRecovery() bool
InstallInRoot() bool
InstallInVendor() bool
- InstallBypassMake() bool
InstallForceOS() (*OsType, *ArchType)
RequiredModuleNames() []string
@@ -487,7 +495,6 @@
InstallInRecovery() bool
InstallInRoot() bool
InstallInVendor() bool
- InstallBypassMake() bool
InstallForceOS() (*OsType, *ArchType)
HideFromMake()
IsHideFromMake() bool
@@ -862,6 +869,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)
@@ -1018,9 +1032,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)
@@ -1082,7 +1093,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 {
@@ -1100,14 +1112,45 @@
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)
+ }
+ }
+
data.Append(required)
+
+ var err error
+ constraints := constraintAttributes{}
+ constraints.Target_compatible_with, 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 enabled attribute: %s", err)
+ }
+ return constraints
}
// A ModuleBase object contains the properties that are common to all Android
@@ -1138,7 +1181,7 @@
// }
// }
//
-// func NewMyModule() android.Module) {
+// func NewMyModule() android.Module {
// m := &myModule{}
// m.AddProperties(&m.properties)
// android.InitAndroidModule(m)
@@ -1162,17 +1205,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
@@ -1190,7 +1230,6 @@
installFiles InstallPaths
installFilesDepSet *installPathsDepSet
checkbuildFiles Paths
- tidyFiles WritablePaths
packagingSpecs []PackagingSpec
packagingSpecsDepSet *packagingSpecsDepSet
noticeFiles Paths
@@ -1206,7 +1245,6 @@
// Only set on the final variant of each module
installTarget WritablePath
checkbuildTarget WritablePath
- tidyTarget WritablePath
blueprintDir string
hooks hooks
@@ -1220,14 +1258,19 @@
initRcPaths Paths
vintfFragmentsPaths Paths
+
+ // set of dependency module:location mappings used to populate the license metadata for
+ // apex containers.
+ licenseInstallMap []string
}
// 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.
@@ -1253,7 +1296,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) {
@@ -1279,7 +1322,7 @@
// 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 m.commonProperties.UnconvertedBp2buildDeps
+ return FirstUniqueStrings(m.commonProperties.UnconvertedBp2buildDeps)
}
func (m *ModuleBase) AddJSONData(d *map[string]interface{}) {
@@ -1290,6 +1333,8 @@
func (m *ModuleBase) DepsMutator(BottomUpMutatorContext) {}
+// AddProperties "registers" the provided props
+// each value in props MUST be a pointer to a struct
func (m *ModuleBase) AddProperties(props ...interface{}) {
m.registerProps = append(m.registerProps, props...)
}
@@ -1691,10 +1736,6 @@
return false
}
-func (m *ModuleBase) InstallBypassMake() bool {
- return false
-}
-
func (m *ModuleBase) InstallForceOS() (*OsType, *ArchType) {
return nil, nil
}
@@ -1764,20 +1805,24 @@
return append(Paths{}, m.vintfFragmentsPaths...)
}
+// 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) {
+ m.licenseInstallMap = append(m.licenseInstallMap, installMap...)
+}
+
func (m *ModuleBase) generateModuleTarget(ctx ModuleContext) {
var allInstalledFiles InstallPaths
var allCheckbuildFiles Paths
- var allTidyFiles WritablePaths
ctx.VisitAllModuleVariants(func(module Module) {
a := module.base()
allInstalledFiles = append(allInstalledFiles, a.installFiles...)
- // A module's -{checkbuild,tidy} phony targets should
+ // A module's -checkbuild phony targets should
// not be created if the module is not exported to make.
// Those could depend on the build target and fail to compile
// for the current build target.
if !ctx.Config().KatiEnabled() || !shouldSkipAndroidMkProcessing(a) {
allCheckbuildFiles = append(allCheckbuildFiles, a.checkbuildFiles...)
- allTidyFiles = append(allTidyFiles, a.tidyFiles...)
}
})
@@ -1802,13 +1847,6 @@
deps = append(deps, m.checkbuildTarget)
}
- if len(allTidyFiles) > 0 {
- name := namespacePrefix + ctx.ModuleName() + "-tidy"
- ctx.Phony(name, allTidyFiles.Paths()...)
- m.tidyTarget = PathForPhony(ctx, name)
- deps = append(deps, m.tidyTarget)
- }
-
if len(deps) > 0 {
suffix := ""
if ctx.Config().KatiEnabled() {
@@ -2017,7 +2055,6 @@
m.installFiles = append(m.installFiles, ctx.installFiles...)
m.checkbuildFiles = append(m.checkbuildFiles, ctx.checkbuildFiles...)
- m.tidyFiles = append(m.tidyFiles, ctx.tidyFiles...)
m.packagingSpecs = append(m.packagingSpecs, ctx.packagingSpecs...)
m.katiInstalls = append(m.katiInstalls, ctx.katiInstalls...)
m.katiSymlinks = append(m.katiSymlinks, ctx.katiSymlinks...)
@@ -2039,6 +2076,8 @@
m.installFilesDepSet = newInstallPathsDepSet(m.installFiles, dependencyInstallFiles)
m.packagingSpecsDepSet = newPackagingSpecsDepSet(m.packagingSpecs, dependencyPackagingSpecs)
+ buildLicenseMetadata(ctx)
+
m.buildParams = ctx.buildParams
m.ruleParams = ctx.ruleParams
m.variables = ctx.variables
@@ -2085,18 +2124,18 @@
return GlobFiles(e, globPattern, excludes)
}
-func (b *earlyModuleContext) IsSymlink(path Path) bool {
- fileInfo, err := b.config.fs.Lstat(path.String())
+func (e *earlyModuleContext) IsSymlink(path Path) bool {
+ fileInfo, err := e.config.fs.Lstat(path.String())
if err != nil {
- b.ModuleErrorf("os.Lstat(%q) failed: %s", path.String(), err)
+ e.ModuleErrorf("os.Lstat(%q) failed: %s", path.String(), err)
}
return fileInfo.Mode()&os.ModeSymlink == os.ModeSymlink
}
-func (b *earlyModuleContext) Readlink(path Path) string {
- dest, err := b.config.fs.Readlink(path.String())
+func (e *earlyModuleContext) Readlink(path Path) string {
+ dest, err := e.config.fs.Readlink(path.String())
if err != nil {
- b.ModuleErrorf("os.Readlink(%q) failed: %s", path.String(), err)
+ e.ModuleErrorf("os.Readlink(%q) failed: %s", path.String(), err)
}
return dest
}
@@ -2215,7 +2254,6 @@
packagingSpecs []PackagingSpec
installFiles InstallPaths
checkbuildFiles Paths
- tidyFiles WritablePaths
module Module
phonies map[string]Paths
@@ -2235,10 +2273,16 @@
implicitDeps Paths
orderOnlyDeps Paths
executable bool
+ extraFiles *extraFilesZip
absFrom string
}
+type extraFilesZip struct {
+ zip Path
+ dir InstallPath
+}
+
type katiInstalls []katiInstall
// BuiltInstalled returns the katiInstalls in the form used by $(call copy-many-files) in Make, a
@@ -2813,10 +2857,6 @@
return m.module.InstallInRoot()
}
-func (m *moduleContext) InstallBypassMake() bool {
- return m.module.InstallBypassMake()
-}
-
func (m *moduleContext) InstallForceOS() (*OsType, *ArchType) {
return m.module.InstallForceOS()
}
@@ -2841,23 +2881,25 @@
return true
}
- if m.Device() {
- if m.Config().KatiEnabled() && !m.InstallBypassMake() {
- return true
- }
- }
-
return false
}
func (m *moduleContext) InstallFile(installPath InstallPath, name string, srcPath Path,
deps ...Path) InstallPath {
- return m.installFile(installPath, name, srcPath, deps, false)
+ return m.installFile(installPath, name, srcPath, deps, false, nil)
}
func (m *moduleContext) InstallExecutable(installPath InstallPath, name string, srcPath Path,
deps ...Path) InstallPath {
- return m.installFile(installPath, name, srcPath, deps, true)
+ return m.installFile(installPath, name, srcPath, deps, true, nil)
+}
+
+func (m *moduleContext) InstallFileWithExtraFilesZip(installPath InstallPath, name string, srcPath Path,
+ extraZip Path, deps ...Path) InstallPath {
+ return m.installFile(installPath, name, srcPath, deps, false, &extraFilesZip{
+ zip: extraZip,
+ dir: installPath,
+ })
}
func (m *moduleContext) PackageFile(installPath InstallPath, name string, srcPath Path) PackagingSpec {
@@ -2878,7 +2920,8 @@
return spec
}
-func (m *moduleContext) installFile(installPath InstallPath, name string, srcPath Path, deps []Path, executable bool) InstallPath {
+func (m *moduleContext) installFile(installPath InstallPath, name string, srcPath Path, deps []Path,
+ executable bool, extraZip *extraFilesZip) InstallPath {
fullInstallPath := installPath.Join(m, name)
m.module.base().hooks.runInstallHooks(m, srcPath, fullInstallPath, false)
@@ -2896,7 +2939,7 @@
orderOnlyDeps = deps
}
- if m.Config().KatiEnabled() && m.InstallBypassMake() {
+ if m.Config().KatiEnabled() {
// When creating the install rule in Soong but embedding in Make, write the rule to a
// makefile instead of directly to the ninja file so that main.mk can add the
// dependencies from the `required` property that are hard to resolve in Soong.
@@ -2906,6 +2949,7 @@
implicitDeps: implicitDeps,
orderOnlyDeps: orderOnlyDeps,
executable: executable,
+ extraFiles: extraZip,
})
} else {
rule := Cp
@@ -2913,6 +2957,13 @@
rule = CpExecutable
}
+ extraCmds := ""
+ if extraZip != nil {
+ extraCmds += fmt.Sprintf(" && unzip -qDD -d '%s' '%s'",
+ extraZip.dir.String(), extraZip.zip.String())
+ implicitDeps = append(implicitDeps, extraZip.zip)
+ }
+
m.Build(pctx, BuildParams{
Rule: rule,
Description: "install " + fullInstallPath.Base(),
@@ -2921,6 +2972,9 @@
Implicits: implicitDeps,
OrderOnly: orderOnlyDeps,
Default: !m.Config().KatiEnabled(),
+ Args: map[string]string{
+ "extraCmds": extraCmds,
+ },
})
}
@@ -2944,7 +2998,7 @@
}
if !m.skipInstall() {
- if m.Config().KatiEnabled() && m.InstallBypassMake() {
+ if m.Config().KatiEnabled() {
// When creating the symlink rule in Soong but embedding in Make, write the rule to a
// makefile instead of directly to the ninja file so that main.mk can add the
// dependencies from the `required` property that are hard to resolve in Soong.
@@ -2953,6 +3007,10 @@
to: fullInstallPath,
})
} else {
+ // The symlink doesn't need updating when the target is modified, but we sometimes
+ // have a dependency on a symlink to a binary instead of to the binary directly, and
+ // the mtime of the symlink must be updated when the binary is modified, so use a
+ // normal dependency here instead of an order-only dependency.
m.Build(pctx, BuildParams{
Rule: Symlink,
Description: "install symlink " + fullInstallPath.Base(),
@@ -2986,7 +3044,7 @@
m.module.base().hooks.runInstallHooks(m, nil, fullInstallPath, true)
if !m.skipInstall() {
- if m.Config().KatiEnabled() && m.InstallBypassMake() {
+ if m.Config().KatiEnabled() {
// When creating the symlink rule in Soong but embedding in Make, write the rule to a
// makefile instead of directly to the ninja file so that main.mk can add the
// dependencies from the `required` property that are hard to resolve in Soong.
@@ -3023,10 +3081,6 @@
m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
}
-func (m *moduleContext) TidyFile(srcPath WritablePath) {
- m.tidyFiles = append(m.tidyFiles, srcPath)
-}
-
func (m *moduleContext) blueprintModuleContext() blueprint.ModuleContext {
return m.bp
}
@@ -3285,9 +3339,10 @@
type buildTargetSingleton struct{}
-func addAncestors(ctx SingletonContext, dirMap map[string]Paths, mmName func(string) string) []string {
+func AddAncestors(ctx SingletonContext, dirMap map[string]Paths, mmName func(string) string) ([]string, []string) {
// Ensure ancestor directories are in dirMap
// Make directories build their direct subdirectories
+ // Returns a slice of all directories and a slice of top-level directories.
dirs := SortedStringKeys(dirMap)
for _, dir := range dirs {
dir := parentDir(dir)
@@ -3300,34 +3355,31 @@
}
}
dirs = SortedStringKeys(dirMap)
+ var topDirs []string
for _, dir := range dirs {
p := parentDir(dir)
if p != "." && p != "/" {
dirMap[p] = append(dirMap[p], PathForPhony(ctx, mmName(dir)))
+ } else if dir != "." && dir != "/" && dir != "" {
+ topDirs = append(topDirs, dir)
}
}
- return SortedStringKeys(dirMap)
+ return SortedStringKeys(dirMap), topDirs
}
func (c *buildTargetSingleton) GenerateBuildActions(ctx SingletonContext) {
var checkbuildDeps Paths
- var tidyDeps Paths
mmTarget := func(dir string) string {
return "MODULES-IN-" + strings.Replace(filepath.Clean(dir), "/", "-", -1)
}
- mmTidyTarget := func(dir string) string {
- return "tidy-" + strings.Replace(filepath.Clean(dir), "/", "-", -1)
- }
modulesInDir := make(map[string]Paths)
- tidyModulesInDir := make(map[string]Paths)
ctx.VisitAllModules(func(module Module) {
blueprintDir := module.base().blueprintDir
installTarget := module.base().installTarget
checkbuildTarget := module.base().checkbuildTarget
- tidyTarget := module.base().tidyTarget
if checkbuildTarget != nil {
checkbuildDeps = append(checkbuildDeps, checkbuildTarget)
@@ -3337,16 +3389,6 @@
if installTarget != nil {
modulesInDir[blueprintDir] = append(modulesInDir[blueprintDir], installTarget)
}
-
- if tidyTarget != nil {
- tidyDeps = append(tidyDeps, tidyTarget)
- // tidyTarget is in modulesInDir so it will be built with "mm".
- modulesInDir[blueprintDir] = append(modulesInDir[blueprintDir], tidyTarget)
- // tidyModulesInDir contains tidyTarget but not checkbuildTarget
- // or installTarget, so tidy targets in a directory can be built
- // without other checkbuild or install targets.
- tidyModulesInDir[blueprintDir] = append(tidyModulesInDir[blueprintDir], tidyTarget)
- }
})
suffix := ""
@@ -3357,24 +3399,12 @@
// Create a top-level checkbuild target that depends on all modules
ctx.Phony("checkbuild"+suffix, checkbuildDeps...)
- // Create a top-level tidy target that depends on all modules
- ctx.Phony("tidy"+suffix, tidyDeps...)
-
- dirs := addAncestors(ctx, tidyModulesInDir, mmTidyTarget)
-
- // Kati does not generate tidy-* phony targets yet.
- // Create a tidy-<directory> target that depends on all subdirectories
- // and modules in the directory.
- for _, dir := range dirs {
- ctx.Phony(mmTidyTarget(dir), tidyModulesInDir[dir]...)
- }
-
// Make will generate the MODULES-IN-* targets
if ctx.Config().KatiEnabled() {
return
}
- dirs = addAncestors(ctx, modulesInDir, mmTarget)
+ dirs, _ := AddAncestors(ctx, modulesInDir, mmTarget)
// Create a MODULES-IN-<directory> target that depends on all modules in a directory, and
// depends on the MODULES-IN-* targets of all of its subdirectories that contain Android.bp
diff --git a/android/module_test.go b/android/module_test.go
index 9e2b0ca..d9e2c87 100644
--- a/android/module_test.go
+++ b/android/module_test.go
@@ -15,7 +15,12 @@
package android
import (
+ "bytes"
+ "path/filepath"
+ "runtime"
"testing"
+
+ mkparser "android/soong/androidmk/parser"
)
func TestSrcIsModule(t *testing.T) {
@@ -200,16 +205,23 @@
}
func (m *depsModule) GenerateAndroidBuildActions(ctx ModuleContext) {
+ outputFile := PathForModuleOut(ctx, ctx.ModuleName())
+ ctx.Build(pctx, BuildParams{
+ Rule: Touch,
+ Output: outputFile,
+ })
+ installFile := ctx.InstallFile(PathForModuleInstall(ctx), ctx.ModuleName(), outputFile)
+ ctx.InstallSymlink(PathForModuleInstall(ctx, "symlinks"), ctx.ModuleName(), installFile)
}
func (m *depsModule) DepsMutator(ctx BottomUpMutatorContext) {
- ctx.AddDependency(ctx.Module(), nil, m.props.Deps...)
+ ctx.AddDependency(ctx.Module(), installDepTag{}, m.props.Deps...)
}
func depsModuleFactory() Module {
m := &depsModule{}
m.AddProperties(&m.props)
- InitAndroidModule(m)
+ InitAndroidArchModule(m, HostAndDeviceDefault, MultilibCommon)
return m
}
@@ -320,3 +332,286 @@
ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern(expectedErrs)).
RunTestWithBp(t, bp)
}
+
+func TestInstall(t *testing.T) {
+ if runtime.GOOS != "linux" {
+ t.Skip("requires linux")
+ }
+ bp := `
+ deps {
+ name: "foo",
+ deps: ["bar"],
+ }
+
+ deps {
+ name: "bar",
+ deps: ["baz", "qux"],
+ }
+
+ deps {
+ name: "baz",
+ deps: ["qux"],
+ }
+
+ deps {
+ name: "qux",
+ }
+ `
+
+ result := GroupFixturePreparers(
+ prepareForModuleTests,
+ PrepareForTestWithArchMutator,
+ ).RunTestWithBp(t, bp)
+
+ module := func(name string, host bool) TestingModule {
+ variant := "android_common"
+ if host {
+ variant = result.Config.BuildOSCommonTarget.String()
+ }
+ return result.ModuleForTests(name, variant)
+ }
+
+ outputRule := func(name string) TestingBuildParams { return module(name, false).Output(name) }
+
+ installRule := func(name string) TestingBuildParams {
+ return module(name, false).Output(filepath.Join("out/soong/target/product/test_device/system", name))
+ }
+
+ symlinkRule := func(name string) TestingBuildParams {
+ return module(name, false).Output(filepath.Join("out/soong/target/product/test_device/system/symlinks", name))
+ }
+
+ hostOutputRule := func(name string) TestingBuildParams { return module(name, true).Output(name) }
+
+ hostInstallRule := func(name string) TestingBuildParams {
+ return module(name, true).Output(filepath.Join("out/soong/host/linux-x86", name))
+ }
+
+ hostSymlinkRule := func(name string) TestingBuildParams {
+ return module(name, true).Output(filepath.Join("out/soong/host/linux-x86/symlinks", name))
+ }
+
+ assertInputs := func(params TestingBuildParams, inputs ...Path) {
+ t.Helper()
+ AssertArrayString(t, "expected inputs", Paths(inputs).Strings(),
+ append(PathsIfNonNil(params.Input), params.Inputs...).Strings())
+ }
+
+ assertImplicits := func(params TestingBuildParams, implicits ...Path) {
+ t.Helper()
+ AssertArrayString(t, "expected implicit dependencies", Paths(implicits).Strings(),
+ append(PathsIfNonNil(params.Implicit), params.Implicits...).Strings())
+ }
+
+ assertOrderOnlys := func(params TestingBuildParams, orderonlys ...Path) {
+ t.Helper()
+ AssertArrayString(t, "expected orderonly dependencies", Paths(orderonlys).Strings(),
+ params.OrderOnly.Strings())
+ }
+
+ // Check host install rule dependencies
+ assertInputs(hostInstallRule("foo"), hostOutputRule("foo").Output)
+ assertImplicits(hostInstallRule("foo"),
+ hostInstallRule("bar").Output,
+ hostSymlinkRule("bar").Output,
+ hostInstallRule("baz").Output,
+ hostSymlinkRule("baz").Output,
+ hostInstallRule("qux").Output,
+ hostSymlinkRule("qux").Output,
+ )
+ assertOrderOnlys(hostInstallRule("foo"))
+
+ // Check host symlink rule dependencies. Host symlinks must use a normal dependency, not an
+ // order-only dependency, so that the tool gets updated when the symlink is depended on.
+ assertInputs(hostSymlinkRule("foo"), hostInstallRule("foo").Output)
+ assertImplicits(hostSymlinkRule("foo"))
+ assertOrderOnlys(hostSymlinkRule("foo"))
+
+ // Check device install rule dependencies
+ assertInputs(installRule("foo"), outputRule("foo").Output)
+ assertImplicits(installRule("foo"))
+ assertOrderOnlys(installRule("foo"),
+ installRule("bar").Output,
+ symlinkRule("bar").Output,
+ installRule("baz").Output,
+ symlinkRule("baz").Output,
+ installRule("qux").Output,
+ symlinkRule("qux").Output,
+ )
+
+ // Check device symlink rule dependencies. Device symlinks could use an order-only dependency,
+ // but the current implementation uses a normal dependency.
+ assertInputs(symlinkRule("foo"), installRule("foo").Output)
+ assertImplicits(symlinkRule("foo"))
+ assertOrderOnlys(symlinkRule("foo"))
+}
+
+func TestInstallKatiEnabled(t *testing.T) {
+ if runtime.GOOS != "linux" {
+ t.Skip("requires linux")
+ }
+ bp := `
+ deps {
+ name: "foo",
+ deps: ["bar"],
+ }
+
+ deps {
+ name: "bar",
+ deps: ["baz", "qux"],
+ }
+
+ deps {
+ name: "baz",
+ deps: ["qux"],
+ }
+
+ deps {
+ name: "qux",
+ }
+ `
+
+ result := GroupFixturePreparers(
+ prepareForModuleTests,
+ PrepareForTestWithArchMutator,
+ FixtureModifyConfig(SetKatiEnabledForTests),
+ FixtureRegisterWithContext(func(ctx RegistrationContext) {
+ ctx.RegisterSingletonType("makevars", makeVarsSingletonFunc)
+ }),
+ ).RunTestWithBp(t, bp)
+
+ installs := result.SingletonForTests("makevars").Singleton().(*makeVarsSingleton).installsForTesting
+ buf := bytes.NewBuffer(append([]byte(nil), installs...))
+ parser := mkparser.NewParser("makevars", buf)
+
+ nodes, errs := parser.Parse()
+ if len(errs) > 0 {
+ t.Fatalf("error parsing install rules: %s", errs[0])
+ }
+
+ rules := parseMkRules(t, result.Config, nodes)
+
+ module := func(name string, host bool) TestingModule {
+ variant := "android_common"
+ if host {
+ variant = result.Config.BuildOSCommonTarget.String()
+ }
+ return result.ModuleForTests(name, variant)
+ }
+
+ outputRule := func(name string) TestingBuildParams { return module(name, false).Output(name) }
+
+ ruleForOutput := func(output string) installMakeRule {
+ for _, rule := range rules {
+ if rule.target == output {
+ return rule
+ }
+ }
+ t.Fatalf("no make install rule for %s", output)
+ return installMakeRule{}
+ }
+
+ installRule := func(name string) installMakeRule {
+ return ruleForOutput(filepath.Join("out/target/product/test_device/system", name))
+ }
+
+ symlinkRule := func(name string) installMakeRule {
+ return ruleForOutput(filepath.Join("out/target/product/test_device/system/symlinks", name))
+ }
+
+ hostOutputRule := func(name string) TestingBuildParams { return module(name, true).Output(name) }
+
+ hostInstallRule := func(name string) installMakeRule {
+ return ruleForOutput(filepath.Join("out/host/linux-x86", name))
+ }
+
+ hostSymlinkRule := func(name string) installMakeRule {
+ return ruleForOutput(filepath.Join("out/host/linux-x86/symlinks", name))
+ }
+
+ assertDeps := func(rule installMakeRule, deps ...string) {
+ t.Helper()
+ AssertArrayString(t, "expected inputs", deps, rule.deps)
+ }
+
+ assertOrderOnlys := func(rule installMakeRule, orderonlys ...string) {
+ t.Helper()
+ AssertArrayString(t, "expected orderonly dependencies", orderonlys, rule.orderOnlyDeps)
+ }
+
+ // Check host install rule dependencies
+ assertDeps(hostInstallRule("foo"),
+ hostOutputRule("foo").Output.String(),
+ hostInstallRule("bar").target,
+ hostSymlinkRule("bar").target,
+ hostInstallRule("baz").target,
+ hostSymlinkRule("baz").target,
+ hostInstallRule("qux").target,
+ hostSymlinkRule("qux").target,
+ )
+ assertOrderOnlys(hostInstallRule("foo"))
+
+ // Check host symlink rule dependencies. Host symlinks must use a normal dependency, not an
+ // order-only dependency, so that the tool gets updated when the symlink is depended on.
+ assertDeps(hostSymlinkRule("foo"), hostInstallRule("foo").target)
+ assertOrderOnlys(hostSymlinkRule("foo"))
+
+ // Check device install rule dependencies
+ assertDeps(installRule("foo"), outputRule("foo").Output.String())
+ assertOrderOnlys(installRule("foo"),
+ installRule("bar").target,
+ symlinkRule("bar").target,
+ installRule("baz").target,
+ symlinkRule("baz").target,
+ installRule("qux").target,
+ symlinkRule("qux").target,
+ )
+
+ // Check device symlink rule dependencies. Device symlinks could use an order-only dependency,
+ // but the current implementation uses a normal dependency.
+ assertDeps(symlinkRule("foo"), installRule("foo").target)
+ assertOrderOnlys(symlinkRule("foo"))
+}
+
+type installMakeRule struct {
+ target string
+ deps []string
+ orderOnlyDeps []string
+}
+
+func parseMkRules(t *testing.T, config Config, nodes []mkparser.Node) []installMakeRule {
+ var rules []installMakeRule
+ for _, node := range nodes {
+ if mkParserRule, ok := node.(*mkparser.Rule); ok {
+ var rule installMakeRule
+
+ if targets := mkParserRule.Target.Words(); len(targets) == 0 {
+ t.Fatalf("no targets for rule %s", mkParserRule.Dump())
+ } else if len(targets) > 1 {
+ t.Fatalf("unsupported multiple targets for rule %s", mkParserRule.Dump())
+ } else if !targets[0].Const() {
+ t.Fatalf("unsupported non-const target for rule %s", mkParserRule.Dump())
+ } else {
+ rule.target = normalizeStringRelativeToTop(config, targets[0].Value(nil))
+ }
+
+ prereqList := &rule.deps
+ for _, prereq := range mkParserRule.Prerequisites.Words() {
+ if !prereq.Const() {
+ t.Fatalf("unsupported non-const prerequisite for rule %s", mkParserRule.Dump())
+ }
+
+ if prereq.Value(nil) == "|" {
+ prereqList = &rule.orderOnlyDeps
+ continue
+ }
+
+ *prereqList = append(*prereqList, normalizeStringRelativeToTop(config, prereq.Value(nil)))
+ }
+
+ rules = append(rules, rule)
+ }
+ }
+
+ return rules
+}
diff --git a/android/mutator.go b/android/mutator.go
index 4b37377..fa6f2be 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -16,7 +16,6 @@
import (
"reflect"
- "sync"
"android/soong/bazel"
@@ -34,12 +33,12 @@
// continue on to GenerateAndroidBuildActions
// RegisterMutatorsForBazelConversion is a alternate registration pipeline for bp2build. Exported for testing.
-func RegisterMutatorsForBazelConversion(ctx *Context, preArchMutators, bp2buildMutators []RegisterMutatorFunc) {
+func RegisterMutatorsForBazelConversion(ctx *Context, preArchMutators []RegisterMutatorFunc) {
mctx := ®isterMutatorsContext{
bazelConversionMode: true,
}
- bp2buildPreArchMutators = append([]RegisterMutatorFunc{
+ bp2buildMutators := append([]RegisterMutatorFunc{
RegisterNamespaceMutator,
RegisterDefaultsPreArchMutators,
// TODO(b/165114590): this is required to resolve deps that are only prebuilts, but we should
@@ -47,10 +46,7 @@
RegisterPrebuiltsPreArchMutators,
},
preArchMutators...)
-
- for _, f := range bp2buildPreArchMutators {
- f(mctx)
- }
+ bp2buildMutators = append(bp2buildMutators, registerBp2buildConversionMutator)
// Register bp2build mutators
for _, f := range bp2buildMutators {
@@ -216,24 +212,12 @@
}
var bp2buildPreArchMutators = []RegisterMutatorFunc{}
-var bp2buildMutators = map[string]RegisterMutatorFunc{}
-// See http://b/192523357
-var bp2buildLock sync.Mutex
+// A minimal context for Bp2build conversion
+type Bp2buildMutatorContext interface {
+ BazelConversionPathContext
-// RegisterBp2BuildMutator registers specially crafted mutators for
-// converting Blueprint/Android modules into special modules that can
-// be code-generated into Bazel BUILD targets.
-//
-// TODO(b/178068862): bring this into TestContext.
-func RegisterBp2BuildMutator(moduleType string, m func(TopDownMutatorContext)) {
- f := func(ctx RegisterMutatorsContext) {
- ctx.TopDown(moduleType, m)
- }
- // Use a lock to avoid a concurrent map write if RegisterBp2BuildMutator is called in parallel
- bp2buildLock.Lock()
- defer bp2buildLock.Unlock()
- bp2buildMutators[moduleType] = f
+ CreateBazelTargetModule(bazel.BazelTargetModuleProperties, CommonAttributes, interface{})
}
// PreArchBp2BuildMutators adds mutators to be register for converting Android Blueprint modules
@@ -270,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 {
@@ -518,45 +510,34 @@
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)
}
-func (t *topDownMutatorContext) AppendProperties(props ...interface{}) {
- for _, p := range props {
- err := proptools.AppendMatchingProperties(t.Module().base().customizableProperties,
- p, nil)
- if err != nil {
- if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
- t.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
- } else {
- panic(err)
- }
- }
- }
-}
-
-func (t *topDownMutatorContext) PrependProperties(props ...interface{}) {
- for _, p := range props {
- err := proptools.PrependMatchingProperties(t.Module().base().customizableProperties,
- p, nil)
- if err != nil {
- if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
- t.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
- } else {
- panic(err)
- }
- }
- }
-}
-
// android.topDownMutatorContext either has to embed blueprint.TopDownMutatorContext, in which case every method that
// has an overridden version in android.BaseModuleContext has to be manually forwarded to BaseModuleContext to avoid
// ambiguous method errors, or it has to store a blueprint.TopDownMutatorContext non-embedded, in which case every
diff --git a/android/neverallow.go b/android/neverallow.go
index 04366d3..6f9ae58 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -15,6 +15,7 @@
package android
import (
+ "fmt"
"path/filepath"
"reflect"
"regexp"
@@ -133,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 ."),
@@ -249,7 +249,7 @@
continue
}
- if !n.appliesToProperties(properties) {
+ if !n.appliesToProperties(ctx, properties) {
continue
}
@@ -269,8 +269,12 @@
}
}
+type ValueMatcherContext interface {
+ Config() Config
+}
+
type ValueMatcher interface {
- Test(string) bool
+ Test(ValueMatcherContext, string) bool
String() string
}
@@ -278,7 +282,7 @@
expected string
}
-func (m *equalMatcher) Test(value string) bool {
+func (m *equalMatcher) Test(ctx ValueMatcherContext, value string) bool {
return m.expected == value
}
@@ -289,7 +293,7 @@
type anyMatcher struct {
}
-func (m *anyMatcher) Test(value string) bool {
+func (m *anyMatcher) Test(ctx ValueMatcherContext, value string) bool {
return true
}
@@ -303,7 +307,7 @@
prefix string
}
-func (m *startsWithMatcher) Test(value string) bool {
+func (m *startsWithMatcher) Test(ctx ValueMatcherContext, value string) bool {
return strings.HasPrefix(value, m.prefix)
}
@@ -315,7 +319,7 @@
re *regexp.Regexp
}
-func (m *regexMatcher) Test(value string) bool {
+func (m *regexMatcher) Test(ctx ValueMatcherContext, value string) bool {
return m.re.MatchString(value)
}
@@ -327,7 +331,7 @@
allowed []string
}
-func (m *notInListMatcher) Test(value string) bool {
+func (m *notInListMatcher) Test(ctx ValueMatcherContext, value string) bool {
return !InList(value, m.allowed)
}
@@ -337,7 +341,7 @@
type isSetMatcher struct{}
-func (m *isSetMatcher) Test(value string) bool {
+func (m *isSetMatcher) Test(ctx ValueMatcherContext, value string) bool {
return value != ""
}
@@ -347,11 +351,38 @@
var isSetMatcherInstance = &isSetMatcher{}
+type sdkVersionMatcher struct {
+ condition func(ctx ValueMatcherContext, spec SdkSpec) bool
+ description string
+}
+
+func (m *sdkVersionMatcher) Test(ctx ValueMatcherContext, value string) bool {
+ return m.condition(ctx, SdkSpecFromWithConfig(ctx.Config(), value))
+}
+
+func (m *sdkVersionMatcher) String() string {
+ return ".sdk-version(" + m.description + ")"
+}
+
type ruleProperty struct {
fields []string // e.x.: Vndk.Enabled
matcher ValueMatcher
}
+func (r *ruleProperty) String() string {
+ return fmt.Sprintf("%q matches: %s", strings.Join(r.fields, "."), r.matcher)
+}
+
+type ruleProperties []ruleProperty
+
+func (r ruleProperties) String() string {
+ var s []string
+ for _, r := range r {
+ s = append(s, r.String())
+ }
+ return strings.Join(s, " ")
+}
+
// A NeverAllow rule.
type Rule interface {
In(path ...string) Rule
@@ -393,8 +424,8 @@
moduleTypes []string
unlessModuleTypes []string
- props []ruleProperty
- unlessProps []ruleProperty
+ props ruleProperties
+ unlessProps ruleProperties
onlyBootclasspathJar bool
}
@@ -404,16 +435,19 @@
return &rule{directDeps: make(map[string]bool)}
}
+// In adds path(s) where this rule applies.
func (r *rule) In(path ...string) Rule {
r.paths = append(r.paths, cleanPaths(path)...)
return r
}
+// NotIn adds path(s) to that this rule does not apply to.
func (r *rule) NotIn(path ...string) Rule {
r.unlessPaths = append(r.unlessPaths, cleanPaths(path)...)
return r
}
+// InDirectDeps adds dep(s) that are not allowed with this rule.
func (r *rule) InDirectDeps(deps ...string) Rule {
for _, d := range deps {
r.directDeps[d] = true
@@ -421,25 +455,30 @@
return r
}
+// WithOsClass adds osClass(es) that this rule applies to.
func (r *rule) WithOsClass(osClasses ...OsClass) Rule {
r.osClasses = append(r.osClasses, osClasses...)
return r
}
+// ModuleType adds type(s) that this rule applies to.
func (r *rule) ModuleType(types ...string) Rule {
r.moduleTypes = append(r.moduleTypes, types...)
return r
}
+// NotModuleType adds type(s) that this rule does not apply to..
func (r *rule) NotModuleType(types ...string) Rule {
r.unlessModuleTypes = append(r.unlessModuleTypes, types...)
return r
}
+// With specifies property/value combinations that are restricted for this rule.
func (r *rule) With(properties, value string) Rule {
return r.WithMatcher(properties, selectMatcher(value))
}
+// WithMatcher specifies property/matcher combinations that are restricted for this rule.
func (r *rule) WithMatcher(properties string, matcher ValueMatcher) Rule {
r.props = append(r.props, ruleProperty{
fields: fieldNamesForProperties(properties),
@@ -448,10 +487,12 @@
return r
}
+// Without specifies property/value combinations that this rule does not apply to.
func (r *rule) Without(properties, value string) Rule {
return r.WithoutMatcher(properties, selectMatcher(value))
}
+// Without specifies property/matcher combinations that this rule does not apply to.
func (r *rule) WithoutMatcher(properties string, matcher ValueMatcher) Rule {
r.unlessProps = append(r.unlessProps, ruleProperty{
fields: fieldNamesForProperties(properties),
@@ -467,49 +508,54 @@
return &equalMatcher{expected: expected}
}
+// Because specifies a reason for this rule.
func (r *rule) Because(reason string) Rule {
r.reason = reason
return r
}
+// BootclasspathJar whether this rule only applies to Jars in the Bootclasspath
func (r *rule) BootclasspathJar() Rule {
r.onlyBootclasspathJar = true
return r
}
func (r *rule) String() string {
- s := "neverallow"
- for _, v := range r.paths {
- s += " dir:" + v + "*"
+ s := []string{"neverallow requirements. Not allowed:"}
+ if len(r.paths) > 0 {
+ s = append(s, fmt.Sprintf("in dirs: %q", r.paths))
}
- for _, v := range r.unlessPaths {
- s += " -dir:" + v + "*"
+ if len(r.moduleTypes) > 0 {
+ s = append(s, fmt.Sprintf("module types: %q", r.moduleTypes))
}
- for _, v := range r.moduleTypes {
- s += " type:" + v
+ if len(r.props) > 0 {
+ s = append(s, fmt.Sprintf("properties matching: %s", r.props))
}
- for _, v := range r.unlessModuleTypes {
- s += " -type:" + v
+ if len(r.directDeps) > 0 {
+ s = append(s, fmt.Sprintf("dep(s): %q", SortedStringKeys(r.directDeps)))
}
- for _, v := range r.props {
- s += " " + strings.Join(v.fields, ".") + v.matcher.String()
- }
- for _, v := range r.unlessProps {
- s += " -" + strings.Join(v.fields, ".") + v.matcher.String()
- }
- for k := range r.directDeps {
- s += " deps:" + k
- }
- for _, v := range r.osClasses {
- s += " os:" + v.String()
+ if len(r.osClasses) > 0 {
+ s = append(s, fmt.Sprintf("os class(es): %q", r.osClasses))
}
if r.onlyBootclasspathJar {
- s += " inBcp"
+ s = append(s, "in bootclasspath jar")
+ }
+ if len(r.unlessPaths) > 0 {
+ s = append(s, fmt.Sprintf("EXCEPT in dirs: %q", r.unlessPaths))
+ }
+ if len(r.unlessModuleTypes) > 0 {
+ s = append(s, fmt.Sprintf("EXCEPT module types: %q", r.unlessModuleTypes))
+ }
+ if len(r.unlessProps) > 0 {
+ s = append(s, fmt.Sprintf("EXCEPT properties matching: %q", r.unlessProps))
}
if len(r.reason) != 0 {
- s += " which is restricted because " + r.reason
+ s = append(s, " which is restricted because "+r.reason)
}
- return s
+ if len(s) == 1 {
+ s[0] = "neverallow requirements (empty)"
+ }
+ return strings.Join(s, "\n\t")
}
func (r *rule) appliesToPath(dir string) bool {
@@ -560,9 +606,10 @@
return (len(r.moduleTypes) == 0 || InList(moduleType, r.moduleTypes)) && !InList(moduleType, r.unlessModuleTypes)
}
-func (r *rule) appliesToProperties(properties []interface{}) bool {
- includeProps := hasAllProperties(properties, r.props)
- excludeProps := hasAnyProperty(properties, r.unlessProps)
+func (r *rule) appliesToProperties(ctx ValueMatcherContext,
+ properties []interface{}) bool {
+ includeProps := hasAllProperties(ctx, properties, r.props)
+ excludeProps := hasAnyProperty(ctx, properties, r.unlessProps)
return includeProps && !excludeProps
}
@@ -582,6 +629,16 @@
return ¬InListMatcher{allowed}
}
+func LessThanSdkVersion(sdk string) ValueMatcher {
+ return &sdkVersionMatcher{
+ condition: func(ctx ValueMatcherContext, spec SdkSpec) bool {
+ return spec.ApiLevel.LessThan(
+ SdkSpecFromWithConfig(ctx.Config(), sdk).ApiLevel)
+ },
+ description: "lessThan=" + sdk,
+ }
+}
+
// assorted utils
func cleanPaths(paths []string) []string {
@@ -600,25 +657,28 @@
return names
}
-func hasAnyProperty(properties []interface{}, props []ruleProperty) bool {
+func hasAnyProperty(ctx ValueMatcherContext, properties []interface{},
+ props []ruleProperty) bool {
for _, v := range props {
- if hasProperty(properties, v) {
+ if hasProperty(ctx, properties, v) {
return true
}
}
return false
}
-func hasAllProperties(properties []interface{}, props []ruleProperty) bool {
+func hasAllProperties(ctx ValueMatcherContext, properties []interface{},
+ props []ruleProperty) bool {
for _, v := range props {
- if !hasProperty(properties, v) {
+ if !hasProperty(ctx, properties, v) {
return false
}
}
return true
}
-func hasProperty(properties []interface{}, prop ruleProperty) bool {
+func hasProperty(ctx ValueMatcherContext, properties []interface{},
+ prop ruleProperty) bool {
for _, propertyStruct := range properties {
propertiesValue := reflect.ValueOf(propertyStruct).Elem()
for _, v := range prop.fields {
@@ -632,7 +692,7 @@
}
check := func(value string) bool {
- return prop.matcher.Test(value)
+ return prop.matcher.Test(ctx, value)
}
if matchValue(propertiesValue, check) {
diff --git a/android/neverallow_test.go b/android/neverallow_test.go
index 35aadd8..59016d4 100644
--- a/android/neverallow_test.go
+++ b/android/neverallow_test.go
@@ -15,6 +15,7 @@
package android
import (
+ "regexp"
"testing"
"github.com/google/blueprint"
@@ -55,7 +56,37 @@
}`),
},
expectedErrors: []string{
- `module "libother": violates neverallow deps:not_allowed_in_direct_deps`,
+ regexp.QuoteMeta("module \"libother\": violates neverallow requirements. Not allowed:\n\tdep(s): [\"not_allowed_in_direct_deps\"]"),
+ },
+ },
+ {
+ name: "multiple constraints",
+ rules: []Rule{
+ NeverAllow().
+ InDirectDeps("not_allowed_in_direct_deps").
+ In("other").
+ ModuleType("cc_library").
+ NotIn("top").
+ NotModuleType("cc_binary"),
+ },
+ fs: map[string][]byte{
+ "top/Android.bp": []byte(`
+ cc_library {
+ name: "not_allowed_in_direct_deps",
+ }`),
+ "other/Android.bp": []byte(`
+ cc_library {
+ name: "libother",
+ static_libs: ["not_allowed_in_direct_deps"],
+ }`),
+ },
+ expectedErrors: []string{
+ regexp.QuoteMeta(`module "libother": violates neverallow requirements. Not allowed:
+ in dirs: ["other/"]
+ module types: ["cc_library"]
+ dep(s): ["not_allowed_in_direct_deps"]
+ EXCEPT in dirs: ["top/"]
+ EXCEPT module types: ["cc_binary"]`),
},
},
@@ -296,6 +327,48 @@
"Only boot images may be imported as a makefile goal.",
},
},
+ {
+ name: "min_sdk too low",
+ fs: map[string][]byte{
+ "Android.bp": []byte(`
+ java_library {
+ name: "min_sdk_too_low",
+ min_sdk_version: "30",
+ }`),
+ },
+ rules: []Rule{
+ NeverAllow().WithMatcher("min_sdk_version", LessThanSdkVersion("31")),
+ },
+ expectedErrors: []string{
+ "module \"min_sdk_too_low\": violates neverallow",
+ },
+ },
+ {
+ name: "min_sdk high enough",
+ fs: map[string][]byte{
+ "Android.bp": []byte(`
+ java_library {
+ name: "min_sdk_high_enough",
+ min_sdk_version: "31",
+ }`),
+ },
+ rules: []Rule{
+ NeverAllow().WithMatcher("min_sdk_version", LessThanSdkVersion("31")),
+ },
+ },
+ {
+ name: "current min_sdk high enough",
+ fs: map[string][]byte{
+ "Android.bp": []byte(`
+ java_library {
+ name: "current_min_sdk_high_enough",
+ min_sdk_version: "current",
+ }`),
+ },
+ rules: []Rule{
+ NeverAllow().WithMatcher("min_sdk_version", LessThanSdkVersion("31")),
+ },
+ },
}
var prepareForNeverAllowTest = GroupFixturePreparers(
@@ -379,9 +452,10 @@
}
type mockJavaLibraryProperties struct {
- Libs []string
- Sdk_version *string
- Uncompress_dex *bool
+ Libs []string
+ Min_sdk_version *string
+ Sdk_version *string
+ Uncompress_dex *bool
}
type mockJavaLibraryModule struct {
diff --git a/android/package_ctx.go b/android/package_ctx.go
index c19debb..f354db8 100644
--- a/android/package_ctx.go
+++ b/android/package_ctx.go
@@ -19,6 +19,7 @@
"strings"
"github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
"android/soong/remoteexec"
)
@@ -173,7 +174,7 @@
// package-scoped variable's initialization.
func (p PackageContext) HostBinToolVariable(name, path string) blueprint.Variable {
return p.VariableFunc(name, func(ctx PackageVarContext) string {
- return ctx.Config().HostToolPath(ctx, path).String()
+ return proptools.NinjaAndShellEscape(ctx.Config().HostToolPath(ctx, path).String())
})
}
@@ -183,7 +184,7 @@
// package-scoped variable's initialization.
func (p PackageContext) HostJNIToolVariable(name, path string) blueprint.Variable {
return p.VariableFunc(name, func(ctx PackageVarContext) string {
- return ctx.Config().HostJNIToolPath(ctx, path).String()
+ return proptools.NinjaAndShellEscape(ctx.Config().HostJNIToolPath(ctx, path).String())
})
}
@@ -193,7 +194,7 @@
// part of a package-scoped variable's initialization.
func (p PackageContext) HostJavaToolVariable(name, path string) blueprint.Variable {
return p.VariableFunc(name, func(ctx PackageVarContext) string {
- return ctx.Config().HostJavaToolPath(ctx, path).String()
+ return proptools.NinjaAndShellEscape(ctx.Config().HostJavaToolPath(ctx, path).String())
})
}
diff --git a/android/package_test.go b/android/package_test.go
index 7ea10a4..65c4240 100644
--- a/android/package_test.go
+++ b/android/package_test.go
@@ -11,7 +11,7 @@
}{
// Package default_visibility handling is tested in visibility_test.go
{
- name: "package must not accept visibility and name properties",
+ name: "package must not accept visibility, name or licenses properties",
fs: map[string][]byte{
"top/Android.bp": []byte(`
package {
@@ -48,8 +48,7 @@
default_visibility: ["//visibility:private"],
default_applicable_licenses: ["license"],
}
-
- package {
+ package {
}`),
},
expectedErrors: []string{
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/paths.go b/android/paths.go
index 69ab5f7..70e427b 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -112,7 +112,6 @@
InstallInDebugRamdisk() bool
InstallInRecovery() bool
InstallInRoot() bool
- InstallBypassMake() bool
InstallForceOS() (*OsType, *ArchType)
}
@@ -1643,8 +1642,8 @@
return p
}
-// ToMakePath returns a new InstallPath that points to Make's install directory instead of Soong's,
-// i.e. out/ instead of out/soong/.
+// Deprecated: ToMakePath is a noop, PathForModuleInstall always returns Make paths when building
+// embedded in Make.
func (p InstallPath) ToMakePath() InstallPath {
p.makePath = true
return p
@@ -1658,6 +1657,12 @@
return makePathForInstall(ctx, os, arch, partition, ctx.Debug(), pathComponents...)
}
+// PathForHostDexInstall returns an InstallPath representing the install path for the
+// module appended with paths...
+func PathForHostDexInstall(ctx ModuleInstallPathContext, pathComponents ...string) InstallPath {
+ return makePathForInstall(ctx, ctx.Config().BuildOS, ctx.Config().BuildArch, "", ctx.Debug(), pathComponents...)
+}
+
// PathForModuleInPartitionInstall is similar to PathForModuleInstall but partition is provided by the caller
func PathForModuleInPartitionInstall(ctx ModuleInstallPathContext, partition string, pathComponents ...string) InstallPath {
os, arch := osAndArch(ctx)
@@ -1679,9 +1684,6 @@
func makePathForInstall(ctx ModuleInstallPathContext, os OsType, arch ArchType, partition string, debug bool, pathComponents ...string) InstallPath {
ret := pathForInstall(ctx, os, arch, partition, debug, pathComponents...)
- if ctx.InstallBypassMake() && ctx.Config().KatiEnabled() {
- ret = ret.ToMakePath()
- }
return ret
}
@@ -1723,7 +1725,10 @@
soongOutDir: ctx.Config().soongOutDir,
partitionDir: partionPath,
partition: partition,
- makePath: false,
+ }
+
+ if ctx.Config().KatiEnabled() {
+ base.makePath = true
}
return base.Join(ctx, pathComponents...)
@@ -1999,10 +2004,6 @@
return m.inRoot
}
-func (m testModuleInstallPathContext) InstallBypassMake() bool {
- return false
-}
-
func (m testModuleInstallPathContext) InstallForceOS() (*OsType, *ArchType) {
return m.forceOS, m.forceArch
}
@@ -2055,7 +2056,12 @@
// Writes a file to the output directory. Attempting to write directly to the output directory
// will fail due to the sandbox of the soong_build process.
func WriteFileToOutputDir(path WritablePath, data []byte, perm os.FileMode) error {
- return ioutil.WriteFile(absolutePath(path.String()), data, perm)
+ absPath := absolutePath(path.String())
+ err := os.MkdirAll(filepath.Dir(absPath), 0777)
+ if err != nil {
+ return err
+ }
+ return ioutil.WriteFile(absPath, data, perm)
}
func RemoveAllOutputDir(path WritablePath) error {
diff --git a/android/paths_test.go b/android/paths_test.go
index 3f4625d..2f87977 100644
--- a/android/paths_test.go
+++ b/android/paths_test.go
@@ -993,7 +993,7 @@
{
name: "in out dir",
buildDir: "out",
- src: "out/a/b/c",
+ src: "out/soong/a/b/c",
err: "is in output",
},
}
@@ -1486,7 +1486,8 @@
AssertPathRelativeToTopEquals(t, "install path for soong", "out/soong/target/product/test_device/system/install/path", p)
})
t.Run("install for make", func(t *testing.T) {
- p := PathForModuleInstall(ctx, "install/path").ToMakePath()
+ p := PathForModuleInstall(ctx, "install/path")
+ p.makePath = true
AssertPathRelativeToTopEquals(t, "install path for make", "out/target/product/test_device/system/install/path", p)
})
t.Run("output", func(t *testing.T) {
@@ -1500,14 +1501,12 @@
t.Run("mixture", func(t *testing.T) {
paths := Paths{
PathForModuleInstall(ctx, "install/path"),
- PathForModuleInstall(ctx, "install/path").ToMakePath(),
PathForOutput(ctx, "output/path"),
PathForSource(ctx, "source/path"),
}
expected := []string{
"out/soong/target/product/test_device/system/install/path",
- "out/target/product/test_device/system/install/path",
"out/soong/output/path",
"source/path",
}
@@ -1525,7 +1524,7 @@
fmt.Println(p.Rel(), p2.Rel())
// Output:
- // out/system/framework/boot.art out/system/framework/boot.oat
+ // out/soong/system/framework/boot.art out/soong/system/framework/boot.oat
// boot.art boot.oat
}
@@ -1539,7 +1538,7 @@
fmt.Println(p.Rel(), p2.Rel())
// Output:
- // out/system/framework/boot.art out/system/framework/oat/arm/boot.vdex
+ // out/soong/system/framework/boot.art out/soong/system/framework/oat/arm/boot.vdex
// boot.art oat/arm/boot.vdex
}
diff --git a/android/prebuilt.go b/android/prebuilt.go
index e189892..ade92f7 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -97,7 +97,10 @@
type Prebuilt struct {
properties PrebuiltProperties
- srcsSupplier PrebuiltSrcsSupplier
+ // nil if the prebuilt has no srcs property at all. See InitPrebuiltModuleWithoutSrcs.
+ srcsSupplier PrebuiltSrcsSupplier
+
+ // "-" if the prebuilt has no srcs property at all. See InitPrebuiltModuleWithoutSrcs.
srcsPropertyName string
}
@@ -177,6 +180,22 @@
// Return the src value or nil if it is not available.
type PrebuiltSrcsSupplier func(ctx BaseModuleContext, prebuilt Module) []string
+func initPrebuiltModuleCommon(module PrebuiltInterface) *Prebuilt {
+ p := module.Prebuilt()
+ module.AddProperties(&p.properties)
+ return p
+}
+
+// Initialize the module as a prebuilt module that has no dedicated property that lists its
+// sources. SingleSourcePathFromSupplier should not be called for this module.
+//
+// This is the case e.g. for header modules, which provides the headers in source form
+// regardless whether they are prebuilt or not.
+func InitPrebuiltModuleWithoutSrcs(module PrebuiltInterface) {
+ p := initPrebuiltModuleCommon(module)
+ p.srcsPropertyName = "-"
+}
+
// Initialize the module as a prebuilt module that uses the provided supplier to access the
// prebuilt sources of the module.
//
@@ -190,10 +209,6 @@
// The provided property name is used to provide helpful error messages in the event that
// a problem arises, e.g. calling SingleSourcePath() when more than one source is provided.
func InitPrebuiltModuleWithSrcSupplier(module PrebuiltInterface, srcsSupplier PrebuiltSrcsSupplier, srcsPropertyName string) {
- p := module.Prebuilt()
- module.AddProperties(&p.properties)
- module.base().customizableProperties = module.GetProperties()
-
if srcsSupplier == nil {
panic(fmt.Errorf("srcsSupplier must not be nil"))
}
@@ -201,6 +216,7 @@
panic(fmt.Errorf("srcsPropertyName must not be empty"))
}
+ p := initPrebuiltModuleCommon(module)
p.srcsSupplier = srcsSupplier
p.srcsPropertyName = srcsPropertyName
}
@@ -336,7 +352,7 @@
func PrebuiltSelectModuleMutator(ctx TopDownMutatorContext) {
m := ctx.Module()
if p := GetEmbeddedPrebuilt(m); p != nil {
- if p.srcsSupplier == nil {
+ if p.srcsSupplier == nil && p.srcsPropertyName == "" {
panic(fmt.Errorf("prebuilt module did not have InitPrebuiltModule called on it"))
}
if !p.properties.SourceExists {
diff --git a/android/prebuilt_test.go b/android/prebuilt_test.go
index a1f8e63..fa40d1f 100644
--- a/android/prebuilt_test.go
+++ b/android/prebuilt_test.go
@@ -510,9 +510,9 @@
ctx.RegisterModuleType("prebuilt", newPrebuiltModule)
ctx.RegisterModuleType("source", newSourceModule)
ctx.RegisterModuleType("override_source", newOverrideSourceModule)
- ctx.RegisterModuleType("soong_config_module_type", soongConfigModuleTypeFactory)
- ctx.RegisterModuleType("soong_config_string_variable", soongConfigStringVariableDummyFactory)
- ctx.RegisterModuleType("soong_config_bool_variable", soongConfigBoolVariableDummyFactory)
+ ctx.RegisterModuleType("soong_config_module_type", SoongConfigModuleTypeFactory)
+ ctx.RegisterModuleType("soong_config_string_variable", SoongConfigStringVariableDummyFactory)
+ ctx.RegisterModuleType("soong_config_bool_variable", SoongConfigBoolVariableDummyFactory)
}
type prebuiltModule struct {
diff --git a/android/proto.go b/android/proto.go
index 0be7893..64d4d05 100644
--- a/android/proto.go
+++ b/android/proto.go
@@ -15,12 +15,17 @@
package android
import (
+ "android/soong/bazel"
"strings"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
)
+const (
+ canonicalPathFromRootDefault = true
+)
+
// TODO(ccross): protos are often used to communicate between multiple modules. If the only
// way to convert a proto to source is to reference it as a source file, and external modules cannot
// reference source files in other modules, then every module that owns a proto file will need to
@@ -90,7 +95,7 @@
Flags: flags,
Deps: deps,
OutTypeFlag: protoOutFlag,
- CanonicalPathFromRoot: proptools.BoolDefault(p.Proto.Canonical_path_from_root, true),
+ CanonicalPathFromRoot: proptools.BoolDefault(p.Proto.Canonical_path_from_root, canonicalPathFromRootDefault),
Dir: PathForModuleGen(ctx, "proto"),
SubDir: PathForModuleGen(ctx, "proto", ctx.ModuleDir()),
}
@@ -146,3 +151,57 @@
rule.Command().
BuiltTool("dep_fixer").Flag(depFile.String())
}
+
+// Bp2buildProtoInfo contains information necessary to pass on to language specific conversion.
+type Bp2buildProtoInfo struct {
+ Type *string
+ Name string
+}
+
+type protoAttrs struct {
+ Srcs bazel.LabelListAttribute
+ Strip_import_prefix *string
+}
+
+// Bp2buildProtoProperties converts proto properties, creating a proto_library and returning the
+// information necessary for language-specific handling.
+func Bp2buildProtoProperties(ctx Bp2buildMutatorContext, module Module, srcs bazel.LabelListAttribute) (Bp2buildProtoInfo, bool) {
+ var info Bp2buildProtoInfo
+ if srcs.IsEmpty() {
+ return info, false
+ }
+ m := module.base()
+
+ info.Name = m.Name() + "_proto"
+ attrs := protoAttrs{
+ Srcs: srcs,
+ }
+
+ for axis, configToProps := range m.GetArchVariantProperties(ctx, &ProtoProperties{}) {
+ for _, rawProps := range configToProps {
+ var props *ProtoProperties
+ var ok bool
+ if props, ok = rawProps.(*ProtoProperties); !ok {
+ ctx.ModuleErrorf("Could not cast ProtoProperties to expected type")
+ }
+ if axis == bazel.NoConfigAxis {
+ info.Type = props.Proto.Type
+
+ if proptools.BoolDefault(props.Proto.Canonical_path_from_root, canonicalPathFromRootDefault) {
+ // an empty string indicates to strips the package path
+ path := ""
+ attrs.Strip_import_prefix = &path
+ }
+ } else if props.Proto.Type != info.Type && props.Proto.Type != nil {
+ ctx.ModuleErrorf("Cannot handle arch-variant types for protos at this time.")
+ }
+ }
+ }
+
+ ctx.CreateBazelTargetModule(
+ bazel.BazelTargetModuleProperties{Rule_class: "proto_library"},
+ CommonAttributes{Name: info.Name},
+ &attrs)
+
+ return info, true
+}
diff --git a/android/register.go b/android/register.go
index 5984862..1ac4440 100644
--- a/android/register.go
+++ b/android/register.go
@@ -161,6 +161,10 @@
return ctx
}
+func (ctx *Context) SetRunningAsBp2build() {
+ ctx.config.runningAsBp2Build = true
+}
+
// RegisterForBazelConversion registers an alternate shadow pipeline of
// singletons, module types and mutators to register for converting Blueprint
// files to semantically equivalent BUILD files.
@@ -174,13 +178,7 @@
t.register(ctx)
}
- bp2buildMutatorList := []RegisterMutatorFunc{}
- for t, f := range bp2buildMutators {
- ctx.config.bp2buildModuleTypeConfig[t] = true
- bp2buildMutatorList = append(bp2buildMutatorList, f)
- }
-
- RegisterMutatorsForBazelConversion(ctx, bp2buildPreArchMutators, bp2buildMutatorList)
+ RegisterMutatorsForBazelConversion(ctx, bp2buildPreArchMutators)
}
// Register the pipeline of singletons, module types, and mutators for
@@ -192,15 +190,6 @@
t.register(ctx)
}
- if ctx.config.BazelContext.BazelEnabled() {
- // Hydrate the configuration of bp2build-enabled module types. This is
- // required as a signal to identify which modules should be deferred to
- // Bazel in mixed builds, if it is enabled.
- for t, _ := range bp2buildMutators {
- ctx.config.bp2buildModuleTypeConfig[t] = true
- }
- }
-
mutators := collateGloballyRegisteredMutators()
mutators.registerAll(ctx)
diff --git a/android/rule_builder_test.go b/android/rule_builder_test.go
index feee90f..3766bb0 100644
--- a/android/rule_builder_test.go
+++ b/android/rule_builder_test.go
@@ -64,10 +64,10 @@
fmt.Printf("outputs: %q\n", rule.Outputs())
// Output:
- // commands: "ld a.o b.o -o out/linked && echo success"
+ // commands: "ld a.o b.o -o out/soong/linked && echo success"
// tools: ["ld"]
// inputs: ["a.o" "b.o"]
- // outputs: ["out/linked"]
+ // outputs: ["out/soong/linked"]
}
func ExampleRuleBuilder_SymlinkOutputs() {
@@ -79,7 +79,7 @@
Tool(PathForSource(ctx, "ln")).
FlagWithInput("-s ", PathForTesting("a.o")).
SymlinkOutput(PathForOutput(ctx, "a"))
- rule.Command().Text("cp out/a out/b").
+ rule.Command().Text("cp out/soong/a out/soong/b").
ImplicitSymlinkOutput(PathForOutput(ctx, "b"))
fmt.Printf("commands: %q\n", strings.Join(rule.Commands(), " && "))
@@ -89,11 +89,11 @@
fmt.Printf("symlink_outputs: %q\n", rule.SymlinkOutputs())
// Output:
- // commands: "ln -s a.o out/a && cp out/a out/b"
+ // commands: "ln -s a.o out/soong/a && cp out/soong/a out/soong/b"
// tools: ["ln"]
// inputs: ["a.o"]
- // outputs: ["out/a" "out/b"]
- // symlink_outputs: ["out/a" "out/b"]
+ // outputs: ["out/soong/a" "out/soong/b"]
+ // symlink_outputs: ["out/soong/a" "out/soong/b"]
}
func ExampleRuleBuilder_Temporary() {
@@ -117,10 +117,10 @@
fmt.Printf("outputs: %q\n", rule.Outputs())
// Output:
- // commands: "cp a out/b && cp out/b out/c"
+ // commands: "cp a out/soong/b && cp out/soong/b out/soong/c"
// tools: ["cp"]
// inputs: ["a"]
- // outputs: ["out/c"]
+ // outputs: ["out/soong/c"]
}
func ExampleRuleBuilder_DeleteTemporaryFiles() {
@@ -145,10 +145,10 @@
fmt.Printf("outputs: %q\n", rule.Outputs())
// Output:
- // commands: "cp a out/b && cp out/b out/c && rm -f out/b"
+ // commands: "cp a out/soong/b && cp out/soong/b out/soong/c && rm -f out/soong/b"
// tools: ["cp"]
// inputs: ["a"]
- // outputs: ["out/c"]
+ // outputs: ["out/soong/c"]
}
func ExampleRuleBuilder_Installs() {
@@ -168,7 +168,7 @@
fmt.Printf("rule.Installs().String() = %q\n", rule.Installs().String())
// Output:
- // rule.Installs().String() = "out/linked:/bin/linked out/linked:/sbin/linked"
+ // rule.Installs().String() = "out/soong/linked:/bin/linked out/soong/linked:/sbin/linked"
}
func ExampleRuleBuilderCommand() {
@@ -271,7 +271,7 @@
FlagWithRspFileInputList("@", PathForOutput(ctx, "foo.rsp"), PathsForTesting("a.java", "b.java")).
String())
// Output:
- // javac @out/foo.rsp
+ // javac @out/soong/foo.rsp
}
func ExampleRuleBuilderCommand_String() {
@@ -371,15 +371,15 @@
addCommands(rule)
wantCommands := []string{
- "out_local/module/DepFile Flag FlagWithArg=arg FlagWithDepFile=out_local/module/depfile " +
- "FlagWithInput=input FlagWithOutput=out_local/module/output FlagWithRspFileInputList=out_local/rsp " +
- "Input out_local/module/Output out_local/module/SymlinkOutput Text Tool after command2 old cmd",
- "command2 out_local/module/depfile2 input2 out_local/module/output2 tool2",
- "command3 input3 out_local/module/output2 out_local/module/output3 input3 out_local/module/output2",
+ "out_local/soong/module/DepFile Flag FlagWithArg=arg FlagWithDepFile=out_local/soong/module/depfile " +
+ "FlagWithInput=input FlagWithOutput=out_local/soong/module/output FlagWithRspFileInputList=out_local/soong/rsp " +
+ "Input out_local/soong/module/Output out_local/soong/module/SymlinkOutput Text Tool after command2 old cmd",
+ "command2 out_local/soong/module/depfile2 input2 out_local/soong/module/output2 tool2",
+ "command3 input3 out_local/soong/module/output2 out_local/soong/module/output3 input3 out_local/soong/module/output2",
}
- wantDepMergerCommand := "out_local/host/" + ctx.Config().PrebuiltOS() + "/bin/dep_fixer " +
- "out_local/module/DepFile out_local/module/depfile out_local/module/ImplicitDepFile out_local/module/depfile2"
+ wantDepMergerCommand := "out_local/soong/host/" + ctx.Config().PrebuiltOS() + "/bin/dep_fixer " +
+ "out_local/soong/module/DepFile out_local/soong/module/depfile out_local/soong/module/ImplicitDepFile out_local/soong/module/depfile2"
AssertDeepEquals(t, "rule.Commands()", wantCommands, rule.Commands())
@@ -403,13 +403,13 @@
wantCommands := []string{
"__SBOX_SANDBOX_DIR__/out/DepFile Flag FlagWithArg=arg FlagWithDepFile=__SBOX_SANDBOX_DIR__/out/depfile " +
"FlagWithInput=input FlagWithOutput=__SBOX_SANDBOX_DIR__/out/output " +
- "FlagWithRspFileInputList=out_local/rsp Input __SBOX_SANDBOX_DIR__/out/Output " +
+ "FlagWithRspFileInputList=out_local/soong/rsp Input __SBOX_SANDBOX_DIR__/out/Output " +
"__SBOX_SANDBOX_DIR__/out/SymlinkOutput Text Tool after command2 old cmd",
"command2 __SBOX_SANDBOX_DIR__/out/depfile2 input2 __SBOX_SANDBOX_DIR__/out/output2 tool2",
"command3 input3 __SBOX_SANDBOX_DIR__/out/output2 __SBOX_SANDBOX_DIR__/out/output3 input3 __SBOX_SANDBOX_DIR__/out/output2",
}
- wantDepMergerCommand := "out_local/host/" + ctx.Config().PrebuiltOS() + "/bin/dep_fixer __SBOX_SANDBOX_DIR__/out/DepFile __SBOX_SANDBOX_DIR__/out/depfile __SBOX_SANDBOX_DIR__/out/ImplicitDepFile __SBOX_SANDBOX_DIR__/out/depfile2"
+ wantDepMergerCommand := "out_local/soong/host/" + ctx.Config().PrebuiltOS() + "/bin/dep_fixer __SBOX_SANDBOX_DIR__/out/DepFile __SBOX_SANDBOX_DIR__/out/depfile __SBOX_SANDBOX_DIR__/out/ImplicitDepFile __SBOX_SANDBOX_DIR__/out/depfile2"
AssertDeepEquals(t, "rule.Commands()", wantCommands, rule.Commands())
@@ -433,7 +433,7 @@
wantCommands := []string{
"__SBOX_SANDBOX_DIR__/out/DepFile Flag FlagWithArg=arg FlagWithDepFile=__SBOX_SANDBOX_DIR__/out/depfile " +
"FlagWithInput=input FlagWithOutput=__SBOX_SANDBOX_DIR__/out/output " +
- "FlagWithRspFileInputList=out_local/rsp Input __SBOX_SANDBOX_DIR__/out/Output " +
+ "FlagWithRspFileInputList=out_local/soong/rsp Input __SBOX_SANDBOX_DIR__/out/Output " +
"__SBOX_SANDBOX_DIR__/out/SymlinkOutput Text __SBOX_SANDBOX_DIR__/tools/src/Tool after command2 old cmd",
"command2 __SBOX_SANDBOX_DIR__/out/depfile2 input2 __SBOX_SANDBOX_DIR__/out/output2 __SBOX_SANDBOX_DIR__/tools/src/tool2",
"command3 input3 __SBOX_SANDBOX_DIR__/out/output2 __SBOX_SANDBOX_DIR__/out/output3 input3 __SBOX_SANDBOX_DIR__/out/output2",
diff --git a/android/sdk_version.go b/android/sdk_version.go
index 1813e7e..2004c92 100644
--- a/android/sdk_version.go
+++ b/android/sdk_version.go
@@ -117,7 +117,7 @@
return false
}
-// PrebuiltSdkAvailableForUnbundledBuilt tells whether this SdkSpec can have a prebuilt SDK
+// PrebuiltSdkAvailableForUnbundledBuild tells whether this SdkSpec can have a prebuilt SDK
// that can be used for unbundled builds.
func (s SdkSpec) PrebuiltSdkAvailableForUnbundledBuild() bool {
// "", "none", and "core_platform" are not available for unbundled build
@@ -212,6 +212,10 @@
)
func SdkSpecFrom(ctx EarlyModuleContext, str string) SdkSpec {
+ return SdkSpecFromWithConfig(ctx.Config(), str)
+}
+
+func SdkSpecFromWithConfig(config Config, str string) SdkSpec {
switch str {
// special cases first
case "":
@@ -252,7 +256,7 @@
return SdkSpec{SdkInvalid, NoneApiLevel, str}
}
- apiLevel, err := ApiLevelFromUser(ctx, versionString)
+ apiLevel, err := ApiLevelFromUserWithConfig(config, versionString)
if err != nil {
return SdkSpec{SdkInvalid, apiLevel, str}
}
diff --git a/android/sdk_version_test.go b/android/sdk_version_test.go
new file mode 100644
index 0000000..ec81782
--- /dev/null
+++ b/android/sdk_version_test.go
@@ -0,0 +1,89 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package android
+
+import (
+ "testing"
+)
+
+func TestSdkSpecFrom(t *testing.T) {
+ testCases := []struct {
+ input string
+ expected string
+ }{
+ {
+ input: "",
+ expected: "private_current",
+ },
+ {
+ input: "none",
+ expected: "none_(no version)",
+ },
+ {
+ input: "core_platform",
+ expected: "core_platform_current",
+ },
+ {
+ input: "_",
+ expected: "invalid_(no version)",
+ },
+ {
+ input: "_31",
+ expected: "invalid_(no version)",
+ },
+ {
+ input: "system_R",
+ expected: "system_30",
+ },
+ {
+ input: "test_31",
+ expected: "test_31",
+ },
+ {
+ input: "module_current",
+ expected: "module-lib_current",
+ },
+ {
+ input: "31",
+ expected: "public_31",
+ },
+ {
+ input: "S",
+ expected: "public_31",
+ },
+ {
+ input: "current",
+ expected: "public_current",
+ },
+ {
+ input: "Tiramisu",
+ expected: "public_Tiramisu",
+ },
+ }
+
+ config := NullConfig("", "")
+
+ config.productVariables = productVariables{
+ Platform_sdk_version: intPtr(31),
+ Platform_sdk_codename: stringPtr("Tiramisu"),
+ Platform_version_active_codenames: []string{"Tiramisu"},
+ }
+
+ for _, tc := range testCases {
+ if got := SdkSpecFromWithConfig(config, tc.input).String(); tc.expected != got {
+ t.Errorf("Expected %v, got %v", tc.expected, got)
+ }
+ }
+}
diff --git a/android/soong_config_modules.go b/android/soong_config_modules.go
index 17f6d66..91bbce6 100644
--- a/android/soong_config_modules.go
+++ b/android/soong_config_modules.go
@@ -31,10 +31,10 @@
)
func init() {
- RegisterModuleType("soong_config_module_type_import", soongConfigModuleTypeImportFactory)
- RegisterModuleType("soong_config_module_type", soongConfigModuleTypeFactory)
- RegisterModuleType("soong_config_string_variable", soongConfigStringVariableDummyFactory)
- RegisterModuleType("soong_config_bool_variable", soongConfigBoolVariableDummyFactory)
+ RegisterModuleType("soong_config_module_type_import", SoongConfigModuleTypeImportFactory)
+ RegisterModuleType("soong_config_module_type", SoongConfigModuleTypeFactory)
+ RegisterModuleType("soong_config_string_variable", SoongConfigStringVariableDummyFactory)
+ RegisterModuleType("soong_config_bool_variable", SoongConfigBoolVariableDummyFactory)
}
type soongConfigModuleTypeImport struct {
@@ -153,7 +153,7 @@
// Then libacme_foo would build with cflags:
// "-DGENERIC -DSOC_DEFAULT -DFEATURE_DEFAULT -DSIZE=DEFAULT".
-func soongConfigModuleTypeImportFactory() Module {
+func SoongConfigModuleTypeImportFactory() Module {
module := &soongConfigModuleTypeImport{}
module.AddProperties(&module.properties)
@@ -179,6 +179,7 @@
type soongConfigModuleTypeModule struct {
ModuleBase
+ BazelModuleBase
properties soongconfig.ModuleTypeProperties
}
@@ -262,7 +263,7 @@
// SOONG_CONFIG_acme_width := 200
//
// Then libacme_foo would build with cflags "-DGENERIC -DSOC_A -DFEATURE".
-func soongConfigModuleTypeFactory() Module {
+func SoongConfigModuleTypeFactory() Module {
module := &soongConfigModuleTypeModule{}
module.AddProperties(&module.properties)
@@ -296,7 +297,7 @@
// soong_config_string_variable defines a variable and a set of possible string values for use
// in a soong_config_module_type definition.
-func soongConfigStringVariableDummyFactory() Module {
+func SoongConfigStringVariableDummyFactory() Module {
module := &soongConfigStringVariableDummyModule{}
module.AddProperties(&module.properties, &module.stringProperties)
initAndroidModuleBase(module)
@@ -305,7 +306,7 @@
// soong_config_string_variable defines a variable with true or false values for use
// in a soong_config_module_type definition.
-func soongConfigBoolVariableDummyFactory() Module {
+func SoongConfigBoolVariableDummyFactory() Module {
module := &soongConfigBoolVariableDummyModule{}
module.AddProperties(&module.properties)
initAndroidModuleBase(module)
@@ -324,6 +325,9 @@
func (*soongConfigBoolVariableDummyModule) Nameless() {}
func (*soongConfigBoolVariableDummyModule) GenerateAndroidBuildActions(ctx ModuleContext) {}
+// importModuleTypes registers the module factories for a list of module types defined
+// in an Android.bp file. These module factories are scoped for the current Android.bp
+// file only.
func importModuleTypes(ctx LoadHookContext, from string, moduleTypes ...string) {
from = filepath.Clean(from)
if filepath.Ext(from) != ".bp" {
@@ -376,6 +380,9 @@
}
mtDef, errs := soongconfig.Parse(r, from)
+ if ctx.Config().runningAsBp2Build {
+ ctx.Config().Bp2buildSoongConfigDefinitions.AddVars(*mtDef)
+ }
if len(errs) > 0 {
reportErrors(ctx, from, errs...)
@@ -389,7 +396,7 @@
for name, moduleType := range mtDef.ModuleTypes {
factory := globalModuleTypes[moduleType.BaseModuleType]
if factory != nil {
- factories[name] = soongConfigModuleFactory(factory, moduleType)
+ factories[name] = configModuleFactory(factory, moduleType, ctx.Config().runningAsBp2Build)
} else {
reportErrors(ctx, from,
fmt.Errorf("missing global module type factory for %q", moduleType.BaseModuleType))
@@ -404,20 +411,39 @@
}).(map[string]blueprint.ModuleFactory)
}
-// soongConfigModuleFactory takes an existing soongConfigModuleFactory and a ModuleType and returns
-// a new soongConfigModuleFactory that wraps the existing soongConfigModuleFactory and adds conditional on Soong config
-// variables.
-func soongConfigModuleFactory(factory blueprint.ModuleFactory,
- moduleType *soongconfig.ModuleType) blueprint.ModuleFactory {
-
+// configModuleFactory takes an existing soongConfigModuleFactory and a
+// ModuleType to create a new ModuleFactory that uses a custom loadhook.
+func configModuleFactory(factory blueprint.ModuleFactory, moduleType *soongconfig.ModuleType, bp2build bool) blueprint.ModuleFactory {
conditionalFactoryProps := soongconfig.CreateProperties(factory, moduleType)
- if conditionalFactoryProps.IsValid() {
- return func() (blueprint.Module, []interface{}) {
- module, props := factory()
+ if !conditionalFactoryProps.IsValid() {
+ return factory
+ }
- conditionalProps := proptools.CloneEmptyProperties(conditionalFactoryProps)
- props = append(props, conditionalProps.Interface())
+ return func() (blueprint.Module, []interface{}) {
+ module, props := factory()
+ conditionalProps := proptools.CloneEmptyProperties(conditionalFactoryProps)
+ props = append(props, conditionalProps.Interface())
+ if bp2build {
+ // The loadhook is different for bp2build, since we don't want to set a specific
+ // set of property values based on a vendor var -- we want __all of them__ to
+ // generate select statements, so we put the entire soong_config_variables
+ // struct, together with the namespace representing those variables, while
+ // creating the custom module with the factory.
+ AddLoadHook(module, func(ctx LoadHookContext) {
+ if m, ok := module.(Bazelable); ok {
+ m.SetBaseModuleType(moduleType.BaseModuleType)
+ // Instead of applying all properties, keep the entire conditionalProps struct as
+ // part of the custom module so dependent modules can create the selects accordingly
+ m.setNamespacedVariableProps(namespacedVariableProperties{
+ moduleType.ConfigNamespace: []interface{}{conditionalProps.Interface()},
+ })
+ }
+ })
+ } else {
+ // Regular Soong operation wraps the existing module factory with a
+ // conditional on Soong config variables by reading the product
+ // config variables from Make.
AddLoadHook(module, func(ctx LoadHookContext) {
config := ctx.Config().VendorConfig(moduleType.ConfigNamespace)
newProps, err := soongconfig.PropertiesToApply(moduleType, conditionalProps, config)
@@ -429,10 +455,7 @@
ctx.AppendProperties(ps)
}
})
-
- return module, props
}
- } else {
- return factory
+ return module, props
}
}
diff --git a/android/soong_config_modules_test.go b/android/soong_config_modules_test.go
index 0ec9bcb..acb9d18 100644
--- a/android/soong_config_modules_test.go
+++ b/android/soong_config_modules_test.go
@@ -310,10 +310,10 @@
tc.preparer,
PrepareForTestWithDefaults,
FixtureRegisterWithContext(func(ctx RegistrationContext) {
- ctx.RegisterModuleType("soong_config_module_type_import", soongConfigModuleTypeImportFactory)
- ctx.RegisterModuleType("soong_config_module_type", soongConfigModuleTypeFactory)
- ctx.RegisterModuleType("soong_config_string_variable", soongConfigStringVariableDummyFactory)
- ctx.RegisterModuleType("soong_config_bool_variable", soongConfigBoolVariableDummyFactory)
+ ctx.RegisterModuleType("soong_config_module_type_import", SoongConfigModuleTypeImportFactory)
+ ctx.RegisterModuleType("soong_config_module_type", SoongConfigModuleTypeFactory)
+ ctx.RegisterModuleType("soong_config_string_variable", SoongConfigStringVariableDummyFactory)
+ ctx.RegisterModuleType("soong_config_bool_variable", SoongConfigBoolVariableDummyFactory)
ctx.RegisterModuleType("test_defaults", soongConfigTestDefaultsModuleFactory)
ctx.RegisterModuleType("test", soongConfigTestModuleFactory)
}),
@@ -372,10 +372,10 @@
fixtureForVendorVars(map[string]map[string]string{"acme": {"feature1": "1"}}),
PrepareForTestWithDefaults,
FixtureRegisterWithContext(func(ctx RegistrationContext) {
- ctx.RegisterModuleType("soong_config_module_type_import", soongConfigModuleTypeImportFactory)
- ctx.RegisterModuleType("soong_config_module_type", soongConfigModuleTypeFactory)
- ctx.RegisterModuleType("soong_config_string_variable", soongConfigStringVariableDummyFactory)
- ctx.RegisterModuleType("soong_config_bool_variable", soongConfigBoolVariableDummyFactory)
+ ctx.RegisterModuleType("soong_config_module_type_import", SoongConfigModuleTypeImportFactory)
+ ctx.RegisterModuleType("soong_config_module_type", SoongConfigModuleTypeFactory)
+ ctx.RegisterModuleType("soong_config_string_variable", SoongConfigStringVariableDummyFactory)
+ ctx.RegisterModuleType("soong_config_bool_variable", SoongConfigBoolVariableDummyFactory)
ctx.RegisterModuleType("test_defaults", soongConfigTestDefaultsModuleFactory)
ctx.RegisterModuleType("test", soongConfigTestModuleFactory)
}),
diff --git a/android/soongconfig/Android.bp b/android/soongconfig/Android.bp
index e7fa5a0..9bf3344 100644
--- a/android/soongconfig/Android.bp
+++ b/android/soongconfig/Android.bp
@@ -9,6 +9,7 @@
"blueprint",
"blueprint-parser",
"blueprint-proptools",
+ "soong-bazel",
],
srcs: [
"config.go",
diff --git a/android/soongconfig/modules.go b/android/soongconfig/modules.go
index 34b180d..09a5057 100644
--- a/android/soongconfig/modules.go
+++ b/android/soongconfig/modules.go
@@ -20,6 +20,7 @@
"reflect"
"sort"
"strings"
+ "sync"
"github.com/google/blueprint"
"github.com/google/blueprint/parser"
@@ -28,7 +29,7 @@
const conditionsDefault = "conditions_default"
-var soongConfigProperty = proptools.FieldNameForProperty("soong_config_variables")
+var SoongConfigProperty = proptools.FieldNameForProperty("soong_config_variables")
// loadSoongConfigModuleTypeDefinition loads module types from an Android.bp file. It caches the
// result so each file is only parsed once.
@@ -230,6 +231,104 @@
variables map[string]soongConfigVariable
}
+// Bp2BuildSoongConfigDefinition keeps a global record of all soong config
+// string vars, bool vars and value vars created by every
+// soong_config_module_type in this build.
+type Bp2BuildSoongConfigDefinitions struct {
+ StringVars map[string]map[string]bool
+ BoolVars map[string]bool
+ ValueVars map[string]bool
+}
+
+var bp2buildSoongConfigVarsLock sync.Mutex
+
+// SoongConfigVariablesForBp2build extracts information from a
+// SoongConfigDefinition that bp2build needs to generate constraint settings and
+// values for, in order to migrate soong_config_module_type usages to Bazel.
+func (defs *Bp2BuildSoongConfigDefinitions) AddVars(mtDef SoongConfigDefinition) {
+ // In bp2build mode, this method is called concurrently in goroutines from
+ // loadhooks while parsing soong_config_module_type, so add a mutex to
+ // prevent concurrent map writes. See b/207572723
+ bp2buildSoongConfigVarsLock.Lock()
+ defer bp2buildSoongConfigVarsLock.Unlock()
+
+ if defs.StringVars == nil {
+ defs.StringVars = make(map[string]map[string]bool)
+ }
+ if defs.BoolVars == nil {
+ defs.BoolVars = make(map[string]bool)
+ }
+ if defs.ValueVars == nil {
+ defs.ValueVars = make(map[string]bool)
+ }
+ for _, moduleType := range mtDef.ModuleTypes {
+ for _, v := range moduleType.Variables {
+ key := strings.Join([]string{moduleType.ConfigNamespace, v.variableProperty()}, "__")
+ if strVar, ok := v.(*stringVariable); ok {
+ if _, ok := defs.StringVars[key]; !ok {
+ defs.StringVars[key] = make(map[string]bool, 0)
+ }
+ for _, value := range strVar.values {
+ defs.StringVars[key][value] = true
+ }
+ } else if _, ok := v.(*boolVariable); ok {
+ defs.BoolVars[key] = true
+ } else if _, ok := v.(*valueVariable); ok {
+ defs.ValueVars[key] = true
+ } else {
+ panic(fmt.Errorf("Unsupported variable type: %+v", v))
+ }
+ }
+ }
+}
+
+// This is a copy of the one available in soong/android/util.go, but depending
+// on the android package causes a cyclic dependency. A refactoring here is to
+// extract common utils out from android/utils.go for other packages like this.
+func sortedStringKeys(m interface{}) []string {
+ v := reflect.ValueOf(m)
+ if v.Kind() != reflect.Map {
+ panic(fmt.Sprintf("%#v is not a map", m))
+ }
+ keys := v.MapKeys()
+ s := make([]string, 0, len(keys))
+ for _, key := range keys {
+ s = append(s, key.String())
+ }
+ sort.Strings(s)
+ return s
+}
+
+// String emits the Soong config variable definitions as Starlark dictionaries.
+func (defs Bp2BuildSoongConfigDefinitions) String() string {
+ ret := ""
+ ret += "soong_config_bool_variables = {\n"
+ for _, boolVar := range sortedStringKeys(defs.BoolVars) {
+ ret += fmt.Sprintf(" \"%s\": True,\n", boolVar)
+ }
+ ret += "}\n"
+ ret += "\n"
+
+ ret += "soong_config_value_variables = {\n"
+ for _, valueVar := range sortedStringKeys(defs.ValueVars) {
+ ret += fmt.Sprintf(" \"%s\": True,\n", valueVar)
+ }
+ ret += "}\n"
+ ret += "\n"
+
+ ret += "soong_config_string_variables = {\n"
+ for _, stringVar := range sortedStringKeys(defs.StringVars) {
+ ret += fmt.Sprintf(" \"%s\": [\n", stringVar)
+ for _, choice := range sortedStringKeys(defs.StringVars[stringVar]) {
+ ret += fmt.Sprintf(" \"%s\",\n", choice)
+ }
+ ret += fmt.Sprintf(" ],\n")
+ }
+ ret += "}"
+
+ return ret
+}
+
// CreateProperties returns a reflect.Value of a newly constructed type that contains the desired
// property layout for the Soong config variables, with each possible value an interface{} that
// contains a nil pointer to another newly constructed type that contains the affectable properties.
@@ -271,12 +370,12 @@
}
typ := reflect.StructOf([]reflect.StructField{{
- Name: soongConfigProperty,
+ Name: SoongConfigProperty,
Type: reflect.StructOf(fields),
}})
props := reflect.New(typ)
- structConditions := props.Elem().FieldByName(soongConfigProperty)
+ structConditions := props.Elem().FieldByName(SoongConfigProperty)
for i, c := range moduleType.Variables {
c.initializeProperties(structConditions.Field(i), affectablePropertiesType)
@@ -415,7 +514,7 @@
// soong_config_variables are expected to be in the same order as moduleType.Variables.
func PropertiesToApply(moduleType *ModuleType, props reflect.Value, config SoongConfig) ([]interface{}, error) {
var ret []interface{}
- props = props.Elem().FieldByName(soongConfigProperty)
+ props = props.Elem().FieldByName(SoongConfigProperty)
for i, c := range moduleType.Variables {
if ps, err := c.PropertiesToApply(config, props.Field(i)); err != nil {
return nil, err
diff --git a/android/soongconfig/modules_test.go b/android/soongconfig/modules_test.go
index 48cdfe7..b14f8b4 100644
--- a/android/soongconfig/modules_test.go
+++ b/android/soongconfig/modules_test.go
@@ -364,3 +364,117 @@
}
}
}
+
+func Test_Bp2BuildSoongConfigDefinitions(t *testing.T) {
+ testCases := []struct {
+ defs Bp2BuildSoongConfigDefinitions
+ expected string
+ }{
+ {
+ defs: Bp2BuildSoongConfigDefinitions{},
+ expected: `soong_config_bool_variables = {
+}
+
+soong_config_value_variables = {
+}
+
+soong_config_string_variables = {
+}`}, {
+ defs: Bp2BuildSoongConfigDefinitions{
+ BoolVars: map[string]bool{
+ "bool_var": true,
+ },
+ },
+ expected: `soong_config_bool_variables = {
+ "bool_var": True,
+}
+
+soong_config_value_variables = {
+}
+
+soong_config_string_variables = {
+}`}, {
+ defs: Bp2BuildSoongConfigDefinitions{
+ ValueVars: map[string]bool{
+ "value_var": true,
+ },
+ },
+ expected: `soong_config_bool_variables = {
+}
+
+soong_config_value_variables = {
+ "value_var": True,
+}
+
+soong_config_string_variables = {
+}`}, {
+ defs: Bp2BuildSoongConfigDefinitions{
+ StringVars: map[string]map[string]bool{
+ "string_var": map[string]bool{
+ "choice1": true,
+ "choice2": true,
+ "choice3": true,
+ },
+ },
+ },
+ expected: `soong_config_bool_variables = {
+}
+
+soong_config_value_variables = {
+}
+
+soong_config_string_variables = {
+ "string_var": [
+ "choice1",
+ "choice2",
+ "choice3",
+ ],
+}`}, {
+ defs: Bp2BuildSoongConfigDefinitions{
+ BoolVars: map[string]bool{
+ "bool_var_one": true,
+ },
+ ValueVars: map[string]bool{
+ "value_var_one": true,
+ "value_var_two": true,
+ },
+ StringVars: map[string]map[string]bool{
+ "string_var_one": map[string]bool{
+ "choice1": true,
+ "choice2": true,
+ "choice3": true,
+ },
+ "string_var_two": map[string]bool{
+ "foo": true,
+ "bar": true,
+ },
+ },
+ },
+ expected: `soong_config_bool_variables = {
+ "bool_var_one": True,
+}
+
+soong_config_value_variables = {
+ "value_var_one": True,
+ "value_var_two": True,
+}
+
+soong_config_string_variables = {
+ "string_var_one": [
+ "choice1",
+ "choice2",
+ "choice3",
+ ],
+ "string_var_two": [
+ "bar",
+ "foo",
+ ],
+}`},
+ }
+ for _, test := range testCases {
+ actual := test.defs.String()
+ if actual != test.expected {
+ t.Errorf("Expected:\n%s\nbut got:\n%s", test.expected, actual)
+ }
+ }
+}
diff --git a/android/test_suites.go b/android/test_suites.go
index 22f6cf2..55e1da7 100644
--- a/android/test_suites.go
+++ b/android/test_suites.go
@@ -60,7 +60,7 @@
for _, module := range SortedStringKeys(files) {
installedPaths = append(installedPaths, files[module]...)
}
- testCasesDir := pathForInstall(ctx, ctx.Config().BuildOS, X86, "testcases", false).ToMakePath()
+ testCasesDir := pathForInstall(ctx, ctx.Config().BuildOS, X86, "testcases", false)
outputFile := PathForOutput(ctx, "packaging", "robolectric-tests.zip")
rule := NewRuleBuilder(pctx, ctx)
diff --git a/android/testing.go b/android/testing.go
index b9d8fa8..8daf6b7 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -208,16 +208,6 @@
ctx.config.bp2buildPackageConfig = config
}
-// RegisterBp2BuildMutator registers a BazelTargetModule mutator for converting a module
-// type to the equivalent Bazel target.
-func (ctx *TestContext) RegisterBp2BuildMutator(moduleType string, m func(TopDownMutatorContext)) {
- f := func(ctx RegisterMutatorsContext) {
- ctx.TopDown(moduleType, m)
- }
- ctx.config.bp2buildModuleTypeConfig[moduleType] = true
- ctx.bp2buildMutators = append(ctx.bp2buildMutators, f)
-}
-
// PreArchBp2BuildMutators adds mutators to be register for converting Android Blueprint modules
// into Bazel BUILD targets that should run prior to deps and conversion.
func (ctx *TestContext) PreArchBp2BuildMutators(f RegisterMutatorFunc) {
@@ -458,7 +448,8 @@
// RegisterForBazelConversion prepares a test context for bp2build conversion.
func (ctx *TestContext) RegisterForBazelConversion() {
- RegisterMutatorsForBazelConversion(ctx.Context, ctx.bp2buildPreArch, ctx.bp2buildMutators)
+ ctx.SetRunningAsBp2build()
+ RegisterMutatorsForBazelConversion(ctx.Context, ctx.bp2buildPreArch)
}
func (ctx *TestContext) ParseFileList(rootDir string, filePaths []string) (deps []string, errs []error) {
diff --git a/android/util.go b/android/util.go
index a0394f6..0ee253e 100644
--- a/android/util.go
+++ b/android/util.go
@@ -65,22 +65,6 @@
return buf.String()
}
-// SortedIntKeys returns the keys of the given integer-keyed map in the ascending order
-// TODO(asmundak): once Go has generics, combine this with SortedStringKeys below.
-func SortedIntKeys(m interface{}) []int {
- v := reflect.ValueOf(m)
- if v.Kind() != reflect.Map {
- panic(fmt.Sprintf("%#v is not a map", m))
- }
- keys := v.MapKeys()
- s := make([]int, 0, len(keys))
- for _, key := range keys {
- s = append(s, int(key.Int()))
- }
- sort.Ints(s)
- return s
-}
-
// SorterStringKeys returns the keys of the given string-keyed map in the ascending order
func SortedStringKeys(m interface{}) []string {
v := reflect.ValueOf(m)
@@ -96,21 +80,6 @@
return s
}
-// SortedStringMapValues returns the values of the string-values map in the ascending order
-func SortedStringMapValues(m interface{}) []string {
- v := reflect.ValueOf(m)
- if v.Kind() != reflect.Map {
- panic(fmt.Sprintf("%#v is not a map", m))
- }
- keys := v.MapKeys()
- s := make([]string, 0, len(keys))
- for _, key := range keys {
- s = append(s, v.MapIndex(key).String())
- }
- sort.Strings(s)
- return s
-}
-
// IndexList returns the index of the first occurrence of the given string in the list or -1
func IndexList(s string, list []string) int {
for i, l := range list {
diff --git a/android/variable.go b/android/variable.go
index e943640..b300267 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -20,6 +20,9 @@
"runtime"
"strings"
+ "android/soong/android/soongconfig"
+ "android/soong/bazel"
+
"github.com/google/blueprint/proptools"
)
@@ -121,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
@@ -243,30 +249,30 @@
AppsDefaultVersionName *string `json:",omitempty"`
- Allow_missing_dependencies *bool `json:",omitempty"`
- Unbundled_build *bool `json:",omitempty"`
- Unbundled_build_apps *bool `json:",omitempty"`
- Unbundled_build_image *bool `json:",omitempty"`
- Always_use_prebuilt_sdks *bool `json:",omitempty"`
- Skip_boot_jars_check *bool `json:",omitempty"`
- Malloc_not_svelte *bool `json:",omitempty"`
- Malloc_zero_contents *bool `json:",omitempty"`
- Malloc_pattern_fill_contents *bool `json:",omitempty"`
- Safestack *bool `json:",omitempty"`
- HostStaticBinaries *bool `json:",omitempty"`
- Binder32bit *bool `json:",omitempty"`
- UseGoma *bool `json:",omitempty"`
- UseRBE *bool `json:",omitempty"`
- UseRBEJAVAC *bool `json:",omitempty"`
- UseRBER8 *bool `json:",omitempty"`
- UseRBED8 *bool `json:",omitempty"`
- Debuggable *bool `json:",omitempty"`
- Eng *bool `json:",omitempty"`
- Treble_linker_namespaces *bool `json:",omitempty"`
- Enforce_vintf_manifest *bool `json:",omitempty"`
- Uml *bool `json:",omitempty"`
- Arc *bool `json:",omitempty"`
- MinimizeJavaDebugInfo *bool `json:",omitempty"`
+ Allow_missing_dependencies *bool `json:",omitempty"`
+ Unbundled_build *bool `json:",omitempty"`
+ Unbundled_build_apps []string `json:",omitempty"`
+ Unbundled_build_image *bool `json:",omitempty"`
+ Always_use_prebuilt_sdks *bool `json:",omitempty"`
+ Skip_boot_jars_check *bool `json:",omitempty"`
+ Malloc_not_svelte *bool `json:",omitempty"`
+ Malloc_zero_contents *bool `json:",omitempty"`
+ Malloc_pattern_fill_contents *bool `json:",omitempty"`
+ Safestack *bool `json:",omitempty"`
+ HostStaticBinaries *bool `json:",omitempty"`
+ Binder32bit *bool `json:",omitempty"`
+ UseGoma *bool `json:",omitempty"`
+ UseRBE *bool `json:",omitempty"`
+ UseRBEJAVAC *bool `json:",omitempty"`
+ UseRBER8 *bool `json:",omitempty"`
+ UseRBED8 *bool `json:",omitempty"`
+ Debuggable *bool `json:",omitempty"`
+ Eng *bool `json:",omitempty"`
+ Treble_linker_namespaces *bool `json:",omitempty"`
+ Enforce_vintf_manifest *bool `json:",omitempty"`
+ Uml *bool `json:",omitempty"`
+ Arc *bool `json:",omitempty"`
+ MinimizeJavaDebugInfo *bool `json:",omitempty"`
Check_elf_files *bool `json:",omitempty"`
@@ -296,8 +302,6 @@
ClangTidy *bool `json:",omitempty"`
TidyChecks *string `json:",omitempty"`
- SamplingPGO *bool `json:",omitempty"`
-
JavaCoveragePaths []string `json:",omitempty"`
JavaCoverageExcludePaths []string `json:",omitempty"`
@@ -326,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"`
@@ -343,17 +348,24 @@
RecoverySnapshotDirsIncluded []string `json:",omitempty"`
HostFakeSnapshotEnabled bool `json:",omitempty"`
- BoardVendorSepolicyDirs []string `json:",omitempty"`
- BoardOdmSepolicyDirs []string `json:",omitempty"`
- BoardReqdMaskPolicy []string `json:",omitempty"`
- SystemExtPublicSepolicyDirs []string `json:",omitempty"`
- SystemExtPrivateSepolicyDirs []string `json:",omitempty"`
- BoardSepolicyM4Defs []string `json:",omitempty"`
+ BoardVendorSepolicyDirs []string `json:",omitempty"`
+ BoardOdmSepolicyDirs []string `json:",omitempty"`
+ BoardReqdMaskPolicy []string `json:",omitempty"`
+ BoardPlatVendorPolicy []string `json:",omitempty"`
+ BoardSystemExtPublicPrebuiltDirs []string `json:",omitempty"`
+ BoardSystemExtPrivatePrebuiltDirs []string `json:",omitempty"`
+ BoardProductPublicPrebuiltDirs []string `json:",omitempty"`
+ BoardProductPrivatePrebuiltDirs []string `json:",omitempty"`
+ SystemExtPublicSepolicyDirs []string `json:",omitempty"`
+ SystemExtPrivateSepolicyDirs []string `json:",omitempty"`
+ BoardSepolicyM4Defs []string `json:",omitempty"`
BoardSepolicyVers *string `json:",omitempty"`
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"`
@@ -487,14 +499,128 @@
// ProductConfigProperty contains the information for a single property (may be a struct) paired
// with the appropriate ProductConfigVariable.
type ProductConfigProperty struct {
- ProductConfigVariable string
- FullConfig string
- Property interface{}
+ // The name of the product variable, e.g. "safestack", "malloc_not_svelte",
+ // "board"
+ Name string
+
+ // Namespace of the variable, if this is a soong_config_module_type variable
+ // e.g. "acme", "ANDROID", "vendor_name"
+ Namespace string
+
+ // Unique configuration to identify this product config property (i.e. a
+ // primary key), as just using the product variable name is not sufficient.
+ //
+ // For product variables, this is the product variable name + optional
+ // archvariant information. e.g.
+ //
+ // product_variables: {
+ // foo: {
+ // cflags: ["-Dfoo"],
+ // },
+ // },
+ //
+ // FullConfig would be "foo".
+ //
+ // target: {
+ // android: {
+ // product_variables: {
+ // foo: {
+ // cflags: ["-Dfoo-android"],
+ // },
+ // },
+ // },
+ // },
+ //
+ // FullConfig would be "foo-android".
+ //
+ // For soong config variables, this is the namespace + product variable name
+ // + value of the variable, if applicable. The value can also be
+ // conditions_default.
+ //
+ // e.g.
+ //
+ // soong_config_variables: {
+ // feature1: {
+ // conditions_default: {
+ // cflags: ["-DDEFAULT1"],
+ // },
+ // cflags: ["-DFEATURE1"],
+ // },
+ // }
+ //
+ // where feature1 is created in the "acme" namespace, so FullConfig would be
+ // "acme__feature1" and "acme__feature1__conditions_default".
+ //
+ // e.g.
+ //
+ // soong_config_variables: {
+ // board: {
+ // soc_a: {
+ // cflags: ["-DSOC_A"],
+ // },
+ // soc_b: {
+ // cflags: ["-DSOC_B"],
+ // },
+ // soc_c: {},
+ // conditions_default: {
+ // cflags: ["-DSOC_DEFAULT"]
+ // },
+ // },
+ // }
+ //
+ // where board is created in the "acme" namespace, so FullConfig would be
+ // "acme__board__soc_a", "acme__board__soc_b", and
+ // "acme__board__conditions_default"
+ FullConfig string
}
-// ProductConfigProperties is a map of property name to a slice of ProductConfigProperty such that
-// all it all product variable-specific versions of a property are easily accessed together
-type ProductConfigProperties map[string]map[string]ProductConfigProperty
+func (p *ProductConfigProperty) AlwaysEmit() bool {
+ return p.Namespace != ""
+}
+
+func (p *ProductConfigProperty) ConfigurationAxis() bazel.ConfigurationAxis {
+ if p.Namespace == "" {
+ return bazel.ProductVariableConfigurationAxis(p.FullConfig)
+ } else {
+ // Soong config variables can be uniquely identified by the namespace
+ // (e.g. acme, android) and the product variable name (e.g. board, size)
+ return bazel.ProductVariableConfigurationAxis(p.Namespace + "__" + p.Name)
+ }
+}
+
+// SelectKey returns the literal string that represents this variable in a BUILD
+// select statement.
+func (p *ProductConfigProperty) SelectKey() string {
+ if p.Namespace == "" {
+ return strings.ToLower(p.FullConfig)
+ }
+
+ if p.FullConfig == bazel.ConditionsDefaultConfigKey {
+ return bazel.ConditionsDefaultConfigKey
+ }
+
+ value := p.FullConfig
+ if value == p.Name {
+ value = "enabled"
+ }
+ // e.g. acme__feature1__enabled, android__board__soc_a
+ return strings.ToLower(strings.Join([]string{p.Namespace, p.Name, value}, "__"))
+}
+
+// ProductConfigProperties is a map of maps to group property values according
+// their property name and the product config variable they're set under.
+//
+// The outer map key is the name of the property, like "cflags".
+//
+// The inner map key is a ProductConfigProperty, which is a struct of product
+// variable name, namespace, and the "full configuration" of the product
+// variable.
+//
+// e.g. product variable name: board, namespace: acme, full config: vendor_chip_foo
+//
+// The value of the map is the interface{} representing the value of the
+// property, like ["-DDEFINES"] for cflags.
+type ProductConfigProperties map[string]map[ProductConfigProperty]interface{}
// ProductVariableProperties returns a ProductConfigProperties containing only the properties which
// have been set for the module in the given context.
@@ -504,36 +630,281 @@
productConfigProperties := ProductConfigProperties{}
- if moduleBase.variableProperties == nil {
- return productConfigProperties
- }
+ if moduleBase.variableProperties != nil {
+ productVariablesProperty := proptools.FieldNameForProperty("product_variables")
+ productVariableValues(
+ productVariablesProperty,
+ moduleBase.variableProperties,
+ "",
+ "",
+ &productConfigProperties)
- productVariableValues(moduleBase.variableProperties, "", &productConfigProperties)
-
- for _, configToProps := range moduleBase.GetArchVariantProperties(ctx, moduleBase.variableProperties) {
- for config, props := range configToProps {
- // GetArchVariantProperties is creating an instance of the requested type
- // and productVariablesValues expects an interface, so no need to cast
- productVariableValues(props, config, &productConfigProperties)
+ for _, configToProps := range moduleBase.GetArchVariantProperties(ctx, moduleBase.variableProperties) {
+ for config, props := range configToProps {
+ // GetArchVariantProperties is creating an instance of the requested type
+ // and productVariablesValues expects an interface, so no need to cast
+ productVariableValues(
+ productVariablesProperty,
+ props,
+ "",
+ config,
+ &productConfigProperties)
+ }
}
}
+ if m, ok := module.(Bazelable); ok && m.namespacedVariableProps() != nil {
+ for namespace, namespacedVariableProps := range m.namespacedVariableProps() {
+ for _, namespacedVariableProp := range namespacedVariableProps {
+ productVariableValues(
+ soongconfig.SoongConfigProperty,
+ namespacedVariableProp,
+ namespace,
+ "",
+ &productConfigProperties)
+ }
+ }
+ }
+
+ productConfigProperties.zeroValuesForNamespacedVariables()
+
return productConfigProperties
}
-func productVariableValues(variableProps interface{}, suffix string, productConfigProperties *ProductConfigProperties) {
- if suffix != "" {
- suffix = "-" + suffix
+// zeroValuesForNamespacedVariables ensures that selects that contain __only__
+// conditions default values have zero values set for the other non-default
+// values for that select statement.
+//
+// If the ProductConfigProperties map contains these items, as parsed from the .bp file:
+//
+// library_linking_strategy: {
+// prefer_static: {
+// static_libs: [
+// "lib_a",
+// "lib_b",
+// ],
+// },
+// conditions_default: {
+// shared_libs: [
+// "lib_a",
+// "lib_b",
+// ],
+// },
+// },
+//
+// Static_libs {Library_linking_strategy ANDROID prefer_static} [lib_a lib_b]
+// Shared_libs {Library_linking_strategy ANDROID conditions_default} [lib_a lib_b]
+//
+// We need to add this:
+//
+// Shared_libs {Library_linking_strategy ANDROID prefer_static} []
+//
+// so that the following gets generated for the "dynamic_deps" attribute,
+// instead of putting lib_a and lib_b directly into dynamic_deps without a
+// select:
+//
+// dynamic_deps = select({
+// "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": [],
+// "//conditions:default": [
+// "//foo/bar:lib_a",
+// "//foo/bar:lib_b",
+// ],
+// }),
+func (props *ProductConfigProperties) zeroValuesForNamespacedVariables() {
+ // A map of product config properties to the zero values of their respective
+ // property value.
+ zeroValues := make(map[ProductConfigProperty]interface{})
+
+ // A map of prop names (e.g. cflags) to product config properties where the
+ // (prop name, ProductConfigProperty) tuple contains a non-conditions_default key.
+ //
+ // e.g.
+ //
+ // prefer_static: {
+ // static_libs: [
+ // "lib_a",
+ // "lib_b",
+ // ],
+ // },
+ // conditions_default: {
+ // shared_libs: [
+ // "lib_a",
+ // "lib_b",
+ // ],
+ // },
+ //
+ // The tuple of ("static_libs", prefer_static) would be in this map.
+ hasNonDefaultValue := make(map[string]map[ProductConfigProperty]bool)
+
+ // Iterate over all added soong config variables.
+ for propName, v := range *props {
+ for p, intf := range v {
+ if p.Namespace == "" {
+ // If there's no namespace, this isn't a soong config variable,
+ // i.e. this is a product variable. product variables have no
+ // conditions_defaults, so skip them.
+ continue
+ }
+ if p.FullConfig == bazel.ConditionsDefaultConfigKey {
+ // Skip conditions_defaults.
+ continue
+ }
+ if hasNonDefaultValue[propName] == nil {
+ hasNonDefaultValue[propName] = make(map[ProductConfigProperty]bool)
+ hasNonDefaultValue[propName][p] = false
+ }
+ // Create the zero value of the variable.
+ if _, exists := zeroValues[p]; !exists {
+ zeroValue := reflect.Zero(reflect.ValueOf(intf).Type()).Interface()
+ if zeroValue == nil {
+ panic(fmt.Errorf("Expected non-nil zero value for product/config variable %+v\n", intf))
+ }
+ zeroValues[p] = zeroValue
+ }
+ hasNonDefaultValue[propName][p] = true
+ }
}
- variableValues := reflect.ValueOf(variableProps).Elem().FieldByName("Product_variables")
+
+ for propName := range *props {
+ for p, zeroValue := range zeroValues {
+ // Ignore variables that already have a non-default value for that axis
+ if exists, _ := hasNonDefaultValue[propName][p]; !exists {
+ // fmt.Println(propName, p.Namespace, p.Name, p.FullConfig, zeroValue)
+ // Insert the zero value for this propname + product config value.
+ props.AddProductConfigProperty(
+ propName,
+ p.Namespace,
+ p.Name,
+ p.FullConfig,
+ zeroValue,
+ )
+ }
+ }
+ }
+}
+
+func (p *ProductConfigProperties) AddProductConfigProperty(
+ propertyName, namespace, productVariableName, config string, property interface{}) {
+ if (*p)[propertyName] == nil {
+ (*p)[propertyName] = make(map[ProductConfigProperty]interface{})
+ }
+
+ productConfigProp := ProductConfigProperty{
+ Namespace: namespace, // e.g. acme, android
+ Name: productVariableName, // e.g. size, feature1, feature2, FEATURE3, board
+ FullConfig: config, // e.g. size, feature1-x86, size__conditions_default
+ }
+
+ if existing, ok := (*p)[propertyName][productConfigProp]; ok && namespace != "" {
+ switch dst := existing.(type) {
+ case []string:
+ if src, ok := property.([]string); ok {
+ dst = append(dst, src...)
+ (*p)[propertyName][productConfigProp] = dst
+ }
+ default:
+ panic(fmt.Errorf("TODO: handle merging value %s", existing))
+ }
+ } else {
+ (*p)[propertyName][productConfigProp] = property
+ }
+}
+
+var (
+ conditionsDefaultField string = proptools.FieldNameForProperty(bazel.ConditionsDefaultConfigKey)
+)
+
+// maybeExtractConfigVarProp attempts to read this value as a config var struct
+// wrapped by interfaces and ptrs. If it's not the right type, the second return
+// value is false.
+func maybeExtractConfigVarProp(v reflect.Value) (reflect.Value, bool) {
+ if v.Kind() == reflect.Interface {
+ // The conditions_default value can be either
+ // 1) an ptr to an interface of a struct (bool config variables and product variables)
+ // 2) an interface of 1) (config variables with nested structs, like string vars)
+ v = v.Elem()
+ }
+ if v.Kind() != reflect.Ptr {
+ return v, false
+ }
+ v = reflect.Indirect(v)
+ if v.Kind() == reflect.Interface {
+ // Extract the struct from the interface
+ v = v.Elem()
+ }
+
+ if !v.IsValid() {
+ return v, false
+ }
+
+ if v.Kind() != reflect.Struct {
+ return v, false
+ }
+ return v, true
+}
+
+func (productConfigProperties *ProductConfigProperties) AddProductConfigProperties(namespace, suffix string, variableValues reflect.Value) {
+ // variableValues can either be a product_variables or
+ // soong_config_variables struct.
+ //
+ // Example of product_variables:
+ //
+ // product_variables: {
+ // malloc_not_svelte: {
+ // shared_libs: ["malloc_not_svelte_shared_lib"],
+ // whole_static_libs: ["malloc_not_svelte_whole_static_lib"],
+ // exclude_static_libs: [
+ // "malloc_not_svelte_static_lib_excludes",
+ // "malloc_not_svelte_whole_static_lib_excludes",
+ // ],
+ // },
+ // },
+ //
+ // Example of soong_config_variables:
+ //
+ // soong_config_variables: {
+ // feature1: {
+ // conditions_default: {
+ // ...
+ // },
+ // cflags: ...
+ // },
+ // feature2: {
+ // cflags: ...
+ // conditions_default: {
+ // ...
+ // },
+ // },
+ // board: {
+ // soc_a: {
+ // ...
+ // },
+ // soc_a: {
+ // ...
+ // },
+ // soc_c: {},
+ // conditions_default: {
+ // ...
+ // },
+ // },
+ // }
for i := 0; i < variableValues.NumField(); i++ {
+ // e.g. Platform_sdk_version, Unbundled_build, Malloc_not_svelte, etc.
+ productVariableName := variableValues.Type().Field(i).Name
+
variableValue := variableValues.Field(i)
// Check if any properties were set for the module
if variableValue.IsZero() {
+ // e.g. feature1: {}, malloc_not_svelte: {}
continue
}
- // e.g. Platform_sdk_version, Unbundled_build, Malloc_not_svelte, etc.
- productVariableName := variableValues.Type().Field(i).Name
+
+ // Unlike product variables, config variables require a few more
+ // indirections to extract the struct from the reflect.Value.
+ if v, ok := maybeExtractConfigVarProp(variableValue); ok {
+ variableValue = v
+ }
+
for j := 0; j < variableValue.NumField(); j++ {
property := variableValue.Field(j)
// If the property wasn't set, no need to pass it along
@@ -543,19 +914,74 @@
// e.g. Asflags, Cflags, Enabled, etc.
propertyName := variableValue.Type().Field(j).Name
- if (*productConfigProperties)[propertyName] == nil {
- (*productConfigProperties)[propertyName] = make(map[string]ProductConfigProperty)
- }
- config := productVariableName + suffix
- (*productConfigProperties)[propertyName][config] = ProductConfigProperty{
- ProductConfigVariable: productVariableName,
- FullConfig: config,
- Property: property.Interface(),
+
+ if v, ok := maybeExtractConfigVarProp(property); ok {
+ // The field is a struct, which is used by:
+ // 1) soong_config_string_variables
+ //
+ // soc_a: {
+ // cflags: ...,
+ // }
+ //
+ // soc_b: {
+ // cflags: ...,
+ // }
+ //
+ // 2) conditions_default structs for all soong config variable types.
+ //
+ // conditions_default: {
+ // cflags: ...,
+ // static_libs: ...
+ // }
+ field := v
+ for k := 0; k < field.NumField(); k++ {
+ // Iterate over fields of this struct prop.
+ if field.Field(k).IsZero() {
+ continue
+ }
+ // config can also be "conditions_default".
+ config := proptools.PropertyNameForField(propertyName)
+ actualPropertyName := field.Type().Field(k).Name
+
+ productConfigProperties.AddProductConfigProperty(
+ actualPropertyName, // e.g. cflags, static_libs
+ namespace, // e.g. acme, android
+ productVariableName, // e.g. size, feature1, FEATURE2, board
+ config,
+ field.Field(k).Interface(), // e.g. ["-DDEFAULT"], ["foo", "bar"]
+ )
+ }
+ } else if property.Kind() != reflect.Interface {
+ // If not an interface, then this is not a conditions_default or
+ // a struct prop. That is, this is a regular product variable,
+ // or a bool/value config variable.
+ config := productVariableName + suffix
+ productConfigProperties.AddProductConfigProperty(
+ propertyName,
+ namespace,
+ productVariableName,
+ config,
+ property.Interface(),
+ )
}
}
}
}
+// productVariableValues uses reflection to convert a property struct for
+// product_variables and soong_config_variables to structs that can be generated
+// as select statements.
+func productVariableValues(
+ fieldName string, variableProps interface{}, namespace, suffix string, productConfigProperties *ProductConfigProperties) {
+ if suffix != "" {
+ suffix = "-" + suffix
+ }
+
+ // variableValues represent the product_variables or soong_config_variables struct.
+ variableValues := reflect.ValueOf(variableProps).Elem().FieldByName(fieldName)
+ productConfigProperties.AddProductConfigProperties(namespace, suffix, variableValues)
+}
+
func VariableMutator(mctx BottomUpMutatorContext) {
var module Module
var ok bool
@@ -605,7 +1031,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/androidmk/androidmk/android.go b/androidmk/androidmk/android.go
index f3ad152..ae52688 100644
--- a/androidmk/androidmk/android.go
+++ b/androidmk/androidmk/android.go
@@ -58,6 +58,7 @@
"LOCAL_MODULE_STEM": stem,
"LOCAL_MODULE_HOST_OS": hostOs,
"LOCAL_RESOURCE_DIR": localizePathList("resource_dirs"),
+ "LOCAL_NOTICE_FILE": localizePathList("android_license_files"),
"LOCAL_SANITIZE": sanitize(""),
"LOCAL_SANITIZE_DIAG": sanitize("diag."),
"LOCAL_STRIP_MODULE": strip(),
@@ -111,7 +112,6 @@
"LOCAL_PROTOC_OPTIMIZE_TYPE": "proto.type",
"LOCAL_MODULE_OWNER": "owner",
"LOCAL_RENDERSCRIPT_TARGET_API": "renderscript.target_api",
- "LOCAL_NOTICE_FILE": "notice",
"LOCAL_JAVA_LANGUAGE_VERSION": "java_version",
"LOCAL_INSTRUMENTATION_FOR": "instrumentation_for",
"LOCAL_MANIFEST_FILE": "manifest",
@@ -185,6 +185,12 @@
"LOCAL_JACK_COVERAGE_EXCLUDE_FILTER": "jacoco.exclude_filter",
"LOCAL_FULL_LIBS_MANIFEST_FILES": "additional_manifests",
+
+ // will be rewrite later to "license_kinds:" by byfix
+ "LOCAL_LICENSE_KINDS": "android_license_kinds",
+ // will be removed later by byfix
+ // TODO: does this property matter in the license module?
+ "LOCAL_LICENSE_CONDITIONS": "android_license_conditions",
})
addStandardProperties(bpparser.BoolType,
@@ -223,6 +229,8 @@
"LOCAL_IS_UNIT_TEST": "unit_test",
"LOCAL_ENFORCE_USES_LIBRARIES": "enforce_uses_libs",
+
+ "LOCAL_CHECK_ELF_FILES": "check_elf_files",
})
}
diff --git a/androidmk/androidmk/androidmk_test.go b/androidmk/androidmk/androidmk_test.go
index 775a9a8..ea53705 100644
--- a/androidmk/androidmk/androidmk_test.go
+++ b/androidmk/androidmk/androidmk_test.go
@@ -1516,7 +1516,8 @@
],
}
`,
- }, {
+ },
+ {
desc: "Obsolete LOCAL_MODULE_PATH",
in: `
include $(CLEAR_VARS)
@@ -1532,7 +1533,58 @@
name: "foo",
}
-`},
+`,
+ },
+ {
+ desc: "LOCAL_LICENSE_KINDS, LOCAL_LICENSE_CONDITIONS, LOCAL_NOTICE_FILE",
+ // When "android_license_files" is valid, the test requires an Android.mk file
+ // outside the current (and an Android.bp file is required as well if the license
+ // files locates directory), thus a mock file system is needed. The integration
+ // test cases for these scenarios have been added in
+ // $(ANDROID_BUILD_TOP)/build/soong/tests/androidmk_test.sh.
+ in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := foo
+LOCAL_LICENSE_KINDS := license_kind
+LOCAL_LICENSE_CONDITIONS := license_condition
+LOCAL_NOTICE_FILE := license_notice
+include $(BUILD_PACKAGE)
+`,
+ expected: `
+package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: [
+ "Android-Apache-2.0",
+ ],
+}
+
+android_app {
+ name: "foo",
+ // ANDROIDMK TRANSLATION ERROR: Only $(LOCAL_PATH)/.. values are allowed
+ // LOCAL_NOTICE_FILE := license_notice
+
+}
+`,
+ },
+ {
+ desc: "LOCAL_CHECK_ELF_FILES",
+ in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := foo
+LOCAL_SRC_FILES := test.c
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+LOCAL_CHECK_ELF_FILES := false
+include $(BUILD_PREBUILT)
+ `,
+ expected: `
+cc_prebuilt_library_shared {
+ name: "foo",
+ srcs: ["test.c"],
+
+ check_elf_files: false,
+}
+`,
+ },
}
func TestEndToEnd(t *testing.T) {
diff --git a/apex/androidmk.go b/apex/androidmk.go
index 94b8116..8cca137 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -103,16 +103,9 @@
return moduleNames
}
- var postInstallCommands []string
- for _, fi := range a.filesInfo {
- if a.linkToSystemLib && fi.transitiveDep && fi.availableToPlatform() {
- // TODO(jiyong): pathOnDevice should come from fi.module, not being calculated here
- linkTarget := filepath.Join("/system", fi.path())
- linkPath := filepath.Join(a.installDir.ToMakePath().String(), apexBundleName, fi.path())
- mkdirCmd := "mkdir -p " + filepath.Dir(linkPath)
- linkCmd := "ln -sfn " + linkTarget + " " + linkPath
- postInstallCommands = append(postInstallCommands, mkdirCmd, linkCmd)
- }
+ // Avoid creating duplicate build rules for multi-installed APEXes.
+ if proptools.BoolDefault(a.properties.Multi_install_skip_symbol_files, false) {
+ return moduleNames
}
seenDataOutPaths := make(map[string]bool)
@@ -156,7 +149,7 @@
var modulePath string
if apexType == flattenedApex {
// /system/apex/<name>/{lib|framework|...}
- modulePath = filepath.Join(a.installDir.ToMakePath().String(), apexBundleName, fi.installDir)
+ modulePath = filepath.Join(a.installDir.String(), apexBundleName, fi.installDir)
fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", modulePath)
if a.primaryApexType && !symbolFilesNotNeeded {
fmt.Fprintln(w, "LOCAL_SOONG_SYMBOL_PATH :=", pathWhenActivated)
@@ -188,6 +181,8 @@
// we will have duplicated notice entries.
fmt.Fprintln(w, "LOCAL_NO_NOTICE_FILE := true")
}
+ fmt.Fprintln(w, "LOCAL_SOONG_INSTALLED_MODULE :=", filepath.Join(modulePath, fi.stem()))
+ fmt.Fprintln(w, "LOCAL_SOONG_INSTALL_PAIRS :=", fi.builtFile.String()+":"+filepath.Join(modulePath, fi.stem()))
fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", fi.builtFile.String())
fmt.Fprintln(w, "LOCAL_MODULE_CLASS :=", fi.class.nameInMake())
if fi.module != nil {
@@ -258,7 +253,7 @@
if !ok {
panic(fmt.Sprintf("Expected %s to be AndroidAppSet", fi.module))
}
- fmt.Fprintln(w, "LOCAL_APK_SET_INSTALL_FILE :=", as.InstallFile())
+ fmt.Fprintln(w, "LOCAL_APK_SET_INSTALL_FILE :=", as.PackedAdditionalOutputs().String())
fmt.Fprintln(w, "LOCAL_APKCERTS_FILE :=", as.APKCertsFile().String())
fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_android_app_set.mk")
case nativeSharedLib, nativeExecutable, nativeTest:
@@ -272,7 +267,7 @@
fmt.Fprintln(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE :=", ccMod.CoverageOutputFile().String())
}
}
- fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_cc_prebuilt.mk")
+ fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_cc_rust_prebuilt.mk")
default:
fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", fi.stem())
if fi.builtFile == a.manifestPbOut && apexType == flattenedApex {
@@ -297,18 +292,10 @@
if len(patterns) > 0 {
fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES :=", strings.Join(patterns, " "))
}
- if len(a.compatSymlinks) > 0 {
- // For flattened apexes, compat symlinks are attached to apex_manifest.json which is guaranteed for every apex
- postInstallCommands = append(postInstallCommands, a.compatSymlinks...)
- }
}
// File_contexts of flattened APEXes should be merged into file_contexts.bin
fmt.Fprintln(w, "LOCAL_FILE_CONTEXTS :=", a.fileContexts)
-
- if len(postInstallCommands) > 0 {
- fmt.Fprintln(w, "LOCAL_POST_INSTALL_CMD :=", strings.Join(postInstallCommands, " && "))
- }
}
fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
}
@@ -322,16 +309,17 @@
return moduleNames
}
-func (a *apexBundle) writeRequiredModules(w io.Writer, apexBundleName string) {
+func (a *apexBundle) writeRequiredModules(w io.Writer) {
var required []string
var targetRequired []string
var hostRequired []string
- installMapSet := make(map[string]bool) // set of dependency module:location mappings
+ required = append(required, a.RequiredModuleNames()...)
+ targetRequired = append(targetRequired, a.TargetRequiredModuleNames()...)
+ hostRequired = append(hostRequired, a.HostRequiredModuleNames()...)
for _, fi := range a.filesInfo {
required = append(required, fi.requiredModuleNames...)
targetRequired = append(targetRequired, fi.targetRequiredModuleNames...)
hostRequired = append(hostRequired, fi.hostRequiredModuleNames...)
- installMapSet[a.fullModuleName(apexBundleName, &fi)+":"+fi.installDir+"/"+fi.builtFile.Base()] = true
}
if len(required) > 0 {
@@ -343,11 +331,6 @@
if len(hostRequired) > 0 {
fmt.Fprintln(w, "LOCAL_HOST_REQUIRED_MODULES +=", strings.Join(hostRequired, " "))
}
- if len(installMapSet) > 0 {
- var installs []string
- installs = append(installs, android.SortedStringKeys(installMapSet)...)
- fmt.Fprintln(w, "LOCAL_LICENSE_INSTALL_MAP +=", strings.Join(installs, " "))
- }
}
func (a *apexBundle) androidMkForType() android.AndroidMkData {
@@ -369,7 +352,7 @@
if len(moduleNames) > 0 {
fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", strings.Join(moduleNames, " "))
}
- a.writeRequiredModules(w, name)
+ a.writeRequiredModules(w)
fmt.Fprintln(w, "include $(BUILD_PHONY_PACKAGE)")
} else {
@@ -379,13 +362,15 @@
data.Entries.WriteLicenseVariables(w)
fmt.Fprintln(w, "LOCAL_MODULE_CLASS := ETC") // do we need a new class?
fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", a.outputFile.String())
- fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", a.installDir.ToMakePath().String())
+ fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", a.installDir.String())
stemSuffix := apexType.suffix()
if a.isCompressed {
stemSuffix = imageCapexSuffix
}
fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", name+stemSuffix)
fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE :=", !a.installable())
+ fmt.Fprintln(w, "LOCAL_SOONG_INSTALLED_MODULE :=", a.installedFile.String())
+ fmt.Fprintln(w, "LOCAL_SOONG_INSTALL_PAIRS :=", a.outputFile.String()+":"+a.installedFile.String())
// Because apex writes .mk with Custom(), we need to write manually some common properties
// which are available via data.Entries
@@ -409,17 +394,7 @@
if len(a.requiredDeps) > 0 {
fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES +=", strings.Join(a.requiredDeps, " "))
}
- a.writeRequiredModules(w, name)
- var postInstallCommands []string
- if a.prebuiltFileToDelete != "" {
- postInstallCommands = append(postInstallCommands, "rm -rf "+
- filepath.Join(a.installDir.ToMakePath().String(), a.prebuiltFileToDelete))
- }
- // For unflattened apexes, compat symlinks are attached to apex package itself as LOCAL_POST_INSTALL_CMD
- postInstallCommands = append(postInstallCommands, a.compatSymlinks...)
- if len(postInstallCommands) > 0 {
- fmt.Fprintln(w, "LOCAL_POST_INSTALL_CMD :=", strings.Join(postInstallCommands, " && "))
- }
+ a.writeRequiredModules(w)
if a.mergedNotices.Merged.Valid() {
fmt.Fprintln(w, "LOCAL_NOTICE_FILE :=", a.mergedNotices.Merged.Path().String())
@@ -446,23 +421,18 @@
fmt.Fprintf(w, dist)
}
- if a.apisUsedByModuleFile.String() != "" {
- goal := "apps_only"
- distFile := a.apisUsedByModuleFile.String()
- fmt.Fprintf(w, "ifneq (,$(filter $(my_register_name),$(TARGET_BUILD_APPS)))\n"+
- " $(call dist-for-goals,%s,%s:ndk_apis_usedby_apex/$(notdir %s))\n"+
- "endif\n",
- goal, distFile, distFile)
- }
-
- if a.apisBackedByModuleFile.String() != "" {
- goal := "apps_only"
- distFile := a.apisBackedByModuleFile.String()
- fmt.Fprintf(w, "ifneq (,$(filter $(my_register_name),$(TARGET_BUILD_APPS)))\n"+
- " $(call dist-for-goals,%s,%s:ndk_apis_backedby_apex/$(notdir %s))\n"+
- "endif\n",
- goal, distFile, distFile)
- }
+ distCoverageFiles(w, "ndk_apis_usedby_apex", a.nativeApisUsedByModuleFile.String())
+ distCoverageFiles(w, "ndk_apis_backedby_apex", a.nativeApisBackedByModuleFile.String())
+ distCoverageFiles(w, "java_apis_used_by_apex", a.javaApisUsedByModuleFile.String())
}
}}
}
+
+func distCoverageFiles(w io.Writer, dir string, distfile string) {
+ if distfile != "" {
+ goal := "apps_only"
+ fmt.Fprintf(w, "ifneq (,$(filter $(my_register_name),$(TARGET_BUILD_APPS)))\n"+
+ " $(call dist-for-goals,%s,%s:%s/$(notdir %s))\n"+
+ "endif\n", goal, distfile, dir, distfile)
+ }
+}
diff --git a/apex/apex.go b/apex/apex.go
index 33188cb..635ff30 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -54,8 +54,6 @@
ctx.PreArchMutators(registerPreArchMutators)
ctx.PreDepsMutators(RegisterPreDepsMutators)
ctx.PostDepsMutators(RegisterPostDepsMutators)
-
- android.RegisterBp2BuildMutator("apex", ApexBundleBp2Build)
}
func registerPreArchMutators(ctx android.RegisterMutatorsContext) {
@@ -98,6 +96,14 @@
// /system/sepolicy/apex/<module_name>_file_contexts.
File_contexts *string `android:"path"`
+ // Path to the canned fs config file for customizing file's uid/gid/mod/capabilities. The
+ // format is /<path_or_glob> <uid> <gid> <mode> [capabilities=0x<cap>], where path_or_glob is a
+ // path or glob pattern for a file or set of files, uid/gid are numerial values of user ID
+ // and group ID, mode is octal value for the file mode, and cap is hexadecimal value for the
+ // capability. If this property is not set, or a file is missing in the file, default config
+ // is used.
+ Canned_fs_config *string `android:"path"`
+
ApexNativeDependencies
Multilib apexMultilibProperties
@@ -111,6 +117,9 @@
// List of java libraries that are embedded inside this APEX bundle.
Java_libs []string
+ // List of sh binaries that are embedded inside this APEX bundle.
+ Sh_binaries []string
+
// List of platform_compat_config files that are embedded inside this APEX bundle.
Compat_configs []string
@@ -127,6 +136,13 @@
// symlinking to the system libs. Default is true.
Updatable *bool
+ // Marks that this APEX is designed to be updatable in the future, although it's not
+ // updatable yet. This is used to mimic some of the build behaviors that are applied only to
+ // updatable APEXes. Currently, this disables the size optimization, so that the size of
+ // APEX will not increase when the APEX is actually marked as truly updatable. Default is
+ // false.
+ Future_updatable *bool
+
// Whether this APEX can use platform APIs or not. Can be set to true only when `updatable:
// false`. Default is false.
Platform_apis *bool
@@ -145,6 +161,16 @@
// Should be only used in non-system apexes (e.g. vendor: true). Default is false.
Use_vndk_as_stable *bool
+ // Whether this is multi-installed APEX should skip installing symbol files.
+ // Multi-installed APEXes share the same apex_name and are installed at the same time.
+ // Default is false.
+ //
+ // Should be set to true for all multi-installed APEXes except the singular
+ // default version within the multi-installed group.
+ // Only the default version can install symbol files in $(PRODUCT_OUT}/apex,
+ // or else conflicting build rules may be created.
+ Multi_install_skip_symbol_files *bool
+
// List of SDKs that are used to build this APEX. A reference to an SDK should be either
// `name#version` or `name` which is an alias for `name#current`. If left empty,
// `platform#current` is implied. This value affects all modules included in this APEX. In
@@ -399,14 +425,14 @@
// vendor/google/build/build_unbundled_mainline_module.sh for more detail.
bundleModuleFile android.WritablePath
- // Target path to install this APEX. Usually out/target/product/<device>/<partition>/apex.
+ // Target directory to install this APEX. Usually out/target/product/<device>/<partition>/apex.
installDir android.InstallPath
- // List of commands to create symlinks for backward compatibility. These commands will be
- // attached as LOCAL_POST_INSTALL_CMD to apex package itself (for unflattened build) or
- // apex_manifest (for flattened build) so that compat symlinks are always installed
- // regardless of TARGET_FLATTEN_APEX setting.
- compatSymlinks []string
+ // Path where this APEX was installed.
+ installedFile android.InstallPath
+
+ // Installed locations of symlinks for backward compatibility.
+ compatSymlinks android.InstallPaths
// Text file having the list of individual files that are included in this APEX. Used for
// debugging purpose.
@@ -424,8 +450,9 @@
isCompressed bool
// Path of API coverage generate file
- apisUsedByModuleFile android.ModuleOutPath
- apisBackedByModuleFile android.ModuleOutPath
+ nativeApisUsedByModuleFile android.ModuleOutPath
+ nativeApisBackedByModuleFile android.ModuleOutPath
+ javaApisUsedByModuleFile android.ModuleOutPath
// Collect the module directory for IDE info in java/jdeps.go.
modulePaths []string
@@ -603,6 +630,7 @@
sharedLibTag = dependencyTag{name: "sharedLib", payload: true}
testForTag = dependencyTag{name: "test for"}
testTag = dependencyTag{name: "test", payload: true}
+ shBinaryTag = dependencyTag{name: "shBinary", payload: true}
)
// TODO(jiyong): shorten this function signature
@@ -747,6 +775,10 @@
for _, d := range depsList {
addDependenciesForNativeModules(ctx, d, target, imageVariation)
}
+ ctx.AddFarVariationDependencies([]blueprint.Variation{
+ {Mutator: "os", Variation: target.OsVariation()},
+ {Mutator: "arch", Variation: target.ArchVariation()},
+ }, shBinaryTag, a.properties.Sh_binaries...)
}
// Common-arch dependencies come next
@@ -1283,6 +1315,10 @@
return proptools.BoolDefault(a.properties.Updatable, true)
}
+func (a *apexBundle) FutureUpdatable() bool {
+ return proptools.BoolDefault(a.properties.Future_updatable, false)
+}
+
func (a *apexBundle) UsePlatformApis() bool {
return proptools.BoolDefault(a.properties.Platform_apis, false)
}
@@ -1467,6 +1503,9 @@
func apexFileForShBinary(ctx android.BaseModuleContext, sh *sh.ShBinary) apexFile {
dirInApex := filepath.Join("bin", sh.SubDir())
+ if sh.Target().NativeBridge == android.NativeBridgeEnabled {
+ dirInApex = filepath.Join(dirInApex, sh.Target().NativeBridgeRelativePath)
+ }
fileToCopy := sh.OutputFile()
af := newApexFile(ctx, fileToCopy, sh.BaseModuleName(), dirInApex, shBinary, sh)
af.symlinks = sh.Symlinks()
@@ -1644,7 +1683,7 @@
// 1) do some validity checks such as apex_available, min_sdk_version, etc.
a.checkApexAvailability(ctx)
a.checkUpdatable(ctx)
- a.checkMinSdkVersion(ctx)
+ a.CheckMinSdkVersion(ctx)
a.checkStaticLinkingToStubLibraries(ctx)
a.checkStaticExecutables(ctx)
if len(a.properties.Tests) > 0 && !a.testApex {
@@ -1695,6 +1734,7 @@
return true // track transitive dependencies
} else if r, ok := child.(*rust.Module); ok {
fi := apexFileForRustLibrary(ctx, r)
+ fi.isJniLib = isJniLib
filesInfo = append(filesInfo, fi)
} else {
propertyName := "native_shared_libs"
@@ -1707,8 +1747,6 @@
if cc, ok := child.(*cc.Module); ok {
filesInfo = append(filesInfo, apexFileForExecutable(ctx, cc))
return true // track transitive dependencies
- } else if sh, ok := child.(*sh.ShBinary); ok {
- filesInfo = append(filesInfo, apexFileForShBinary(ctx, sh))
} else if py, ok := child.(*python.Module); ok && py.HostToolPath().Valid() {
filesInfo = append(filesInfo, apexFileForPyBinary(ctx, py))
} else if gb, ok := child.(bootstrap.GoBinaryTool); ok && a.Host() {
@@ -1717,7 +1755,13 @@
filesInfo = append(filesInfo, apexFileForRustExecutable(ctx, rust))
return true // track transitive dependencies
} else {
- ctx.PropertyErrorf("binaries", "%q is neither cc_binary, rust_binary, (embedded) py_binary, (host) blueprint_go_binary, (host) bootstrap_go_binary, nor sh_binary", depName)
+ ctx.PropertyErrorf("binaries", "%q is neither cc_binary, rust_binary, (embedded) py_binary, (host) blueprint_go_binary, nor (host) bootstrap_go_binary", depName)
+ }
+ case shBinaryTag:
+ if sh, ok := child.(*sh.ShBinary); ok {
+ filesInfo = append(filesInfo, apexFileForShBinary(ctx, sh))
+ } else {
+ ctx.PropertyErrorf("sh_binaries", "%q is not a sh_binary module", depName)
}
case bcpfTag:
{
@@ -1973,6 +2017,8 @@
}
} else if _, ok := depTag.(android.CopyDirectlyInAnyApexTag); ok {
// nothing
+ } else if depTag == android.DarwinUniversalVariantTag {
+ // nothing
} else if am.CanHaveApexVariants() && am.IsInstallableToApex() {
ctx.ModuleErrorf("unexpected tag %s for indirect dependency %q", android.PrettyPrintTag(depTag), depName)
}
@@ -2074,10 +2120,11 @@
}
forced := ctx.Config().ForceApexSymlinkOptimization()
+ updatable := a.Updatable() || a.FutureUpdatable()
// We don't need the optimization for updatable APEXes, as it might give false signal
// to the system health when the APEXes are still bundled (b/149805758).
- if !forced && a.Updatable() && a.properties.ApexType == imageApex {
+ if !forced && updatable && a.properties.ApexType == imageApex {
a.linkToSystemLib = false
}
@@ -2086,7 +2133,9 @@
a.linkToSystemLib = false
}
- a.compatSymlinks = makeCompatSymlinks(a.BaseModuleName(), ctx)
+ if a.properties.ApexType != zipApex {
+ a.compatSymlinks = makeCompatSymlinks(a.BaseModuleName(), ctx, a.primaryApexType)
+ }
////////////////////////////////////////////////////////////////////////////////////////////
// 4) generate the build rules to create the APEX. This is done in builder.go.
@@ -2141,6 +2190,40 @@
filesToAdd = append(filesToAdd, *af)
}
+ if pathInApex := bootclasspathFragmentInfo.ProfileInstallPathInApex(); pathInApex != "" {
+ pathOnHost := bootclasspathFragmentInfo.ProfilePathOnHost()
+ tempPath := android.PathForModuleOut(ctx, "boot_image_profile", pathInApex)
+
+ if pathOnHost != nil {
+ // We need to copy the profile to a temporary path with the right filename because the apexer
+ // will take the filename as is.
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cp,
+ Input: pathOnHost,
+ Output: tempPath,
+ })
+ } else {
+ // At this point, the boot image profile cannot be generated. It is probably because the boot
+ // image profile source file does not exist on the branch, or it is not available for the
+ // current build target.
+ // However, we cannot enforce the boot image profile to be generated because some build
+ // targets (such as module SDK) do not need it. It is only needed when the APEX is being
+ // built. Therefore, we create an error rule so that an error will occur at the ninja phase
+ // only if the APEX is being built.
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.ErrorRule,
+ Output: tempPath,
+ Args: map[string]string{
+ "error": "Boot image profile cannot be generated",
+ },
+ })
+ }
+
+ androidMkModuleName := filepath.Base(pathInApex)
+ af := newApexFile(ctx, tempPath, androidMkModuleName, filepath.Dir(pathInApex), etc, nil)
+ filesToAdd = append(filesToAdd, af)
+ }
+
return filesToAdd
}
@@ -2267,18 +2350,28 @@
//
// TODO(jiyong): move these checks to a separate go file.
+var _ android.ModuleWithMinSdkVersionCheck = (*apexBundle)(nil)
+
// Entures that min_sdk_version of the included modules are equal or less than the min_sdk_version
// of this apexBundle.
-func (a *apexBundle) checkMinSdkVersion(ctx android.ModuleContext) {
+func (a *apexBundle) CheckMinSdkVersion(ctx android.ModuleContext) {
if a.testApex || a.vndkApex {
return
}
// apexBundle::minSdkVersion reports its own errors.
minSdkVersion := a.minSdkVersion(ctx)
- android.CheckMinSdkVersion(a, ctx, minSdkVersion)
+ android.CheckMinSdkVersion(ctx, minSdkVersion, a.WalkPayloadDeps)
}
-func (a *apexBundle) minSdkVersion(ctx android.BaseModuleContext) android.ApiLevel {
+func (a *apexBundle) MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
+ return android.SdkSpec{
+ Kind: android.SdkNone,
+ ApiLevel: a.minSdkVersion(ctx),
+ Raw: String(a.properties.Min_sdk_version),
+ }
+}
+
+func (a *apexBundle) minSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel {
ver := proptools.String(a.properties.Min_sdk_version)
if ver == "" {
return android.NoneApiLevel
@@ -2344,6 +2437,12 @@
if a.UsePlatformApis() {
ctx.PropertyErrorf("updatable", "updatable APEXes can't use platform APIs")
}
+ if a.SocSpecific() || a.DeviceSpecific() {
+ ctx.PropertyErrorf("updatable", "vendor APEXes are not updatable")
+ }
+ if a.FutureUpdatable() {
+ ctx.PropertyErrorf("future_updatable", "Already updatable. Remove `future_updatable: true:`")
+ }
a.checkJavaStableSdkVersion(ctx)
a.checkClasspathFragments(ctx)
}
@@ -2544,7 +2643,7 @@
//
// Module separator
//
- m["com.android.bluetooth.updatable"] = []string{
+ m["com.android.bluetooth"] = []string{
"android.hardware.audio.common@5.0",
"android.hardware.bluetooth.a2dp@1.0",
"android.hardware.bluetooth.audio@2.0",
@@ -2651,7 +2750,6 @@
"libbuildversion",
"libmath",
"libprocpartition",
- "libsync",
}
//
// Module separator
@@ -2759,7 +2857,6 @@
"libstagefright_metadatautils",
"libstagefright_mpeg2extractor",
"libstagefright_mpeg2support",
- "libsync",
"libui",
"libui_headers",
"libunwindstack",
@@ -2900,7 +2997,6 @@
"libstagefright_m4vh263dec",
"libstagefright_m4vh263enc",
"libstagefright_mp3dec",
- "libsync",
"libui",
"libui_headers",
"libunwindstack",
@@ -3106,15 +3202,16 @@
BootclasspathJar().
With("apex_available", module_name).
WithMatcher("permitted_packages", android.NotInList(module_packages)).
+ WithMatcher("min_sdk_version", android.LessThanSdkVersion("Tiramisu")).
Because("jars that are part of the " + module_name +
" module may only allow these packages: " + strings.Join(module_packages, ",") +
- ". Please jarjar or move code around.")
+ " with min_sdk < T. Please jarjar or move code around.")
rules = append(rules, permittedPackagesRule)
}
return rules
}
-// DO NOT EDIT! These are the package prefixes that are exempted from being AOT'ed by ART.
+// DO NOT EDIT! These are the package prefixes that are exempted from being AOT'ed by ART on Q/R/S.
// Adding code to the bootclasspath in new packages will cause issues on module update.
func qModulesPackages() map[string][]string {
return map[string][]string{
@@ -3128,7 +3225,7 @@
}
}
-// DO NOT EDIT! These are the package prefixes that are exempted from being AOT'ed by ART.
+// DO NOT EDIT! These are the package prefixes that are exempted from being AOT'ed by ART on R/S.
// Adding code to the bootclasspath in new packages will cause issues on module update.
func rModulesPackages() map[string][]string {
return map[string][]string{
@@ -3171,80 +3268,70 @@
File_contexts bazel.LabelAttribute
Key bazel.LabelAttribute
Certificate bazel.LabelAttribute
- Min_sdk_version string
+ Min_sdk_version *string
Updatable bazel.BoolAttribute
Installable bazel.BoolAttribute
Native_shared_libs bazel.LabelListAttribute
- Binaries bazel.StringListAttribute
+ Binaries bazel.LabelListAttribute
Prebuilts bazel.LabelListAttribute
}
-func ApexBundleBp2Build(ctx android.TopDownMutatorContext) {
- module, ok := ctx.Module().(*apexBundle)
- if !ok {
- // Not an APEX bundle
- return
- }
- if !module.ConvertWithBp2build(ctx) {
- return
- }
+// ConvertWithBp2build performs bp2build conversion of an apex
+func (a *apexBundle) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
+ // We do not convert apex_test modules at this time
if ctx.ModuleType() != "apex" {
return
}
- apexBundleBp2BuildInternal(ctx, module)
-}
-
-func apexBundleBp2BuildInternal(ctx android.TopDownMutatorContext, module *apexBundle) {
var manifestLabelAttribute bazel.LabelAttribute
- if module.properties.Manifest != nil {
- manifestLabelAttribute.SetValue(android.BazelLabelForModuleSrcSingle(ctx, *module.properties.Manifest))
+ if a.properties.Manifest != nil {
+ manifestLabelAttribute.SetValue(android.BazelLabelForModuleSrcSingle(ctx, *a.properties.Manifest))
}
var androidManifestLabelAttribute bazel.LabelAttribute
- if module.properties.AndroidManifest != nil {
- androidManifestLabelAttribute.SetValue(android.BazelLabelForModuleSrcSingle(ctx, *module.properties.AndroidManifest))
+ if a.properties.AndroidManifest != nil {
+ androidManifestLabelAttribute.SetValue(android.BazelLabelForModuleSrcSingle(ctx, *a.properties.AndroidManifest))
}
var fileContextsLabelAttribute bazel.LabelAttribute
- if module.properties.File_contexts != nil {
- fileContextsLabelAttribute.SetValue(android.BazelLabelForModuleDepSingle(ctx, *module.properties.File_contexts))
+ if a.properties.File_contexts != nil {
+ fileContextsLabelAttribute.SetValue(android.BazelLabelForModuleDepSingle(ctx, *a.properties.File_contexts))
}
- var minSdkVersion string
- if module.properties.Min_sdk_version != nil {
- minSdkVersion = *module.properties.Min_sdk_version
+ var minSdkVersion *string
+ if a.properties.Min_sdk_version != nil {
+ minSdkVersion = a.properties.Min_sdk_version
}
var keyLabelAttribute bazel.LabelAttribute
- if module.overridableProperties.Key != nil {
- keyLabelAttribute.SetValue(android.BazelLabelForModuleDepSingle(ctx, *module.overridableProperties.Key))
+ if a.overridableProperties.Key != nil {
+ keyLabelAttribute.SetValue(android.BazelLabelForModuleDepSingle(ctx, *a.overridableProperties.Key))
}
var certificateLabelAttribute bazel.LabelAttribute
- if module.overridableProperties.Certificate != nil {
- certificateLabelAttribute.SetValue(android.BazelLabelForModuleDepSingle(ctx, *module.overridableProperties.Certificate))
+ if a.overridableProperties.Certificate != nil {
+ certificateLabelAttribute.SetValue(android.BazelLabelForModuleDepSingle(ctx, *a.overridableProperties.Certificate))
}
- nativeSharedLibs := module.properties.ApexNativeDependencies.Native_shared_libs
+ nativeSharedLibs := a.properties.ApexNativeDependencies.Native_shared_libs
nativeSharedLibsLabelList := android.BazelLabelForModuleDeps(ctx, nativeSharedLibs)
nativeSharedLibsLabelListAttribute := bazel.MakeLabelListAttribute(nativeSharedLibsLabelList)
- prebuilts := module.overridableProperties.Prebuilts
+ prebuilts := a.overridableProperties.Prebuilts
prebuiltsLabelList := android.BazelLabelForModuleDeps(ctx, prebuilts)
prebuiltsLabelListAttribute := bazel.MakeLabelListAttribute(prebuiltsLabelList)
- binaries := module.properties.ApexNativeDependencies.Binaries
- binariesStringListAttribute := bazel.MakeStringListAttribute(binaries)
+ binaries := android.BazelLabelForModuleDeps(ctx, a.properties.ApexNativeDependencies.Binaries)
+ binariesLabelListAttribute := bazel.MakeLabelListAttribute(binaries)
var updatableAttribute bazel.BoolAttribute
- if module.properties.Updatable != nil {
- updatableAttribute.Value = module.properties.Updatable
+ if a.properties.Updatable != nil {
+ updatableAttribute.Value = a.properties.Updatable
}
var installableAttribute bazel.BoolAttribute
- if module.properties.Installable != nil {
- installableAttribute.Value = module.properties.Installable
+ if a.properties.Installable != nil {
+ installableAttribute.Value = a.properties.Installable
}
attrs := &bazelApexBundleAttributes{
@@ -3257,7 +3344,7 @@
Updatable: updatableAttribute,
Installable: installableAttribute,
Native_shared_libs: nativeSharedLibsLabelListAttribute,
- Binaries: binariesStringListAttribute,
+ Binaries: binariesLabelListAttribute,
Prebuilts: prebuiltsLabelListAttribute,
}
@@ -3266,5 +3353,5 @@
Bzl_load_location: "//build/bazel/rules:apex.bzl",
}
- ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name()}, attrs)
+ ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: a.Name()}, attrs)
}
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 8aaa31a..727a1f2 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -215,7 +215,9 @@
variables.CertificateOverrides = []string{"myapex_keytest:myapex.certificate.override"}
variables.Platform_sdk_codename = proptools.StringPtr("Q")
variables.Platform_sdk_final = proptools.BoolPtr(false)
- variables.Platform_version_active_codenames = []string{"Q"}
+ // "Tiramisu" needs to be in the next line for compatibility with soong code,
+ // not because of these tests specifically (it's not used by the tests)
+ variables.Platform_version_active_codenames = []string{"Q", "Tiramisu"}
variables.Platform_vndk_version = proptools.StringPtr("29")
}),
)
@@ -2579,22 +2581,21 @@
`)
generateFsRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("generateFsConfig")
- dirs := strings.Split(generateFsRule.Args["exec_paths"], " ")
+ cmd := generateFsRule.RuleParams.Command
// Ensure that the subdirectories are all listed
- ensureListContains(t, dirs, "etc")
- ensureListContains(t, dirs, "etc/foo")
- ensureListContains(t, dirs, "etc/foo/bar")
- ensureListContains(t, dirs, "lib64")
- ensureListContains(t, dirs, "lib64/foo")
- ensureListContains(t, dirs, "lib64/foo/bar")
- ensureListContains(t, dirs, "lib")
- ensureListContains(t, dirs, "lib/foo")
- ensureListContains(t, dirs, "lib/foo/bar")
-
- ensureListContains(t, dirs, "bin")
- ensureListContains(t, dirs, "bin/foo")
- ensureListContains(t, dirs, "bin/foo/bar")
+ ensureContains(t, cmd, "/etc ")
+ ensureContains(t, cmd, "/etc/foo ")
+ ensureContains(t, cmd, "/etc/foo/bar ")
+ ensureContains(t, cmd, "/lib64 ")
+ ensureContains(t, cmd, "/lib64/foo ")
+ ensureContains(t, cmd, "/lib64/foo/bar ")
+ ensureContains(t, cmd, "/lib ")
+ ensureContains(t, cmd, "/lib/foo ")
+ ensureContains(t, cmd, "/lib/foo/bar ")
+ ensureContains(t, cmd, "/bin ")
+ ensureContains(t, cmd, "/bin/foo ")
+ ensureContains(t, cmd, "/bin/foo/bar ")
}
func TestFilesInSubDirWhenNativeBridgeEnabled(t *testing.T) {
@@ -2656,7 +2657,10 @@
}
func TestVendorApex(t *testing.T) {
- ctx := testApex(t, `
+ result := android.GroupFixturePreparers(
+ prepareForApexTest,
+ android.FixtureModifyConfig(android.SetKatiEnabledForTests),
+ ).RunTestWithBp(t, `
apex {
name: "myapex",
key: "myapex.key",
@@ -2680,24 +2684,24 @@
}
`)
- ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+ ensureExactContents(t, result.TestContext, "myapex", "android_common_myapex_image", []string{
"bin/mybin",
"lib64/libfoo.so",
// TODO(b/159195575): Add an option to use VNDK libs from VNDK APEX
"lib64/libc++.so",
})
- apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
- data := android.AndroidMkDataForTest(t, ctx, apexBundle)
+ apexBundle := result.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+ data := android.AndroidMkDataForTest(t, result.TestContext, apexBundle)
name := apexBundle.BaseModuleName()
prefix := "TARGET_"
var builder strings.Builder
data.Custom(&builder, name, prefix, "", data)
- androidMk := android.StringRelativeToTop(ctx.Config(), builder.String())
+ androidMk := android.StringRelativeToTop(result.Config, builder.String())
installPath := "out/target/product/test_device/vendor/apex"
ensureContains(t, androidMk, "LOCAL_MODULE_PATH := "+installPath)
- apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule")
+ apexManifestRule := result.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule")
requireNativeLibs := names(apexManifestRule.Args["requireNativeLibs"])
ensureListNotContains(t, requireNativeLibs, ":vndk")
}
@@ -4248,7 +4252,7 @@
apex {
name: "myapex",
key: "myapex.key",
- binaries: ["myscript"],
+ sh_binaries: ["myscript"],
updatable: false,
}
@@ -6204,7 +6208,7 @@
})
// Permission XML should point to the activated path of impl jar of java_sdk_library
sdkLibrary := ctx.ModuleForTests("foo.xml", "android_common_myapex").Rule("java_sdk_xml")
- ensureContains(t, sdkLibrary.RuleParams.Command, `<library name=\"foo\" file=\"/apex/myapex/javalib/foo.jar\"`)
+ ensureMatches(t, sdkLibrary.RuleParams.Command, `<library\\n\s+name=\\\"foo\\\"\\n\s+file=\\\"/apex/myapex/javalib/foo.jar\\\"`)
}
func TestJavaSDKLibrary_WithinApex(t *testing.T) {
@@ -7035,6 +7039,7 @@
`, insert))
}
}),
+ dexpreopt.FixtureSetBootImageProfiles("art/build/boot/boot-image-profile.txt"),
).
ExtendWithErrorHandler(errorHandler).
RunTestWithBp(t, bp)
@@ -7042,6 +7047,75 @@
return result.TestContext
}
+func TestDuplicateDeapexeresFromPrebuiltApexes(t *testing.T) {
+ preparers := android.GroupFixturePreparers(
+ java.PrepareForTestWithJavaDefaultModules,
+ PrepareForTestWithApexBuildComponents,
+ ).
+ ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
+ "Multiple installable prebuilt APEXes provide ambiguous deapexers: com.android.myapex and com.mycompany.android.myapex"))
+
+ bpBase := `
+ apex_set {
+ name: "com.android.myapex",
+ installable: true,
+ exported_bootclasspath_fragments: ["my-bootclasspath-fragment"],
+ set: "myapex.apks",
+ }
+
+ apex_set {
+ name: "com.mycompany.android.myapex",
+ apex_name: "com.android.myapex",
+ installable: true,
+ exported_bootclasspath_fragments: ["my-bootclasspath-fragment"],
+ set: "company-myapex.apks",
+ }
+
+ prebuilt_bootclasspath_fragment {
+ name: "my-bootclasspath-fragment",
+ apex_available: ["com.android.myapex"],
+ %s
+ }
+ `
+
+ t.Run("java_import", func(t *testing.T) {
+ _ = preparers.RunTestWithBp(t, fmt.Sprintf(bpBase, `contents: ["libfoo"]`)+`
+ java_import {
+ name: "libfoo",
+ jars: ["libfoo.jar"],
+ apex_available: ["com.android.myapex"],
+ }
+ `)
+ })
+
+ t.Run("java_sdk_library_import", func(t *testing.T) {
+ _ = preparers.RunTestWithBp(t, fmt.Sprintf(bpBase, `contents: ["libfoo"]`)+`
+ java_sdk_library_import {
+ name: "libfoo",
+ public: {
+ jars: ["libbar.jar"],
+ },
+ apex_available: ["com.android.myapex"],
+ }
+ `)
+ })
+
+ t.Run("prebuilt_bootclasspath_fragment", func(t *testing.T) {
+ _ = preparers.RunTestWithBp(t, fmt.Sprintf(bpBase, `
+ image_name: "art",
+ contents: ["libfoo"],
+ `)+`
+ java_sdk_library_import {
+ name: "libfoo",
+ public: {
+ jars: ["libbar.jar"],
+ },
+ apex_available: ["com.android.myapex"],
+ }
+ `)
+ })
+}
+
func TestUpdatable_should_set_min_sdk_version(t *testing.T) {
testApexError(t, `"myapex" .*: updatable: updatable APEXes should set min_sdk_version`, `
apex {
@@ -7073,6 +7147,23 @@
`)
}
+func TestUpdatable_cannot_be_vendor_apex(t *testing.T) {
+ testApexError(t, `"myapex" .*: updatable: vendor APEXes are not updatable`, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ updatable: true,
+ soc_specific: true,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+ `)
+}
+
func TestUpdatable_should_not_set_generate_classpaths_proto(t *testing.T) {
testApexError(t, `"mysystemserverclasspathfragment" .* it must not set generate_classpaths_proto to false`, `
apex {
@@ -7339,6 +7430,7 @@
apex_available: ["myapex"],
sdk_version: "none",
system_modules: "none",
+ min_sdk_version: "30",
}
java_library {
name: "nonbcp_lib2",
@@ -7347,9 +7439,11 @@
permitted_packages: ["a.b"],
sdk_version: "none",
system_modules: "none",
+ min_sdk_version: "30",
}
apex {
name: "myapex",
+ min_sdk_version: "30",
key: "myapex.key",
java_libs: ["bcp_lib1", "nonbcp_lib2"],
updatable: false,
@@ -7362,8 +7456,8 @@
},
},
{
- name: "Bootclasspath apex jar not satisfying allowed module packages.",
- expectedError: `module "bcp_lib2" .* which is restricted because jars that are part of the myapex module may only allow these packages: foo.bar. Please jarjar or move code around.`,
+ name: "Bootclasspath apex jar not satisfying allowed module packages on Q.",
+ expectedError: `(?s)module "bcp_lib2" .* which is restricted because jars that are part of the myapex module may only allow these packages: foo.bar with min_sdk < T. Please jarjar or move code around.`,
bp: `
java_library {
name: "bcp_lib1",
@@ -7372,6 +7466,7 @@
permitted_packages: ["foo.bar"],
sdk_version: "none",
system_modules: "none",
+ min_sdk_version: "29",
}
java_library {
name: "bcp_lib2",
@@ -7380,9 +7475,85 @@
permitted_packages: ["foo.bar", "bar.baz"],
sdk_version: "none",
system_modules: "none",
+ min_sdk_version: "29",
}
apex {
name: "myapex",
+ min_sdk_version: "29",
+ key: "myapex.key",
+ java_libs: ["bcp_lib1", "bcp_lib2"],
+ updatable: false,
+ }
+ `,
+ bootJars: []string{"bcp_lib1", "bcp_lib2"},
+ modulesPackages: map[string][]string{
+ "myapex": []string{
+ "foo.bar",
+ },
+ },
+ },
+ {
+ name: "Bootclasspath apex jar not satisfying allowed module packages on R.",
+ expectedError: `(?s)module "bcp_lib2" .* which is restricted because jars that are part of the myapex module may only allow these packages: foo.bar with min_sdk < T. Please jarjar or move code around.`,
+ bp: `
+ java_library {
+ name: "bcp_lib1",
+ srcs: ["lib1/src/*.java"],
+ apex_available: ["myapex"],
+ permitted_packages: ["foo.bar"],
+ sdk_version: "none",
+ system_modules: "none",
+ min_sdk_version: "30",
+ }
+ java_library {
+ name: "bcp_lib2",
+ srcs: ["lib2/src/*.java"],
+ apex_available: ["myapex"],
+ permitted_packages: ["foo.bar", "bar.baz"],
+ sdk_version: "none",
+ system_modules: "none",
+ min_sdk_version: "30",
+ }
+ apex {
+ name: "myapex",
+ min_sdk_version: "30",
+ key: "myapex.key",
+ java_libs: ["bcp_lib1", "bcp_lib2"],
+ updatable: false,
+ }
+ `,
+ bootJars: []string{"bcp_lib1", "bcp_lib2"},
+ modulesPackages: map[string][]string{
+ "myapex": []string{
+ "foo.bar",
+ },
+ },
+ },
+ {
+ name: "Bootclasspath apex jar >= T not satisfying Q/R/S allowed module packages.",
+ expectedError: "",
+ bp: `
+ java_library {
+ name: "bcp_lib1",
+ srcs: ["lib1/src/*.java"],
+ apex_available: ["myapex"],
+ permitted_packages: ["foo.bar"],
+ sdk_version: "none",
+ system_modules: "none",
+ min_sdk_version: "current",
+ }
+ java_library {
+ name: "bcp_lib2",
+ srcs: ["lib2/src/*.java"],
+ apex_available: ["myapex"],
+ permitted_packages: ["foo.bar", "bar.baz"],
+ sdk_version: "none",
+ system_modules: "none",
+ min_sdk_version: "current",
+ }
+ apex {
+ name: "myapex",
+ min_sdk_version: "current",
key: "myapex.key",
java_libs: ["bcp_lib1", "bcp_lib2"],
updatable: false,
@@ -8332,7 +8503,7 @@
java_import {
name: "foo",
jars: ["foo.jar"],
- installable: true,
+ apex_available: ["myapex"],
}
`,
dexpreopt.FixtureSetApexSystemServerJars("myapex:foo"),
@@ -8350,6 +8521,224 @@
})
}
+func TestAndroidMk_RequiredModules(t *testing.T) {
+ ctx := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ updatable: false,
+ java_libs: ["foo"],
+ required: ["otherapex"],
+ }
+
+ apex {
+ name: "otherapex",
+ key: "myapex.key",
+ updatable: false,
+ java_libs: ["foo"],
+ required: ["otherapex"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ java_library {
+ name: "foo",
+ srcs: ["foo.java"],
+ apex_available: ["myapex", "otherapex"],
+ installable: true,
+ }
+ `)
+
+ apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+ data := android.AndroidMkDataForTest(t, ctx, apexBundle)
+ var builder strings.Builder
+ data.Custom(&builder, apexBundle.BaseModuleName(), "TARGET_", "", data)
+ androidMk := builder.String()
+ ensureContains(t, androidMk, "LOCAL_REQUIRED_MODULES += otherapex")
+}
+
+func TestSdkLibraryCanHaveHigherMinSdkVersion(t *testing.T) {
+ preparer := android.GroupFixturePreparers(
+ PrepareForTestWithApexBuildComponents,
+ prepareForTestWithMyapex,
+ java.PrepareForTestWithJavaSdkLibraryFiles,
+ java.PrepareForTestWithJavaDefaultModules,
+ android.PrepareForTestWithAndroidBuildComponents,
+ dexpreopt.FixtureSetApexBootJars("myapex:mybootclasspathlib"),
+ dexpreopt.FixtureSetApexSystemServerJars("myapex:mysystemserverclasspathlib"),
+ )
+
+ // Test java_sdk_library in bootclasspath_fragment may define higher min_sdk_version than the apex
+ t.Run("bootclasspath_fragment jar has higher min_sdk_version than apex", func(t *testing.T) {
+ preparer.RunTestWithBp(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ bootclasspath_fragments: ["mybootclasspathfragment"],
+ min_sdk_version: "30",
+ updatable: false,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ bootclasspath_fragment {
+ name: "mybootclasspathfragment",
+ contents: ["mybootclasspathlib"],
+ apex_available: ["myapex"],
+ }
+
+ java_sdk_library {
+ name: "mybootclasspathlib",
+ srcs: ["mybootclasspathlib.java"],
+ apex_available: ["myapex"],
+ compile_dex: true,
+ unsafe_ignore_missing_latest_api: true,
+ min_sdk_version: "31",
+ static_libs: ["util"],
+ }
+
+ java_library {
+ name: "util",
+ srcs: ["a.java"],
+ apex_available: ["myapex"],
+ min_sdk_version: "31",
+ static_libs: ["another_util"],
+ }
+
+ java_library {
+ name: "another_util",
+ srcs: ["a.java"],
+ min_sdk_version: "31",
+ apex_available: ["myapex"],
+ }
+ `)
+ })
+
+ // Test java_sdk_library in systemserverclasspath_fragment may define higher min_sdk_version than the apex
+ t.Run("systemserverclasspath_fragment jar has higher min_sdk_version than apex", func(t *testing.T) {
+ preparer.RunTestWithBp(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ systemserverclasspath_fragments: ["mysystemserverclasspathfragment"],
+ min_sdk_version: "30",
+ updatable: false,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ systemserverclasspath_fragment {
+ name: "mysystemserverclasspathfragment",
+ contents: ["mysystemserverclasspathlib"],
+ apex_available: ["myapex"],
+ }
+
+ java_sdk_library {
+ name: "mysystemserverclasspathlib",
+ srcs: ["mysystemserverclasspathlib.java"],
+ apex_available: ["myapex"],
+ compile_dex: true,
+ min_sdk_version: "32",
+ unsafe_ignore_missing_latest_api: true,
+ static_libs: ["util"],
+ }
+
+ java_library {
+ name: "util",
+ srcs: ["a.java"],
+ apex_available: ["myapex"],
+ min_sdk_version: "31",
+ static_libs: ["another_util"],
+ }
+
+ java_library {
+ name: "another_util",
+ srcs: ["a.java"],
+ min_sdk_version: "31",
+ apex_available: ["myapex"],
+ }
+ `)
+ })
+
+ t.Run("bootclasspath_fragment jar must set min_sdk_version", func(t *testing.T) {
+ preparer.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "mybootclasspathlib".*must set min_sdk_version`)).
+ RunTestWithBp(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ bootclasspath_fragments: ["mybootclasspathfragment"],
+ min_sdk_version: "30",
+ updatable: false,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ bootclasspath_fragment {
+ name: "mybootclasspathfragment",
+ contents: ["mybootclasspathlib"],
+ apex_available: ["myapex"],
+ }
+
+ java_sdk_library {
+ name: "mybootclasspathlib",
+ srcs: ["mybootclasspathlib.java"],
+ apex_available: ["myapex"],
+ compile_dex: true,
+ unsafe_ignore_missing_latest_api: true,
+ }
+ `)
+ })
+
+ t.Run("systemserverclasspath_fragment jar must set min_sdk_version", func(t *testing.T) {
+ preparer.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "mysystemserverclasspathlib".*must set min_sdk_version`)).
+ RunTestWithBp(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ systemserverclasspath_fragments: ["mysystemserverclasspathfragment"],
+ min_sdk_version: "30",
+ updatable: false,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ systemserverclasspath_fragment {
+ name: "mysystemserverclasspathfragment",
+ contents: ["mysystemserverclasspathlib"],
+ apex_available: ["myapex"],
+ }
+
+ java_sdk_library {
+ name: "mysystemserverclasspathlib",
+ srcs: ["mysystemserverclasspathlib.java"],
+ apex_available: ["myapex"],
+ compile_dex: true,
+ unsafe_ignore_missing_latest_api: true,
+ }
+ `)
+ })
+}
+
func TestMain(m *testing.M) {
os.Exit(m.Run())
}
diff --git a/apex/bootclasspath_fragment_test.go b/apex/bootclasspath_fragment_test.go
index cb7d3d1..ce828e1 100644
--- a/apex/bootclasspath_fragment_test.go
+++ b/apex/bootclasspath_fragment_test.go
@@ -16,11 +16,13 @@
import (
"fmt"
+ "path"
"sort"
"strings"
"testing"
"android/soong/android"
+ "android/soong/dexpreopt"
"android/soong/java"
"github.com/google/blueprint/proptools"
@@ -35,11 +37,14 @@
)
// Some additional files needed for the art apex.
-var prepareForTestWithArtApex = android.FixtureMergeMockFs(android.MockFS{
- "com.android.art.avbpubkey": nil,
- "com.android.art.pem": nil,
- "system/sepolicy/apex/com.android.art-file_contexts": nil,
-})
+var prepareForTestWithArtApex = android.GroupFixturePreparers(
+ android.FixtureMergeMockFs(android.MockFS{
+ "com.android.art.avbpubkey": nil,
+ "com.android.art.pem": nil,
+ "system/sepolicy/apex/com.android.art-file_contexts": nil,
+ }),
+ dexpreopt.FixtureSetBootImageProfiles("art/build/boot/boot-image-profile.txt"),
+)
func TestBootclasspathFragments(t *testing.T) {
result := android.GroupFixturePreparers(
@@ -408,6 +413,7 @@
).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/arm/boot.art",
"javalib/arm/boot.oat",
@@ -437,6 +443,24 @@
checkCopiesToPredefinedLocationForArt(t, result.Config, module, "bar", "foo")
})
+ t.Run("boot image disable generate profile", 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"),
+ dexpreopt.FixtureDisableGenerateProfile(true),
+ ).RunTest(t)
+
+ files := getFiles(t, result.TestContext, "com.android.art", "android_common_com.android.art_image")
+ for _, file := range files {
+ matched, _ := path.Match("etc/boot-image.prof", file.path)
+ android.AssertBoolEquals(t, "\"etc/boot-image.prof\" should not be in the APEX", matched, false)
+ }
+ })
+
t.Run("boot image files with preferred prebuilt", func(t *testing.T) {
result := android.GroupFixturePreparers(
commonPreparer,
@@ -451,6 +475,7 @@
).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/arm/boot.art",
"javalib/arm/boot.oat",
@@ -542,7 +567,7 @@
}
func TestBootclasspathFragmentInPrebuiltArtApex(t *testing.T) {
- result := android.GroupFixturePreparers(
+ preparers := android.GroupFixturePreparers(
prepareForTestWithBootclasspathFragment,
prepareForTestWithArtApex,
@@ -553,7 +578,9 @@
// Configure some libraries in the art bootclasspath_fragment.
java.FixtureConfigureBootJars("com.android.art:foo", "com.android.art:bar"),
- ).RunTestWithBp(t, `
+ )
+
+ bp := `
prebuilt_apex {
name: "com.android.art",
arch: {
@@ -599,22 +626,45 @@
all_flags: "mybootclasspathfragment/all-flags.csv",
},
}
- `)
- java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art", []string{
- `com.android.art.apex.selector`,
- `prebuilt_mybootclasspathfragment`,
+ // A prebuilt apex with the same apex_name that shouldn't interfere when it isn't enabled.
+ prebuilt_apex {
+ name: "com.mycompany.android.art",
+ apex_name: "com.android.art",
+ %s
+ src: "com.mycompany.android.art.apex",
+ exported_bootclasspath_fragments: ["mybootclasspathfragment"],
+ }
+ `
+
+ t.Run("disabled alternative APEX", func(t *testing.T) {
+ result := preparers.RunTestWithBp(t, fmt.Sprintf(bp, "enabled: false,"))
+
+ java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art", []string{
+ `com.android.art.apex.selector`,
+ `prebuilt_mybootclasspathfragment`,
+ })
+
+ java.CheckModuleDependencies(t, result.TestContext, "mybootclasspathfragment", "android_common_com.android.art", []string{
+ `com.android.art.deapexer`,
+ `dex2oatd`,
+ `prebuilt_bar`,
+ `prebuilt_foo`,
+ })
+
+ module := result.ModuleForTests("mybootclasspathfragment", "android_common_com.android.art")
+ checkCopiesToPredefinedLocationForArt(t, result.Config, module, "bar", "foo")
+
+ // Check that the right deapexer module was chosen for a boot image.
+ param := module.Output("out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art")
+ android.AssertStringDoesContain(t, "didn't find the expected deapexer in the input path", param.Input.String(), "/com.android.art.deapexer")
})
- java.CheckModuleDependencies(t, result.TestContext, "mybootclasspathfragment", "android_common_com.android.art", []string{
- `com.android.art.deapexer`,
- `dex2oatd`,
- `prebuilt_bar`,
- `prebuilt_foo`,
+ t.Run("enabled alternative APEX", func(t *testing.T) {
+ preparers.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
+ "Multiple installable prebuilt APEXes provide ambiguous deapexers: com.android.art and com.mycompany.android.art")).
+ RunTestWithBp(t, fmt.Sprintf(bp, ""))
})
-
- module := result.ModuleForTests("mybootclasspathfragment", "android_common_com.android.art")
- checkCopiesToPredefinedLocationForArt(t, result.Config, module, "bar", "foo")
}
// checkCopiesToPredefinedLocationForArt checks that the supplied modules are copied to the
diff --git a/apex/builder.go b/apex/builder.go
index e22d694..ea25537 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -67,23 +67,11 @@
pctx.HostBinToolVariable("sload_f2fs", "sload_f2fs")
pctx.HostBinToolVariable("make_erofs", "make_erofs")
pctx.HostBinToolVariable("apex_compression_tool", "apex_compression_tool")
+ pctx.HostBinToolVariable("dexdeps", "dexdeps")
pctx.SourcePathVariable("genNdkUsedbyApexPath", "build/soong/scripts/gen_ndk_usedby_apex.sh")
}
var (
- // Create a canned fs config file where all files and directories are
- // by default set to (uid/gid/mode) = (1000/1000/0644)
- // TODO(b/113082813) make this configurable using config.fs syntax
- generateFsConfig = pctx.StaticRule("generateFsConfig", blueprint.RuleParams{
- Command: `( set -e; echo '/ 1000 1000 0755' ` +
- `&& for i in ${ro_paths}; do echo "/$$i 1000 1000 0644"; done ` +
- `&& for i in ${exec_paths}; do echo "/$$i 0 2000 0755"; done ` +
- `&& ( tr ' ' '\n' <${out}.apklist | for i in ${apk_paths}; do read apk; echo "/$$i 0 2000 0755"; zipinfo -1 $$apk | sed "s:\(.*\):/$$i/\1 1000 1000 0644:"; done ) ) > ${out}`,
- Description: "fs_config ${out}",
- Rspfile: "$out.apklist",
- RspfileContent: "$in",
- }, "ro_paths", "exec_paths", "apk_paths")
-
apexManifestRule = pctx.StaticRule("apexManifestRule", blueprint.RuleParams{
Command: `rm -f $out && ${jsonmodify} $in ` +
`-a provideNativeLibs ${provideNativeLibs} ` +
@@ -413,18 +401,37 @@
func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) {
apexType := a.properties.ApexType
suffix := apexType.suffix()
+ apexName := proptools.StringDefault(a.properties.Apex_name, a.BaseModuleName())
////////////////////////////////////////////////////////////////////////////////////////////
// Step 1: copy built files to appropriate directories under the image directory
imageDir := android.PathForModuleOut(ctx, "image"+suffix)
+ installSymbolFiles := !ctx.Config().KatiEnabled() || a.ExportedToMake()
+
+ // b/140136207. When there are overriding APEXes for a VNDK APEX, the symbols file for the overridden
+ // APEX and the overriding APEX will have the same installation paths at /apex/com.android.vndk.v<ver>
+ // as their apexName will be the same. To avoid the path conflicts, skip installing the symbol files
+ // for the overriding VNDK APEXes.
+ if a.vndkApex && len(a.overridableProperties.Overrides) > 0 {
+ installSymbolFiles = false
+ }
+
+ // Avoid creating duplicate build rules for multi-installed APEXes.
+ if proptools.BoolDefault(a.properties.Multi_install_skip_symbol_files, false) {
+ installSymbolFiles = false
+
+ }
+ // set of dependency module:location mappings
+ installMapSet := make(map[string]bool)
+
// TODO(jiyong): use the RuleBuilder
var copyCommands []string
var implicitInputs []android.Path
+ pathWhenActivated := android.PathForModuleInPartitionInstall(ctx, "apex", apexName)
for _, fi := range a.filesInfo {
destPath := imageDir.Join(ctx, fi.path()).String()
-
// Prepare the destination path
destPathDir := filepath.Dir(destPath)
if fi.class == appSet {
@@ -432,6 +439,8 @@
}
copyCommands = append(copyCommands, "mkdir -p "+destPathDir)
+ installMapPath := fi.builtFile
+
// Copy the built file to the directory. But if the symlink optimization is turned
// on, place a symlink to the corresponding file in /system partition instead.
if a.linkToSystemLib && fi.transitiveDep && fi.availableToPlatform() {
@@ -439,20 +448,38 @@
pathOnDevice := filepath.Join("/system", fi.path())
copyCommands = append(copyCommands, "ln -sfn "+pathOnDevice+" "+destPath)
} else {
+ var installedPath android.InstallPath
if fi.class == appSet {
copyCommands = append(copyCommands,
- fmt.Sprintf("unzip -qDD -d %s %s", destPathDir, fi.builtFile.String()))
+ fmt.Sprintf("unzip -qDD -d %s %s", destPathDir,
+ fi.module.(*java.AndroidAppSet).PackedAdditionalOutputs().String()))
+ if installSymbolFiles {
+ installedPath = ctx.InstallFileWithExtraFilesZip(pathWhenActivated.Join(ctx, fi.installDir),
+ fi.stem(), fi.builtFile, fi.module.(*java.AndroidAppSet).PackedAdditionalOutputs())
+ }
} else {
copyCommands = append(copyCommands, "cp -f "+fi.builtFile.String()+" "+destPath)
+ if installSymbolFiles {
+ installedPath = ctx.InstallFile(pathWhenActivated.Join(ctx, fi.installDir), fi.stem(), fi.builtFile)
+ }
}
implicitInputs = append(implicitInputs, fi.builtFile)
- }
+ if installSymbolFiles {
+ implicitInputs = append(implicitInputs, installedPath)
+ }
- // Create additional symlinks pointing the file inside the APEX (if any). Note that
- // this is independent from the symlink optimization.
- for _, symlinkPath := range fi.symlinkPaths() {
- symlinkDest := imageDir.Join(ctx, symlinkPath).String()
- copyCommands = append(copyCommands, "ln -sfn "+filepath.Base(destPath)+" "+symlinkDest)
+ // Create additional symlinks pointing the file inside the APEX (if any). Note that
+ // this is independent from the symlink optimization.
+ for _, symlinkPath := range fi.symlinkPaths() {
+ symlinkDest := imageDir.Join(ctx, symlinkPath).String()
+ copyCommands = append(copyCommands, "ln -sfn "+filepath.Base(destPath)+" "+symlinkDest)
+ if installSymbolFiles {
+ installedSymlink := ctx.InstallSymlink(pathWhenActivated.Join(ctx, filepath.Dir(symlinkPath)), filepath.Base(symlinkPath), installedPath)
+ implicitInputs = append(implicitInputs, installedSymlink)
+ }
+ }
+
+ installMapPath = installedPath
}
// Copy the test files (if any)
@@ -469,8 +496,21 @@
copyCommands = append(copyCommands, "cp -f "+d.SrcPath.String()+" "+dataDest)
implicitInputs = append(implicitInputs, d.SrcPath)
}
+
+ installMapSet[installMapPath.String()+":"+fi.installDir+"/"+fi.builtFile.Base()] = true
}
implicitInputs = append(implicitInputs, a.manifestPbOut)
+ if installSymbolFiles {
+ installedManifest := ctx.InstallFile(pathWhenActivated, "apex_manifest.pb", a.manifestPbOut)
+ installedKey := ctx.InstallFile(pathWhenActivated, "apex_pubkey", a.publicKeyFile)
+ implicitInputs = append(implicitInputs, installedManifest, installedKey)
+ }
+
+ if len(installMapSet) > 0 {
+ var installs []string
+ installs = append(installs, android.SortedStringKeys(installMapSet)...)
+ a.SetLicenseInstallMap(installs)
+ }
////////////////////////////////////////////////////////////////////////////////////////////
// Step 1.a: Write the list of files in this APEX to a txt file and compare it against
@@ -530,55 +570,11 @@
// Figure out if need to compress apex.
compressionEnabled := ctx.Config().CompressedApex() && proptools.BoolDefault(a.properties.Compressible, false) && !a.testApex && !ctx.Config().UnbundledBuildApps()
if apexType == imageApex {
+
////////////////////////////////////////////////////////////////////////////////////
// Step 2: create canned_fs_config which encodes filemode,uid,gid of each files
// in this APEX. The file will be used by apexer in later steps.
- // TODO(jiyong): make this as a function
- // TODO(jiyong): use the RuleBuilder
- var readOnlyPaths = []string{"apex_manifest.json", "apex_manifest.pb"}
- var executablePaths []string // this also includes dirs
- var extractedAppSetPaths android.Paths
- var extractedAppSetDirs []string
- for _, f := range a.filesInfo {
- pathInApex := f.path()
- if f.installDir == "bin" || strings.HasPrefix(f.installDir, "bin/") {
- executablePaths = append(executablePaths, pathInApex)
- for _, d := range f.dataPaths {
- readOnlyPaths = append(readOnlyPaths, filepath.Join(f.installDir, d.RelativeInstallPath, d.SrcPath.Rel()))
- }
- for _, s := range f.symlinks {
- executablePaths = append(executablePaths, filepath.Join(f.installDir, s))
- }
- } else if f.class == appSet {
- extractedAppSetPaths = append(extractedAppSetPaths, f.builtFile)
- extractedAppSetDirs = append(extractedAppSetDirs, f.installDir)
- } else {
- readOnlyPaths = append(readOnlyPaths, pathInApex)
- }
- dir := f.installDir
- for !android.InList(dir, executablePaths) && dir != "" {
- executablePaths = append(executablePaths, dir)
- dir, _ = filepath.Split(dir) // move up to the parent
- if len(dir) > 0 {
- // remove trailing slash
- dir = dir[:len(dir)-1]
- }
- }
- }
- sort.Strings(readOnlyPaths)
- sort.Strings(executablePaths)
- cannedFsConfig := android.PathForModuleOut(ctx, "canned_fs_config")
- ctx.Build(pctx, android.BuildParams{
- Rule: generateFsConfig,
- Output: cannedFsConfig,
- Description: "generate fs config",
- Inputs: extractedAppSetPaths,
- Args: map[string]string{
- "ro_paths": strings.Join(readOnlyPaths, " "),
- "exec_paths": strings.Join(executablePaths, " "),
- "apk_paths": strings.Join(extractedAppSetDirs, " "),
- },
- })
+ cannedFsConfig := a.buildCannedFsConfig(ctx)
implicitInputs = append(implicitInputs, cannedFsConfig)
////////////////////////////////////////////////////////////////////////////////////
@@ -707,12 +703,12 @@
"readelf": "${config.ClangBin}/llvm-readelf",
},
})
- a.apisUsedByModuleFile = apisUsedbyOutputFile
+ a.nativeApisUsedByModuleFile = apisUsedbyOutputFile
- var libNames []string
+ var nativeLibNames []string
for _, f := range a.filesInfo {
if f.class == nativeSharedLib {
- libNames = append(libNames, f.stem())
+ nativeLibNames = append(nativeLibNames, f.stem())
}
}
apisBackedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_backing.txt")
@@ -720,9 +716,25 @@
rule.Command().
Tool(android.PathForSource(ctx, "build/soong/scripts/gen_ndk_backedby_apex.sh")).
Output(apisBackedbyOutputFile).
- Flags(libNames)
+ Flags(nativeLibNames)
rule.Build("ndk_backedby_list", "Generate API libraries backed by Apex")
- a.apisBackedByModuleFile = apisBackedbyOutputFile
+ a.nativeApisBackedByModuleFile = apisBackedbyOutputFile
+
+ var javaLibOrApkPath []android.Path
+ for _, f := range a.filesInfo {
+ if f.class == javaSharedLib || f.class == app {
+ javaLibOrApkPath = append(javaLibOrApkPath, f.builtFile)
+ }
+ }
+ javaApiUsedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_using.xml")
+ javaUsedByRule := android.NewRuleBuilder(pctx, ctx)
+ javaUsedByRule.Command().
+ Tool(android.PathForSource(ctx, "build/soong/scripts/gen_java_usedby_apex.sh")).
+ BuiltTool("dexdeps").
+ Output(javaApiUsedbyOutputFile).
+ Inputs(javaLibOrApkPath)
+ javaUsedByRule.Build("java_usedby_list", "Generate Java APIs used by Apex")
+ a.javaApisUsedByModuleFile = javaApiUsedbyOutputFile
bundleConfig := a.buildBundleConfig(ctx)
@@ -823,47 +835,55 @@
a.outputFile = signedCompressedOutputFile
}
+ installSuffix := suffix
+ if a.isCompressed {
+ installSuffix = imageCapexSuffix
+ }
+
// Install to $OUT/soong/{target,host}/.../apex.
- ctx.InstallFile(a.installDir, a.Name()+suffix, a.outputFile)
+ a.installedFile = ctx.InstallFile(a.installDir, a.Name()+installSuffix, a.outputFile,
+ a.compatSymlinks.Paths()...)
// installed-files.txt is dist'ed
a.installedFilesFile = a.buildInstalledFilesFile(ctx, a.outputFile, imageDir)
}
-// Context "decorator", overriding the InstallBypassMake method to always reply `true`.
-type flattenedApexContext struct {
- android.ModuleContext
-}
-
-func (c *flattenedApexContext) InstallBypassMake() bool {
- return true
-}
-
// buildFlattenedApex creates rules for a flattened APEX. Flattened APEX actually doesn't have a
// single output file. It is a phony target for all the files under /system/apex/<name> directory.
// This function creates the installation rules for the files.
func (a *apexBundle) buildFlattenedApex(ctx android.ModuleContext) {
bundleName := a.Name()
+ installedSymlinks := append(android.InstallPaths(nil), a.compatSymlinks...)
if a.installable() {
for _, fi := range a.filesInfo {
dir := filepath.Join("apex", bundleName, fi.installDir)
- target := ctx.InstallFile(android.PathForModuleInstall(ctx, dir), fi.stem(), fi.builtFile)
- for _, sym := range fi.symlinks {
- ctx.InstallSymlink(android.PathForModuleInstall(ctx, dir), sym, target)
+ installDir := android.PathForModuleInstall(ctx, dir)
+ if a.linkToSystemLib && fi.transitiveDep && fi.availableToPlatform() {
+ // TODO(jiyong): pathOnDevice should come from fi.module, not being calculated here
+ pathOnDevice := filepath.Join("/system", fi.path())
+ installedSymlinks = append(installedSymlinks,
+ ctx.InstallAbsoluteSymlink(installDir, fi.stem(), pathOnDevice))
+ } else {
+ target := ctx.InstallFile(installDir, fi.stem(), fi.builtFile)
+ for _, sym := range fi.symlinks {
+ installedSymlinks = append(installedSymlinks,
+ ctx.InstallSymlink(installDir, sym, target))
+ }
}
}
+
+ // Create install rules for the files added in GenerateAndroidBuildActions after
+ // buildFlattenedApex is called. Add the links to system libs (if any) as dependencies
+ // of the apex_manifest.pb file since it is always present.
+ dir := filepath.Join("apex", bundleName)
+ installDir := android.PathForModuleInstall(ctx, dir)
+ ctx.InstallFile(installDir, "apex_manifest.pb", a.manifestPbOut, installedSymlinks.Paths()...)
+ ctx.InstallFile(installDir, "apex_pubkey", a.publicKeyFile)
}
a.fileContexts = a.buildFileContexts(ctx)
- // Temporarily wrap the original `ctx` into a `flattenedApexContext` to have it reply true
- // to `InstallBypassMake()` (thus making the call `android.PathForModuleInstall` below use
- // `android.pathForInstallInMakeDir` instead of `android.PathForOutput`) to return the
- // correct path to the flattened APEX (as its contents is installed by Make, not Soong).
- // TODO(jiyong): Why do we need to set outputFile for flattened APEX? We don't seem to use
- // it and it actually points to a path that can never be built. Remove this.
- factx := flattenedApexContext{ctx}
- a.outputFile = android.PathForModuleInstall(&factx, "apex", bundleName)
+ a.outputFile = android.PathForModuleInstall(ctx, "apex", bundleName)
}
// getCertificateAndPrivateKey retrieves the cert and the private key that will be used to sign
@@ -995,3 +1015,65 @@
a.lintReports = java.BuildModuleLintReportZips(ctx, depSetsBuilder.Build())
}
+
+func (a *apexBundle) buildCannedFsConfig(ctx android.ModuleContext) android.OutputPath {
+ var readOnlyPaths = []string{"apex_manifest.json", "apex_manifest.pb"}
+ var executablePaths []string // this also includes dirs
+ var appSetDirs []string
+ appSetFiles := make(map[string]android.Path)
+ for _, f := range a.filesInfo {
+ pathInApex := f.path()
+ if f.installDir == "bin" || strings.HasPrefix(f.installDir, "bin/") {
+ executablePaths = append(executablePaths, pathInApex)
+ for _, d := range f.dataPaths {
+ readOnlyPaths = append(readOnlyPaths, filepath.Join(f.installDir, d.RelativeInstallPath, d.SrcPath.Rel()))
+ }
+ for _, s := range f.symlinks {
+ executablePaths = append(executablePaths, filepath.Join(f.installDir, s))
+ }
+ } else if f.class == appSet {
+ appSetDirs = append(appSetDirs, f.installDir)
+ appSetFiles[f.installDir] = f.builtFile
+ } else {
+ readOnlyPaths = append(readOnlyPaths, pathInApex)
+ }
+ dir := f.installDir
+ for !android.InList(dir, executablePaths) && dir != "" {
+ executablePaths = append(executablePaths, dir)
+ dir, _ = filepath.Split(dir) // move up to the parent
+ if len(dir) > 0 {
+ // remove trailing slash
+ dir = dir[:len(dir)-1]
+ }
+ }
+ }
+ sort.Strings(readOnlyPaths)
+ sort.Strings(executablePaths)
+ sort.Strings(appSetDirs)
+
+ cannedFsConfig := android.PathForModuleOut(ctx, "canned_fs_config")
+ builder := android.NewRuleBuilder(pctx, ctx)
+ cmd := builder.Command()
+ cmd.Text("(")
+ cmd.Text("echo '/ 1000 1000 0755';")
+ for _, p := range readOnlyPaths {
+ cmd.Textf("echo '/%s 1000 1000 0644';", p)
+ }
+ for _, p := range executablePaths {
+ cmd.Textf("echo '/%s 0 2000 0755';", p)
+ }
+ for _, dir := range appSetDirs {
+ cmd.Textf("echo '/%s 0 2000 0755';", dir)
+ file := appSetFiles[dir]
+ cmd.Text("zipinfo -1").Input(file).Textf(`| sed "s:\(.*\):/%s/\1 1000 1000 0644:";`, dir)
+ }
+ // Custom fs_config is "appended" to the last so that entries from the file are preferred
+ // over default ones set above.
+ if a.properties.Canned_fs_config != nil {
+ cmd.Text("cat").Input(android.PathForModuleSrc(ctx, *a.properties.Canned_fs_config))
+ }
+ cmd.Text(")").FlagWithOutput("> ", cannedFsConfig)
+ builder.Build("generateFsConfig", fmt.Sprintf("Generating canned fs config for %s", a.BaseModuleName()))
+
+ return cannedFsConfig.OutputPath
+}
diff --git a/apex/key.go b/apex/key.go
index 259060f..829410e 100644
--- a/apex/key.go
+++ b/apex/key.go
@@ -34,8 +34,6 @@
func registerApexKeyBuildComponents(ctx android.RegistrationContext) {
ctx.RegisterModuleType("apex_key", ApexKeyFactory)
ctx.RegisterSingletonType("apex_keys_text", apexKeysTextFactory)
-
- android.RegisterBp2BuildMutator("apex_key", ApexKeyBp2Build)
}
type apexKey struct {
@@ -209,20 +207,9 @@
Private_key bazel.LabelAttribute
}
-func ApexKeyBp2Build(ctx android.TopDownMutatorContext) {
- module, ok := ctx.Module().(*apexKey)
- if !ok {
- // Not an APEX key
- return
- }
- if !module.ConvertWithBp2build(ctx) {
- return
- }
- if ctx.ModuleType() != "apex_key" {
- return
- }
-
- apexKeyBp2BuildInternal(ctx, module)
+// ConvertWithBp2build performs conversion apexKey for bp2build
+func (m *apexKey) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
+ apexKeyBp2BuildInternal(ctx, m)
}
func apexKeyBp2BuildInternal(ctx android.TopDownMutatorContext, module *apexKey) {
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index 61e7a0b..02d8075 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -17,11 +17,13 @@
import (
"fmt"
"io"
+ "path/filepath"
"strconv"
"strings"
"android/soong/android"
"android/soong/java"
+
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
)
@@ -53,18 +55,17 @@
installDir android.InstallPath
installFilename string
+ installedFile android.InstallPath
outputApex android.WritablePath
// A list of apexFile objects created in prebuiltCommon.initApexFilesForAndroidMk which are used
// to create make modules in prebuiltCommon.AndroidMkEntries.
apexFilesForAndroidMk []apexFile
- // list of commands to create symlinks for backward compatibility.
- // these commands will be attached as LOCAL_POST_INSTALL_CMD
- compatSymlinks []string
+ // Installed locations of symlinks for backward compatibility.
+ compatSymlinks android.InstallPaths
- hostRequired []string
- postInstallCommands []string
+ hostRequired []string
}
type sanitizedPrebuilt interface {
@@ -221,15 +222,12 @@
Host_required: p.hostRequired,
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- entries.SetString("LOCAL_MODULE_PATH", p.installDir.ToMakePath().String())
+ entries.SetString("LOCAL_MODULE_PATH", p.installDir.String())
entries.SetString("LOCAL_MODULE_STEM", p.installFilename)
+ entries.SetPath("LOCAL_SOONG_INSTALLED_MODULE", p.installedFile)
+ entries.SetString("LOCAL_SOONG_INSTALL_PAIRS", p.outputApex.String()+":"+p.installedFile.String())
entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", !p.installable())
entries.AddStrings("LOCAL_OVERRIDES_MODULES", p.prebuiltCommonProperties.Overrides...)
- postInstallCommands := append([]string{}, p.postInstallCommands...)
- postInstallCommands = append(postInstallCommands, p.compatSymlinks...)
- if len(postInstallCommands) > 0 {
- entries.SetString("LOCAL_POST_INSTALL_CMD", strings.Join(postInstallCommands, " && "))
- }
p.addRequiredModules(entries)
},
},
@@ -258,7 +256,10 @@
Include: "$(BUILD_SYSTEM)/soong_java_prebuilt.mk",
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- entries.SetString("LOCAL_MODULE_PATH", p.installDir.ToMakePath().String())
+ entries.SetString("LOCAL_MODULE_PATH", p.installDir.String())
+ entries.SetString("LOCAL_SOONG_INSTALLED_MODULE", filepath.Join(p.installDir.String(), fi.stem()))
+ entries.SetString("LOCAL_SOONG_INSTALL_PAIRS",
+ fi.builtFile.String()+":"+filepath.Join(p.installDir.String(), fi.stem()))
// soong_java_prebuilt.mk sets LOCAL_MODULE_SUFFIX := .jar Therefore
// we need to remove the suffix from LOCAL_MODULE_STEM, otherwise
@@ -756,15 +757,15 @@
// Save the files that need to be made available to Make.
p.initApexFilesForAndroidMk(ctx)
- if p.installable() {
- ctx.InstallFile(p.installDir, p.installFilename, p.inputApex)
- }
-
// in case that prebuilt_apex replaces source apex (using prefer: prop)
- p.compatSymlinks = makeCompatSymlinks(p.BaseModuleName(), ctx)
+ p.compatSymlinks = makeCompatSymlinks(p.BaseModuleName(), ctx, true)
// or that prebuilt_apex overrides other apexes (using overrides: prop)
for _, overridden := range p.prebuiltCommonProperties.Overrides {
- p.compatSymlinks = append(p.compatSymlinks, makeCompatSymlinks(overridden, ctx)...)
+ p.compatSymlinks = append(p.compatSymlinks, makeCompatSymlinks(overridden, ctx, true)...)
+ }
+
+ if p.installable() {
+ p.installedFile = ctx.InstallFile(p.installDir, p.installFilename, p.inputApex, p.compatSymlinks.Paths()...)
}
}
@@ -960,14 +961,14 @@
a.installDir = android.PathForModuleInstall(ctx, "apex")
if a.installable() {
- ctx.InstallFile(a.installDir, a.installFilename, a.outputApex)
+ a.installedFile = ctx.InstallFile(a.installDir, a.installFilename, a.outputApex)
}
// in case that apex_set replaces source apex (using prefer: prop)
- a.compatSymlinks = makeCompatSymlinks(a.BaseModuleName(), ctx)
+ a.compatSymlinks = makeCompatSymlinks(a.BaseModuleName(), ctx, true)
// or that apex_set overrides other apexes (using overrides: prop)
for _, overridden := range a.prebuiltCommonProperties.Overrides {
- a.compatSymlinks = append(a.compatSymlinks, makeCompatSymlinks(overridden, ctx)...)
+ a.compatSymlinks = append(a.compatSymlinks, makeCompatSymlinks(overridden, ctx, true)...)
}
}
diff --git a/apex/systemserver_classpath_fragment_test.go b/apex/systemserver_classpath_fragment_test.go
index 412fa0e..d037664 100644
--- a/apex/systemserver_classpath_fragment_test.go
+++ b/apex/systemserver_classpath_fragment_test.go
@@ -231,3 +231,95 @@
`prebuilt_foo`,
})
}
+
+func TestSystemserverclasspathFragmentStandaloneContents(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForTestWithSystemserverclasspathFragment,
+ prepareForTestWithMyapex,
+ dexpreopt.FixtureSetApexStandaloneSystemServerJars("myapex:foo"),
+ ).RunTestWithBp(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ systemserverclasspath_fragments: [
+ "mysystemserverclasspathfragment",
+ ],
+ updatable: false,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ java_library {
+ name: "foo",
+ srcs: ["b.java"],
+ installable: true,
+ apex_available: [
+ "myapex",
+ ],
+ }
+
+ systemserverclasspath_fragment {
+ name: "mysystemserverclasspathfragment",
+ standalone_contents: [
+ "foo",
+ ],
+ apex_available: [
+ "myapex",
+ ],
+ }
+ `)
+
+ ensureExactContents(t, result.TestContext, "myapex", "android_common_myapex_image", []string{
+ "etc/classpaths/systemserverclasspath.pb",
+ "javalib/foo.jar",
+ })
+}
+
+func TestPrebuiltStandaloneSystemserverclasspathFragmentContents(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForTestWithSystemserverclasspathFragment,
+ prepareForTestWithMyapex,
+ dexpreopt.FixtureSetApexStandaloneSystemServerJars("myapex:foo"),
+ ).RunTestWithBp(t, `
+ prebuilt_apex {
+ name: "myapex",
+ arch: {
+ arm64: {
+ src: "myapex-arm64.apex",
+ },
+ arm: {
+ src: "myapex-arm.apex",
+ },
+ },
+ exported_systemserverclasspath_fragments: ["mysystemserverclasspathfragment"],
+ }
+
+ java_import {
+ name: "foo",
+ jars: ["foo.jar"],
+ apex_available: [
+ "myapex",
+ ],
+ }
+
+ prebuilt_systemserverclasspath_fragment {
+ name: "mysystemserverclasspathfragment",
+ prefer: true,
+ standalone_contents: [
+ "foo",
+ ],
+ apex_available: [
+ "myapex",
+ ],
+ }
+ `)
+
+ java.CheckModuleDependencies(t, result.TestContext, "mysystemserverclasspathfragment", "android_common_myapex", []string{
+ `myapex.deapexer`,
+ `prebuilt_foo`,
+ })
+}
diff --git a/apex/testing.go b/apex/testing.go
index 69bd73e..337c862 100644
--- a/apex/testing.go
+++ b/apex/testing.go
@@ -24,6 +24,7 @@
android.MockFS{
// Needed by apex.
"system/core/rootdir/etc/public.libraries.android.txt": nil,
+ "build/soong/scripts/gen_java_usedby_apex.sh": nil,
"build/soong/scripts/gen_ndk_backedby_apex.sh": nil,
// Needed by prebuilt_apex.
"build/soong/scripts/unpack-prebuilt-apex.sh": nil,
diff --git a/apex/vndk.go b/apex/vndk.go
index 75c0fb0..ef3e5e1 100644
--- a/apex/vndk.go
+++ b/apex/vndk.go
@@ -15,7 +15,6 @@
package apex
import (
- "path/filepath"
"strings"
"android/soong/android"
@@ -96,11 +95,14 @@
}
// name is module.BaseModuleName() which is used as LOCAL_MODULE_NAME and also LOCAL_OVERRIDES_*
-func makeCompatSymlinks(name string, ctx android.ModuleContext) (symlinks []string) {
+func makeCompatSymlinks(name string, ctx android.ModuleContext, primaryApex bool) (symlinks android.InstallPaths) {
// small helper to add symlink commands
- addSymlink := func(target, dir, linkName string) {
- link := filepath.Join(dir, linkName)
- symlinks = append(symlinks, "mkdir -p "+dir+" && rm -rf "+link+" && ln -sf "+target+" "+link)
+ addSymlink := func(target string, dir android.InstallPath, linkName string) {
+ if primaryApex {
+ symlinks = append(symlinks, ctx.InstallAbsoluteSymlink(dir, linkName, target))
+ } else {
+ symlinks = append(symlinks, dir.Join(ctx, linkName))
+ }
}
// TODO(b/142911355): [VNDK APEX] Fix hard-coded references to /system/lib/vndk
@@ -118,14 +120,15 @@
// the name of vndk apex is formatted "com.android.vndk.v" + version
apexName := vndkApexNamePrefix + vndkVersion
if ctx.Config().Android64() {
- addSymlink("/apex/"+apexName+"/lib64", "$(TARGET_OUT)/lib64", "vndk-sp-"+vndkVersion)
- addSymlink("/apex/"+apexName+"/lib64", "$(TARGET_OUT)/lib64", "vndk-"+vndkVersion)
+ dir := android.PathForModuleInPartitionInstall(ctx, "system", "lib64")
+ addSymlink("/apex/"+apexName+"/lib64", dir, "vndk-sp-"+vndkVersion)
+ addSymlink("/apex/"+apexName+"/lib64", dir, "vndk-"+vndkVersion)
}
if !ctx.Config().Android64() || ctx.DeviceConfig().DeviceSecondaryArch() != "" {
- addSymlink("/apex/"+apexName+"/lib", "$(TARGET_OUT)/lib", "vndk-sp-"+vndkVersion)
- addSymlink("/apex/"+apexName+"/lib", "$(TARGET_OUT)/lib", "vndk-"+vndkVersion)
+ dir := android.PathForModuleInPartitionInstall(ctx, "system", "lib")
+ addSymlink("/apex/"+apexName+"/lib", dir, "vndk-sp-"+vndkVersion)
+ addSymlink("/apex/"+apexName+"/lib", dir, "vndk-"+vndkVersion)
}
- return
}
// http://b/121248172 - create a link from /system/usr/icu to
@@ -133,19 +136,9 @@
// A symlink can't overwrite a directory and the /system/usr/icu directory once
// existed so the required structure must be created whatever we find.
if name == "com.android.i18n" {
- addSymlink("/apex/com.android.i18n/etc/icu", "$(TARGET_OUT)/usr", "icu")
- return
+ dir := android.PathForModuleInPartitionInstall(ctx, "system", "usr")
+ addSymlink("/apex/com.android.i18n/etc/icu", dir, "icu")
}
- // TODO(b/124106384): Clean up compat symlinks for ART binaries.
- if name == "com.android.art" || strings.HasPrefix(name, "com.android.art.") {
- addSymlink("/apex/com.android.art/bin/dalvikvm", "$(TARGET_OUT)/bin", "dalvikvm")
- dex2oat := "dex2oat32"
- if ctx.Config().Android64() {
- dex2oat = "dex2oat64"
- }
- addSymlink("/apex/com.android.art/bin/"+dex2oat, "$(TARGET_OUT)/bin", "dex2oat")
- return
- }
- return
+ return symlinks
}
diff --git a/bazel/aquery.go b/bazel/aquery.go
index 0dedcf4..fd8cf67 100644
--- a/bazel/aquery.go
+++ b/bazel/aquery.go
@@ -18,6 +18,7 @@
"encoding/json"
"fmt"
"path/filepath"
+ "regexp"
"strings"
"github.com/google/blueprint/proptools"
@@ -59,6 +60,8 @@
InputDepSetIds []int
Mnemonic string
OutputIds []int
+ TemplateContent string
+ Substitutions []KeyValuePair
}
// actionGraphContainer contains relevant portions of Bazel's aquery proto, ActionGraphContainer.
@@ -100,6 +103,20 @@
artifactIdToPath map[int]string
}
+// The tokens should be substituted with the value specified here, instead of the
+// one returned in 'substitutions' of TemplateExpand action.
+var TemplateActionOverriddenTokens = map[string]string{
+ // Uses "python3" for %python_binary% instead of the value returned by aquery
+ // which is "py3wrapper.sh". See removePy3wrapperScript.
+ "%python_binary%": "python3",
+}
+
+// This pattern matches the MANIFEST file created for a py_binary target.
+var manifestFilePattern = regexp.MustCompile(".*/.+\\.runfiles/MANIFEST$")
+
+// The file name of py3wrapper.sh, which is used by py_binary targets.
+var py3wrapperFileName = "/py3wrapper.sh"
+
func newAqueryHandler(aqueryResult actionGraphContainer) (*aqueryArtifactHandler, error) {
pathFragments := map[int]pathFragment{}
for _, pathFragment := range aqueryResult.PathFragments {
@@ -163,7 +180,31 @@
}
}
}
- return inputPaths, nil
+
+ // TODO(b/197135294): Clean up this custom runfiles handling logic when
+ // SourceSymlinkManifest and SymlinkTree actions are supported.
+ filteredInputPaths := filterOutPy3wrapperAndManifestFileFromInputPaths(inputPaths)
+
+ return filteredInputPaths, nil
+}
+
+// See go/python-binary-host-mixed-build for more details.
+// 1) For py3wrapper.sh, there is no action for creating py3wrapper.sh in the aquery output of
+// Bazel py_binary targets, so there is no Ninja build statements generated for creating it.
+// 2) For MANIFEST file, SourceSymlinkManifest action is in aquery output of Bazel py_binary targets,
+// but it doesn't contain sufficient information so no Ninja build statements are generated
+// for creating it.
+// So in mixed build mode, when these two are used as input of some Ninja build statement,
+// since there is no build statement to create them, they should be removed from input paths.
+func filterOutPy3wrapperAndManifestFileFromInputPaths(inputPaths []string) []string {
+ filteredInputPaths := []string{}
+ for _, path := range inputPaths {
+ if strings.HasSuffix(path, py3wrapperFileName) || manifestFilePattern.MatchString(path) {
+ continue
+ }
+ filteredInputPaths = append(filteredInputPaths, path)
+ }
+ return filteredInputPaths
}
func (a *aqueryArtifactHandler) artifactIdsFromDepsetId(depsetId int) ([]int, error) {
@@ -230,7 +271,7 @@
}
buildStatement := BuildStatement{
- Command: strings.Join(proptools.ShellEscapeList(actionEntry.Arguments), " "),
+ Command: strings.Join(proptools.ShellEscapeListIncludingSpaces(actionEntry.Arguments), " "),
Depfile: depfile,
OutputPaths: outputPaths,
InputPaths: inputPaths,
@@ -245,10 +286,49 @@
out := outputPaths[0]
outDir := proptools.ShellEscapeIncludingSpaces(filepath.Dir(out))
out = proptools.ShellEscapeIncludingSpaces(out)
- in := proptools.ShellEscapeIncludingSpaces(inputPaths[0])
- // Use hard links, because some soong actions expect real files (for example, `cp -d`).
- buildStatement.Command = fmt.Sprintf("mkdir -p %[1]s && rm -f %[2]s && ln -f %[3]s %[2]s", outDir, out, in)
+ in := filepath.Join("$PWD", proptools.ShellEscapeIncludingSpaces(inputPaths[0]))
+ // Use absolute paths, because some soong actions don't play well with relative paths (for example, `cp -d`).
+ buildStatement.Command = fmt.Sprintf("mkdir -p %[1]s && rm -f %[2]s && ln -sf %[3]s %[2]s", outDir, out, in)
buildStatement.SymlinkPaths = outputPaths[:]
+ } else if isTemplateExpandAction(actionEntry) && len(actionEntry.Arguments) < 1 {
+ if len(outputPaths) != 1 {
+ return nil, fmt.Errorf("Expect 1 output to template expand action, got: output %q", outputPaths)
+ }
+ expandedTemplateContent := expandTemplateContent(actionEntry)
+ // The expandedTemplateContent is escaped for being used in double quotes and shell unescape,
+ // and the new line characters (\n) are also changed to \\n which avoids some Ninja escape on \n, which might
+ // change \n to space and mess up the format of Python programs.
+ // sed is used to convert \\n back to \n before saving to output file.
+ // See go/python-binary-host-mixed-build for more details.
+ command := fmt.Sprintf(`/bin/bash -c 'echo "%[1]s" | sed "s/\\\\n/\\n/g" > %[2]s && chmod a+x %[2]s'`,
+ escapeCommandlineArgument(expandedTemplateContent), outputPaths[0])
+ buildStatement.Command = command
+ } else if isPythonZipperAction(actionEntry) {
+ if len(inputPaths) < 1 || len(outputPaths) != 1 {
+ return nil, fmt.Errorf("Expect 1+ input and 1 output to python zipper action, got: input %q, output %q", inputPaths, outputPaths)
+ }
+ buildStatement.InputPaths, buildStatement.Command = removePy3wrapperScript(buildStatement)
+ buildStatement.Command = addCommandForPyBinaryRunfilesDir(buildStatement, inputPaths[0], outputPaths[0])
+ // Add the python zip file as input of the corresponding python binary stub script in Ninja build statements.
+ // In Ninja build statements, the outputs of dependents of a python binary have python binary stub script as input,
+ // which is not sufficient without the python zip file from which runfiles directory is created for py_binary.
+ //
+ // The following logic relies on that Bazel aquery output returns actions in the order that
+ // PythonZipper is after TemplateAction of creating Python binary stub script. If later Bazel doesn't return actions
+ // in that order, the following logic might not find the build statement generated for Python binary
+ // stub script and the build might fail. So the check of pyBinaryFound is added to help debug in case later Bazel might change aquery output.
+ // See go/python-binary-host-mixed-build for more details.
+ pythonZipFilePath := outputPaths[0]
+ pyBinaryFound := false
+ for i, _ := range buildStatements {
+ if len(buildStatements[i].OutputPaths) == 1 && buildStatements[i].OutputPaths[0]+".zip" == pythonZipFilePath {
+ buildStatements[i].InputPaths = append(buildStatements[i].InputPaths, pythonZipFilePath)
+ pyBinaryFound = true
+ }
+ }
+ if !pyBinaryFound {
+ return nil, fmt.Errorf("Could not find the correspondinging Python binary stub script of PythonZipper: %q", outputPaths)
+ }
} else if len(actionEntry.Arguments) < 1 {
return nil, fmt.Errorf("received action with no command: [%v]", buildStatement)
}
@@ -258,10 +338,85 @@
return buildStatements, nil
}
+// expandTemplateContent substitutes the tokens in a template.
+func expandTemplateContent(actionEntry action) string {
+ replacerString := []string{}
+ for _, pair := range actionEntry.Substitutions {
+ value := pair.Value
+ if val, ok := TemplateActionOverriddenTokens[pair.Key]; ok {
+ value = val
+ }
+ replacerString = append(replacerString, pair.Key, value)
+ }
+ replacer := strings.NewReplacer(replacerString...)
+ return replacer.Replace(actionEntry.TemplateContent)
+}
+
+func escapeCommandlineArgument(str string) string {
+ // \->\\, $->\$, `->\`, "->\", \n->\\n, '->'"'"'
+ replacer := strings.NewReplacer(
+ `\`, `\\`,
+ `$`, `\$`,
+ "`", "\\`",
+ `"`, `\"`,
+ "\n", "\\n",
+ `'`, `'"'"'`,
+ )
+ return replacer.Replace(str)
+}
+
+// removePy3wrapperScript removes py3wrapper.sh from the input paths and command of the action of
+// creating python zip file in mixed build mode. py3wrapper.sh is returned as input by aquery but
+// there is no action returned by aquery for creating it. So in mixed build "python3" is used
+// as the PYTHON_BINARY in python binary stub script, and py3wrapper.sh is not needed and should be
+// removed from input paths and command of creating python zip file.
+// See go/python-binary-host-mixed-build for more details.
+// TODO(b/205879240) remove this after py3wrapper.sh could be created in the mixed build mode.
+func removePy3wrapperScript(bs BuildStatement) (newInputPaths []string, newCommand string) {
+ // Remove from inputs
+ filteredInputPaths := []string{}
+ for _, path := range bs.InputPaths {
+ if !strings.HasSuffix(path, py3wrapperFileName) {
+ filteredInputPaths = append(filteredInputPaths, path)
+ }
+ }
+ newInputPaths = filteredInputPaths
+
+ // Remove from command line
+ var re = regexp.MustCompile(`\S*` + py3wrapperFileName)
+ newCommand = re.ReplaceAllString(bs.Command, "")
+ return
+}
+
+// addCommandForPyBinaryRunfilesDir adds commands creating python binary runfiles directory.
+// runfiles directory is created by using MANIFEST file and MANIFEST file is the output of
+// SourceSymlinkManifest action is in aquery output of Bazel py_binary targets,
+// but since SourceSymlinkManifest doesn't contain sufficient information
+// so MANIFEST file could not be created, which also blocks the creation of runfiles directory.
+// See go/python-binary-host-mixed-build for more details.
+// TODO(b/197135294) create runfiles directory from MANIFEST file once it can be created from SourceSymlinkManifest action.
+func addCommandForPyBinaryRunfilesDir(bs BuildStatement, zipperCommandPath, zipFilePath string) string {
+ // Unzip the zip file, zipFilePath looks like <python_binary>.zip
+ runfilesDirName := zipFilePath[0:len(zipFilePath)-4] + ".runfiles"
+ command := fmt.Sprintf("%s x %s -d %s", zipperCommandPath, zipFilePath, runfilesDirName)
+ // Create a symbolic link in <python_binary>.runfiles/, which is the expected structure
+ // when running the python binary stub script.
+ command += fmt.Sprintf(" && ln -sf runfiles/__main__ %s", runfilesDirName)
+ return bs.Command + " && " + command
+}
+
func isSymlinkAction(a action) bool {
return a.Mnemonic == "Symlink" || a.Mnemonic == "SolibSymlink"
}
+func isTemplateExpandAction(a action) bool {
+ return a.Mnemonic == "TemplateExpand"
+}
+
+func isPythonZipperAction(a action) bool {
+ return a.Mnemonic == "PythonZipper"
+}
+
func shouldSkipAction(a action) bool {
// TODO(b/180945121): Handle complex symlink actions.
if a.Mnemonic == "SymlinkTree" || a.Mnemonic == "SourceSymlinkManifest" {
diff --git a/bazel/aquery_test.go b/bazel/aquery_test.go
index 88066c8..68e50c2 100644
--- a/bazel/aquery_test.go
+++ b/bazel/aquery_test.go
@@ -709,7 +709,7 @@
}
expectedBuildStatements := []BuildStatement{
BuildStatement{
- Command: "/bin/bash -c touch bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_out",
+ Command: "/bin/bash -c 'touch bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_out'",
OutputPaths: []string{"bazel-out/sourceroot/k8-fastbuild/bin/testpkg/test_out"},
InputPaths: inputPaths,
Mnemonic: "Action",
@@ -859,7 +859,7 @@
BuildStatement{
Command: "mkdir -p one/symlink_subdir && " +
"rm -f one/symlink_subdir/symlink && " +
- "ln -f one/file_subdir/file one/symlink_subdir/symlink",
+ "ln -sf $PWD/one/file_subdir/file one/symlink_subdir/symlink",
InputPaths: []string{"one/file_subdir/file"},
OutputPaths: []string{"one/symlink_subdir/symlink"},
SymlinkPaths: []string{"one/symlink_subdir/symlink"},
@@ -923,14 +923,14 @@
BuildStatement{
Command: "mkdir -p 'one/symlink subdir' && " +
"rm -f 'one/symlink subdir/symlink' && " +
- "ln -f 'one/file subdir/file' 'one/symlink subdir/symlink'",
+ "ln -sf $PWD/'one/file subdir/file' 'one/symlink subdir/symlink'",
InputPaths: []string{"one/file subdir/file"},
OutputPaths: []string{"one/symlink subdir/symlink"},
SymlinkPaths: []string{"one/symlink subdir/symlink"},
Mnemonic: "SolibSymlink",
},
}
- assertBuildStatements(t, actual, expectedBuildStatements)
+ assertBuildStatements(t, expectedBuildStatements, actual)
}
func TestSymlinkMultipleInputs(t *testing.T) {
@@ -1015,6 +1015,355 @@
assertError(t, err, `Expect 1 input and 1 output to symlink action, got: input ["file"], output ["symlink" "other_symlink"]`)
}
+func TestTemplateExpandActionSubstitutions(t *testing.T) {
+ const inputString = `
+{
+ "artifacts": [{
+ "id": 1,
+ "pathFragmentId": 1
+ }],
+ "actions": [{
+ "targetId": 1,
+ "actionKey": "x",
+ "mnemonic": "TemplateExpand",
+ "configurationId": 1,
+ "outputIds": [1],
+ "primaryOutputId": 1,
+ "executionPlatform": "//build/bazel/platforms:linux_x86_64",
+ "templateContent": "Test template substitutions: %token1%, %python_binary%",
+ "substitutions": [{
+ "key": "%token1%",
+ "value": "abcd"
+ },{
+ "key": "%python_binary%",
+ "value": "python3"
+ }]
+ }],
+ "pathFragments": [{
+ "id": 1,
+ "label": "template_file"
+ }]
+}`
+
+ actual, err := AqueryBuildStatements([]byte(inputString))
+
+ if err != nil {
+ t.Errorf("Unexpected error %q", err)
+ }
+
+ expectedBuildStatements := []BuildStatement{
+ BuildStatement{
+ Command: "/bin/bash -c 'echo \"Test template substitutions: abcd, python3\" | sed \"s/\\\\\\\\n/\\\\n/g\" > template_file && " +
+ "chmod a+x template_file'",
+ OutputPaths: []string{"template_file"},
+ Mnemonic: "TemplateExpand",
+ },
+ }
+ assertBuildStatements(t, expectedBuildStatements, actual)
+}
+
+func TestTemplateExpandActionNoOutput(t *testing.T) {
+ const inputString = `
+{
+ "artifacts": [{
+ "id": 1,
+ "pathFragmentId": 1
+ }],
+ "actions": [{
+ "targetId": 1,
+ "actionKey": "x",
+ "mnemonic": "TemplateExpand",
+ "configurationId": 1,
+ "primaryOutputId": 1,
+ "executionPlatform": "//build/bazel/platforms:linux_x86_64",
+ "templateContent": "Test template substitutions: %token1%, %python_binary%",
+ "substitutions": [{
+ "key": "%token1%",
+ "value": "abcd"
+ },{
+ "key": "%python_binary%",
+ "value": "python3"
+ }]
+ }],
+ "pathFragments": [{
+ "id": 1,
+ "label": "template_file"
+ }]
+}`
+
+ _, err := AqueryBuildStatements([]byte(inputString))
+ assertError(t, err, `Expect 1 output to template expand action, got: output []`)
+}
+
+func TestPythonZipperActionSuccess(t *testing.T) {
+ const inputString = `
+{
+ "artifacts": [{
+ "id": 1,
+ "pathFragmentId": 1
+ },{
+ "id": 2,
+ "pathFragmentId": 2
+ },{
+ "id": 3,
+ "pathFragmentId": 3
+ },{
+ "id": 4,
+ "pathFragmentId": 4
+ },{
+ "id": 5,
+ "pathFragmentId": 10
+ },{
+ "id": 10,
+ "pathFragmentId": 20
+ }],
+ "actions": [{
+ "targetId": 1,
+ "actionKey": "x",
+ "mnemonic": "TemplateExpand",
+ "configurationId": 1,
+ "outputIds": [1],
+ "primaryOutputId": 1,
+ "executionPlatform": "//build/bazel/platforms:linux_x86_64",
+ "templateContent": "Test template substitutions: %token1%, %python_binary%",
+ "substitutions": [{
+ "key": "%token1%",
+ "value": "abcd"
+ },{
+ "key": "%python_binary%",
+ "value": "python3"
+ }]
+ },{
+ "targetId": 1,
+ "actionKey": "x",
+ "mnemonic": "PythonZipper",
+ "configurationId": 1,
+ "arguments": ["../bazel_tools/tools/zip/zipper/zipper", "cC", "python_binary.zip", "__main__.py\u003dbazel-out/k8-fastbuild/bin/python_binary.temp", "__init__.py\u003d", "runfiles/__main__/__init__.py\u003d", "runfiles/__main__/python_binary.py\u003dpython_binary.py", "runfiles/bazel_tools/tools/python/py3wrapper.sh\u003dbazel-out/bazel_tools/k8-fastbuild/bin/tools/python/py3wrapper.sh"],
+ "outputIds": [2],
+ "inputDepSetIds": [1],
+ "primaryOutputId": 2
+ }],
+ "depSetOfFiles": [{
+ "id": 1,
+ "directArtifactIds": [4, 3, 5]
+ }],
+ "pathFragments": [{
+ "id": 1,
+ "label": "python_binary"
+ },{
+ "id": 2,
+ "label": "python_binary.zip"
+ },{
+ "id": 3,
+ "label": "python_binary.py"
+ },{
+ "id": 9,
+ "label": ".."
+ }, {
+ "id": 8,
+ "label": "bazel_tools",
+ "parentId": 9
+ }, {
+ "id": 7,
+ "label": "tools",
+ "parentId": 8
+ }, {
+ "id": 6,
+ "label": "zip",
+ "parentId": 7
+ }, {
+ "id": 5,
+ "label": "zipper",
+ "parentId": 6
+ }, {
+ "id": 4,
+ "label": "zipper",
+ "parentId": 5
+ },{
+ "id": 16,
+ "label": "bazel-out"
+ },{
+ "id": 15,
+ "label": "bazel_tools",
+ "parentId": 16
+ }, {
+ "id": 14,
+ "label": "k8-fastbuild",
+ "parentId": 15
+ }, {
+ "id": 13,
+ "label": "bin",
+ "parentId": 14
+ }, {
+ "id": 12,
+ "label": "tools",
+ "parentId": 13
+ }, {
+ "id": 11,
+ "label": "python",
+ "parentId": 12
+ }, {
+ "id": 10,
+ "label": "py3wrapper.sh",
+ "parentId": 11
+ },{
+ "id": 20,
+ "label": "python_binary"
+ }]
+}`
+ actual, err := AqueryBuildStatements([]byte(inputString))
+
+ if err != nil {
+ t.Errorf("Unexpected error %q", err)
+ }
+
+ expectedBuildStatements := []BuildStatement{
+ BuildStatement{
+ Command: "/bin/bash -c 'echo \"Test template substitutions: abcd, python3\" | sed \"s/\\\\\\\\n/\\\\n/g\" > python_binary && " +
+ "chmod a+x python_binary'",
+ InputPaths: []string{"python_binary.zip"},
+ OutputPaths: []string{"python_binary"},
+ Mnemonic: "TemplateExpand",
+ },
+ BuildStatement{
+ Command: "../bazel_tools/tools/zip/zipper/zipper cC python_binary.zip __main__.py=bazel-out/k8-fastbuild/bin/python_binary.temp " +
+ "__init__.py= runfiles/__main__/__init__.py= runfiles/__main__/python_binary.py=python_binary.py && " +
+ "../bazel_tools/tools/zip/zipper/zipper x python_binary.zip -d python_binary.runfiles && ln -sf runfiles/__main__ python_binary.runfiles",
+ InputPaths: []string{"../bazel_tools/tools/zip/zipper/zipper", "python_binary.py"},
+ OutputPaths: []string{"python_binary.zip"},
+ Mnemonic: "PythonZipper",
+ },
+ }
+ assertBuildStatements(t, expectedBuildStatements, actual)
+}
+
+func TestPythonZipperActionNoInput(t *testing.T) {
+ const inputString = `
+{
+ "artifacts": [{
+ "id": 1,
+ "pathFragmentId": 1
+ },{
+ "id": 2,
+ "pathFragmentId": 2
+ }],
+ "actions": [{
+ "targetId": 1,
+ "actionKey": "x",
+ "mnemonic": "PythonZipper",
+ "configurationId": 1,
+ "arguments": ["../bazel_tools/tools/zip/zipper/zipper", "cC", "python_binary.zip", "__main__.py\u003dbazel-out/k8-fastbuild/bin/python_binary.temp", "__init__.py\u003d", "runfiles/__main__/__init__.py\u003d", "runfiles/__main__/python_binary.py\u003dpython_binary.py", "runfiles/bazel_tools/tools/python/py3wrapper.sh\u003dbazel-out/bazel_tools/k8-fastbuild/bin/tools/python/py3wrapper.sh"],
+ "outputIds": [2],
+ "primaryOutputId": 2
+ }],
+ "pathFragments": [{
+ "id": 1,
+ "label": "python_binary"
+ },{
+ "id": 2,
+ "label": "python_binary.zip"
+ }]
+}`
+ _, err := AqueryBuildStatements([]byte(inputString))
+ assertError(t, err, `Expect 1+ input and 1 output to python zipper action, got: input [], output ["python_binary.zip"]`)
+}
+
+func TestPythonZipperActionNoOutput(t *testing.T) {
+ const inputString = `
+{
+ "artifacts": [{
+ "id": 1,
+ "pathFragmentId": 1
+ },{
+ "id": 2,
+ "pathFragmentId": 2
+ },{
+ "id": 3,
+ "pathFragmentId": 3
+ },{
+ "id": 4,
+ "pathFragmentId": 4
+ },{
+ "id": 5,
+ "pathFragmentId": 10
+ }],
+ "actions": [{
+ "targetId": 1,
+ "actionKey": "x",
+ "mnemonic": "PythonZipper",
+ "configurationId": 1,
+ "arguments": ["../bazel_tools/tools/zip/zipper/zipper", "cC", "python_binary.zip", "__main__.py\u003dbazel-out/k8-fastbuild/bin/python_binary.temp", "__init__.py\u003d", "runfiles/__main__/__init__.py\u003d", "runfiles/__main__/python_binary.py\u003dpython_binary.py", "runfiles/bazel_tools/tools/python/py3wrapper.sh\u003dbazel-out/bazel_tools/k8-fastbuild/bin/tools/python/py3wrapper.sh"],
+ "inputDepSetIds": [1]
+ }],
+ "depSetOfFiles": [{
+ "id": 1,
+ "directArtifactIds": [4, 3, 5]
+ }],
+ "pathFragments": [{
+ "id": 1,
+ "label": "python_binary"
+ },{
+ "id": 2,
+ "label": "python_binary.zip"
+ },{
+ "id": 3,
+ "label": "python_binary.py"
+ },{
+ "id": 9,
+ "label": ".."
+ }, {
+ "id": 8,
+ "label": "bazel_tools",
+ "parentId": 9
+ }, {
+ "id": 7,
+ "label": "tools",
+ "parentId": 8
+ }, {
+ "id": 6,
+ "label": "zip",
+ "parentId": 7
+ }, {
+ "id": 5,
+ "label": "zipper",
+ "parentId": 6
+ }, {
+ "id": 4,
+ "label": "zipper",
+ "parentId": 5
+ },{
+ "id": 16,
+ "label": "bazel-out"
+ },{
+ "id": 15,
+ "label": "bazel_tools",
+ "parentId": 16
+ }, {
+ "id": 14,
+ "label": "k8-fastbuild",
+ "parentId": 15
+ }, {
+ "id": 13,
+ "label": "bin",
+ "parentId": 14
+ }, {
+ "id": 12,
+ "label": "tools",
+ "parentId": 13
+ }, {
+ "id": 11,
+ "label": "python",
+ "parentId": 12
+ }, {
+ "id": 10,
+ "label": "py3wrapper.sh",
+ "parentId": 11
+ }]
+}`
+ _, err := AqueryBuildStatements([]byte(inputString))
+ assertError(t, err, `Expect 1+ input and 1 output to python zipper action, got: input ["../bazel_tools/tools/zip/zipper/zipper" "python_binary.py"], output []`)
+}
+
func assertError(t *testing.T, err error, expected string) {
t.Helper()
if err == nil {
@@ -1029,7 +1378,7 @@
func assertBuildStatements(t *testing.T, expected []BuildStatement, actual []BuildStatement) {
t.Helper()
if len(expected) != len(actual) {
- t.Errorf("expected %d build statements, but got %d,\n expected: %v,\n actual: %v",
+ t.Errorf("expected %d build statements, but got %d,\n expected: %#v,\n actual: %#v",
len(expected), len(actual), expected, actual)
return
}
@@ -1040,7 +1389,7 @@
continue ACTUAL_LOOP
}
}
- t.Errorf("unexpected build statement %v.\n expected: %v",
+ t.Errorf("unexpected build statement %#v.\n expected: %#v",
actualStatement, expected)
return
}
diff --git a/bazel/configurability.go b/bazel/configurability.go
index f05c8e5..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",
@@ -158,9 +177,9 @@
}
// SelectKey returns the Bazel select key for a given configurationType and config string.
-func (ct configurationType) SelectKey(config string) string {
- ct.validateConfig(config)
- switch ct {
+func (ca ConfigurationAxis) SelectKey(config string) string {
+ ca.validateConfig(config)
+ switch ca.configurationType {
case noConfig:
panic(fmt.Errorf("SelectKey is unnecessary for noConfig ConfigurationType "))
case arch:
@@ -170,12 +189,13 @@
case osArch:
return platformOsArchMap[config]
case productVariables:
- if config == ConditionsDefaultConfigKey {
+ if strings.HasSuffix(config, ConditionsDefaultConfigKey) {
+ // e.g. "acme__feature1__conditions_default" or "android__board__conditions_default"
return ConditionsDefaultSelectKey
}
- return fmt.Sprintf("%s:%s", productVariableBazelPackage, strings.ToLower(config))
+ return fmt.Sprintf("%s:%s", productVariableBazelPackage, config)
default:
- panic(fmt.Errorf("Unrecognized ConfigurationType %d", ct))
+ panic(fmt.Errorf("Unrecognized ConfigurationType %d", ca.configurationType))
}
}
diff --git a/bazel/cquery/request_type.go b/bazel/cquery/request_type.go
index 0bd71c6..41f9886 100644
--- a/bazel/cquery/request_type.go
+++ b/bazel/cquery/request_type.go
@@ -17,6 +17,7 @@
CcStaticLibraryFiles []string
Includes []string
SystemIncludes []string
+ Headers []string
// Archives owned by the current target (not by its dependencies). These will
// be a subset of OutputFiles. (or static libraries, this will be equal to OutputFiles,
// but general cc_library will also have dynamic libraries in output files).
@@ -105,6 +106,7 @@
includes = cc_info.compilation_context.includes.to_list()
system_includes = cc_info.compilation_context.system_includes.to_list()
+headers = [f.path for f in cc_info.compilation_context.headers.to_list()]
ccObjectFiles = []
staticLibraries = []
@@ -145,6 +147,7 @@
ccObjectFiles,
includes,
system_includes,
+ headers,
rootStaticArchives,
rootDynamicLibraries,
[toc_file]
@@ -161,7 +164,7 @@
var ccObjects []string
splitString := strings.Split(rawString, "|")
- if expectedLen := 8; len(splitString) != expectedLen {
+ if expectedLen := 9; len(splitString) != expectedLen {
return CcInfo{}, fmt.Errorf("Expected %d items, got %q", expectedLen, splitString)
}
outputFilesString := splitString[0]
@@ -172,15 +175,17 @@
ccObjects = splitOrEmpty(ccObjectsString, ", ")
includes := splitOrEmpty(splitString[3], ", ")
systemIncludes := splitOrEmpty(splitString[4], ", ")
- rootStaticArchives := splitOrEmpty(splitString[5], ", ")
- rootDynamicLibraries := splitOrEmpty(splitString[6], ", ")
- tocFile := splitString[7] // NOTE: Will be the empty string if there wasn't
+ headers := splitOrEmpty(splitString[5], ", ")
+ rootStaticArchives := splitOrEmpty(splitString[6], ", ")
+ rootDynamicLibraries := splitOrEmpty(splitString[7], ", ")
+ tocFile := splitString[8] // NOTE: Will be the empty string if there wasn't
return CcInfo{
OutputFiles: outputFiles,
CcObjectFiles: ccObjects,
CcStaticLibraryFiles: ccStaticLibraries,
Includes: includes,
SystemIncludes: systemIncludes,
+ Headers: headers,
RootStaticArchives: rootStaticArchives,
RootDynamicLibraries: rootDynamicLibraries,
TocFile: tocFile,
diff --git a/bazel/cquery/request_type_test.go b/bazel/cquery/request_type_test.go
index 34d0832..d3bcb45 100644
--- a/bazel/cquery/request_type_test.go
+++ b/bazel/cquery/request_type_test.go
@@ -71,13 +71,14 @@
}{
{
description: "no result",
- input: "|||||||",
+ input: "||||||||",
expectedOutput: CcInfo{
OutputFiles: []string{},
CcObjectFiles: []string{},
CcStaticLibraryFiles: []string{},
Includes: []string{},
SystemIncludes: []string{},
+ Headers: []string{},
RootStaticArchives: []string{},
RootDynamicLibraries: []string{},
TocFile: "",
@@ -85,13 +86,14 @@
},
{
description: "only output",
- input: "test|||||||",
+ input: "test||||||||",
expectedOutput: CcInfo{
OutputFiles: []string{"test"},
CcObjectFiles: []string{},
CcStaticLibraryFiles: []string{},
Includes: []string{},
SystemIncludes: []string{},
+ Headers: []string{},
RootStaticArchives: []string{},
RootDynamicLibraries: []string{},
TocFile: "",
@@ -99,13 +101,14 @@
},
{
description: "all items set",
- input: "out1, out2|static_lib1, static_lib2|object1, object2|., dir/subdir|system/dir, system/other/dir|rootstaticarchive1|rootdynamiclibrary1|lib.so.toc",
+ input: "out1, out2|static_lib1, static_lib2|object1, object2|., dir/subdir|system/dir, system/other/dir|dir/subdir/hdr.h|rootstaticarchive1|rootdynamiclibrary1|lib.so.toc",
expectedOutput: CcInfo{
OutputFiles: []string{"out1", "out2"},
CcObjectFiles: []string{"object1", "object2"},
CcStaticLibraryFiles: []string{"static_lib1", "static_lib2"},
Includes: []string{".", "dir/subdir"},
SystemIncludes: []string{"system/dir", "system/other/dir"},
+ Headers: []string{"dir/subdir/hdr.h"},
RootStaticArchives: []string{"rootstaticarchive1"},
RootDynamicLibraries: []string{"rootdynamiclibrary1"},
TocFile: "lib.so.toc",
@@ -115,13 +118,13 @@
description: "too few result splits",
input: "|",
expectedOutput: CcInfo{},
- expectedErrorMessage: fmt.Sprintf("Expected %d items, got %q", 8, []string{"", ""}),
+ expectedErrorMessage: fmt.Sprintf("Expected %d items, got %q", 9, []string{"", ""}),
},
{
description: "too many result splits",
- input: strings.Repeat("|", 8),
+ input: strings.Repeat("|", 50),
expectedOutput: CcInfo{},
- expectedErrorMessage: fmt.Sprintf("Expected %d items, got %q", 8, make([]string, 9)),
+ expectedErrorMessage: fmt.Sprintf("Expected %d items, got %q", 9, make([]string, 51)),
},
}
for _, tc := range testCases {
diff --git a/bazel/properties.go b/bazel/properties.go
index facbedd..870d293 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -107,6 +107,14 @@
return dirs
}
+// Add inserts the label Label at the end of the LabelList.
+func (ll *LabelList) Add(label *Label) {
+ if label == nil {
+ return
+ }
+ ll.Includes = append(ll.Includes, *label)
+}
+
// Append appends the fields of other labelList to the corresponding fields of ll.
func (ll *LabelList) Append(other LabelList) {
if len(ll.Includes) > 0 || len(other.Includes) > 0 {
@@ -236,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
@@ -263,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))
}
@@ -316,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.
@@ -335,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: %s", 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)
@@ -366,9 +539,23 @@
// labelListSelectValues supports config-specific label_list typed Bazel attribute values.
type labelListSelectValues map[string]LabelList
-func (ll labelListSelectValues) appendSelects(other labelListSelectValues) {
+func (ll labelListSelectValues) addSelects(label labelSelectValues) {
+ for k, v := range label {
+ if label == nil {
+ continue
+ }
+ l := ll[k]
+ (&l).Add(v)
+ ll[k] = l
+ }
+}
+
+func (ll labelListSelectValues) appendSelects(other labelListSelectValues, forceSpecifyEmptyList bool) {
for k, v := range other {
l := ll[k]
+ if forceSpecifyEmptyList && l.IsNil() && !v.IsNil() {
+ l.Includes = []Label{}
+ }
(&l).Append(v)
ll[k] = l
}
@@ -400,6 +587,12 @@
// This mode facilitates use of attribute defaults: an empty list should
// override the default.
ForceSpecifyEmptyList bool
+
+ // If true, signal the intent to the code generator to emit all select keys,
+ // even if the Includes list for that key is empty. This mode facilitates
+ // specific select statements where an empty list for a non-default select
+ // key has a meaning.
+ EmitEmptyList bool
}
type configurableLabelLists map[ConfigurationAxis]labelListSelectValues
@@ -418,17 +611,22 @@
cll[axis][config] = list
}
-func (cll configurableLabelLists) Append(other configurableLabelLists) {
+func (cll configurableLabelLists) Append(other configurableLabelLists, forceSpecifyEmptyList bool) {
for axis, otherSelects := range other {
selects := cll[axis]
if selects == nil {
selects = make(labelListSelectValues, len(otherSelects))
}
- selects.appendSelects(otherSelects)
+ selects.appendSelects(otherSelects, forceSpecifyEmptyList)
cll[axis] = selects
}
}
+func (lla *LabelListAttribute) Clone() *LabelListAttribute {
+ result := &LabelListAttribute{ForceSpecifyEmptyList: lla.ForceSpecifyEmptyList}
+ return result.Append(*lla)
+}
+
// MakeLabelListAttribute initializes a LabelListAttribute with the non-arch specific value.
func MakeLabelListAttribute(value LabelList) LabelListAttribute {
return LabelListAttribute{
@@ -482,21 +680,47 @@
}
// Append all values, including os and arch specific ones, from another
-// LabelListAttribute to this LabelListAttribute.
-func (lla *LabelListAttribute) Append(other LabelListAttribute) {
- if lla.ForceSpecifyEmptyList && !other.Value.IsNil() {
+// LabelListAttribute to this LabelListAttribute. Returns this LabelListAttribute.
+func (lla *LabelListAttribute) Append(other LabelListAttribute) *LabelListAttribute {
+ forceSpecifyEmptyList := lla.ForceSpecifyEmptyList || other.ForceSpecifyEmptyList
+ if forceSpecifyEmptyList && lla.Value.IsNil() && !other.Value.IsNil() {
lla.Value.Includes = []Label{}
}
lla.Value.Append(other.Value)
if lla.ConfigurableValues == nil {
lla.ConfigurableValues = make(configurableLabelLists)
}
- lla.ConfigurableValues.Append(other.ConfigurableValues)
+ lla.ConfigurableValues.Append(other.ConfigurableValues, forceSpecifyEmptyList)
+ return lla
+}
+
+// Add inserts the labels for each axis of LabelAttribute at the end of corresponding axis's
+// LabelList within the LabelListAttribute
+func (lla *LabelListAttribute) Add(label *LabelAttribute) {
+ if label == nil {
+ return
+ }
+
+ lla.Value.Add(label.Value)
+ if lla.ConfigurableValues == nil && label.ConfigurableValues != nil {
+ lla.ConfigurableValues = make(configurableLabelLists)
+ }
+ for axis, _ := range label.ConfigurableValues {
+ if _, exists := lla.ConfigurableValues[axis]; !exists {
+ lla.ConfigurableValues[axis] = make(labelListSelectValues)
+ }
+ lla.ConfigurableValues[axis].addSelects(label.ConfigurableValues[axis])
+ }
}
// 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.
@@ -512,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() {
@@ -560,7 +802,7 @@
// LabelMapper is a function that takes a OtherModuleContext and returns a (potentially changed)
// label and whether it was changed.
-type LabelMapper func(OtherModuleContext, string) (string, bool)
+type LabelMapper func(OtherModuleContext, Label) (string, bool)
// LabelPartition contains descriptions of a partition for labels
type LabelPartition struct {
@@ -582,7 +824,7 @@
// not.
func (lf LabelPartition) filter(ctx OtherModuleContext, label Label) *Label {
if lf.LabelMapper != nil {
- if newLabel, changed := lf.LabelMapper(ctx, label.Label); changed {
+ if newLabel, changed := lf.LabelMapper(ctx, label); changed {
return &Label{newLabel, label.OriginalModuleName}
}
}
@@ -746,17 +988,28 @@
// 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
// StringListAttribute to this StringListAttribute
-func (sla *StringListAttribute) Append(other StringListAttribute) {
+func (sla *StringListAttribute) Append(other StringListAttribute) *StringListAttribute {
sla.Value = append(sla.Value, other.Value...)
if sla.ConfigurableValues == nil {
sla.ConfigurableValues = make(configurableStringLists)
}
sla.ConfigurableValues.Append(other.ConfigurableValues)
+ return sla
+}
+
+func (sla *StringListAttribute) Clone() *StringListAttribute {
+ result := &StringListAttribute{}
+ return result.Append(*sla)
}
// SetSelectValue set a value for a bazel select for the given axis, config and value.
diff --git a/bazel/properties_test.go b/bazel/properties_test.go
index 7a7d6f3..c7f9776 100644
--- a/bazel/properties_test.go
+++ b/bazel/properties_test.go
@@ -313,16 +313,16 @@
// labelAddSuffixForTypeMapper returns a LabelMapper that adds suffix to label name for modules of
// typ
func labelAddSuffixForTypeMapper(suffix, typ string) LabelMapper {
- return func(omc OtherModuleContext, label string) (string, bool) {
- m, ok := omc.ModuleFromName(label)
+ return func(omc OtherModuleContext, label Label) (string, bool) {
+ m, ok := omc.ModuleFromName(label.Label)
if !ok {
- return label, false
+ return label.Label, false
}
mTyp := omc.OtherModuleType(m)
if typ == mTyp {
- return label + suffix, true
+ return label.Label + suffix, true
}
- return label, false
+ return label.Label, false
}
}
diff --git a/bp2build/Android.bp b/bp2build/Android.bp
index 1250e92..ae0fb11 100644
--- a/bp2build/Android.bp
+++ b/bp2build/Android.bp
@@ -18,6 +18,8 @@
],
deps: [
"soong-android",
+ "soong-android-soongconfig",
+ "soong-shared",
"soong-apex",
"soong-bazel",
"soong-cc",
@@ -26,18 +28,21 @@
"soong-genrule",
"soong-python",
"soong-sh",
+ "soong-ui-metrics",
],
testSrcs: [
"android_app_certificate_conversion_test.go",
+ "android_app_conversion_test.go",
"apex_conversion_test.go",
"apex_key_conversion_test.go",
"build_conversion_test.go",
"bzl_conversion_test.go",
+ "cc_binary_conversion_test.go",
"cc_genrule_conversion_test.go",
"cc_library_conversion_test.go",
"cc_library_headers_conversion_test.go",
- "cc_library_static_conversion_test.go",
"cc_library_shared_conversion_test.go",
+ "cc_library_static_conversion_test.go",
"cc_object_conversion_test.go",
"conversion_test.go",
"filegroup_conversion_test.go",
@@ -47,6 +52,7 @@
"python_binary_conversion_test.go",
"python_library_conversion_test.go",
"sh_conversion_test.go",
+ "soong_config_module_type_conversion_test.go",
"testing.go",
],
pluginFor: [
diff --git a/bp2build/android_app_certificate_conversion_test.go b/bp2build/android_app_certificate_conversion_test.go
index 022c687..035a352 100644
--- a/bp2build/android_app_certificate_conversion_test.go
+++ b/bp2build/android_app_certificate_conversion_test.go
@@ -31,19 +31,19 @@
func TestAndroidAppCertificateSimple(t *testing.T) {
runAndroidAppCertificateTestCase(t, bp2buildTestCase{
- description: "Android app certificate - simple example",
- moduleTypeUnderTest: "android_app_certificate",
- moduleTypeUnderTestFactory: java.AndroidAppCertificateFactory,
- moduleTypeUnderTestBp2BuildMutator: java.AndroidAppCertificateBp2Build,
- filesystem: map[string]string{},
+ description: "Android app certificate - simple example",
+ moduleTypeUnderTest: "android_app_certificate",
+ moduleTypeUnderTestFactory: java.AndroidAppCertificateFactory,
+ filesystem: map[string]string{},
blueprint: `
android_app_certificate {
name: "com.android.apogee.cert",
certificate: "chamber_of_secrets_dir",
}
`,
- expectedBazelTargets: []string{`android_app_certificate(
- name = "com.android.apogee.cert",
- certificate = "chamber_of_secrets_dir",
-)`}})
+ expectedBazelTargets: []string{
+ makeBazelTarget("android_app_certificate", "com.android.apogee.cert", attrNameToString{
+ "certificate": `"chamber_of_secrets_dir"`,
+ }),
+ }})
}
diff --git a/bp2build/android_app_conversion_test.go b/bp2build/android_app_conversion_test.go
new file mode 100644
index 0000000..153817b
--- /dev/null
+++ b/bp2build/android_app_conversion_test.go
@@ -0,0 +1,90 @@
+// 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 bp2build
+
+import (
+ "android/soong/android"
+ "android/soong/java"
+
+ "testing"
+)
+
+func runAndroidAppTestCase(t *testing.T, tc bp2buildTestCase) {
+ t.Helper()
+ runBp2BuildTestCase(t, registerAndroidAppModuleTypes, tc)
+}
+
+func registerAndroidAppModuleTypes(ctx android.RegistrationContext) {
+}
+
+func TestMinimalAndroidApp(t *testing.T) {
+ runAndroidAppTestCase(t, bp2buildTestCase{
+ description: "Android app - simple example",
+ moduleTypeUnderTest: "android_app",
+ moduleTypeUnderTestFactory: java.AndroidAppFactory,
+ filesystem: map[string]string{
+ "app.java": "",
+ "res/res.png": "",
+ "AndroidManifest.xml": "",
+ },
+ blueprint: `
+android_app {
+ name: "TestApp",
+ srcs: ["app.java"],
+ sdk_version: "current",
+}
+`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("android_binary", "TestApp", attrNameToString{
+ "srcs": `["app.java"]`,
+ "manifest": `"AndroidManifest.xml"`,
+ "resource_files": `["res/res.png"]`,
+ }),
+ }})
+}
+
+func TestAndroidAppAllSupportedFields(t *testing.T) {
+ runAndroidAppTestCase(t, bp2buildTestCase{
+ description: "Android app - all supported fields",
+ moduleTypeUnderTest: "android_app",
+ moduleTypeUnderTestFactory: java.AndroidAppFactory,
+ filesystem: map[string]string{
+ "app.java": "",
+ "resa/res.png": "",
+ "resb/res.png": "",
+ "manifest/AndroidManifest.xml": "",
+ },
+ blueprint: `
+android_app {
+ name: "TestApp",
+ srcs: ["app.java"],
+ sdk_version: "current",
+ package_name: "com.google",
+ resource_dirs: ["resa", "resb"],
+ manifest: "manifest/AndroidManifest.xml",
+}
+`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("android_binary", "TestApp", attrNameToString{
+ "srcs": `["app.java"]`,
+ "manifest": `"manifest/AndroidManifest.xml"`,
+ "resource_files": `[
+ "resa/res.png",
+ "resb/res.png",
+ ]`,
+ "custom_package": `"com.google"`,
+ }),
+ }})
+}
diff --git a/bp2build/apex_conversion_test.go b/bp2build/apex_conversion_test.go
index 456f18a..a3825e6 100644
--- a/bp2build/apex_conversion_test.go
+++ b/bp2build/apex_conversion_test.go
@@ -19,6 +19,7 @@
"android/soong/apex"
"android/soong/cc"
"android/soong/java"
+ "android/soong/sh"
"testing"
)
@@ -32,6 +33,8 @@
// CC module types needed as they can be APEX dependencies
cc.RegisterCCBuildComponents(ctx)
+ ctx.RegisterModuleType("sh_binary", sh.ShBinaryFactory)
+ ctx.RegisterModuleType("cc_binary", cc.BinaryFactory)
ctx.RegisterModuleType("cc_library", cc.LibraryFactory)
ctx.RegisterModuleType("apex_key", apex.ApexKeyFactory)
ctx.RegisterModuleType("android_app_certificate", java.AndroidAppCertificateFactory)
@@ -40,60 +43,62 @@
func TestApexBundleSimple(t *testing.T) {
runApexTestCase(t, bp2buildTestCase{
- description: "apex - simple example",
- moduleTypeUnderTest: "apex",
- moduleTypeUnderTestFactory: apex.BundleFactory,
- moduleTypeUnderTestBp2BuildMutator: apex.ApexBundleBp2Build,
- filesystem: map[string]string{},
+ description: "apex - example with all props",
+ moduleTypeUnderTest: "apex",
+ moduleTypeUnderTestFactory: apex.BundleFactory,
+ filesystem: map[string]string{},
blueprint: `
apex_key {
- name: "com.android.apogee.key",
- public_key: "com.android.apogee.avbpubkey",
- private_key: "com.android.apogee.pem",
+ name: "com.android.apogee.key",
+ public_key: "com.android.apogee.avbpubkey",
+ private_key: "com.android.apogee.pem",
bazel_module: { bp2build_available: false },
}
android_app_certificate {
- name: "com.android.apogee.certificate",
- certificate: "com.android.apogee",
- bazel_module: { bp2build_available: false },
-}
-
-cc_library {
- name: "native_shared_lib_1",
+ name: "com.android.apogee.certificate",
+ certificate: "com.android.apogee",
bazel_module: { bp2build_available: false },
}
cc_library {
- name: "native_shared_lib_2",
+ name: "native_shared_lib_1",
+ bazel_module: { bp2build_available: false },
+}
+
+cc_library {
+ name: "native_shared_lib_2",
bazel_module: { bp2build_available: false },
}
// TODO(b/194878861): Add bp2build support for prebuilt_etc
cc_library {
- name: "pretend_prebuilt_1",
- bazel_module: { bp2build_available: false },
+ name: "pretend_prebuilt_1",
+ bazel_module: { bp2build_available: false },
}
// TODO(b/194878861): Add bp2build support for prebuilt_etc
cc_library {
- name: "pretend_prebuilt_2",
- bazel_module: { bp2build_available: false },
+ name: "pretend_prebuilt_2",
+ bazel_module: { bp2build_available: false },
}
filegroup {
name: "com.android.apogee-file_contexts",
- srcs: [
- "com.android.apogee-file_contexts",
- ],
- bazel_module: { bp2build_available: false },
+ srcs: [
+ "com.android.apogee-file_contexts",
+ ],
+ bazel_module: { bp2build_available: false },
}
+cc_binary { name: "cc_binary_1", bazel_module: { bp2build_available: false } }
+sh_binary { name: "sh_binary_2", bazel_module: { bp2build_available: false } }
+
apex {
name: "com.android.apogee",
manifest: "apogee_manifest.json",
androidManifest: "ApogeeAndroidManifest.xml",
- file_contexts: "com.android.apogee-file_contexts",
+ file_contexts: "com.android.apogee-file_contexts",
min_sdk_version: "29",
key: "com.android.apogee.key",
certificate: "com.android.apogee.certificate",
@@ -104,8 +109,8 @@
"native_shared_lib_2",
],
binaries: [
- "binary_1",
- "binary_2",
+ "cc_binary_1",
+ "sh_binary_2",
],
prebuilts: [
"pretend_prebuilt_1",
@@ -113,57 +118,56 @@
],
}
`,
- expectedBazelTargets: []string{`apex(
- name = "com.android.apogee",
- android_manifest = "ApogeeAndroidManifest.xml",
- binaries = [
- "binary_1",
- "binary_2",
- ],
- certificate = ":com.android.apogee.certificate",
- file_contexts = ":com.android.apogee-file_contexts",
- installable = False,
- key = ":com.android.apogee.key",
- manifest = "apogee_manifest.json",
- min_sdk_version = "29",
- native_shared_libs = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("apex", "com.android.apogee", attrNameToString{
+ "android_manifest": `"ApogeeAndroidManifest.xml"`,
+ "binaries": `[
+ ":cc_binary_1",
+ ":sh_binary_2",
+ ]`,
+ "certificate": `":com.android.apogee.certificate"`,
+ "file_contexts": `":com.android.apogee-file_contexts"`,
+ "installable": "False",
+ "key": `":com.android.apogee.key"`,
+ "manifest": `"apogee_manifest.json"`,
+ "min_sdk_version": `"29"`,
+ "native_shared_libs": `[
":native_shared_lib_1",
":native_shared_lib_2",
- ],
- prebuilts = [
+ ]`,
+ "prebuilts": `[
":pretend_prebuilt_1",
":pretend_prebuilt_2",
- ],
- updatable = False,
-)`}})
+ ]`,
+ "updatable": "False",
+ }),
+ }})
}
func TestApexBundleDefaultPropertyValues(t *testing.T) {
runApexTestCase(t, bp2buildTestCase{
- description: "apex - default property values",
- moduleTypeUnderTest: "apex",
- moduleTypeUnderTestFactory: apex.BundleFactory,
- moduleTypeUnderTestBp2BuildMutator: apex.ApexBundleBp2Build,
- filesystem: map[string]string{},
+ description: "apex - default property values",
+ moduleTypeUnderTest: "apex",
+ moduleTypeUnderTestFactory: apex.BundleFactory,
+ filesystem: map[string]string{},
blueprint: `
apex {
name: "com.android.apogee",
manifest: "apogee_manifest.json",
}
`,
- expectedBazelTargets: []string{`apex(
- name = "com.android.apogee",
- manifest = "apogee_manifest.json",
-)`}})
+ expectedBazelTargets: []string{makeBazelTarget("apex", "com.android.apogee", attrNameToString{
+ "manifest": `"apogee_manifest.json"`,
+ }),
+ }})
}
func TestApexBundleHasBazelModuleProps(t *testing.T) {
runApexTestCase(t, bp2buildTestCase{
- description: "apex - has bazel module props",
- moduleTypeUnderTest: "apex",
- moduleTypeUnderTestFactory: apex.BundleFactory,
- moduleTypeUnderTestBp2BuildMutator: apex.ApexBundleBp2Build,
- filesystem: map[string]string{},
+ description: "apex - has bazel module props",
+ moduleTypeUnderTest: "apex",
+ moduleTypeUnderTestFactory: apex.BundleFactory,
+ filesystem: map[string]string{},
blueprint: `
apex {
name: "apogee",
@@ -171,8 +175,8 @@
bazel_module: { bp2build_available: true },
}
`,
- expectedBazelTargets: []string{`apex(
- name = "apogee",
- manifest = "manifest.json",
-)`}})
+ expectedBazelTargets: []string{makeBazelTarget("apex", "apogee", attrNameToString{
+ "manifest": `"manifest.json"`,
+ }),
+ }})
}
diff --git a/bp2build/apex_key_conversion_test.go b/bp2build/apex_key_conversion_test.go
index 8e1aa09..1d949901 100644
--- a/bp2build/apex_key_conversion_test.go
+++ b/bp2build/apex_key_conversion_test.go
@@ -31,11 +31,10 @@
func TestApexKeySimple(t *testing.T) {
runApexKeyTestCase(t, bp2buildTestCase{
- description: "apex key - simple example",
- moduleTypeUnderTest: "apex_key",
- moduleTypeUnderTestFactory: apex.ApexKeyFactory,
- moduleTypeUnderTestBp2BuildMutator: apex.ApexKeyBp2Build,
- filesystem: map[string]string{},
+ description: "apex key - simple example",
+ moduleTypeUnderTest: "apex_key",
+ moduleTypeUnderTestFactory: apex.ApexKeyFactory,
+ filesystem: map[string]string{},
blueprint: `
apex_key {
name: "com.android.apogee.key",
@@ -43,9 +42,9 @@
private_key: "com.android.apogee.pem",
}
`,
- expectedBazelTargets: []string{`apex_key(
- name = "com.android.apogee.key",
- private_key = "com.android.apogee.pem",
- public_key = "com.android.apogee.avbpubkey",
-)`}})
+ expectedBazelTargets: []string{makeBazelTarget("apex_key", "com.android.apogee.key", attrNameToString{
+ "private_key": `"com.android.apogee.pem"`,
+ "public_key": `"com.android.apogee.avbpubkey"`,
+ }),
+ }})
}
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index aa1cf70..54b59af 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -259,7 +259,7 @@
// Simple metrics tracking for bp2build
metrics := CodegenMetrics{
- ruleClassCount: make(map[string]int),
+ ruleClassCount: make(map[string]uint64),
}
dirs := make(map[string]bool)
@@ -532,8 +532,8 @@
// prettyPrint a property value into the equivalent Starlark representation
// recursively.
-func prettyPrint(propertyValue reflect.Value, indent int) (string, error) {
- if isZero(propertyValue) {
+func prettyPrint(propertyValue reflect.Value, indent int, emitZeroValues bool) (string, error) {
+ if !emitZeroValues && isZero(propertyValue) {
// A property value being set or unset actually matters -- Soong does set default
// values for unset properties, like system_shared_libs = ["libc", "libm", "libdl"] at
// https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/linker.go;l=281-287;drc=f70926eef0b9b57faf04c17a1062ce50d209e480
@@ -556,7 +556,7 @@
case reflect.Int, reflect.Uint, reflect.Int64:
ret = fmt.Sprintf("%v", propertyValue.Interface())
case reflect.Ptr:
- return prettyPrint(propertyValue.Elem(), indent)
+ return prettyPrint(propertyValue.Elem(), indent, emitZeroValues)
case reflect.Slice:
if propertyValue.Len() == 0 {
return "[]", nil
@@ -565,7 +565,7 @@
if propertyValue.Len() == 1 {
// Single-line list for list with only 1 element
ret += "["
- indexedValue, err := prettyPrint(propertyValue.Index(0), indent)
+ indexedValue, err := prettyPrint(propertyValue.Index(0), indent, emitZeroValues)
if err != nil {
return "", err
}
@@ -575,7 +575,7 @@
// otherwise, use a multiline list.
ret += "[\n"
for i := 0; i < propertyValue.Len(); i++ {
- indexedValue, err := prettyPrint(propertyValue.Index(i), indent+1)
+ indexedValue, err := prettyPrint(propertyValue.Index(i), indent+1, emitZeroValues)
if err != nil {
return "", err
}
@@ -660,7 +660,7 @@
}
propertyName := proptools.PropertyNameForField(field.Name)
- prettyPrintedValue, err := prettyPrint(fieldValue, indent+1)
+ prettyPrintedValue, err := prettyPrint(fieldValue, indent+1, false)
if err != nil {
panic(
fmt.Errorf(
@@ -698,9 +698,9 @@
} else {
return true
}
- // Always print bools, if you want a bool attribute to be able to take the default value, use a
- // bool pointer instead
- case reflect.Bool:
+ // Always print bool/strings, if you want a bool/string attribute to be able to take the default value, use a
+ // pointer instead
+ case reflect.Bool, reflect.String:
return false
default:
if !value.IsValid() {
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index ee1d862..1440b6f 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -41,6 +41,7 @@
soong_module_deps = [
],
bool_prop = False,
+ string_prop = "",
)`,
},
{
@@ -58,6 +59,7 @@
soong_module_deps = [
],
bool_prop = True,
+ string_prop = "",
)`,
},
{
@@ -76,6 +78,7 @@
],
bool_prop = False,
owner = "a_string_with\"quotes\"_and_\\backslashes\\\\",
+ string_prop = "",
)`,
},
{
@@ -94,6 +97,7 @@
],
bool_prop = False,
required = ["bar"],
+ string_prop = "",
)`,
},
{
@@ -111,6 +115,7 @@
soong_module_deps = [
],
bool_prop = False,
+ string_prop = "",
target_required = [
"qux",
"bazqux",
@@ -147,6 +152,7 @@
"tag": ".bar",
"targets": ["goal_bar"],
}],
+ string_prop = "",
)`,
},
{
@@ -179,6 +185,7 @@
}],
owner = "custom_owner",
required = ["bar"],
+ string_prop = "",
target_required = [
"qux",
"bazqux",
@@ -223,39 +230,52 @@
func TestGenerateBazelTargetModules(t *testing.T) {
testCases := []bp2buildTestCase{
{
- description: "string props",
+ description: "string ptr props",
blueprint: `custom {
name: "foo",
- string_list_prop: ["a", "b"],
- string_prop: "a",
+ string_ptr_prop: "",
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`custom(
- name = "foo",
- string_list_prop = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("custom", "foo", attrNameToString{
+ "string_ptr_prop": `""`,
+ }),
+ },
+ },
+ {
+ description: "string props",
+ blueprint: `custom {
+ name: "foo",
+ string_list_prop: ["a", "b"],
+ string_ptr_prop: "a",
+ bazel_module: { bp2build_available: true },
+}`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("custom", "foo", attrNameToString{
+ "string_list_prop": `[
"a",
"b",
- ],
- string_prop = "a",
-)`,
+ ]`,
+ "string_ptr_prop": `"a"`,
+ }),
},
},
{
description: "control characters",
blueprint: `custom {
- name: "control_characters",
+ name: "foo",
string_list_prop: ["\t", "\n"],
- string_prop: "a\t\n\r",
+ string_ptr_prop: "a\t\n\r",
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`custom(
- name = "control_characters",
- string_list_prop = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("custom", "foo", attrNameToString{
+ "string_list_prop": `[
"\t",
"\n",
- ],
- string_prop = "a\t\n\r",
-)`,
+ ]`,
+ "string_ptr_prop": `"a\t\n\r"`,
+ }),
},
},
{
@@ -271,14 +291,13 @@
arch_paths: ["abc"],
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`custom(
- name = "dep",
- arch_paths = ["abc"],
-)`,
- `custom(
- name = "has_dep",
- arch_paths = [":dep"],
-)`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("custom", "dep", attrNameToString{
+ "arch_paths": `["abc"]`,
+ }),
+ makeBazelTarget("custom", "has_dep", attrNameToString{
+ "arch_paths": `[":dep"]`,
+ }),
},
},
{
@@ -311,9 +330,9 @@
},
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`custom(
- name = "arch_paths",
- arch_paths = select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("custom", "arch_paths", attrNameToString{
+ "arch_paths": `select({
"//build/bazel/platforms/arch:arm": [
"arm.txt",
"lib32.txt",
@@ -368,8 +387,8 @@
"windows.txt",
],
"//conditions:default": [],
- }),
-)`,
+ })`,
+ }),
},
},
{
@@ -389,17 +408,16 @@
arch_paths: ["abc"],
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`custom(
- name = "dep",
- arch_paths = ["abc"],
-)`,
- `custom(
- name = "has_dep",
- arch_paths = select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("custom", "dep", attrNameToString{
+ "arch_paths": `["abc"]`,
+ }),
+ makeBazelTarget("custom", "has_dep", attrNameToString{
+ "arch_paths": `select({
"//build/bazel/platforms/arch:x86": [":dep"],
"//conditions:default": [],
- }),
-)`,
+ })`,
+ }),
},
},
{
@@ -409,10 +427,10 @@
embedded_prop: "abc",
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`custom(
- name = "embedded_props",
- embedded_attr = "abc",
-)`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("custom", "embedded_props", attrNameToString{
+ "embedded_attr": `"abc"`,
+ }),
},
},
{
@@ -422,10 +440,10 @@
other_embedded_prop: "abc",
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`custom(
- name = "ptr_to_embedded_props",
- other_embedded_attr = "abc",
-)`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("custom", "ptr_to_embedded_props", attrNameToString{
+ "other_embedded_attr": `"abc"`,
+ }),
},
},
}
@@ -452,7 +470,7 @@
android.FailIfErrored(t, err)
if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount {
- t.Errorf("Expected %d bazel target, got %d", expectedCount, actualCount)
+ t.Errorf("Expected %d bazel target (%s),\ngot %d (%s)", expectedCount, testCase.expectedBazelTargets, actualCount, bazelTargets)
} else {
for i, expectedBazelTarget := range testCase.expectedBazelTargets {
actualBazelTarget := bazelTargets[i]
@@ -578,6 +596,7 @@
{
bp: `custom {
name: "bar",
+ one_to_many_prop: true,
bazel_module: { bp2build_available: true },
}`,
expectedBazelTarget: `my_library(
@@ -602,7 +621,6 @@
config := android.TestConfig(buildDir, nil, testCase.bp, nil)
ctx := android.NewTestContext(config)
ctx.RegisterModuleType("custom", customModuleFactory)
- ctx.RegisterBp2BuildMutator("custom", customBp2BuildMutatorFromStarlark)
ctx.RegisterForBazelConversion()
_, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
@@ -640,90 +658,81 @@
func TestModuleTypeBp2Build(t *testing.T) {
testCases := []bp2buildTestCase{
{
- description: "filegroup with does not specify srcs",
- moduleTypeUnderTest: "filegroup",
- moduleTypeUnderTestFactory: android.FileGroupFactory,
- moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
+ description: "filegroup with does not specify srcs",
+ moduleTypeUnderTest: "filegroup",
+ moduleTypeUnderTestFactory: android.FileGroupFactory,
blueprint: `filegroup {
name: "fg_foo",
bazel_module: { bp2build_available: true },
}`,
expectedBazelTargets: []string{
- `filegroup(
- name = "fg_foo",
-)`,
+ makeBazelTarget("filegroup", "fg_foo", map[string]string{}),
},
},
{
- description: "filegroup with no srcs",
- moduleTypeUnderTest: "filegroup",
- moduleTypeUnderTestFactory: android.FileGroupFactory,
- moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
+ description: "filegroup with no srcs",
+ moduleTypeUnderTest: "filegroup",
+ moduleTypeUnderTestFactory: android.FileGroupFactory,
blueprint: `filegroup {
name: "fg_foo",
srcs: [],
bazel_module: { bp2build_available: true },
}`,
expectedBazelTargets: []string{
- `filegroup(
- name = "fg_foo",
-)`,
+ makeBazelTarget("filegroup", "fg_foo", map[string]string{}),
},
},
{
- description: "filegroup with srcs",
- moduleTypeUnderTest: "filegroup",
- moduleTypeUnderTestFactory: android.FileGroupFactory,
- moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
+ description: "filegroup with srcs",
+ moduleTypeUnderTest: "filegroup",
+ moduleTypeUnderTestFactory: android.FileGroupFactory,
blueprint: `filegroup {
name: "fg_foo",
srcs: ["a", "b"],
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`filegroup(
- name = "fg_foo",
- srcs = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("filegroup", "fg_foo", map[string]string{
+ "srcs": `[
"a",
"b",
- ],
-)`,
+ ]`,
+ }),
},
},
{
- description: "filegroup with excludes srcs",
- moduleTypeUnderTest: "filegroup",
- moduleTypeUnderTestFactory: android.FileGroupFactory,
- moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
+ description: "filegroup with excludes srcs",
+ moduleTypeUnderTest: "filegroup",
+ moduleTypeUnderTestFactory: android.FileGroupFactory,
blueprint: `filegroup {
name: "fg_foo",
srcs: ["a", "b"],
exclude_srcs: ["a"],
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`filegroup(
- name = "fg_foo",
- srcs = ["b"],
-)`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("filegroup", "fg_foo", map[string]string{
+ "srcs": `["b"]`,
+ }),
},
},
{
- description: "filegroup with glob",
- moduleTypeUnderTest: "filegroup",
- moduleTypeUnderTestFactory: android.FileGroupFactory,
- moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
+ description: "filegroup with glob",
+ moduleTypeUnderTest: "filegroup",
+ moduleTypeUnderTestFactory: android.FileGroupFactory,
blueprint: `filegroup {
- name: "foo",
+ name: "fg_foo",
srcs: ["**/*.txt"],
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`filegroup(
- name = "foo",
- srcs = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("filegroup", "fg_foo", map[string]string{
+ "srcs": `[
"other/a.txt",
"other/b.txt",
"other/subdir/a.txt",
- ],
-)`,
+ ]`,
+ }),
},
filesystem: map[string]string{
"other/a.txt": "",
@@ -733,25 +742,10 @@
},
},
{
- description: "filegroup with glob in subdir",
- moduleTypeUnderTest: "filegroup",
- moduleTypeUnderTestFactory: android.FileGroupFactory,
- moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
- blueprint: `filegroup {
- name: "foo",
- srcs: ["a.txt"],
- bazel_module: { bp2build_available: true },
-}`,
- dir: "other",
- expectedBazelTargets: []string{`filegroup(
- name = "fg_foo",
- srcs = [
- "a.txt",
- "b.txt",
- "subdir/a.txt",
- ],
-)`,
- },
+ description: "filegroup with glob in subdir",
+ moduleTypeUnderTest: "filegroup",
+ moduleTypeUnderTestFactory: android.FileGroupFactory,
+ dir: "other",
filesystem: map[string]string{
"other/Android.bp": `filegroup {
name: "fg_foo",
@@ -763,28 +757,28 @@
"other/subdir/a.txt": "",
"other/file": "",
},
+ expectedBazelTargets: []string{
+ makeBazelTarget("filegroup", "fg_foo", map[string]string{
+ "srcs": `[
+ "a.txt",
+ "b.txt",
+ "subdir/a.txt",
+ ]`,
+ }),
+ },
},
{
- description: "depends_on_other_dir_module",
- moduleTypeUnderTest: "filegroup",
- moduleTypeUnderTestFactory: android.FileGroupFactory,
- moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
+ description: "depends_on_other_dir_module",
+ moduleTypeUnderTest: "filegroup",
+ moduleTypeUnderTestFactory: android.FileGroupFactory,
blueprint: `filegroup {
- name: "foobar",
+ name: "fg_foo",
srcs: [
":foo",
"c",
],
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`filegroup(
- name = "foobar",
- srcs = [
- "//other:foo",
- "c",
- ],
-)`,
- },
filesystem: map[string]string{
"other/Android.bp": `filegroup {
name: "foo",
@@ -792,13 +786,20 @@
bazel_module: { bp2build_available: true },
}`,
},
+ expectedBazelTargets: []string{
+ makeBazelTarget("filegroup", "fg_foo", map[string]string{
+ "srcs": `[
+ "//other:foo",
+ "c",
+ ]`,
+ }),
+ },
},
{
- description: "depends_on_other_unconverted_module_error",
- moduleTypeUnderTest: "filegroup",
- moduleTypeUnderTestFactory: android.FileGroupFactory,
- moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
- unconvertedDepsMode: errorModulesUnconvertedDeps,
+ description: "depends_on_other_unconverted_module_error",
+ moduleTypeUnderTest: "filegroup",
+ moduleTypeUnderTestFactory: android.FileGroupFactory,
+ unconvertedDepsMode: errorModulesUnconvertedDeps,
blueprint: `filegroup {
name: "foobar",
srcs: [
@@ -828,18 +829,16 @@
func TestAllowlistingBp2buildTargetsExplicitly(t *testing.T) {
testCases := []struct {
- moduleTypeUnderTest string
- moduleTypeUnderTestFactory android.ModuleFactory
- moduleTypeUnderTestBp2BuildMutator bp2buildMutator
- bp string
- expectedCount int
- description string
+ moduleTypeUnderTest string
+ moduleTypeUnderTestFactory android.ModuleFactory
+ bp string
+ expectedCount int
+ description string
}{
{
- description: "explicitly unavailable",
- moduleTypeUnderTest: "filegroup",
- moduleTypeUnderTestFactory: android.FileGroupFactory,
- moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
+ description: "explicitly unavailable",
+ moduleTypeUnderTest: "filegroup",
+ moduleTypeUnderTestFactory: android.FileGroupFactory,
bp: `filegroup {
name: "foo",
srcs: ["a", "b"],
@@ -848,10 +847,9 @@
expectedCount: 0,
},
{
- description: "implicitly unavailable",
- moduleTypeUnderTest: "filegroup",
- moduleTypeUnderTestFactory: android.FileGroupFactory,
- moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
+ description: "implicitly unavailable",
+ moduleTypeUnderTest: "filegroup",
+ moduleTypeUnderTestFactory: android.FileGroupFactory,
bp: `filegroup {
name: "foo",
srcs: ["a", "b"],
@@ -859,10 +857,9 @@
expectedCount: 0,
},
{
- description: "explicitly available",
- moduleTypeUnderTest: "filegroup",
- moduleTypeUnderTestFactory: android.FileGroupFactory,
- moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
+ description: "explicitly available",
+ moduleTypeUnderTest: "filegroup",
+ moduleTypeUnderTestFactory: android.FileGroupFactory,
bp: `filegroup {
name: "foo",
srcs: ["a", "b"],
@@ -871,12 +868,12 @@
expectedCount: 1,
},
{
- description: "generates more than 1 target if needed",
- moduleTypeUnderTest: "custom",
- moduleTypeUnderTestFactory: customModuleFactory,
- moduleTypeUnderTestBp2BuildMutator: customBp2BuildMutatorFromStarlark,
+ description: "generates more than 1 target if needed",
+ moduleTypeUnderTest: "custom",
+ moduleTypeUnderTestFactory: customModuleFactory,
bp: `custom {
name: "foo",
+ one_to_many_prop: true,
bazel_module: { bp2build_available: true },
}`,
expectedCount: 3,
@@ -889,7 +886,6 @@
config := android.TestConfig(buildDir, nil, testCase.bp, nil)
ctx := android.NewTestContext(config)
ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
- ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator)
ctx.RegisterForBazelConversion()
_, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
@@ -909,20 +905,18 @@
func TestAllowlistingBp2buildTargetsWithConfig(t *testing.T) {
testCases := []struct {
- moduleTypeUnderTest string
- moduleTypeUnderTestFactory android.ModuleFactory
- moduleTypeUnderTestBp2BuildMutator bp2buildMutator
- expectedCount map[string]int
- description string
- bp2buildConfig android.Bp2BuildConfig
- checkDir string
- fs map[string]string
+ moduleTypeUnderTest string
+ moduleTypeUnderTestFactory android.ModuleFactory
+ expectedCount map[string]int
+ description string
+ bp2buildConfig android.Bp2BuildConfig
+ checkDir string
+ fs map[string]string
}{
{
- description: "test bp2build config package and subpackages config",
- moduleTypeUnderTest: "filegroup",
- moduleTypeUnderTestFactory: android.FileGroupFactory,
- moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
+ description: "test bp2build config package and subpackages config",
+ moduleTypeUnderTest: "filegroup",
+ moduleTypeUnderTestFactory: android.FileGroupFactory,
expectedCount: map[string]int{
"migrated": 1,
"migrated/but_not_really": 0,
@@ -944,10 +938,9 @@
},
},
{
- description: "test bp2build config opt-in and opt-out",
- moduleTypeUnderTest: "filegroup",
- moduleTypeUnderTestFactory: android.FileGroupFactory,
- moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
+ description: "test bp2build config opt-in and opt-out",
+ moduleTypeUnderTest: "filegroup",
+ moduleTypeUnderTestFactory: android.FileGroupFactory,
expectedCount: map[string]int{
"package-opt-in": 2,
"package-opt-in/subpackage": 0,
@@ -998,7 +991,6 @@
config := android.TestConfig(buildDir, nil, "", fs)
ctx := android.NewTestContext(config)
ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
- ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator)
ctx.RegisterBp2BuildConfig(testCase.bp2buildConfig)
ctx.RegisterForBazelConversion()
@@ -1029,10 +1021,9 @@
func TestCombineBuildFilesBp2buildTargets(t *testing.T) {
testCases := []bp2buildTestCase{
{
- description: "filegroup bazel_module.label",
- moduleTypeUnderTest: "filegroup",
- moduleTypeUnderTestFactory: android.FileGroupFactory,
- moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
+ description: "filegroup bazel_module.label",
+ moduleTypeUnderTest: "filegroup",
+ moduleTypeUnderTestFactory: android.FileGroupFactory,
blueprint: `filegroup {
name: "fg_foo",
bazel_module: { label: "//other:fg_foo" },
@@ -1045,19 +1036,18 @@
},
},
{
- description: "multiple bazel_module.label same BUILD",
- moduleTypeUnderTest: "filegroup",
- moduleTypeUnderTestFactory: android.FileGroupFactory,
- moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
+ description: "multiple bazel_module.label same BUILD",
+ moduleTypeUnderTest: "filegroup",
+ moduleTypeUnderTestFactory: android.FileGroupFactory,
blueprint: `filegroup {
- name: "fg_foo",
- bazel_module: { label: "//other:fg_foo" },
- }
+ name: "fg_foo",
+ bazel_module: { label: "//other:fg_foo" },
+ }
- filegroup {
- name: "foo",
- bazel_module: { label: "//other:foo" },
- }`,
+ filegroup {
+ name: "foo",
+ bazel_module: { label: "//other:foo" },
+ }`,
expectedBazelTargets: []string{
`// BUILD file`,
},
@@ -1066,60 +1056,56 @@
},
},
{
- description: "filegroup bazel_module.label and bp2build in subdir",
- moduleTypeUnderTest: "filegroup",
- moduleTypeUnderTestFactory: android.FileGroupFactory,
- moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
- dir: "other",
- blueprint: ``,
+ description: "filegroup bazel_module.label and bp2build in subdir",
+ moduleTypeUnderTest: "filegroup",
+ moduleTypeUnderTestFactory: android.FileGroupFactory,
+ dir: "other",
+ blueprint: ``,
filesystem: map[string]string{
"other/Android.bp": `filegroup {
- name: "fg_foo",
- bazel_module: {
- bp2build_available: true,
- },
- }
- filegroup {
- name: "fg_bar",
- bazel_module: {
- label: "//other:fg_bar"
- },
- }`,
+ name: "fg_foo",
+ bazel_module: {
+ bp2build_available: true,
+ },
+ }
+ filegroup {
+ name: "fg_bar",
+ bazel_module: {
+ label: "//other:fg_bar"
+ },
+ }`,
"other/BUILD.bazel": `// definition for fg_bar`,
},
expectedBazelTargets: []string{
- `filegroup(
- name = "fg_foo",
-)`, `// definition for fg_bar`,
+ makeBazelTarget("filegroup", "fg_foo", map[string]string{}),
+ `// definition for fg_bar`,
},
},
{
- description: "filegroup bazel_module.label and filegroup bp2build",
- moduleTypeUnderTest: "filegroup",
- moduleTypeUnderTestFactory: android.FileGroupFactory,
- moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
- blueprint: `filegroup {
- name: "fg_foo",
- bazel_module: {
- label: "//other:fg_foo",
- },
- }
+ description: "filegroup bazel_module.label and filegroup bp2build",
+ moduleTypeUnderTest: "filegroup",
+ moduleTypeUnderTestFactory: android.FileGroupFactory,
- filegroup {
- name: "fg_bar",
- bazel_module: {
- bp2build_available: true,
- },
- }`,
- expectedBazelTargets: []string{
- `filegroup(
- name = "fg_bar",
-)`,
- `// BUILD file`,
- },
filesystem: map[string]string{
"other/BUILD.bazel": `// BUILD file`,
},
+ blueprint: `filegroup {
+ name: "fg_foo",
+ bazel_module: {
+ label: "//other:fg_foo",
+ },
+ }
+
+ filegroup {
+ name: "fg_bar",
+ bazel_module: {
+ bp2build_available: true,
+ },
+ }`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("filegroup", "fg_bar", map[string]string{}),
+ `// BUILD file`,
+ },
},
}
@@ -1139,7 +1125,6 @@
config := android.TestConfig(buildDir, nil, testCase.blueprint, fs)
ctx := android.NewTestContext(config)
ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
- ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator)
ctx.RegisterForBazelConversion()
_, errs := ctx.ParseFileList(dir, toParse)
@@ -1185,26 +1170,15 @@
func TestGlobExcludeSrcs(t *testing.T) {
testCases := []bp2buildTestCase{
{
- description: "filegroup top level exclude_srcs",
- moduleTypeUnderTest: "filegroup",
- moduleTypeUnderTestFactory: android.FileGroupFactory,
- moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
+ description: "filegroup top level exclude_srcs",
+ moduleTypeUnderTest: "filegroup",
+ moduleTypeUnderTestFactory: android.FileGroupFactory,
blueprint: `filegroup {
name: "fg_foo",
srcs: ["**/*.txt"],
exclude_srcs: ["c.txt"],
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`filegroup(
- name = "fg_foo",
- srcs = [
- "a.txt",
- "b.txt",
- "//dir:e.txt",
- "//dir:f.txt",
- ],
-)`,
- },
filesystem: map[string]string{
"a.txt": "",
"b.txt": "",
@@ -1213,14 +1187,23 @@
"dir/e.txt": "",
"dir/f.txt": "",
},
+ expectedBazelTargets: []string{
+ makeBazelTarget("filegroup", "fg_foo", map[string]string{
+ "srcs": `[
+ "a.txt",
+ "b.txt",
+ "//dir:e.txt",
+ "//dir:f.txt",
+ ]`,
+ }),
+ },
},
{
- description: "filegroup in subdir exclude_srcs",
- moduleTypeUnderTest: "filegroup",
- moduleTypeUnderTestFactory: android.FileGroupFactory,
- moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
- blueprint: "",
- dir: "dir",
+ description: "filegroup in subdir exclude_srcs",
+ moduleTypeUnderTest: "filegroup",
+ moduleTypeUnderTestFactory: android.FileGroupFactory,
+ blueprint: "",
+ dir: "dir",
filesystem: map[string]string{
"dir/Android.bp": `filegroup {
name: "fg_foo",
@@ -1235,142 +1218,81 @@
"dir/subdir/e.txt": "",
"dir/subdir/f.txt": "",
},
- expectedBazelTargets: []string{`filegroup(
- name = "fg_foo",
- srcs = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("filegroup", "fg_foo", map[string]string{
+ "srcs": `[
"a.txt",
"//dir/subdir:e.txt",
"//dir/subdir:f.txt",
- ],
-)`,
+ ]`,
+ }),
},
},
}
- dir := "."
for _, testCase := range testCases {
- fs := make(map[string][]byte)
- toParse := []string{
- "Android.bp",
- }
- for f, content := range testCase.filesystem {
- if strings.HasSuffix(f, "Android.bp") {
- toParse = append(toParse, f)
- }
- fs[f] = []byte(content)
- }
- config := android.TestConfig(buildDir, nil, testCase.blueprint, fs)
- ctx := android.NewTestContext(config)
- ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
- ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator)
- ctx.RegisterForBazelConversion()
-
- _, errs := ctx.ParseFileList(dir, toParse)
- if errored(t, testCase, errs) {
- continue
- }
- _, errs = ctx.ResolveDependencies(config)
- if errored(t, testCase, errs) {
- continue
- }
-
- checkDir := dir
- if testCase.dir != "" {
- checkDir = testCase.dir
- }
- codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
- bazelTargets, err := generateBazelTargetsForDir(codegenCtx, checkDir)
- android.FailIfErrored(t, err)
- if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount {
- t.Errorf("%s: Expected %d bazel target, got %d\n%s", testCase.description, expectedCount, actualCount, bazelTargets)
- } else {
- for i, target := range bazelTargets {
- if w, g := testCase.expectedBazelTargets[i], target.content; w != g {
- t.Errorf(
- "%s: Expected generated Bazel target to be '%s', got '%s'",
- testCase.description,
- w,
- g,
- )
- }
- }
- }
+ t.Run(testCase.description, func(t *testing.T) {
+ runBp2BuildTestCaseSimple(t, testCase)
+ })
}
}
func TestCommonBp2BuildModuleAttrs(t *testing.T) {
testCases := []bp2buildTestCase{
{
- description: "Required into data test",
- moduleTypeUnderTest: "filegroup",
- moduleTypeUnderTestFactory: android.FileGroupFactory,
- moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
- blueprint: `filegroup {
- name: "reqd",
-}
-
+ description: "Required into data test",
+ moduleTypeUnderTest: "filegroup",
+ moduleTypeUnderTestFactory: android.FileGroupFactory,
+ blueprint: simpleModuleDoNotConvertBp2build("filegroup", "reqd") + `
filegroup {
name: "fg_foo",
required: ["reqd"],
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`filegroup(
- name = "fg_foo",
- data = [":reqd"],
-)`,
- `filegroup(
- name = "reqd",
-)`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("filegroup", "fg_foo", map[string]string{
+ "data": `[":reqd"]`,
+ }),
},
},
{
- description: "Required via arch into data test",
- moduleTypeUnderTest: "python_library",
- moduleTypeUnderTestFactory: python.PythonLibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: python.PythonLibraryBp2Build,
- blueprint: `python_library {
- name: "reqdx86",
- bazel_module: { bp2build_available: false, },
-}
-
-python_library {
- name: "reqdarm",
- bazel_module: { bp2build_available: false, },
-}
-
+ description: "Required via arch into data test",
+ moduleTypeUnderTest: "python_library",
+ moduleTypeUnderTestFactory: python.PythonLibraryFactory,
+ blueprint: simpleModuleDoNotConvertBp2build("python_library", "reqdx86") +
+ simpleModuleDoNotConvertBp2build("python_library", "reqdarm") + `
python_library {
name: "fg_foo",
arch: {
- arm: {
- required: ["reqdarm"],
- },
- x86: {
- required: ["reqdx86"],
- },
+ arm: {
+ required: ["reqdarm"],
+ },
+ x86: {
+ required: ["reqdx86"],
+ },
},
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`py_library(
- name = "fg_foo",
- data = select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("py_library", "fg_foo", map[string]string{
+ "data": `select({
"//build/bazel/platforms/arch:arm": [":reqdarm"],
"//build/bazel/platforms/arch:x86": [":reqdx86"],
"//conditions:default": [],
- }),
- srcs_version = "PY3",
-)`,
+ })`,
+ "srcs_version": `"PY3"`,
+ }),
},
},
{
- description: "Required appended to data test",
- moduleTypeUnderTest: "python_library",
- moduleTypeUnderTestFactory: python.PythonLibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: python.PythonLibraryBp2Build,
- blueprint: `python_library {
- name: "reqd",
- srcs: ["src.py"],
-}
-
+ description: "Required appended to data test",
+ moduleTypeUnderTest: "python_library",
+ moduleTypeUnderTestFactory: python.PythonLibraryFactory,
+ filesystem: map[string]string{
+ "data.bin": "",
+ "src.py": "",
+ },
+ blueprint: simpleModuleDoNotConvertBp2build("python_library", "reqd") + `
python_library {
name: "fg_foo",
data: ["data.bin"],
@@ -1378,52 +1300,36 @@
bazel_module: { bp2build_available: true },
}`,
expectedBazelTargets: []string{
- `py_library(
- name = "fg_foo",
- data = [
+ makeBazelTarget("py_library", "fg_foo", map[string]string{
+ "data": `[
"data.bin",
":reqd",
- ],
- srcs_version = "PY3",
-)`,
- `py_library(
- name = "reqd",
- srcs = ["src.py"],
- srcs_version = "PY3",
-)`,
- },
- filesystem: map[string]string{
- "data.bin": "",
- "src.py": "",
+ ]`,
+ "srcs_version": `"PY3"`,
+ }),
},
},
{
- description: "All props-to-attrs at once together test",
- moduleTypeUnderTest: "filegroup",
- moduleTypeUnderTestFactory: android.FileGroupFactory,
- moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
- blueprint: `filegroup {
- name: "reqd"
-}
+ description: "All props-to-attrs at once together test",
+ moduleTypeUnderTest: "filegroup",
+ moduleTypeUnderTestFactory: android.FileGroupFactory,
+ blueprint: simpleModuleDoNotConvertBp2build("filegroup", "reqd") + `
filegroup {
name: "fg_foo",
required: ["reqd"],
bazel_module: { bp2build_available: true },
}`,
expectedBazelTargets: []string{
- `filegroup(
- name = "fg_foo",
- data = [":reqd"],
-)`,
- `filegroup(
- name = "reqd",
-)`,
+ makeBazelTarget("filegroup", "fg_foo", map[string]string{
+ "data": `[":reqd"]`,
+ }),
},
- filesystem: map[string]string{},
},
}
- for _, test := range testCases {
- runBp2BuildTestCaseSimple(t, test)
+ for _, tc := range testCases {
+ t.Run(tc.description, func(t *testing.T) {
+ runBp2BuildTestCaseSimple(t, tc)
+ })
}
}
diff --git a/bp2build/bzl_conversion_test.go b/bp2build/bzl_conversion_test.go
index 1e78c0e..f3345a6 100644
--- a/bp2build/bzl_conversion_test.go
+++ b/bp2build/bzl_conversion_test.go
@@ -100,6 +100,7 @@
# nested_props_ptr start
# "nested_prop": attr.string(),
# nested_props_ptr end
+ "one_to_many_prop": attr.bool(),
"other_embedded_prop": attr.string(),
"string_list_prop": attr.string_list(),
"string_prop": attr.string(),
@@ -128,6 +129,7 @@
# nested_props_ptr start
# "nested_prop": attr.string(),
# nested_props_ptr end
+ "one_to_many_prop": attr.bool(),
"other_embedded_prop": attr.string(),
"string_list_prop": attr.string_list(),
"string_prop": attr.string(),
@@ -156,6 +158,7 @@
# nested_props_ptr start
# "nested_prop": attr.string(),
# nested_props_ptr end
+ "one_to_many_prop": attr.bool(),
"other_embedded_prop": attr.string(),
"string_list_prop": attr.string_list(),
"string_prop": attr.string(),
diff --git a/bp2build/cc_binary_conversion_test.go b/bp2build/cc_binary_conversion_test.go
index 0b71d89..a156480 100644
--- a/bp2build/cc_binary_conversion_test.go
+++ b/bp2build/cc_binary_conversion_test.go
@@ -24,10 +24,29 @@
)
const (
- ccBinaryTypePlaceHolder = "{rule_name}"
- compatibleWithPlaceHolder = "{target_compatible_with}"
+ ccBinaryTypePlaceHolder = "{rule_name}"
)
+type testBazelTarget struct {
+ typ string
+ name string
+ attrs attrNameToString
+}
+
+func generateBazelTargetsForTest(targets []testBazelTarget) []string {
+ ret := make([]string, 0, len(targets))
+ for _, t := range targets {
+ ret = append(ret, makeBazelTarget(t.typ, t.name, t.attrs))
+ }
+ return ret
+}
+
+type ccBinaryBp2buildTestCase struct {
+ description string
+ blueprint string
+ targets []testBazelTarget
+}
+
func registerCcBinaryModuleTypes(ctx android.RegistrationContext) {
cc.RegisterCCBuildComponents(ctx)
ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
@@ -36,55 +55,58 @@
ctx.RegisterModuleType("genrule", genrule.GenRuleFactory)
}
-var binaryReplacer = strings.NewReplacer(ccBinaryTypePlaceHolder, "cc_binary", compatibleWithPlaceHolder, "")
-var hostBinaryReplacer = strings.NewReplacer(ccBinaryTypePlaceHolder, "cc_binary_host", compatibleWithPlaceHolder, `
- target_compatible_with = select({
- "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
- "//conditions:default": [],
- }),`)
+var binaryReplacer = strings.NewReplacer(ccBinaryTypePlaceHolder, "cc_binary")
+var hostBinaryReplacer = strings.NewReplacer(ccBinaryTypePlaceHolder, "cc_binary_host")
-func runCcBinaryTests(t *testing.T, tc bp2buildTestCase) {
+func runCcBinaryTests(t *testing.T, tc ccBinaryBp2buildTestCase) {
t.Helper()
runCcBinaryTestCase(t, tc)
runCcHostBinaryTestCase(t, tc)
}
-func runCcBinaryTestCase(t *testing.T, tc bp2buildTestCase) {
+func runCcBinaryTestCase(t *testing.T, tc ccBinaryBp2buildTestCase) {
t.Helper()
- testCase := tc
- testCase.expectedBazelTargets = append([]string{}, tc.expectedBazelTargets...)
- testCase.moduleTypeUnderTest = "cc_binary"
- testCase.moduleTypeUnderTestFactory = cc.BinaryFactory
- testCase.moduleTypeUnderTestBp2BuildMutator = cc.BinaryBp2build
- testCase.description = fmt.Sprintf("%s %s", testCase.moduleTypeUnderTest, testCase.description)
- testCase.blueprint = binaryReplacer.Replace(testCase.blueprint)
- for i, et := range testCase.expectedBazelTargets {
- testCase.expectedBazelTargets[i] = binaryReplacer.Replace(et)
+ moduleTypeUnderTest := "cc_binary"
+ testCase := bp2buildTestCase{
+ expectedBazelTargets: generateBazelTargetsForTest(tc.targets),
+ moduleTypeUnderTest: moduleTypeUnderTest,
+ moduleTypeUnderTestFactory: cc.BinaryFactory,
+ description: fmt.Sprintf("%s %s", moduleTypeUnderTest, tc.description),
+ blueprint: binaryReplacer.Replace(tc.blueprint),
}
t.Run(testCase.description, func(t *testing.T) {
+ t.Helper()
runBp2BuildTestCase(t, registerCcBinaryModuleTypes, testCase)
})
}
-func runCcHostBinaryTestCase(t *testing.T, tc bp2buildTestCase) {
+func runCcHostBinaryTestCase(t *testing.T, tc ccBinaryBp2buildTestCase) {
t.Helper()
testCase := tc
- testCase.expectedBazelTargets = append([]string{}, tc.expectedBazelTargets...)
- testCase.moduleTypeUnderTest = "cc_binary_host"
- testCase.moduleTypeUnderTestFactory = cc.BinaryHostFactory
- testCase.moduleTypeUnderTestBp2BuildMutator = cc.BinaryHostBp2build
- testCase.description = fmt.Sprintf("%s %s", testCase.moduleTypeUnderTest, testCase.description)
- testCase.blueprint = hostBinaryReplacer.Replace(testCase.blueprint)
- for i, et := range testCase.expectedBazelTargets {
- testCase.expectedBazelTargets[i] = hostBinaryReplacer.Replace(et)
+ for i, tar := range testCase.targets {
+ if tar.typ != "cc_binary" {
+ continue
+ }
+ tar.attrs["target_compatible_with"] = `select({
+ "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+ "//conditions:default": [],
+ })`
+ testCase.targets[i] = tar
}
+ moduleTypeUnderTest := "cc_binary_host"
t.Run(testCase.description, func(t *testing.T) {
- runBp2BuildTestCase(t, registerCcBinaryModuleTypes, testCase)
+ runBp2BuildTestCase(t, registerCcBinaryModuleTypes, bp2buildTestCase{
+ expectedBazelTargets: generateBazelTargetsForTest(testCase.targets),
+ moduleTypeUnderTest: moduleTypeUnderTest,
+ moduleTypeUnderTestFactory: cc.BinaryHostFactory,
+ description: fmt.Sprintf("%s %s", moduleTypeUnderTest, tc.description),
+ blueprint: hostBinaryReplacer.Replace(testCase.blueprint),
+ })
})
}
func TestBasicCcBinary(t *testing.T) {
- runCcBinaryTests(t, bp2buildTestCase{
+ runCcBinaryTests(t, ccBinaryBp2buildTestCase{
description: "basic -- properties -> attrs with little/no transformation",
blueprint: `
{rule_name} {
@@ -107,33 +129,35 @@
},
}
`,
- expectedBazelTargets: []string{`cc_binary(
- name = "foo",
- absolute_includes = ["absolute_dir"],
- asflags = ["-Dasflag"],
- conlyflags = ["-Dconlyflag"],
- copts = ["-Dcopt"],
- cppflags = ["-Dcppflag"],
- linkopts = ["ld-flag"],
- local_includes = [
+ targets: []testBazelTarget{
+ {"cc_binary", "foo", attrNameToString{
+ "absolute_includes": `["absolute_dir"]`,
+ "asflags": `["-Dasflag"]`,
+ "conlyflags": `["-Dconlyflag"]`,
+ "copts": `["-Dcopt"]`,
+ "cppflags": `["-Dcppflag"]`,
+ "linkopts": `["ld-flag"]`,
+ "local_includes": `[
"dir",
".",
- ],
- rtti = True,
- srcs = ["a.cc"],
- strip = {
+ ]`,
+ "rtti": `True`,
+ "srcs": `["a.cc"]`,
+ "strip": `{
"all": True,
"keep_symbols": True,
"keep_symbols_and_debug_frame": True,
"keep_symbols_list": ["symbol"],
"none": True,
- },{target_compatible_with}
-)`},
+ }`,
+ },
+ },
+ },
})
}
func TestCcBinaryWithSharedLdflagDisableFeature(t *testing.T) {
- runCcBinaryTests(t, bp2buildTestCase{
+ runCcBinaryTests(t, ccBinaryBp2buildTestCase{
description: `ldflag "-shared" disables static_flag feature`,
blueprint: `
{rule_name} {
@@ -142,16 +166,18 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_binary(
- name = "foo",
- features = ["-static_flag"],
- linkopts = ["-shared"],{target_compatible_with}
-)`},
+ targets: []testBazelTarget{
+ {"cc_binary", "foo", attrNameToString{
+ "features": `["-static_flag"]`,
+ "linkopts": `["-shared"]`,
+ },
+ },
+ },
})
}
func TestCcBinaryWithLinkStatic(t *testing.T) {
- runCcBinaryTests(t, bp2buildTestCase{
+ runCcBinaryTests(t, ccBinaryBp2buildTestCase{
description: "link static",
blueprint: `
{rule_name} {
@@ -160,15 +186,17 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_binary(
- name = "foo",
- linkshared = False,{target_compatible_with}
-)`},
+ targets: []testBazelTarget{
+ {"cc_binary", "foo", attrNameToString{
+ "linkshared": `False`,
+ },
+ },
+ },
})
}
func TestCcBinaryVersionScript(t *testing.T) {
- runCcBinaryTests(t, bp2buildTestCase{
+ runCcBinaryTests(t, ccBinaryBp2buildTestCase{
description: `version script`,
blueprint: `
{rule_name} {
@@ -177,16 +205,18 @@
version_script: "vs",
}
`,
- expectedBazelTargets: []string{`cc_binary(
- name = "foo",
- additional_linker_inputs = ["vs"],
- linkopts = ["-Wl,--version-script,$(location vs)"],{target_compatible_with}
-)`},
+ targets: []testBazelTarget{
+ {"cc_binary", "foo", attrNameToString{
+ "additional_linker_inputs": `["vs"]`,
+ "linkopts": `["-Wl,--version-script,$(location vs)"]`,
+ },
+ },
+ },
})
}
func TestCcBinarySplitSrcsByLang(t *testing.T) {
- runCcHostBinaryTestCase(t, bp2buildTestCase{
+ runCcHostBinaryTestCase(t, ccBinaryBp2buildTestCase{
description: "split srcs by lang",
blueprint: `
{rule_name} {
@@ -200,36 +230,40 @@
include_build_directory: false,
}
` + simpleModuleDoNotConvertBp2build("filegroup", "fg_foo"),
- expectedBazelTargets: []string{`cc_binary(
- name = "foo",
- srcs = [
+ targets: []testBazelTarget{
+ {"cc_binary", "foo", attrNameToString{
+ "srcs": `[
"cpponly.cpp",
":fg_foo_cpp_srcs",
- ],
- srcs_as = [
+ ]`,
+ "srcs_as": `[
"asonly.S",
":fg_foo_as_srcs",
- ],
- srcs_c = [
+ ]`,
+ "srcs_c": `[
"conly.c",
":fg_foo_c_srcs",
- ],{target_compatible_with}
-)`},
+ ]`,
+ },
+ },
+ },
})
}
func TestCcBinaryDoNotDistinguishBetweenDepsAndImplementationDeps(t *testing.T) {
- runCcBinaryTestCase(t, bp2buildTestCase{
+ runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
description: "no implementation deps",
blueprint: `
genrule {
name: "generated_hdr",
cmd: "nothing to see here",
+ bazel_module: { bp2build_available: false },
}
genrule {
name: "export_generated_hdr",
cmd: "nothing to see here",
+ bazel_module: { bp2build_available: false },
}
{rule_name} {
@@ -251,26 +285,29 @@
simpleModuleDoNotConvertBp2build("cc_library_static", "not_explicitly_exported_whole_static_dep") +
simpleModuleDoNotConvertBp2build("cc_library", "shared_dep") +
simpleModuleDoNotConvertBp2build("cc_library", "implementation_shared_dep"),
- expectedBazelTargets: []string{`cc_binary(
- name = "foo",
- deps = [
+ targets: []testBazelTarget{
+ {"cc_binary", "foo", attrNameToString{
+ "deps": `[
":implementation_static_dep",
":static_dep",
- ],
- dynamic_deps = [
+ ]`,
+ "dynamic_deps": `[
":implementation_shared_dep",
":shared_dep",
- ],
- srcs = [
+ ]`,
+ "srcs": `[
"foo.cpp",
":generated_hdr",
":export_generated_hdr",
- ],{target_compatible_with}
- whole_archive_deps = [
+ ]`,
+ "whole_archive_deps": `[
":not_explicitly_exported_whole_static_dep",
":whole_static_dep",
- ],
-)`},
+ ]`,
+ "local_includes": `["."]`,
+ },
+ },
+ },
})
}
@@ -278,19 +315,21 @@
baseTestCases := []struct {
description string
soongProperty string
- bazelAttr string
+ bazelAttr attrNameToString
}{
{
description: "nocrt: true",
soongProperty: `nocrt: true,`,
- bazelAttr: ` link_crt = False,`,
+ bazelAttr: attrNameToString{"link_crt": `False`},
},
{
description: "nocrt: false",
soongProperty: `nocrt: false,`,
+ bazelAttr: attrNameToString{},
},
{
description: "nocrt: not set",
+ bazelAttr: attrNameToString{},
},
}
@@ -300,24 +339,16 @@
}
`
- baseBazelTarget := `cc_binary(
- name = "foo",%s{target_compatible_with}
-)`
-
for _, btc := range baseTestCases {
prop := btc.soongProperty
if len(prop) > 0 {
prop = "\n" + prop
}
- attr := btc.bazelAttr
- if len(attr) > 0 {
- attr = "\n" + attr
- }
- runCcBinaryTests(t, bp2buildTestCase{
+ runCcBinaryTests(t, ccBinaryBp2buildTestCase{
description: btc.description,
blueprint: fmt.Sprintf(baseBlueprint, prop),
- expectedBazelTargets: []string{
- fmt.Sprintf(baseBazelTarget, attr),
+ targets: []testBazelTarget{
+ {"cc_binary", "foo", btc.bazelAttr},
},
})
}
@@ -327,20 +358,21 @@
baseTestCases := []struct {
description string
soongProperty string
- bazelAttr string
+ bazelAttr attrNameToString
}{
{
description: "no_libcrt: true",
soongProperty: `no_libcrt: true,`,
- bazelAttr: ` use_libcrt = False,`,
+ bazelAttr: attrNameToString{"use_libcrt": `False`},
},
{
description: "no_libcrt: false",
soongProperty: `no_libcrt: false,`,
- bazelAttr: ` use_libcrt = True,`,
+ bazelAttr: attrNameToString{"use_libcrt": `True`},
},
{
description: "no_libcrt: not set",
+ bazelAttr: attrNameToString{},
},
}
@@ -350,24 +382,16 @@
}
`
- baseBazelTarget := `cc_binary(
- name = "foo",{target_compatible_with}%s
-)`
-
for _, btc := range baseTestCases {
prop := btc.soongProperty
if len(prop) > 0 {
prop = "\n" + prop
}
- attr := btc.bazelAttr
- if len(attr) > 0 {
- attr = "\n" + attr
- }
- runCcBinaryTests(t, bp2buildTestCase{
+ runCcBinaryTests(t, ccBinaryBp2buildTestCase{
description: btc.description,
blueprint: fmt.Sprintf(baseBlueprint, prop),
- expectedBazelTargets: []string{
- fmt.Sprintf(baseBazelTarget, attr),
+ targets: []testBazelTarget{
+ {"cc_binary", "foo", btc.bazelAttr},
},
})
}
@@ -377,31 +401,35 @@
baseTestCases := []struct {
description string
soongProperty string
- bazelAttr string
+ bazelAttr attrNameToString
}{
{
description: "pack_relocation: true",
soongProperty: `pack_relocations: true,`,
+ bazelAttr: attrNameToString{},
},
{
description: "pack_relocations: false",
soongProperty: `pack_relocations: false,`,
- bazelAttr: ` features = ["disable_pack_relocations"],`,
+ bazelAttr: attrNameToString{"features": `["disable_pack_relocations"]`},
},
{
description: "pack_relocations: not set",
+ bazelAttr: attrNameToString{},
},
{
description: "pack_relocation: true",
soongProperty: `allow_undefined_symbols: true,`,
- bazelAttr: ` features = ["-no_undefined_symbols"],`,
+ bazelAttr: attrNameToString{"features": `["-no_undefined_symbols"]`},
},
{
description: "allow_undefined_symbols: false",
soongProperty: `allow_undefined_symbols: false,`,
+ bazelAttr: attrNameToString{},
},
{
description: "allow_undefined_symbols: not set",
+ bazelAttr: attrNameToString{},
},
}
@@ -410,26 +438,65 @@
include_build_directory: false,
}
`
-
- baseBazelTarget := `cc_binary(
- name = "foo",%s{target_compatible_with}
-)`
-
for _, btc := range baseTestCases {
prop := btc.soongProperty
if len(prop) > 0 {
prop = "\n" + prop
}
- attr := btc.bazelAttr
- if len(attr) > 0 {
- attr = "\n" + attr
- }
- runCcBinaryTests(t, bp2buildTestCase{
+ runCcBinaryTests(t, ccBinaryBp2buildTestCase{
description: btc.description,
blueprint: fmt.Sprintf(baseBlueprint, prop),
- expectedBazelTargets: []string{
- fmt.Sprintf(baseBazelTarget, attr),
+ targets: []testBazelTarget{
+ {"cc_binary", "foo", btc.bazelAttr},
},
})
}
}
+
+func TestCcBinarySharedProto(t *testing.T) {
+ runCcBinaryTests(t, ccBinaryBp2buildTestCase{
+ blueprint: soongCcProtoLibraries + `{rule_name} {
+ name: "foo",
+ srcs: ["foo.proto"],
+ proto: {
+ canonical_path_from_root: false,
+ },
+ include_build_directory: false,
+}`,
+ targets: []testBazelTarget{
+ {"proto_library", "foo_proto", attrNameToString{
+ "srcs": `["foo.proto"]`,
+ }}, {"cc_lite_proto_library", "foo_cc_proto_lite", attrNameToString{
+ "deps": `[":foo_proto"]`,
+ }}, {"cc_binary", "foo", attrNameToString{
+ "dynamic_deps": `[":libprotobuf-cpp-lite"]`,
+ "whole_archive_deps": `[":foo_cc_proto_lite"]`,
+ }},
+ },
+ })
+}
+
+func TestCcBinaryStaticProto(t *testing.T) {
+ runCcBinaryTests(t, ccBinaryBp2buildTestCase{
+ blueprint: soongCcProtoLibraries + `{rule_name} {
+ name: "foo",
+ srcs: ["foo.proto"],
+ static_executable: true,
+ proto: {
+ canonical_path_from_root: false,
+ },
+ include_build_directory: false,
+}`,
+ targets: []testBazelTarget{
+ {"proto_library", "foo_proto", attrNameToString{
+ "srcs": `["foo.proto"]`,
+ }}, {"cc_lite_proto_library", "foo_cc_proto_lite", attrNameToString{
+ "deps": `[":foo_proto"]`,
+ }}, {"cc_binary", "foo", attrNameToString{
+ "deps": `[":libprotobuf-cpp-lite"]`,
+ "whole_archive_deps": `[":foo_cc_proto_lite"]`,
+ "linkshared": `False`,
+ }},
+ },
+ })
+}
diff --git a/bp2build/cc_genrule_conversion_test.go b/bp2build/cc_genrule_conversion_test.go
index a7e9cb2..440b462 100644
--- a/bp2build/cc_genrule_conversion_test.go
+++ b/bp2build/cc_genrule_conversion_test.go
@@ -19,7 +19,6 @@
"android/soong/android"
"android/soong/cc"
- "android/soong/genrule"
)
var otherCcGenruleBp = map[string]string{
@@ -39,15 +38,14 @@
func runCcGenruleTestCase(t *testing.T, tc bp2buildTestCase) {
t.Helper()
+ (&tc).moduleTypeUnderTest = "cc_genrule"
+ (&tc).moduleTypeUnderTestFactory = cc.GenRuleFactory
runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc)
}
func TestCliVariableReplacement(t *testing.T) {
runCcGenruleTestCase(t, bp2buildTestCase{
- description: "cc_genrule with command line variable replacements",
- moduleTypeUnderTest: "cc_genrule",
- moduleTypeUnderTestFactory: cc.GenRuleFactory,
- moduleTypeUnderTestBp2BuildMutator: genrule.CcGenruleBp2Build,
+ description: "cc_genrule with command line variable replacements",
blueprint: `cc_genrule {
name: "foo.tool",
out: ["foo_tool.out"],
@@ -65,29 +63,24 @@
bazel_module: { bp2build_available: true },
}`,
expectedBazelTargets: []string{
- `genrule(
- name = "foo",
- cmd = "$(location :foo.tool) --genDir=$(RULEDIR) arg $(SRCS) $(OUTS)",
- outs = ["foo.out"],
- srcs = ["foo.in"],
- tools = [":foo.tool"],
-)`,
- `genrule(
- name = "foo.tool",
- cmd = "cp $(SRCS) $(OUTS)",
- outs = ["foo_tool.out"],
- srcs = ["foo_tool.in"],
-)`,
+ makeBazelTarget("genrule", "foo", attrNameToString{
+ "cmd": `"$(location :foo.tool) --genDir=$(RULEDIR) arg $(SRCS) $(OUTS)"`,
+ "outs": `["foo.out"]`,
+ "srcs": `["foo.in"]`,
+ "tools": `[":foo.tool"]`,
+ }),
+ makeBazelTarget("genrule", "foo.tool", attrNameToString{
+ "cmd": `"cp $(SRCS) $(OUTS)"`,
+ "outs": `["foo_tool.out"]`,
+ "srcs": `["foo_tool.in"]`,
+ }),
},
})
}
func TestUsingLocationsLabel(t *testing.T) {
runCcGenruleTestCase(t, bp2buildTestCase{
- description: "cc_genrule using $(locations :label)",
- moduleTypeUnderTest: "cc_genrule",
- moduleTypeUnderTestFactory: cc.GenRuleFactory,
- moduleTypeUnderTestBp2BuildMutator: genrule.CcGenruleBp2Build,
+ description: "cc_genrule using $(locations :label)",
blueprint: `cc_genrule {
name: "foo.tools",
out: ["foo_tool.out", "foo_tool2.out"],
@@ -104,32 +97,28 @@
cmd: "$(locations :foo.tools) -s $(out) $(in)",
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`genrule(
- name = "foo",
- cmd = "$(locations :foo.tools) -s $(OUTS) $(SRCS)",
- outs = ["foo.out"],
- srcs = ["foo.in"],
- tools = [":foo.tools"],
-)`,
- `genrule(
- name = "foo.tools",
- cmd = "cp $(SRCS) $(OUTS)",
- outs = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("genrule", "foo", attrNameToString{
+ "cmd": `"$(locations :foo.tools) -s $(OUTS) $(SRCS)"`,
+ "outs": `["foo.out"]`,
+ "srcs": `["foo.in"]`,
+ "tools": `[":foo.tools"]`,
+ }),
+ makeBazelTarget("genrule", "foo.tools", attrNameToString{
+ "cmd": `"cp $(SRCS) $(OUTS)"`,
+ "outs": `[
"foo_tool.out",
"foo_tool2.out",
- ],
- srcs = ["foo_tool.in"],
-)`,
+ ]`,
+ "srcs": `["foo_tool.in"]`,
+ }),
},
})
}
func TestUsingLocationsAbsoluteLabel(t *testing.T) {
runCcGenruleTestCase(t, bp2buildTestCase{
- description: "cc_genrule using $(locations //absolute:label)",
- moduleTypeUnderTest: "cc_genrule",
- moduleTypeUnderTestFactory: cc.GenRuleFactory,
- moduleTypeUnderTestBp2BuildMutator: genrule.CcGenruleBp2Build,
+ description: "cc_genrule using $(locations //absolute:label)",
blueprint: `cc_genrule {
name: "foo",
out: ["foo.out"],
@@ -138,24 +127,21 @@
cmd: "$(locations :foo.tool) -s $(out) $(in)",
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`genrule(
- name = "foo",
- cmd = "$(locations //other:foo.tool) -s $(OUTS) $(SRCS)",
- outs = ["foo.out"],
- srcs = ["foo.in"],
- tools = ["//other:foo.tool"],
-)`,
- },
filesystem: otherCcGenruleBp,
+ expectedBazelTargets: []string{
+ makeBazelTarget("genrule", "foo", attrNameToString{
+ "cmd": `"$(locations //other:foo.tool) -s $(OUTS) $(SRCS)"`,
+ "outs": `["foo.out"]`,
+ "srcs": `["foo.in"]`,
+ "tools": `["//other:foo.tool"]`,
+ }),
+ },
})
}
func TestSrcsUsingAbsoluteLabel(t *testing.T) {
runCcGenruleTestCase(t, bp2buildTestCase{
- description: "cc_genrule srcs using $(locations //absolute:label)",
- moduleTypeUnderTest: "cc_genrule",
- moduleTypeUnderTestFactory: cc.GenRuleFactory,
- moduleTypeUnderTestBp2BuildMutator: genrule.CcGenruleBp2Build,
+ description: "cc_genrule srcs using $(locations //absolute:label)",
blueprint: `cc_genrule {
name: "foo",
out: ["foo.out"],
@@ -164,24 +150,21 @@
cmd: "$(locations :foo.tool) -s $(out) $(location :other.tool)",
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`genrule(
- name = "foo",
- cmd = "$(locations //other:foo.tool) -s $(OUTS) $(location //other:other.tool)",
- outs = ["foo.out"],
- srcs = ["//other:other.tool"],
- tools = ["//other:foo.tool"],
-)`,
- },
filesystem: otherCcGenruleBp,
+ expectedBazelTargets: []string{
+ makeBazelTarget("genrule", "foo", attrNameToString{
+ "cmd": `"$(locations //other:foo.tool) -s $(OUTS) $(location //other:other.tool)"`,
+ "outs": `["foo.out"]`,
+ "srcs": `["//other:other.tool"]`,
+ "tools": `["//other:foo.tool"]`,
+ }),
+ },
})
}
func TestLocationsLabelUsesFirstToolFile(t *testing.T) {
runCcGenruleTestCase(t, bp2buildTestCase{
- description: "cc_genrule using $(location) label should substitute first tool label automatically",
- moduleTypeUnderTest: "cc_genrule",
- moduleTypeUnderTestFactory: cc.GenRuleFactory,
- moduleTypeUnderTestBp2BuildMutator: genrule.CcGenruleBp2Build,
+ description: "cc_genrule using $(location) label should substitute first tool label automatically",
blueprint: `cc_genrule {
name: "foo",
out: ["foo.out"],
@@ -190,27 +173,24 @@
cmd: "$(location) -s $(out) $(in)",
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`genrule(
- name = "foo",
- cmd = "$(location //other:foo.tool) -s $(OUTS) $(SRCS)",
- outs = ["foo.out"],
- srcs = ["foo.in"],
- tools = [
+ filesystem: otherCcGenruleBp,
+ expectedBazelTargets: []string{
+ makeBazelTarget("genrule", "foo", attrNameToString{
+ "cmd": `"$(location //other:foo.tool) -s $(OUTS) $(SRCS)"`,
+ "outs": `["foo.out"]`,
+ "srcs": `["foo.in"]`,
+ "tools": `[
"//other:foo.tool",
"//other:other.tool",
- ],
-)`,
+ ]`,
+ }),
},
- filesystem: otherCcGenruleBp,
})
}
func TestLocationsLabelUsesFirstTool(t *testing.T) {
runCcGenruleTestCase(t, bp2buildTestCase{
- description: "cc_genrule using $(locations) label should substitute first tool label automatically",
- moduleTypeUnderTest: "cc_genrule",
- moduleTypeUnderTestFactory: cc.GenRuleFactory,
- moduleTypeUnderTestBp2BuildMutator: genrule.CcGenruleBp2Build,
+ description: "cc_genrule using $(locations) label should substitute first tool label automatically",
blueprint: `cc_genrule {
name: "foo",
out: ["foo.out"],
@@ -219,27 +199,24 @@
cmd: "$(locations) -s $(out) $(in)",
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`genrule(
- name = "foo",
- cmd = "$(locations //other:foo.tool) -s $(OUTS) $(SRCS)",
- outs = ["foo.out"],
- srcs = ["foo.in"],
- tools = [
+ filesystem: otherCcGenruleBp,
+ expectedBazelTargets: []string{
+ makeBazelTarget("genrule", "foo", attrNameToString{
+ "cmd": `"$(locations //other:foo.tool) -s $(OUTS) $(SRCS)"`,
+ "outs": `["foo.out"]`,
+ "srcs": `["foo.in"]`,
+ "tools": `[
"//other:foo.tool",
"//other:other.tool",
- ],
-)`,
+ ]`,
+ }),
},
- filesystem: otherCcGenruleBp,
})
}
func TestWithoutToolsOrToolFiles(t *testing.T) {
runCcGenruleTestCase(t, bp2buildTestCase{
- description: "cc_genrule without tools or tool_files can convert successfully",
- moduleTypeUnderTest: "cc_genrule",
- moduleTypeUnderTestFactory: cc.GenRuleFactory,
- moduleTypeUnderTestBp2BuildMutator: genrule.CcGenruleBp2Build,
+ description: "cc_genrule without tools or tool_files can convert successfully",
blueprint: `cc_genrule {
name: "foo",
out: ["foo.out"],
@@ -247,12 +224,12 @@
cmd: "cp $(in) $(out)",
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`genrule(
- name = "foo",
- cmd = "cp $(SRCS) $(OUTS)",
- outs = ["foo.out"],
- srcs = ["foo.in"],
-)`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("genrule", "foo", attrNameToString{
+ "cmd": `"cp $(SRCS) $(OUTS)"`,
+ "outs": `["foo.out"]`,
+ "srcs": `["foo.in"]`,
+ }),
},
})
}
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index cbdc167..59a2389 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -39,6 +39,19 @@
native_bridge_supported: true,
src: "",
}`
+
+ soongCcProtoLibraries = `
+cc_library {
+ name: "libprotobuf-cpp-lite",
+ bazel_module: { bp2build_available: false },
+}
+
+cc_library {
+ name: "libprotobuf-cpp-full",
+ bazel_module: { bp2build_available: false },
+}`
+
+ soongCcProtoPreamble = soongCcLibraryPreamble + soongCcProtoLibraries
)
func runCcLibraryTestCase(t *testing.T, tc bp2buildTestCase) {
@@ -57,10 +70,9 @@
func TestCcLibrarySimple(t *testing.T) {
runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library - simple example",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ description: "cc_library - simple example",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
filesystem: map[string]string{
"android.cpp": "",
"bionic.cpp": "",
@@ -81,8 +93,8 @@
"x86_64.cpp": "",
"foo-dir/a.h": "",
},
- blueprint: soongCcLibraryPreamble + `
-cc_library_headers { name: "some-headers" }
+ blueprint: soongCcLibraryPreamble +
+ simpleModuleDoNotConvertBp2build("cc_library_headers", "some-headers") + `
cc_library {
name: "foo-lib",
srcs: ["impl.cpp"],
@@ -117,17 +129,16 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library(
- name = "foo-lib",
- copts = ["-Wall"],
- export_includes = ["foo-dir"],
- implementation_deps = [":some-headers"],
- linkopts = ["-Wl,--exclude-libs=bar.a"] + select({
+ expectedBazelTargets: makeCcLibraryTargets("foo-lib", attrNameToString{
+ "copts": `["-Wall"]`,
+ "export_includes": `["foo-dir"]`,
+ "implementation_deps": `[":some-headers"]`,
+ "linkopts": `["-Wl,--exclude-libs=bar.a"] + select({
"//build/bazel/platforms/arch:x86": ["-Wl,--exclude-libs=baz.a"],
"//build/bazel/platforms/arch:x86_64": ["-Wl,--exclude-libs=qux.a"],
"//conditions:default": [],
- }),
- srcs = ["impl.cpp"] + select({
+ })`,
+ "srcs": `["impl.cpp"] + select({
"//build/bazel/platforms/arch:x86": ["x86.cpp"],
"//build/bazel/platforms/arch:x86_64": ["x86_64.cpp"],
"//conditions:default": [],
@@ -140,16 +151,16 @@
"//build/bazel/platforms/os:linux": ["linux.cpp"],
"//build/bazel/platforms/os:linux_bionic": ["bionic.cpp"],
"//conditions:default": [],
- }),
-)`}})
+ })`,
+ }),
+ })
}
func TestCcLibraryTrimmedLdAndroid(t *testing.T) {
runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library - trimmed example of //bionic/linker:ld-android",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ description: "cc_library - trimmed example of //bionic/linker:ld-android",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
filesystem: map[string]string{
"ld-android.cpp": "",
"linked_list.h": "",
@@ -157,8 +168,8 @@
"linker_block_allocator.h": "",
"linker_cfi.h": "",
},
- blueprint: soongCcLibraryPreamble + `
-cc_library_headers { name: "libc_headers" }
+ blueprint: soongCcLibraryPreamble +
+ simpleModuleDoNotConvertBp2build("cc_library_headers", "libc_headers") + `
cc_library {
name: "fake-ld-android",
srcs: ["ld_android.cpp"],
@@ -188,16 +199,16 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library(
- name = "fake-ld-android",
- copts = [
+ expectedBazelTargets: makeCcLibraryTargets("fake-ld-android", attrNameToString{
+ "srcs": `["ld_android.cpp"]`,
+ "copts": `[
"-Wall",
"-Wextra",
"-Wunused",
"-Werror",
- ],
- implementation_deps = [":libc_headers"],
- linkopts = [
+ ]`,
+ "implementation_deps": `[":libc_headers"]`,
+ "linkopts": `[
"-Wl,--exclude-libs=libgcc.a",
"-Wl,--exclude-libs=libgcc_stripped.a",
"-Wl,--exclude-libs=libclang_rt.builtins-arm-android.a",
@@ -208,19 +219,17 @@
"//build/bazel/platforms/arch:x86": ["-Wl,--exclude-libs=libgcc_eh.a"],
"//build/bazel/platforms/arch:x86_64": ["-Wl,--exclude-libs=libgcc_eh.a"],
"//conditions:default": [],
- }),
- srcs = ["ld_android.cpp"],
-)`},
+ })`,
+ }),
})
}
func TestCcLibraryExcludeSrcs(t *testing.T) {
runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library exclude_srcs - trimmed example of //external/arm-optimized-routines:libarm-optimized-routines-math",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
- dir: "external",
+ description: "cc_library exclude_srcs - trimmed example of //external/arm-optimized-routines:libarm-optimized-routines-math",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ dir: "external",
filesystem: map[string]string{
"external/math/cosf.c": "",
"external/math/erf.c": "",
@@ -255,24 +264,22 @@
`,
},
blueprint: soongCcLibraryPreamble,
- expectedBazelTargets: []string{`cc_library(
- name = "fake-libarm-optimized-routines-math",
- copts = select({
+ expectedBazelTargets: makeCcLibraryTargets("fake-libarm-optimized-routines-math", attrNameToString{
+ "copts": `select({
"//build/bazel/platforms/arch:arm64": ["-DHAVE_FAST_FMA=1"],
"//conditions:default": [],
- }),
- local_includes = ["."],
- srcs_c = ["math/cosf.c"],
-)`},
+ })`,
+ "local_includes": `["."]`,
+ "srcs_c": `["math/cosf.c"]`,
+ }),
})
}
func TestCcLibrarySharedStaticProps(t *testing.T) {
runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library shared/static props",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ description: "cc_library shared/static props",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
filesystem: map[string]string{
"both.cpp": "",
"sharedonly.cpp": "",
@@ -348,37 +355,59 @@
bazel_module: { bp2build_available: false },
}
`,
- expectedBazelTargets: []string{`cc_library(
- name = "a",
- copts = ["bothflag"],
- implementation_deps = [":static_dep_for_both"],
- implementation_dynamic_deps = [":shared_dep_for_both"],
- shared = {
- "copts": ["sharedflag"],
- "implementation_deps": [":static_dep_for_shared"],
- "implementation_dynamic_deps": [":shared_dep_for_shared"],
- "srcs": ["sharedonly.cpp"],
- "whole_archive_deps": [":whole_static_lib_for_shared"],
- },
- srcs = ["both.cpp"],
- static = {
- "copts": ["staticflag"],
- "implementation_deps": [":static_dep_for_static"],
- "implementation_dynamic_deps": [":shared_dep_for_static"],
- "srcs": ["staticonly.cpp"],
- "whole_archive_deps": [":whole_static_lib_for_static"],
- },
- whole_archive_deps = [":whole_static_lib_for_both"],
-)`},
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", attrNameToString{
+ "copts": `[
+ "bothflag",
+ "staticflag",
+ ]`,
+ "implementation_deps": `[
+ ":static_dep_for_both",
+ ":static_dep_for_static",
+ ]`,
+ "implementation_dynamic_deps": `[
+ ":shared_dep_for_both",
+ ":shared_dep_for_static",
+ ]`,
+ "srcs": `[
+ "both.cpp",
+ "staticonly.cpp",
+ ]`,
+ "whole_archive_deps": `[
+ ":whole_static_lib_for_both",
+ ":whole_static_lib_for_static",
+ ]`}),
+ makeBazelTarget("cc_library_shared", "a", attrNameToString{
+ "copts": `[
+ "bothflag",
+ "sharedflag",
+ ]`,
+ "implementation_deps": `[
+ ":static_dep_for_both",
+ ":static_dep_for_shared",
+ ]`,
+ "implementation_dynamic_deps": `[
+ ":shared_dep_for_both",
+ ":shared_dep_for_shared",
+ ]`,
+ "srcs": `[
+ "both.cpp",
+ "sharedonly.cpp",
+ ]`,
+ "whole_archive_deps": `[
+ ":whole_static_lib_for_both",
+ ":whole_static_lib_for_shared",
+ ]`,
+ }),
+ },
})
}
func TestCcLibraryDeps(t *testing.T) {
runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library shared/static props",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ description: "cc_library shared/static props",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
filesystem: map[string]string{
"both.cpp": "",
"sharedonly.cpp": "",
@@ -432,52 +461,80 @@
simpleModuleDoNotConvertBp2build("cc_library", "implementation_shared_dep_for_static") +
simpleModuleDoNotConvertBp2build("cc_library", "shared_dep_for_both") +
simpleModuleDoNotConvertBp2build("cc_library", "implementation_shared_dep_for_both"),
- expectedBazelTargets: []string{`cc_library(
- name = "a",
- copts = ["bothflag"],
- deps = [":static_dep_for_both"],
- dynamic_deps = [":shared_dep_for_both"],
- implementation_deps = [":implementation_static_dep_for_both"],
- implementation_dynamic_deps = [":implementation_shared_dep_for_both"],
- shared = {
- "copts": ["sharedflag"],
- "deps": [":static_dep_for_shared"],
- "dynamic_deps": [":shared_dep_for_shared"],
- "implementation_deps": [":implementation_static_dep_for_shared"],
- "implementation_dynamic_deps": [":implementation_shared_dep_for_shared"],
- "srcs": ["sharedonly.cpp"],
- "whole_archive_deps": [
- ":not_explicitly_exported_whole_static_dep_for_shared",
- ":whole_static_dep_for_shared",
- ],
- },
- srcs = ["both.cpp"],
- static = {
- "copts": ["staticflag"],
- "deps": [":static_dep_for_static"],
- "dynamic_deps": [":shared_dep_for_static"],
- "implementation_deps": [":implementation_static_dep_for_static"],
- "implementation_dynamic_deps": [":implementation_shared_dep_for_static"],
- "srcs": ["staticonly.cpp"],
- "whole_archive_deps": [
- ":not_explicitly_exported_whole_static_dep_for_static",
- ":whole_static_dep_for_static",
- ],
- },
- whole_archive_deps = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", attrNameToString{
+ "copts": `[
+ "bothflag",
+ "staticflag",
+ ]`,
+ "deps": `[
+ ":static_dep_for_both",
+ ":static_dep_for_static",
+ ]`,
+ "dynamic_deps": `[
+ ":shared_dep_for_both",
+ ":shared_dep_for_static",
+ ]`,
+ "implementation_deps": `[
+ ":implementation_static_dep_for_both",
+ ":implementation_static_dep_for_static",
+ ]`,
+ "implementation_dynamic_deps": `[
+ ":implementation_shared_dep_for_both",
+ ":implementation_shared_dep_for_static",
+ ]`,
+ "srcs": `[
+ "both.cpp",
+ "staticonly.cpp",
+ ]`,
+ "whole_archive_deps": `[
":not_explicitly_exported_whole_static_dep_for_both",
":whole_static_dep_for_both",
- ],
-)`},
- })
+ ":not_explicitly_exported_whole_static_dep_for_static",
+ ":whole_static_dep_for_static",
+ ]`,
+ }),
+ makeBazelTarget("cc_library_shared", "a", attrNameToString{
+ "copts": `[
+ "bothflag",
+ "sharedflag",
+ ]`,
+ "deps": `[
+ ":static_dep_for_both",
+ ":static_dep_for_shared",
+ ]`,
+ "dynamic_deps": `[
+ ":shared_dep_for_both",
+ ":shared_dep_for_shared",
+ ]`,
+ "implementation_deps": `[
+ ":implementation_static_dep_for_both",
+ ":implementation_static_dep_for_shared",
+ ]`,
+ "implementation_dynamic_deps": `[
+ ":implementation_shared_dep_for_both",
+ ":implementation_shared_dep_for_shared",
+ ]`,
+ "srcs": `[
+ "both.cpp",
+ "sharedonly.cpp",
+ ]`,
+ "whole_archive_deps": `[
+ ":not_explicitly_exported_whole_static_dep_for_both",
+ ":whole_static_dep_for_both",
+ ":not_explicitly_exported_whole_static_dep_for_shared",
+ ":whole_static_dep_for_shared",
+ ]`,
+ })},
+ },
+ )
}
func TestCcLibraryWholeStaticLibsAlwaysLink(t *testing.T) {
runCcLibraryTestCase(t, bp2buildTestCase{
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
- dir: "foo/bar",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ dir: "foo/bar",
filesystem: map[string]string{
"foo/bar/Android.bp": `
cc_library {
@@ -501,26 +558,30 @@
`,
},
blueprint: soongCcLibraryPreamble,
- expectedBazelTargets: []string{`cc_library(
- name = "a",
- shared = {
- "whole_archive_deps": [":whole_static_lib_for_shared_alwayslink"],
- },
- static = {
- "whole_archive_deps": [":whole_static_lib_for_static_alwayslink"],
- },
- whole_archive_deps = [":whole_static_lib_for_both_alwayslink"],
-)`},
- })
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", attrNameToString{
+ "whole_archive_deps": `[
+ ":whole_static_lib_for_both_alwayslink",
+ ":whole_static_lib_for_static_alwayslink",
+ ]`,
+ }),
+ makeBazelTarget("cc_library_shared", "a", attrNameToString{
+ "whole_archive_deps": `[
+ ":whole_static_lib_for_both_alwayslink",
+ ":whole_static_lib_for_shared_alwayslink",
+ ]`,
+ }),
+ },
+ },
+ )
}
func TestCcLibrarySharedStaticPropsInArch(t *testing.T) {
runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library shared/static props in arch",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
- dir: "foo/bar",
+ description: "cc_library shared/static props in arch",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ dir: "foo/bar",
filesystem: map[string]string{
"foo/bar/arm.cpp": "",
"foo/bar/x86.cpp": "",
@@ -591,71 +652,86 @@
`,
},
blueprint: soongCcLibraryPreamble,
- expectedBazelTargets: []string{`cc_library(
- name = "a",
- copts = ["bothflag"],
- implementation_deps = [":static_dep_for_both"],
- local_includes = ["."],
- shared = {
- "copts": ["sharedflag"] + select({
- "//build/bazel/platforms/arch:arm": ["-DARM_SHARED"],
- "//conditions:default": [],
- }) + select({
- "//build/bazel/platforms/os:android": ["-DANDROID_SHARED"],
- "//conditions:default": [],
- }) + select({
- "//build/bazel/platforms/os_arch:android_arm": ["-DANDROID_ARM_SHARED"],
- "//conditions:default": [],
- }),
- "implementation_deps": [":static_dep_for_shared"] + select({
- "//build/bazel/platforms/arch:arm": [":arm_static_dep_for_shared"],
- "//conditions:default": [],
- }) + select({
- "//build/bazel/platforms/os:android": [":android_dep_for_shared"],
- "//conditions:default": [],
- }),
- "implementation_dynamic_deps": select({
- "//build/bazel/platforms/arch:arm": [":arm_shared_dep_for_shared"],
- "//conditions:default": [],
- }),
- "srcs": ["sharedonly.cpp"] + select({
- "//build/bazel/platforms/arch:arm": ["arm_shared.cpp"],
- "//conditions:default": [],
- }) + select({
- "//build/bazel/platforms/os:android": ["android_shared.cpp"],
- "//conditions:default": [],
- }),
- "whole_archive_deps": select({
- "//build/bazel/platforms/arch:arm": [":arm_whole_static_dep_for_shared"],
- "//conditions:default": [],
- }),
- },
- srcs = ["both.cpp"],
- static = {
- "copts": ["staticflag"] + select({
- "//build/bazel/platforms/arch:x86": ["-DX86_STATIC"],
- "//conditions:default": [],
- }),
- "implementation_deps": [":static_dep_for_static"] + select({
- "//build/bazel/platforms/arch:x86": [":x86_dep_for_static"],
- "//conditions:default": [],
- }),
- "srcs": ["staticonly.cpp"] + select({
- "//build/bazel/platforms/arch:x86": ["x86_static.cpp"],
- "//conditions:default": [],
- }),
- },
-)`},
- })
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", attrNameToString{
+ "copts": `[
+ "bothflag",
+ "staticflag",
+ ] + select({
+ "//build/bazel/platforms/arch:x86": ["-DX86_STATIC"],
+ "//conditions:default": [],
+ })`,
+ "implementation_deps": `[
+ ":static_dep_for_both",
+ ":static_dep_for_static",
+ ] + select({
+ "//build/bazel/platforms/arch:x86": [":x86_dep_for_static"],
+ "//conditions:default": [],
+ })`,
+ "local_includes": `["."]`,
+ "srcs": `[
+ "both.cpp",
+ "staticonly.cpp",
+ ] + select({
+ "//build/bazel/platforms/arch:x86": ["x86_static.cpp"],
+ "//conditions:default": [],
+ })`,
+ }),
+ makeBazelTarget("cc_library_shared", "a", attrNameToString{
+ "copts": `[
+ "bothflag",
+ "sharedflag",
+ ] + select({
+ "//build/bazel/platforms/arch:arm": ["-DARM_SHARED"],
+ "//conditions:default": [],
+ }) + select({
+ "//build/bazel/platforms/os:android": ["-DANDROID_SHARED"],
+ "//conditions:default": [],
+ }) + select({
+ "//build/bazel/platforms/os_arch:android_arm": ["-DANDROID_ARM_SHARED"],
+ "//conditions:default": [],
+ })`,
+ "implementation_deps": `[
+ ":static_dep_for_both",
+ ":static_dep_for_shared",
+ ] + select({
+ "//build/bazel/platforms/arch:arm": [":arm_static_dep_for_shared"],
+ "//conditions:default": [],
+ }) + select({
+ "//build/bazel/platforms/os:android": [":android_dep_for_shared"],
+ "//conditions:default": [],
+ })`,
+ "implementation_dynamic_deps": `select({
+ "//build/bazel/platforms/arch:arm": [":arm_shared_dep_for_shared"],
+ "//conditions:default": [],
+ })`,
+ "local_includes": `["."]`,
+ "srcs": `[
+ "both.cpp",
+ "sharedonly.cpp",
+ ] + select({
+ "//build/bazel/platforms/arch:arm": ["arm_shared.cpp"],
+ "//conditions:default": [],
+ }) + select({
+ "//build/bazel/platforms/os:android": ["android_shared.cpp"],
+ "//conditions:default": [],
+ })`,
+ "whole_archive_deps": `select({
+ "//build/bazel/platforms/arch:arm": [":arm_whole_static_dep_for_shared"],
+ "//conditions:default": [],
+ })`,
+ }),
+ },
+ },
+ )
}
func TestCcLibrarySharedStaticPropsWithMixedSources(t *testing.T) {
runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library shared/static props with c/cpp/s mixed sources",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
- dir: "foo/bar",
+ description: "cc_library shared/static props with c/cpp/s mixed sources",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ dir: "foo/bar",
filesystem: map[string]string{
"foo/bar/both_source.cpp": "",
"foo/bar/both_source.cc": "",
@@ -729,66 +805,65 @@
`,
},
blueprint: soongCcLibraryPreamble,
- expectedBazelTargets: []string{`cc_library(
- name = "a",
- local_includes = ["."],
- shared = {
- "srcs": [
- "shared_source.cpp",
- "shared_source.cc",
- ":shared_filegroup_cpp_srcs",
- ],
- "srcs_as": [
- "shared_source.s",
- "shared_source.S",
- ":shared_filegroup_as_srcs",
- ],
- "srcs_c": [
- "shared_source.c",
- ":shared_filegroup_c_srcs",
- ],
- },
- srcs = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", attrNameToString{
+ "local_includes": `["."]`,
+ "srcs": `[
"both_source.cpp",
"both_source.cc",
":both_filegroup_cpp_srcs",
- ],
- srcs_as = [
+ "static_source.cpp",
+ "static_source.cc",
+ ":static_filegroup_cpp_srcs",
+ ]`,
+ "srcs_as": `[
"both_source.s",
"both_source.S",
":both_filegroup_as_srcs",
- ],
- srcs_c = [
+ "static_source.s",
+ "static_source.S",
+ ":static_filegroup_as_srcs",
+ ]`,
+ "srcs_c": `[
"both_source.c",
":both_filegroup_c_srcs",
- ],
- static = {
- "srcs": [
- "static_source.cpp",
- "static_source.cc",
- ":static_filegroup_cpp_srcs",
- ],
- "srcs_as": [
- "static_source.s",
- "static_source.S",
- ":static_filegroup_as_srcs",
- ],
- "srcs_c": [
- "static_source.c",
- ":static_filegroup_c_srcs",
- ],
- },
-)`},
- })
+ "static_source.c",
+ ":static_filegroup_c_srcs",
+ ]`,
+ }),
+ makeBazelTarget("cc_library_shared", "a", attrNameToString{
+ "local_includes": `["."]`,
+ "srcs": `[
+ "both_source.cpp",
+ "both_source.cc",
+ ":both_filegroup_cpp_srcs",
+ "shared_source.cpp",
+ "shared_source.cc",
+ ":shared_filegroup_cpp_srcs",
+ ]`,
+ "srcs_as": `[
+ "both_source.s",
+ "both_source.S",
+ ":both_filegroup_as_srcs",
+ "shared_source.s",
+ "shared_source.S",
+ ":shared_filegroup_as_srcs",
+ ]`,
+ "srcs_c": `[
+ "both_source.c",
+ ":both_filegroup_c_srcs",
+ "shared_source.c",
+ ":shared_filegroup_c_srcs",
+ ]`,
+ })}})
}
func TestCcLibraryNonConfiguredVersionScript(t *testing.T) {
runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library non-configured version script",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
- dir: "foo/bar",
+ description: "cc_library non-configured version script",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ dir: "foo/bar",
filesystem: map[string]string{
"foo/bar/Android.bp": `
cc_library {
@@ -801,22 +876,21 @@
`,
},
blueprint: soongCcLibraryPreamble,
- expectedBazelTargets: []string{`cc_library(
- name = "a",
- additional_linker_inputs = ["v.map"],
- linkopts = ["-Wl,--version-script,$(location v.map)"],
- srcs = ["a.cpp"],
-)`},
- })
+ expectedBazelTargets: makeCcLibraryTargets("a", attrNameToString{
+ "additional_linker_inputs": `["v.map"]`,
+ "linkopts": `["-Wl,--version-script,$(location v.map)"]`,
+ "srcs": `["a.cpp"]`,
+ }),
+ },
+ )
}
func TestCcLibraryConfiguredVersionScript(t *testing.T) {
runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library configured version script",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
- dir: "foo/bar",
+ description: "cc_library configured version script",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ dir: "foo/bar",
filesystem: map[string]string{
"foo/bar/Android.bp": `
cc_library {
@@ -837,29 +911,28 @@
`,
},
blueprint: soongCcLibraryPreamble,
- expectedBazelTargets: []string{`cc_library(
- name = "a",
- additional_linker_inputs = select({
+ expectedBazelTargets: makeCcLibraryTargets("a", attrNameToString{
+ "additional_linker_inputs": `select({
"//build/bazel/platforms/arch:arm": ["arm.map"],
"//build/bazel/platforms/arch:arm64": ["arm64.map"],
"//conditions:default": [],
- }),
- linkopts = select({
+ })`,
+ "linkopts": `select({
"//build/bazel/platforms/arch:arm": ["-Wl,--version-script,$(location arm.map)"],
"//build/bazel/platforms/arch:arm64": ["-Wl,--version-script,$(location arm64.map)"],
"//conditions:default": [],
- }),
- srcs = ["a.cpp"],
-)`},
- })
+ })`,
+ "srcs": `["a.cpp"]`,
+ }),
+ },
+ )
}
func TestCcLibrarySharedLibs(t *testing.T) {
runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library shared_libs",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ description: "cc_library shared_libs",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
blueprint: soongCcLibraryPreamble + `
cc_library {
name: "mylib",
@@ -872,19 +945,47 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library(
- name = "a",
- implementation_dynamic_deps = [":mylib"],
-)`},
- })
+ expectedBazelTargets: makeCcLibraryTargets("a", attrNameToString{
+ "implementation_dynamic_deps": `[":mylib"]`,
+ }),
+ },
+ )
}
func TestCcLibraryFeatures(t *testing.T) {
+ expected_targets := []string{}
+ expected_targets = append(expected_targets, makeCcLibraryTargets("a", attrNameToString{
+ "features": `[
+ "disable_pack_relocations",
+ "-no_undefined_symbols",
+ ]`,
+ "srcs": `["a.cpp"]`,
+ })...)
+ expected_targets = append(expected_targets, makeCcLibraryTargets("b", attrNameToString{
+ "features": `select({
+ "//build/bazel/platforms/arch:x86_64": [
+ "disable_pack_relocations",
+ "-no_undefined_symbols",
+ ],
+ "//conditions:default": [],
+ })`,
+ "srcs": `["b.cpp"]`,
+ })...)
+ expected_targets = append(expected_targets, makeCcLibraryTargets("c", attrNameToString{
+ "features": `select({
+ "//build/bazel/platforms/os:darwin": [
+ "disable_pack_relocations",
+ "-no_undefined_symbols",
+ ],
+ "//conditions:default": [],
+ })`,
+ "srcs": `["c.cpp"]`,
+ })...)
+
runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library pack_relocations test",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ description: "cc_library pack_relocations test",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
blueprint: soongCcLibraryPreamble + `
cc_library {
name: "a",
@@ -917,43 +1018,15 @@
},
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library(
- name = "a",
- features = [
- "disable_pack_relocations",
- "-no_undefined_symbols",
- ],
- srcs = ["a.cpp"],
-)`, `cc_library(
- name = "b",
- features = select({
- "//build/bazel/platforms/arch:x86_64": [
- "disable_pack_relocations",
- "-no_undefined_symbols",
- ],
- "//conditions:default": [],
- }),
- srcs = ["b.cpp"],
-)`, `cc_library(
- name = "c",
- features = select({
- "//build/bazel/platforms/os:darwin": [
- "disable_pack_relocations",
- "-no_undefined_symbols",
- ],
- "//conditions:default": [],
- }),
- srcs = ["c.cpp"],
-)`},
+ expectedBazelTargets: expected_targets,
})
}
func TestCcLibrarySpacesInCopts(t *testing.T) {
runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library spaces in copts",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ description: "cc_library spaces in copts",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
blueprint: soongCcLibraryPreamble + `
cc_library {
name: "a",
@@ -961,22 +1034,21 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library(
- name = "a",
- copts = [
+ expectedBazelTargets: makeCcLibraryTargets("a", attrNameToString{
+ "copts": `[
"-include",
"header.h",
- ],
-)`},
- })
+ ]`,
+ }),
+ },
+ )
}
func TestCcLibraryCppFlagsGoesIntoCopts(t *testing.T) {
runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library cppflags usage",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ description: "cc_library cppflags usage",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
blueprint: soongCcLibraryPreamble + `cc_library {
name: "a",
srcs: ["a.cpp"],
@@ -998,10 +1070,9 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library(
- name = "a",
- copts = ["-Wall"],
- cppflags = [
+ expectedBazelTargets: makeCcLibraryTargets("a", attrNameToString{
+ "copts": `["-Wall"]`,
+ "cppflags": `[
"-fsigned-char",
"-pedantic",
] + select({
@@ -1010,18 +1081,18 @@
}) + select({
"//build/bazel/platforms/os:android": ["-DANDROID=1"],
"//conditions:default": [],
- }),
- srcs = ["a.cpp"],
-)`},
- })
+ })`,
+ "srcs": `["a.cpp"]`,
+ }),
+ },
+ )
}
func TestCcLibraryExcludeLibs(t *testing.T) {
runCcLibraryTestCase(t, bp2buildTestCase{
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
- filesystem: map[string]string{},
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ filesystem: map[string]string{},
blueprint: soongCcLibraryStaticPreamble + `
cc_library {
name: "foo_static",
@@ -1096,42 +1167,39 @@
bazel_module: { bp2build_available: false },
}
`,
- expectedBazelTargets: []string{
- `cc_library(
- name = "foo_static",
- implementation_deps = select({
+ expectedBazelTargets: makeCcLibraryTargets("foo_static", attrNameToString{
+ "implementation_deps": `select({
"//build/bazel/platforms/arch:arm": [],
"//conditions:default": [":arm_static_lib_excludes_bp2build_cc_library_static"],
}) + select({
"//build/bazel/product_variables:malloc_not_svelte": [],
"//conditions:default": [":malloc_not_svelte_static_lib_excludes_bp2build_cc_library_static"],
- }),
- implementation_dynamic_deps = select({
+ })`,
+ "implementation_dynamic_deps": `select({
"//build/bazel/platforms/arch:arm": [],
"//conditions:default": [":arm_shared_lib_excludes"],
}) + select({
"//build/bazel/product_variables:malloc_not_svelte": [":malloc_not_svelte_shared_lib"],
"//conditions:default": [],
- }),
- srcs_c = ["common.c"],
- whole_archive_deps = select({
+ })`,
+ "srcs_c": `["common.c"]`,
+ "whole_archive_deps": `select({
"//build/bazel/platforms/arch:arm": [],
"//conditions:default": [":arm_whole_static_lib_excludes_bp2build_cc_library_static"],
}) + select({
"//build/bazel/product_variables:malloc_not_svelte": [":malloc_not_svelte_whole_static_lib_bp2build_cc_library_static"],
"//conditions:default": [":malloc_not_svelte_whole_static_lib_excludes_bp2build_cc_library_static"],
- }),
-)`,
- },
- })
+ })`,
+ }),
+ },
+ )
}
func TestCCLibraryNoCrtTrue(t *testing.T) {
runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library - nocrt: true emits attribute",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ description: "cc_library - nocrt: true emits attribute",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
filesystem: map[string]string{
"impl.cpp": "",
},
@@ -1143,19 +1211,19 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library(
- name = "foo-lib",
- link_crt = False,
- srcs = ["impl.cpp"],
-)`}})
+ expectedBazelTargets: makeCcLibraryTargets("foo-lib", attrNameToString{
+ "link_crt": `False`,
+ "srcs": `["impl.cpp"]`,
+ }),
+ },
+ )
}
func TestCCLibraryNoCrtFalse(t *testing.T) {
runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library - nocrt: false - does not emit attribute",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ description: "cc_library - nocrt: false - does not emit attribute",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
filesystem: map[string]string{
"impl.cpp": "",
},
@@ -1167,18 +1235,17 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library(
- name = "foo-lib",
- srcs = ["impl.cpp"],
-)`}})
+ expectedBazelTargets: makeCcLibraryTargets("foo-lib", attrNameToString{
+ "srcs": `["impl.cpp"]`,
+ }),
+ })
}
func TestCCLibraryNoCrtArchVariant(t *testing.T) {
runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library - nocrt in select",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ description: "cc_library - nocrt in select",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
filesystem: map[string]string{
"impl.cpp": "",
},
@@ -1203,15 +1270,12 @@
func TestCCLibraryNoLibCrtTrue(t *testing.T) {
runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library - simple example",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
filesystem: map[string]string{
"impl.cpp": "",
},
blueprint: soongCcLibraryPreamble + `
-cc_library_headers { name: "some-headers" }
cc_library {
name: "foo-lib",
srcs: ["impl.cpp"],
@@ -1219,23 +1283,45 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library(
- name = "foo-lib",
- srcs = ["impl.cpp"],
- use_libcrt = False,
-)`}})
+ expectedBazelTargets: makeCcLibraryTargets("foo-lib", attrNameToString{
+ "srcs": `["impl.cpp"]`,
+ "use_libcrt": `False`,
+ }),
+ })
+}
+
+func makeCcLibraryTargets(name string, attrs attrNameToString) []string {
+ STATIC_ONLY_ATTRS := map[string]bool{}
+ SHARED_ONLY_ATTRS := map[string]bool{
+ "link_crt": true,
+ "additional_linker_inputs": true,
+ "linkopts": true,
+ "strip": true,
+ }
+ sharedAttrs := attrNameToString{}
+ staticAttrs := attrNameToString{}
+ for key, val := range attrs {
+ if _, staticOnly := STATIC_ONLY_ATTRS[key]; !staticOnly {
+ sharedAttrs[key] = val
+ }
+ if _, sharedOnly := SHARED_ONLY_ATTRS[key]; !sharedOnly {
+ staticAttrs[key] = val
+ }
+ }
+ sharedTarget := makeBazelTarget("cc_library_shared", name, sharedAttrs)
+ staticTarget := makeBazelTarget("cc_library_static", name+"_bp2build_cc_library_static", staticAttrs)
+
+ return []string{staticTarget, sharedTarget}
}
func TestCCLibraryNoLibCrtFalse(t *testing.T) {
runCcLibraryTestCase(t, bp2buildTestCase{
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
filesystem: map[string]string{
"impl.cpp": "",
},
blueprint: soongCcLibraryPreamble + `
-cc_library_headers { name: "some-headers" }
cc_library {
name: "foo-lib",
srcs: ["impl.cpp"],
@@ -1243,18 +1329,17 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library(
- name = "foo-lib",
- srcs = ["impl.cpp"],
- use_libcrt = True,
-)`}})
+ expectedBazelTargets: makeCcLibraryTargets("foo-lib", attrNameToString{
+ "srcs": `["impl.cpp"]`,
+ "use_libcrt": `True`,
+ }),
+ })
}
func TestCCLibraryNoLibCrtArchVariant(t *testing.T) {
runCcLibraryTestCase(t, bp2buildTestCase{
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
filesystem: map[string]string{
"impl.cpp": "",
},
@@ -1273,23 +1358,138 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library(
- name = "foo-lib",
- srcs = ["impl.cpp"],
- use_libcrt = select({
+ expectedBazelTargets: makeCcLibraryTargets("foo-lib", attrNameToString{
+ "srcs": `["impl.cpp"]`,
+ "use_libcrt": `select({
"//build/bazel/platforms/arch:arm": False,
"//build/bazel/platforms/arch:x86": False,
"//conditions:default": None,
- }),
-)`}})
+ })`,
+ }),
+ })
+}
+
+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{
+ "strip": `{
+ "all": True,
+ }`,
+ })...)
+ expectedTargets = append(expectedTargets, makeCcLibraryTargets("keep_symbols", attrNameToString{
+ "strip": `{
+ "keep_symbols": True,
+ }`,
+ })...)
+ expectedTargets = append(expectedTargets, makeCcLibraryTargets("keep_symbols_and_debug_frame", attrNameToString{
+ "strip": `{
+ "keep_symbols_and_debug_frame": True,
+ }`,
+ })...)
+ expectedTargets = append(expectedTargets, makeCcLibraryTargets("keep_symbols_list", attrNameToString{
+ "strip": `{
+ "keep_symbols_list": ["symbol"],
+ }`,
+ })...)
+ expectedTargets = append(expectedTargets, makeCcLibraryTargets("none", attrNameToString{
+ "strip": `{
+ "none": True,
+ }`,
+ })...)
+ expectedTargets = append(expectedTargets, makeCcLibraryTargets("nothing", attrNameToString{})...)
+
runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library strip args",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ description: "cc_library strip args",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
blueprint: soongCcLibraryPreamble + `
cc_library {
name: "nothing",
@@ -1331,43 +1531,15 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library(
- name = "all",
- strip = {
- "all": True,
- },
-)`, `cc_library(
- name = "keep_symbols",
- strip = {
- "keep_symbols": True,
- },
-)`, `cc_library(
- name = "keep_symbols_and_debug_frame",
- strip = {
- "keep_symbols_and_debug_frame": True,
- },
-)`, `cc_library(
- name = "keep_symbols_list",
- strip = {
- "keep_symbols_list": ["symbol"],
- },
-)`, `cc_library(
- name = "none",
- strip = {
- "none": True,
- },
-)`, `cc_library(
- name = "nothing",
-)`},
+ expectedBazelTargets: expectedTargets,
})
}
func TestCcLibraryStripWithArch(t *testing.T) {
runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library strip args",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ description: "cc_library strip args",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
blueprint: soongCcLibraryPreamble + `
cc_library {
name: "multi-arch",
@@ -1393,9 +1565,8 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library(
- name = "multi-arch",
- strip = {
+ expectedBazelTargets: makeCcLibraryTargets("multi-arch", attrNameToString{
+ "strip": `{
"keep_symbols": select({
"//build/bazel/platforms/arch:arm64": True,
"//conditions:default": None,
@@ -1411,17 +1582,17 @@
],
"//conditions:default": [],
}),
- },
-)`},
- })
+ }`,
+ }),
+ },
+ )
}
func TestCcLibrary_SystemSharedLibsRootEmpty(t *testing.T) {
runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library system_shared_libs empty at root",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ description: "cc_library system_shared_libs empty at root",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
blueprint: soongCcLibraryPreamble + `
cc_library {
name: "root_empty",
@@ -1429,19 +1600,18 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library(
- name = "root_empty",
- system_dynamic_deps = [],
-)`},
- })
+ expectedBazelTargets: makeCcLibraryTargets("root_empty", attrNameToString{
+ "system_dynamic_deps": `[]`,
+ }),
+ },
+ )
}
func TestCcLibrary_SystemSharedLibsStaticEmpty(t *testing.T) {
runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library system_shared_libs empty for static variant",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ description: "cc_library system_shared_libs empty for static variant",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
blueprint: soongCcLibraryPreamble + `
cc_library {
name: "static_empty",
@@ -1451,21 +1621,20 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library(
- name = "static_empty",
- static = {
- "system_dynamic_deps": [],
- },
-)`},
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "static_empty_bp2build_cc_library_static", attrNameToString{
+ "system_dynamic_deps": "[]",
+ }),
+ makeBazelTarget("cc_library_shared", "static_empty", attrNameToString{}),
+ },
})
}
func TestCcLibrary_SystemSharedLibsSharedEmpty(t *testing.T) {
runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library system_shared_libs empty for shared variant",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ description: "cc_library system_shared_libs empty for shared variant",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
blueprint: soongCcLibraryPreamble + `
cc_library {
name: "shared_empty",
@@ -1475,21 +1644,20 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library(
- name = "shared_empty",
- shared = {
- "system_dynamic_deps": [],
- },
-)`},
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "shared_empty_bp2build_cc_library_static", attrNameToString{}),
+ makeBazelTarget("cc_library_shared", "shared_empty", attrNameToString{
+ "system_dynamic_deps": "[]",
+ }),
+ },
})
}
func TestCcLibrary_SystemSharedLibsSharedBionicEmpty(t *testing.T) {
runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library system_shared_libs empty for shared, bionic variant",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ description: "cc_library system_shared_libs empty for shared, bionic variant",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
blueprint: soongCcLibraryPreamble + `
cc_library {
name: "shared_empty",
@@ -1503,12 +1671,12 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library(
- name = "shared_empty",
- shared = {
- "system_dynamic_deps": [],
- },
-)`},
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "shared_empty_bp2build_cc_library_static", attrNameToString{}),
+ makeBazelTarget("cc_library_shared", "shared_empty", attrNameToString{
+ "system_dynamic_deps": "[]",
+ }),
+ },
})
}
@@ -1518,10 +1686,9 @@
// only for linux_bionic, but `android` had `["libc", "libdl", "libm"].
// b/195791252 tracks the fix.
runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library system_shared_libs empty for linux_bionic variant",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ description: "cc_library system_shared_libs empty for linux_bionic variant",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
blueprint: soongCcLibraryPreamble + `
cc_library {
name: "target_linux_bionic_empty",
@@ -1533,19 +1700,18 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library(
- name = "target_linux_bionic_empty",
- system_dynamic_deps = [],
-)`},
- })
+ expectedBazelTargets: makeCcLibraryTargets("target_linux_bionic_empty", attrNameToString{
+ "system_dynamic_deps": `[]`,
+ }),
+ },
+ )
}
func TestCcLibrary_SystemSharedLibsBionicEmpty(t *testing.T) {
runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library system_shared_libs empty for bionic variant",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ description: "cc_library system_shared_libs empty for bionic variant",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
blueprint: soongCcLibraryPreamble + `
cc_library {
name: "target_bionic_empty",
@@ -1557,19 +1723,18 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library(
- name = "target_bionic_empty",
- system_dynamic_deps = [],
-)`},
- })
+ expectedBazelTargets: makeCcLibraryTargets("target_bionic_empty", attrNameToString{
+ "system_dynamic_deps": `[]`,
+ }),
+ },
+ )
}
func TestCcLibrary_SystemSharedLibsSharedAndRoot(t *testing.T) {
runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library system_shared_libs set for shared and root",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ description: "cc_library system_shared_libs set for shared and root",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
blueprint: soongCcLibraryPreamble + `
cc_library {
name: "libc",
@@ -1589,25 +1754,27 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library(
- name = "foo",
- shared = {
- "system_dynamic_deps": [":libm"],
- },
- system_dynamic_deps = [":libc"],
-)`},
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", attrNameToString{
+ "system_dynamic_deps": `[":libc"]`,
+ }),
+ makeBazelTarget("cc_library_shared", "foo", attrNameToString{
+ "system_dynamic_deps": `[
+ ":libc",
+ ":libm",
+ ]`,
+ }),
+ },
})
}
func TestCcLibraryOsSelects(t *testing.T) {
runCcLibraryTestCase(t, bp2buildTestCase{
- description: "cc_library - selects for all os targets",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
- filesystem: map[string]string{},
+ description: "cc_library - selects for all os targets",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ filesystem: map[string]string{},
blueprint: soongCcLibraryPreamble + `
-cc_library_headers { name: "some-headers" }
cc_library {
name: "foo-lib",
srcs: ["base.cpp"],
@@ -1637,9 +1804,8 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library(
- name = "foo-lib",
- srcs = ["base.cpp"] + select({
+ expectedBazelTargets: makeCcLibraryTargets("foo-lib", attrNameToString{
+ "srcs": `["base.cpp"] + select({
"//build/bazel/platforms/os:android": [
"linux.cpp",
"bionic.cpp",
@@ -1660,16 +1826,19 @@
],
"//build/bazel/platforms/os:windows": ["windows.cpp"],
"//conditions:default": [],
- }),
-)`}})
-
+ })`,
+ }),
+ },
+ )
}
func TestCcLibraryCppStdWithGnuExtensions_ConvertsToFeatureAttr(t *testing.T) {
type testCase struct {
cpp_std string
+ c_std string
gnu_extensions string
bazel_cpp_std string
+ bazel_c_std string
}
testCases := []testCase{
@@ -1679,109 +1848,545 @@
// not set, only emit if gnu_extensions is disabled. the default (gnu+17
// is set in the toolchain.)
{cpp_std: "", gnu_extensions: "", bazel_cpp_std: ""},
- {cpp_std: "", gnu_extensions: "false", bazel_cpp_std: "c++17"},
+ {cpp_std: "", gnu_extensions: "false", bazel_cpp_std: "c++17", bazel_c_std: "c99"},
{cpp_std: "", gnu_extensions: "true", bazel_cpp_std: ""},
// experimental defaults to gnu++2a
{cpp_std: "experimental", gnu_extensions: "", bazel_cpp_std: "gnu++2a"},
- {cpp_std: "experimental", gnu_extensions: "false", bazel_cpp_std: "c++2a"},
+ {cpp_std: "experimental", gnu_extensions: "false", bazel_cpp_std: "c++2a", bazel_c_std: "c99"},
{cpp_std: "experimental", gnu_extensions: "true", bazel_cpp_std: "gnu++2a"},
// Explicitly setting a c++ std does not use replace gnu++ std even if
// gnu_extensions is true.
// "c++11",
{cpp_std: "c++11", gnu_extensions: "", bazel_cpp_std: "c++11"},
- {cpp_std: "c++11", gnu_extensions: "false", bazel_cpp_std: "c++11"},
+ {cpp_std: "c++11", gnu_extensions: "false", bazel_cpp_std: "c++11", bazel_c_std: "c99"},
{cpp_std: "c++11", gnu_extensions: "true", bazel_cpp_std: "c++11"},
// "c++17",
{cpp_std: "c++17", gnu_extensions: "", bazel_cpp_std: "c++17"},
- {cpp_std: "c++17", gnu_extensions: "false", bazel_cpp_std: "c++17"},
+ {cpp_std: "c++17", gnu_extensions: "false", bazel_cpp_std: "c++17", bazel_c_std: "c99"},
{cpp_std: "c++17", gnu_extensions: "true", bazel_cpp_std: "c++17"},
// "c++2a",
{cpp_std: "c++2a", gnu_extensions: "", bazel_cpp_std: "c++2a"},
- {cpp_std: "c++2a", gnu_extensions: "false", bazel_cpp_std: "c++2a"},
+ {cpp_std: "c++2a", gnu_extensions: "false", bazel_cpp_std: "c++2a", bazel_c_std: "c99"},
{cpp_std: "c++2a", gnu_extensions: "true", bazel_cpp_std: "c++2a"},
// "c++98",
{cpp_std: "c++98", gnu_extensions: "", bazel_cpp_std: "c++98"},
- {cpp_std: "c++98", gnu_extensions: "false", bazel_cpp_std: "c++98"},
+ {cpp_std: "c++98", gnu_extensions: "false", bazel_cpp_std: "c++98", bazel_c_std: "c99"},
{cpp_std: "c++98", gnu_extensions: "true", bazel_cpp_std: "c++98"},
// gnu++ is replaced with c++ if gnu_extensions is explicitly false.
// "gnu++11",
{cpp_std: "gnu++11", gnu_extensions: "", bazel_cpp_std: "gnu++11"},
- {cpp_std: "gnu++11", gnu_extensions: "false", bazel_cpp_std: "c++11"},
+ {cpp_std: "gnu++11", gnu_extensions: "false", bazel_cpp_std: "c++11", bazel_c_std: "c99"},
{cpp_std: "gnu++11", gnu_extensions: "true", bazel_cpp_std: "gnu++11"},
// "gnu++17",
{cpp_std: "gnu++17", gnu_extensions: "", bazel_cpp_std: "gnu++17"},
- {cpp_std: "gnu++17", gnu_extensions: "false", bazel_cpp_std: "c++17"},
+ {cpp_std: "gnu++17", gnu_extensions: "false", bazel_cpp_std: "c++17", bazel_c_std: "c99"},
{cpp_std: "gnu++17", gnu_extensions: "true", bazel_cpp_std: "gnu++17"},
+
+ // some c_std test cases
+ {c_std: "experimental", gnu_extensions: "", bazel_c_std: "gnu11"},
+ {c_std: "experimental", gnu_extensions: "false", bazel_cpp_std: "c++17", bazel_c_std: "c11"},
+ {c_std: "experimental", gnu_extensions: "true", bazel_c_std: "gnu11"},
+ {c_std: "gnu11", cpp_std: "gnu++17", gnu_extensions: "", bazel_cpp_std: "gnu++17", bazel_c_std: "gnu11"},
+ {c_std: "gnu11", cpp_std: "gnu++17", gnu_extensions: "false", bazel_cpp_std: "c++17", bazel_c_std: "c11"},
+ {c_std: "gnu11", cpp_std: "gnu++17", gnu_extensions: "true", bazel_cpp_std: "gnu++17", bazel_c_std: "gnu11"},
}
- for _, tc := range testCases {
- cppStdAttr := ""
+ for i, tc := range testCases {
+ name_prefix := fmt.Sprintf("a_%v", i)
+ cppStdProp := ""
if tc.cpp_std != "" {
- cppStdAttr = fmt.Sprintf(" cpp_std: \"%s\",", tc.cpp_std)
+ cppStdProp = fmt.Sprintf(" cpp_std: \"%s\",", tc.cpp_std)
}
- gnuExtensionsAttr := ""
+ cStdProp := ""
+ if tc.c_std != "" {
+ cStdProp = fmt.Sprintf(" c_std: \"%s\",", tc.c_std)
+ }
+ gnuExtensionsProp := ""
if tc.gnu_extensions != "" {
- gnuExtensionsAttr = fmt.Sprintf(" gnu_extensions: %s,", tc.gnu_extensions)
+ gnuExtensionsProp = fmt.Sprintf(" gnu_extensions: %s,", tc.gnu_extensions)
}
- bazelCppStdAttr := ""
+ attrs := attrNameToString{}
if tc.bazel_cpp_std != "" {
- bazelCppStdAttr = fmt.Sprintf("\n cpp_std = \"%s\",", tc.bazel_cpp_std)
+ attrs["cpp_std"] = fmt.Sprintf(`"%s"`, tc.bazel_cpp_std)
+ }
+ if tc.bazel_c_std != "" {
+ attrs["c_std"] = fmt.Sprintf(`"%s"`, tc.bazel_c_std)
}
runCcLibraryTestCase(t, bp2buildTestCase{
description: fmt.Sprintf(
"cc_library with cpp_std: %s and gnu_extensions: %s", tc.cpp_std, tc.gnu_extensions),
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
blueprint: soongCcLibraryPreamble + fmt.Sprintf(`
cc_library {
- name: "a",
+ name: "%s_full",
%s // cpp_std: *string
+%s // c_std: *string
%s // gnu_extensions: *bool
include_build_directory: false,
}
-`, cppStdAttr, gnuExtensionsAttr),
- expectedBazelTargets: []string{fmt.Sprintf(`cc_library(
- name = "a",%s
-)`, bazelCppStdAttr)},
+`, name_prefix, cppStdProp, cStdProp, gnuExtensionsProp),
+ expectedBazelTargets: makeCcLibraryTargets(name_prefix+"_full", attrs),
})
runCcLibraryStaticTestCase(t, bp2buildTestCase{
description: fmt.Sprintf(
"cc_library_static with cpp_std: %s and gnu_extensions: %s", tc.cpp_std, tc.gnu_extensions),
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
blueprint: soongCcLibraryPreamble + fmt.Sprintf(`
cc_library_static {
- name: "a",
+ name: "%s_static",
%s // cpp_std: *string
+%s // c_std: *string
%s // gnu_extensions: *bool
include_build_directory: false,
}
-`, cppStdAttr, gnuExtensionsAttr),
- expectedBazelTargets: []string{fmt.Sprintf(`cc_library_static(
- name = "a",%s
-)`, bazelCppStdAttr)},
+`, name_prefix, cppStdProp, cStdProp, gnuExtensionsProp),
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", name_prefix+"_static", attrs),
+ },
})
runCcLibrarySharedTestCase(t, bp2buildTestCase{
description: fmt.Sprintf(
"cc_library_shared with cpp_std: %s and gnu_extensions: %s", tc.cpp_std, tc.gnu_extensions),
- moduleTypeUnderTest: "cc_library_shared",
- moduleTypeUnderTestFactory: cc.LibrarySharedFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibrarySharedBp2Build,
+ moduleTypeUnderTest: "cc_library_shared",
+ moduleTypeUnderTestFactory: cc.LibrarySharedFactory,
blueprint: soongCcLibraryPreamble + fmt.Sprintf(`
cc_library_shared {
- name: "a",
+ name: "%s_shared",
%s // cpp_std: *string
+%s // c_std: *string
%s // gnu_extensions: *bool
include_build_directory: false,
}
-`, cppStdAttr, gnuExtensionsAttr),
- expectedBazelTargets: []string{fmt.Sprintf(`cc_library_shared(
- name = "a",%s
-)`, bazelCppStdAttr)},
+`, name_prefix, cppStdProp, cStdProp, gnuExtensionsProp),
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_shared", name_prefix+"_shared", attrs),
+ },
})
}
}
+
+func TestCcLibraryProtoSimple(t *testing.T) {
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ blueprint: soongCcProtoPreamble + `cc_library {
+ name: "foo",
+ srcs: ["foo.proto"],
+ include_build_directory: false,
+}`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("proto_library", "foo_proto", attrNameToString{
+ "srcs": `["foo.proto"]`,
+ "strip_import_prefix": `""`,
+ }), makeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", attrNameToString{
+ "deps": `[":foo_proto"]`,
+ }), makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", attrNameToString{
+ "implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`,
+ "deps": `[":libprotobuf-cpp-lite"]`,
+ }), makeBazelTarget("cc_library_shared", "foo", attrNameToString{
+ "dynamic_deps": `[":libprotobuf-cpp-lite"]`,
+ }),
+ },
+ })
+}
+
+func TestCcLibraryProtoNoCanonicalPathFromRoot(t *testing.T) {
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ blueprint: soongCcProtoPreamble + `cc_library {
+ name: "foo",
+ srcs: ["foo.proto"],
+ proto: { canonical_path_from_root: false},
+ include_build_directory: false,
+}`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("proto_library", "foo_proto", attrNameToString{
+ "srcs": `["foo.proto"]`,
+ }), makeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", attrNameToString{
+ "deps": `[":foo_proto"]`,
+ }), makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", attrNameToString{
+ "implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`,
+ "deps": `[":libprotobuf-cpp-lite"]`,
+ }), makeBazelTarget("cc_library_shared", "foo", attrNameToString{
+ "dynamic_deps": `[":libprotobuf-cpp-lite"]`,
+ }),
+ },
+ })
+}
+
+func TestCcLibraryProtoExplicitCanonicalPathFromRoot(t *testing.T) {
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ blueprint: soongCcProtoPreamble + `cc_library {
+ name: "foo",
+ srcs: ["foo.proto"],
+ proto: { canonical_path_from_root: true},
+ include_build_directory: false,
+}`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("proto_library", "foo_proto", attrNameToString{
+ "srcs": `["foo.proto"]`,
+ "strip_import_prefix": `""`,
+ }), makeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", attrNameToString{
+ "deps": `[":foo_proto"]`,
+ }), makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", attrNameToString{
+ "implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`,
+ "deps": `[":libprotobuf-cpp-lite"]`,
+ }), makeBazelTarget("cc_library_shared", "foo", attrNameToString{
+ "dynamic_deps": `[":libprotobuf-cpp-lite"]`,
+ }),
+ },
+ })
+}
+
+func TestCcLibraryProtoFull(t *testing.T) {
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ blueprint: soongCcProtoPreamble + `cc_library {
+ name: "foo",
+ srcs: ["foo.proto"],
+ proto: {
+ canonical_path_from_root: false,
+ type: "full",
+ },
+ include_build_directory: false,
+}`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("proto_library", "foo_proto", attrNameToString{
+ "srcs": `["foo.proto"]`,
+ }), makeBazelTarget("cc_proto_library", "foo_cc_proto", attrNameToString{
+ "deps": `[":foo_proto"]`,
+ }), makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", attrNameToString{
+ "implementation_whole_archive_deps": `[":foo_cc_proto"]`,
+ "deps": `[":libprotobuf-cpp-full"]`,
+ }), makeBazelTarget("cc_library_shared", "foo", attrNameToString{
+ "dynamic_deps": `[":libprotobuf-cpp-full"]`,
+ }),
+ },
+ })
+}
+
+func TestCcLibraryProtoLite(t *testing.T) {
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ blueprint: soongCcProtoPreamble + `cc_library {
+ name: "foo",
+ srcs: ["foo.proto"],
+ proto: {
+ canonical_path_from_root: false,
+ type: "lite",
+ },
+ include_build_directory: false,
+}`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("proto_library", "foo_proto", attrNameToString{
+ "srcs": `["foo.proto"]`,
+ }), makeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", attrNameToString{
+ "deps": `[":foo_proto"]`,
+ }), makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", attrNameToString{
+ "implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`,
+ "deps": `[":libprotobuf-cpp-lite"]`,
+ }), makeBazelTarget("cc_library_shared", "foo", attrNameToString{
+ "dynamic_deps": `[":libprotobuf-cpp-lite"]`,
+ }),
+ },
+ })
+}
+
+func TestCcLibraryProtoExportHeaders(t *testing.T) {
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ blueprint: soongCcProtoPreamble + `cc_library {
+ name: "foo",
+ srcs: ["foo.proto"],
+ proto: {
+ canonical_path_from_root: false,
+ export_proto_headers: true,
+ },
+ include_build_directory: false,
+}`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("proto_library", "foo_proto", attrNameToString{
+ "srcs": `["foo.proto"]`,
+ }), makeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", attrNameToString{
+ "deps": `[":foo_proto"]`,
+ }), makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", attrNameToString{
+ "deps": `[":libprotobuf-cpp-lite"]`,
+ "whole_archive_deps": `[":foo_cc_proto_lite"]`,
+ }), makeBazelTarget("cc_library_shared", "foo", attrNameToString{
+ "dynamic_deps": `[":libprotobuf-cpp-lite"]`,
+ "whole_archive_deps": `[":foo_cc_proto_lite"]`,
+ }),
+ },
+ })
+}
+
+func TestCcLibraryProtoFilegroups(t *testing.T) {
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ blueprint: soongCcProtoPreamble +
+ simpleModuleDoNotConvertBp2build("filegroup", "a_fg_proto") +
+ simpleModuleDoNotConvertBp2build("filegroup", "b_protos") +
+ simpleModuleDoNotConvertBp2build("filegroup", "c-proto-srcs") +
+ simpleModuleDoNotConvertBp2build("filegroup", "proto-srcs-d") + `
+cc_library {
+ name: "a",
+ srcs: [":a_fg_proto"],
+ proto: {
+ canonical_path_from_root: false,
+ export_proto_headers: true,
+ },
+ include_build_directory: false,
+}
+
+cc_library {
+ name: "b",
+ srcs: [":b_protos"],
+ proto: {
+ canonical_path_from_root: false,
+ export_proto_headers: true,
+ },
+ include_build_directory: false,
+}
+
+cc_library {
+ name: "c",
+ srcs: [":c-proto-srcs"],
+ proto: {
+ canonical_path_from_root: false,
+ export_proto_headers: true,
+ },
+ include_build_directory: false,
+}
+
+cc_library {
+ name: "d",
+ srcs: [":proto-srcs-d"],
+ proto: {
+ canonical_path_from_root: false,
+ export_proto_headers: true,
+ },
+ include_build_directory: false,
+}`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("proto_library", "a_proto", attrNameToString{
+ "srcs": `[":a_fg_proto"]`,
+ }), makeBazelTarget("cc_lite_proto_library", "a_cc_proto_lite", attrNameToString{
+ "deps": `[":a_proto"]`,
+ }), makeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", attrNameToString{
+ "deps": `[":libprotobuf-cpp-lite"]`,
+ "whole_archive_deps": `[":a_cc_proto_lite"]`,
+ "srcs": `[":a_fg_proto_cpp_srcs"]`,
+ "srcs_as": `[":a_fg_proto_as_srcs"]`,
+ "srcs_c": `[":a_fg_proto_c_srcs"]`,
+ }), makeBazelTarget("cc_library_shared", "a", attrNameToString{
+ "dynamic_deps": `[":libprotobuf-cpp-lite"]`,
+ "whole_archive_deps": `[":a_cc_proto_lite"]`,
+ "srcs": `[":a_fg_proto_cpp_srcs"]`,
+ "srcs_as": `[":a_fg_proto_as_srcs"]`,
+ "srcs_c": `[":a_fg_proto_c_srcs"]`,
+ }), makeBazelTarget("proto_library", "b_proto", attrNameToString{
+ "srcs": `[":b_protos"]`,
+ }), makeBazelTarget("cc_lite_proto_library", "b_cc_proto_lite", attrNameToString{
+ "deps": `[":b_proto"]`,
+ }), makeBazelTarget("cc_library_static", "b_bp2build_cc_library_static", attrNameToString{
+ "deps": `[":libprotobuf-cpp-lite"]`,
+ "whole_archive_deps": `[":b_cc_proto_lite"]`,
+ "srcs": `[":b_protos_cpp_srcs"]`,
+ "srcs_as": `[":b_protos_as_srcs"]`,
+ "srcs_c": `[":b_protos_c_srcs"]`,
+ }), makeBazelTarget("cc_library_shared", "b", attrNameToString{
+ "dynamic_deps": `[":libprotobuf-cpp-lite"]`,
+ "whole_archive_deps": `[":b_cc_proto_lite"]`,
+ "srcs": `[":b_protos_cpp_srcs"]`,
+ "srcs_as": `[":b_protos_as_srcs"]`,
+ "srcs_c": `[":b_protos_c_srcs"]`,
+ }), makeBazelTarget("proto_library", "c_proto", attrNameToString{
+ "srcs": `[":c-proto-srcs"]`,
+ }), makeBazelTarget("cc_lite_proto_library", "c_cc_proto_lite", attrNameToString{
+ "deps": `[":c_proto"]`,
+ }), makeBazelTarget("cc_library_static", "c_bp2build_cc_library_static", attrNameToString{
+ "deps": `[":libprotobuf-cpp-lite"]`,
+ "whole_archive_deps": `[":c_cc_proto_lite"]`,
+ "srcs": `[":c-proto-srcs_cpp_srcs"]`,
+ "srcs_as": `[":c-proto-srcs_as_srcs"]`,
+ "srcs_c": `[":c-proto-srcs_c_srcs"]`,
+ }), makeBazelTarget("cc_library_shared", "c", attrNameToString{
+ "dynamic_deps": `[":libprotobuf-cpp-lite"]`,
+ "whole_archive_deps": `[":c_cc_proto_lite"]`,
+ "srcs": `[":c-proto-srcs_cpp_srcs"]`,
+ "srcs_as": `[":c-proto-srcs_as_srcs"]`,
+ "srcs_c": `[":c-proto-srcs_c_srcs"]`,
+ }), makeBazelTarget("proto_library", "d_proto", attrNameToString{
+ "srcs": `[":proto-srcs-d"]`,
+ }), makeBazelTarget("cc_lite_proto_library", "d_cc_proto_lite", attrNameToString{
+ "deps": `[":d_proto"]`,
+ }), makeBazelTarget("cc_library_static", "d_bp2build_cc_library_static", attrNameToString{
+ "deps": `[":libprotobuf-cpp-lite"]`,
+ "whole_archive_deps": `[":d_cc_proto_lite"]`,
+ "srcs": `[":proto-srcs-d_cpp_srcs"]`,
+ "srcs_as": `[":proto-srcs-d_as_srcs"]`,
+ "srcs_c": `[":proto-srcs-d_c_srcs"]`,
+ }), makeBazelTarget("cc_library_shared", "d", attrNameToString{
+ "dynamic_deps": `[":libprotobuf-cpp-lite"]`,
+ "whole_archive_deps": `[":d_cc_proto_lite"]`,
+ "srcs": `[":proto-srcs-d_cpp_srcs"]`,
+ "srcs_as": `[":proto-srcs-d_as_srcs"]`,
+ "srcs_c": `[":proto-srcs-d_c_srcs"]`,
+ }),
+ },
+ })
+}
+
+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"],
+ })`,
+ }),
+ }})
+}
diff --git a/bp2build/cc_library_headers_conversion_test.go b/bp2build/cc_library_headers_conversion_test.go
index e43672b..594c050 100644
--- a/bp2build/cc_library_headers_conversion_test.go
+++ b/bp2build/cc_library_headers_conversion_test.go
@@ -78,10 +78,9 @@
func TestCcLibraryHeadersSimple(t *testing.T) {
runCcLibraryHeadersTestCase(t, bp2buildTestCase{
- description: "cc_library_headers test",
- moduleTypeUnderTest: "cc_library_headers",
- moduleTypeUnderTestFactory: cc.LibraryHeaderFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryHeadersBp2Build,
+ description: "cc_library_headers test",
+ moduleTypeUnderTest: "cc_library_headers",
+ moduleTypeUnderTestFactory: cc.LibraryHeaderFactory,
filesystem: map[string]string{
"lib-1/lib1a.h": "",
"lib-1/lib1b.h": "",
@@ -128,9 +127,9 @@
// TODO: Also support export_header_lib_headers
}`,
- expectedBazelTargets: []string{`cc_library_headers(
- name = "foo_headers",
- export_includes = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_headers", "foo_headers", attrNameToString{
+ "export_includes": `[
"dir-1",
"dir-2",
] + select({
@@ -138,22 +137,22 @@
"//build/bazel/platforms/arch:x86": ["arch_x86_exported_include_dir"],
"//build/bazel/platforms/arch:x86_64": ["arch_x86_64_exported_include_dir"],
"//conditions:default": [],
- }),
- implementation_deps = [
+ })`,
+ "implementation_deps": `[
":lib-1",
":lib-2",
- ],
-)`},
+ ]`,
+ }),
+ },
})
}
func TestCcLibraryHeadersOsSpecificHeader(t *testing.T) {
runCcLibraryHeadersTestCase(t, bp2buildTestCase{
- description: "cc_library_headers test with os-specific header_libs props",
- moduleTypeUnderTest: "cc_library_headers",
- moduleTypeUnderTestFactory: cc.LibraryHeaderFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryHeadersBp2Build,
- filesystem: map[string]string{},
+ description: "cc_library_headers test with os-specific header_libs props",
+ moduleTypeUnderTest: "cc_library_headers",
+ moduleTypeUnderTestFactory: cc.LibraryHeaderFactory,
+ filesystem: map[string]string{},
blueprint: soongCcLibraryPreamble + `
cc_library_headers {
name: "android-lib",
@@ -191,27 +190,27 @@
},
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_headers(
- name = "foo_headers",
- implementation_deps = [":base-lib"] + select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_headers", "foo_headers", attrNameToString{
+ "implementation_deps": `[":base-lib"] + select({
"//build/bazel/platforms/os:android": [":android-lib"],
"//build/bazel/platforms/os:darwin": [":darwin-lib"],
"//build/bazel/platforms/os:linux": [":linux-lib"],
"//build/bazel/platforms/os:linux_bionic": [":linux_bionic-lib"],
"//build/bazel/platforms/os:windows": [":windows-lib"],
"//conditions:default": [],
- }),
-)`},
+ })`,
+ }),
+ },
})
}
func TestCcLibraryHeadersOsSpecficHeaderLibsExportHeaderLibHeaders(t *testing.T) {
runCcLibraryHeadersTestCase(t, bp2buildTestCase{
- description: "cc_library_headers test with os-specific header_libs and export_header_lib_headers props",
- moduleTypeUnderTest: "cc_library_headers",
- moduleTypeUnderTestFactory: cc.LibraryHeaderFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryHeadersBp2Build,
- filesystem: map[string]string{},
+ description: "cc_library_headers test with os-specific header_libs and export_header_lib_headers props",
+ moduleTypeUnderTest: "cc_library_headers",
+ moduleTypeUnderTestFactory: cc.LibraryHeaderFactory,
+ filesystem: map[string]string{},
blueprint: soongCcLibraryPreamble + `
cc_library_headers {
name: "android-lib",
@@ -231,27 +230,27 @@
},
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_headers(
- name = "foo_headers",
- deps = select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_headers", "foo_headers", attrNameToString{
+ "deps": `select({
"//build/bazel/platforms/os:android": [":exported-lib"],
"//conditions:default": [],
- }),
- implementation_deps = select({
+ })`,
+ "implementation_deps": `select({
"//build/bazel/platforms/os:android": [":android-lib"],
"//conditions:default": [],
- }),
-)`},
+ })`,
+ }),
+ },
})
}
func TestCcLibraryHeadersArchAndTargetExportSystemIncludes(t *testing.T) {
runCcLibraryHeadersTestCase(t, bp2buildTestCase{
- description: "cc_library_headers test with arch-specific and target-specific export_system_include_dirs props",
- moduleTypeUnderTest: "cc_library_headers",
- moduleTypeUnderTestFactory: cc.LibraryHeaderFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryHeadersBp2Build,
- filesystem: map[string]string{},
+ description: "cc_library_headers test with arch-specific and target-specific export_system_include_dirs props",
+ moduleTypeUnderTest: "cc_library_headers",
+ moduleTypeUnderTestFactory: cc.LibraryHeaderFactory,
+ filesystem: map[string]string{},
blueprint: soongCcLibraryPreamble + `cc_library_headers {
name: "foo_headers",
export_system_include_dirs: [
@@ -288,9 +287,9 @@
},
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_headers(
- name = "foo_headers",
- export_system_includes = ["shared_include_dir"] + select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_headers", "foo_headers", attrNameToString{
+ "export_system_includes": `["shared_include_dir"] + select({
"//build/bazel/platforms/arch:arm": ["arm_include_dir"],
"//build/bazel/platforms/arch:x86_64": ["x86_64_include_dir"],
"//conditions:default": [],
@@ -299,17 +298,17 @@
"//build/bazel/platforms/os:darwin": ["darwin_include_dir"],
"//build/bazel/platforms/os:linux": ["linux_include_dir"],
"//conditions:default": [],
- }),
-)`},
+ })`,
+ }),
+ },
})
}
func TestCcLibraryHeadersNoCrtIgnored(t *testing.T) {
runCcLibraryHeadersTestCase(t, bp2buildTestCase{
- description: "cc_library_headers test",
- moduleTypeUnderTest: "cc_library_headers",
- moduleTypeUnderTestFactory: cc.LibraryHeaderFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryHeadersBp2Build,
+ description: "cc_library_headers test",
+ moduleTypeUnderTest: "cc_library_headers",
+ moduleTypeUnderTestFactory: cc.LibraryHeaderFactory,
filesystem: map[string]string{
"lib-1/lib1a.h": "",
"lib-1/lib1b.h": "",
@@ -330,9 +329,10 @@
no_libcrt: true,
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_headers(
- name = "lib-1",
- export_includes = ["lib-1"],
-)`},
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_headers", "lib-1", attrNameToString{
+ "export_includes": `["lib-1"]`,
+ }),
+ },
})
}
diff --git a/bp2build/cc_library_shared_conversion_test.go b/bp2build/cc_library_shared_conversion_test.go
index bb15776..97a600a 100644
--- a/bp2build/cc_library_shared_conversion_test.go
+++ b/bp2build/cc_library_shared_conversion_test.go
@@ -33,19 +33,19 @@
ctx.RegisterModuleType("toolchain_library", cc.ToolchainLibraryFactory)
ctx.RegisterModuleType("cc_library_headers", cc.LibraryHeaderFactory)
ctx.RegisterModuleType("cc_library_static", cc.LibraryStaticFactory)
+ ctx.RegisterModuleType("cc_library", cc.LibraryFactory)
}
func runCcLibrarySharedTestCase(t *testing.T, tc bp2buildTestCase) {
t.Helper()
+ (&tc).moduleTypeUnderTest = "cc_library_shared"
+ (&tc).moduleTypeUnderTestFactory = cc.LibrarySharedFactory
runBp2BuildTestCase(t, registerCcLibrarySharedModuleTypes, tc)
}
func TestCcLibrarySharedSimple(t *testing.T) {
runCcLibrarySharedTestCase(t, bp2buildTestCase{
- description: "cc_library_shared simple overall test",
- moduleTypeUnderTest: "cc_library_shared",
- moduleTypeUnderTestFactory: cc.LibrarySharedFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibrarySharedBp2Build,
+ description: "cc_library_shared simple overall test",
filesystem: map[string]string{
// NOTE: include_dir headers *should not* appear in Bazel hdrs later (?)
"include_dir_1/include_dir_1_a.h": "",
@@ -140,52 +140,50 @@
// TODO: Also support export_header_lib_headers
}`,
- expectedBazelTargets: []string{`cc_library_shared(
- name = "foo_shared",
- absolute_includes = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_shared", "foo_shared", attrNameToString{
+ "absolute_includes": `[
"include_dir_1",
"include_dir_2",
- ],
- copts = [
+ ]`,
+ "copts": `[
"-Dflag1",
"-Dflag2",
- ],
- export_includes = [
+ ]`,
+ "export_includes": `[
"export_include_dir_1",
"export_include_dir_2",
- ],
- implementation_deps = [
+ ]`,
+ "implementation_deps": `[
":header_lib_1",
":header_lib_2",
- ],
- implementation_dynamic_deps = [
+ ]`,
+ "implementation_dynamic_deps": `[
":shared_lib_1",
":shared_lib_2",
- ],
- local_includes = [
+ ]`,
+ "local_includes": `[
"local_include_dir_1",
"local_include_dir_2",
".",
- ],
- srcs = [
+ ]`,
+ "srcs": `[
"foo_shared1.cc",
"foo_shared2.cc",
- ],
- whole_archive_deps = [
+ ]`,
+ "whole_archive_deps": `[
":whole_static_lib_1",
":whole_static_lib_2",
- ],
-)`},
+ ]`,
+ }),
+ },
})
}
func TestCcLibrarySharedArchSpecificSharedLib(t *testing.T) {
runCcLibrarySharedTestCase(t, bp2buildTestCase{
- description: "cc_library_shared arch-specific shared_libs with whole_static_libs",
- moduleTypeUnderTest: "cc_library_shared",
- moduleTypeUnderTestFactory: cc.LibrarySharedFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibrarySharedBp2Build,
- filesystem: map[string]string{},
+ description: "cc_library_shared arch-specific shared_libs with whole_static_libs",
+ filesystem: map[string]string{},
blueprint: soongCcLibrarySharedPreamble + `
cc_library_static {
name: "static_dep",
@@ -200,27 +198,25 @@
arch: { arm64: { shared_libs: ["shared_dep"], whole_static_libs: ["static_dep"] } },
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_shared(
- name = "foo_shared",
- implementation_dynamic_deps = select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_shared", "foo_shared", attrNameToString{
+ "implementation_dynamic_deps": `select({
"//build/bazel/platforms/arch:arm64": [":shared_dep"],
"//conditions:default": [],
- }),
- whole_archive_deps = select({
+ })`,
+ "whole_archive_deps": `select({
"//build/bazel/platforms/arch:arm64": [":static_dep"],
"//conditions:default": [],
- }),
-)`},
+ })`,
+ }),
+ },
})
}
func TestCcLibrarySharedOsSpecificSharedLib(t *testing.T) {
- runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_shared os-specific shared_libs",
- moduleTypeUnderTest: "cc_library_shared",
- moduleTypeUnderTestFactory: cc.LibrarySharedFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibrarySharedBp2Build,
- filesystem: map[string]string{},
+ runCcLibrarySharedTestCase(t, bp2buildTestCase{
+ description: "cc_library_shared os-specific shared_libs",
+ filesystem: map[string]string{},
blueprint: soongCcLibrarySharedPreamble + `
cc_library_shared {
name: "shared_dep",
@@ -231,23 +227,21 @@
target: { android: { shared_libs: ["shared_dep"], } },
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_shared(
- name = "foo_shared",
- implementation_dynamic_deps = select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_shared", "foo_shared", attrNameToString{
+ "implementation_dynamic_deps": `select({
"//build/bazel/platforms/os:android": [":shared_dep"],
"//conditions:default": [],
- }),
-)`},
+ })`,
+ }),
+ },
})
}
func TestCcLibrarySharedBaseArchOsSpecificSharedLib(t *testing.T) {
runCcLibrarySharedTestCase(t, bp2buildTestCase{
- description: "cc_library_shared base, arch, and os-specific shared_libs",
- moduleTypeUnderTest: "cc_library_shared",
- moduleTypeUnderTestFactory: cc.LibrarySharedFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibrarySharedBp2Build,
- filesystem: map[string]string{},
+ description: "cc_library_shared base, arch, and os-specific shared_libs",
+ filesystem: map[string]string{},
blueprint: soongCcLibrarySharedPreamble + `
cc_library_shared {
name: "shared_dep",
@@ -268,25 +262,23 @@
arch: { arm64: { shared_libs: ["shared_dep3"] } },
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_shared(
- name = "foo_shared",
- implementation_dynamic_deps = [":shared_dep"] + select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_shared", "foo_shared", attrNameToString{
+ "implementation_dynamic_deps": `[":shared_dep"] + select({
"//build/bazel/platforms/arch:arm64": [":shared_dep3"],
"//conditions:default": [],
}) + select({
"//build/bazel/platforms/os:android": [":shared_dep2"],
"//conditions:default": [],
- }),
-)`},
+ })`,
+ }),
+ },
})
}
func TestCcLibrarySharedSimpleExcludeSrcs(t *testing.T) {
runCcLibrarySharedTestCase(t, bp2buildTestCase{
- description: "cc_library_shared simple exclude_srcs",
- moduleTypeUnderTest: "cc_library_shared",
- moduleTypeUnderTestFactory: cc.LibrarySharedFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibrarySharedBp2Build,
+ description: "cc_library_shared simple exclude_srcs",
filesystem: map[string]string{
"common.c": "",
"foo-a.c": "",
@@ -299,23 +291,21 @@
exclude_srcs: ["foo-excluded.c"],
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_shared(
- name = "foo_shared",
- srcs_c = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_shared", "foo_shared", attrNameToString{
+ "srcs_c": `[
"common.c",
"foo-a.c",
- ],
-)`},
+ ]`,
+ }),
+ },
})
}
func TestCcLibrarySharedStrip(t *testing.T) {
runCcLibrarySharedTestCase(t, bp2buildTestCase{
- description: "cc_library_shared stripping",
- moduleTypeUnderTest: "cc_library_shared",
- moduleTypeUnderTestFactory: cc.LibrarySharedFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibrarySharedBp2Build,
- filesystem: map[string]string{},
+ description: "cc_library_shared stripping",
+ filesystem: map[string]string{},
blueprint: soongCcLibrarySharedPreamble + `
cc_library_shared {
name: "foo_shared",
@@ -328,9 +318,9 @@
},
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_shared(
- name = "foo_shared",
- strip = {
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_shared", "foo_shared", attrNameToString{
+ "strip": `{
"all": True,
"keep_symbols": False,
"keep_symbols_and_debug_frame": True,
@@ -339,17 +329,15 @@
"sym2",
],
"none": False,
- },
-)`},
+ }`,
+ }),
+ },
})
}
func TestCcLibrarySharedVersionScript(t *testing.T) {
runCcLibrarySharedTestCase(t, bp2buildTestCase{
- description: "cc_library_shared version script",
- moduleTypeUnderTest: "cc_library_shared",
- moduleTypeUnderTestFactory: cc.LibrarySharedFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibrarySharedBp2Build,
+ description: "cc_library_shared version script",
filesystem: map[string]string{
"version_script": "",
},
@@ -359,20 +347,18 @@
version_script: "version_script",
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_shared(
- name = "foo_shared",
- additional_linker_inputs = ["version_script"],
- linkopts = ["-Wl,--version-script,$(location version_script)"],
-)`},
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_shared", "foo_shared", attrNameToString{
+ "additional_linker_inputs": `["version_script"]`,
+ "linkopts": `["-Wl,--version-script,$(location version_script)"]`,
+ }),
+ },
})
}
func TestCcLibrarySharedNoCrtTrue(t *testing.T) {
runCcLibrarySharedTestCase(t, bp2buildTestCase{
- description: "cc_library_shared - nocrt: true emits attribute",
- moduleTypeUnderTest: "cc_library_shared",
- moduleTypeUnderTestFactory: cc.LibrarySharedFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibrarySharedBp2Build,
+ description: "cc_library_shared - nocrt: true emits attribute",
filesystem: map[string]string{
"impl.cpp": "",
},
@@ -384,19 +370,18 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library_shared(
- name = "foo_shared",
- link_crt = False,
- srcs = ["impl.cpp"],
-)`}})
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_shared", "foo_shared", attrNameToString{
+ "link_crt": `False`,
+ "srcs": `["impl.cpp"]`,
+ }),
+ },
+ })
}
func TestCcLibrarySharedNoCrtFalse(t *testing.T) {
runCcLibrarySharedTestCase(t, bp2buildTestCase{
- description: "cc_library_shared - nocrt: false doesn't emit attribute",
- moduleTypeUnderTest: "cc_library_shared",
- moduleTypeUnderTestFactory: cc.LibrarySharedFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibrarySharedBp2Build,
+ description: "cc_library_shared - nocrt: false doesn't emit attribute",
filesystem: map[string]string{
"impl.cpp": "",
},
@@ -408,18 +393,17 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library_shared(
- name = "foo_shared",
- srcs = ["impl.cpp"],
-)`}})
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_shared", "foo_shared", attrNameToString{
+ "srcs": `["impl.cpp"]`,
+ }),
+ },
+ })
}
func TestCcLibrarySharedNoCrtArchVariant(t *testing.T) {
runCcLibrarySharedTestCase(t, bp2buildTestCase{
- description: "cc_library_shared - nocrt in select",
- moduleTypeUnderTest: "cc_library_shared",
- moduleTypeUnderTestFactory: cc.LibrarySharedFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibrarySharedBp2Build,
+ description: "cc_library_shared - nocrt in select",
filesystem: map[string]string{
"impl.cpp": "",
},
@@ -441,3 +425,42 @@
expectedErr: fmt.Errorf("Android.bp:16:1: module \"foo_shared\": nocrt is not supported for arch variants"),
})
}
+
+func TestCcLibrarySharedProto(t *testing.T) {
+ runCcLibrarySharedTestCase(t, bp2buildTestCase{
+ blueprint: soongCcProtoPreamble + `cc_library_shared {
+ name: "foo",
+ srcs: ["foo.proto"],
+ proto: {
+ canonical_path_from_root: false,
+ export_proto_headers: true,
+ },
+ include_build_directory: false,
+}`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("proto_library", "foo_proto", attrNameToString{
+ "srcs": `["foo.proto"]`,
+ }), makeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", attrNameToString{
+ "deps": `[":foo_proto"]`,
+ }), makeBazelTarget("cc_library_shared", "foo", attrNameToString{
+ "dynamic_deps": `[":libprotobuf-cpp-lite"]`,
+ "whole_archive_deps": `[":foo_cc_proto_lite"]`,
+ }),
+ },
+ })
+}
+
+func TestCcLibrarySharedUseVersionLib(t *testing.T) {
+ runCcLibrarySharedTestCase(t, bp2buildTestCase{
+ blueprint: soongCcProtoPreamble + `cc_library_shared {
+ name: "foo",
+ use_version_lib: true,
+ include_build_directory: false,
+}`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_shared", "foo", attrNameToString{
+ "use_version_lib": "True",
+ }),
+ },
+ })
+}
diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go
index 9887811..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) {
@@ -79,15 +78,15 @@
func runCcLibraryStaticTestCase(t *testing.T, tc bp2buildTestCase) {
t.Helper()
+
+ (&tc).moduleTypeUnderTest = "cc_library_static"
+ (&tc).moduleTypeUnderTestFactory = cc.LibraryStaticFactory
runBp2BuildTestCase(t, registerCcLibraryStaticModuleTypes, tc)
}
func TestCcLibraryStaticSimple(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static test",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static test",
filesystem: map[string]string{
// NOTE: include_dir headers *should not* appear in Bazel hdrs later (?)
"include_dir_1/include_dir_1_a.h": "",
@@ -182,49 +181,47 @@
// TODO: Also support export_header_lib_headers
}`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- absolute_includes = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "absolute_includes": `[
"include_dir_1",
"include_dir_2",
- ],
- copts = [
+ ]`,
+ "copts": `[
"-Dflag1",
"-Dflag2",
- ],
- export_includes = [
+ ]`,
+ "export_includes": `[
"export_include_dir_1",
"export_include_dir_2",
- ],
- implementation_deps = [
+ ]`,
+ "implementation_deps": `[
":header_lib_1",
":header_lib_2",
":static_lib_1",
":static_lib_2",
- ],
- local_includes = [
+ ]`,
+ "local_includes": `[
"local_include_dir_1",
"local_include_dir_2",
".",
- ],
- srcs = [
+ ]`,
+ "srcs": `[
"foo_static1.cc",
"foo_static2.cc",
- ],
- whole_archive_deps = [
+ ]`,
+ "whole_archive_deps": `[
":whole_static_lib_1",
":whole_static_lib_2",
- ],
-)`},
+ ]`,
+ }),
+ },
})
}
func TestCcLibraryStaticSubpackage(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static subpackage test",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static subpackage test",
filesystem: map[string]string{
// subpackage with subdirectory
"subpackage/Android.bp": "",
@@ -247,20 +244,18 @@
"subpackage",
],
}`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- absolute_includes = ["subpackage"],
- local_includes = ["."],
-)`},
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "absolute_includes": `["subpackage"]`,
+ "local_includes": `["."]`,
+ }),
+ },
})
}
func TestCcLibraryStaticExportIncludeDir(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static export include dir",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static export include dir",
filesystem: map[string]string{
// subpackage with subdirectory
"subpackage/Android.bp": "",
@@ -273,19 +268,17 @@
export_include_dirs: ["subpackage"],
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- export_includes = ["subpackage"],
-)`},
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "export_includes": `["subpackage"]`,
+ }),
+ },
})
}
func TestCcLibraryStaticExportSystemIncludeDir(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static export system include dir",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static export system include dir",
filesystem: map[string]string{
// subpackage with subdirectory
"subpackage/Android.bp": "",
@@ -298,20 +291,18 @@
export_system_include_dirs: ["subpackage"],
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- export_system_includes = ["subpackage"],
-)`},
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "export_system_includes": `["subpackage"]`,
+ }),
+ },
})
}
func TestCcLibraryStaticManyIncludeDirs(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static include_dirs, local_include_dirs, export_include_dirs (b/183742505)",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- dir: "subpackage",
+ description: "cc_library_static include_dirs, local_include_dirs, export_include_dirs (b/183742505)",
+ dir: "subpackage",
filesystem: map[string]string{
// subpackage with subdirectory
"subpackage/Android.bp": `
@@ -335,28 +326,25 @@
"subpackage3/subsubpackage/header.h": "",
},
blueprint: soongCcLibraryStaticPreamble,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- absolute_includes = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "absolute_includes": `[
"subpackage/subsubpackage",
"subpackage2",
"subpackage3/subsubpackage",
- ],
- export_includes = ["./exported_subsubpackage"],
- local_includes = [
+ ]`,
+ "export_includes": `["./exported_subsubpackage"]`,
+ "local_includes": `[
"subsubpackage2",
".",
- ],
-)`},
+ ]`,
+ })},
})
}
func TestCcLibraryStaticIncludeBuildDirectoryDisabled(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static include_build_directory disabled",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static include_build_directory disabled",
filesystem: map[string]string{
// subpackage with subdirectory
"subpackage/Android.bp": "",
@@ -370,20 +358,18 @@
local_include_dirs: ["subpackage2"],
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- absolute_includes = ["subpackage"],
- local_includes = ["subpackage2"],
-)`},
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "absolute_includes": `["subpackage"]`,
+ "local_includes": `["subpackage2"]`,
+ }),
+ },
})
}
func TestCcLibraryStaticIncludeBuildDirectoryEnabled(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static include_build_directory enabled",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static include_build_directory enabled",
filesystem: map[string]string{
// subpackage with subdirectory
"subpackage/Android.bp": "",
@@ -399,24 +385,22 @@
local_include_dirs: ["subpackage2"],
include_build_directory: true,
}`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- absolute_includes = ["subpackage"],
- local_includes = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "absolute_includes": `["subpackage"]`,
+ "local_includes": `[
"subpackage2",
".",
- ],
-)`},
+ ]`,
+ }),
+ },
})
}
func TestCcLibraryStaticArchSpecificStaticLib(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static arch-specific static_libs",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- filesystem: map[string]string{},
+ description: "cc_library_static arch-specific static_libs",
+ filesystem: map[string]string{},
blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "static_dep",
@@ -431,27 +415,25 @@
arch: { arm64: { static_libs: ["static_dep"], whole_static_libs: ["static_dep2"] } },
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- implementation_deps = select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "implementation_deps": `select({
"//build/bazel/platforms/arch:arm64": [":static_dep"],
"//conditions:default": [],
- }),
- whole_archive_deps = select({
+ })`,
+ "whole_archive_deps": `select({
"//build/bazel/platforms/arch:arm64": [":static_dep2"],
"//conditions:default": [],
- }),
-)`},
+ })`,
+ }),
+ },
})
}
func TestCcLibraryStaticOsSpecificStaticLib(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static os-specific static_libs",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- filesystem: map[string]string{},
+ description: "cc_library_static os-specific static_libs",
+ filesystem: map[string]string{},
blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "static_dep",
@@ -466,27 +448,25 @@
target: { android: { static_libs: ["static_dep"], whole_static_libs: ["static_dep2"] } },
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- implementation_deps = select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "implementation_deps": `select({
"//build/bazel/platforms/os:android": [":static_dep"],
"//conditions:default": [],
- }),
- whole_archive_deps = select({
+ })`,
+ "whole_archive_deps": `select({
"//build/bazel/platforms/os:android": [":static_dep2"],
"//conditions:default": [],
- }),
-)`},
+ })`,
+ }),
+ },
})
}
func TestCcLibraryStaticBaseArchOsSpecificStaticLib(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static base, arch and os-specific static_libs",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- filesystem: map[string]string{},
+ description: "cc_library_static base, arch and os-specific static_libs",
+ filesystem: map[string]string{},
blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "static_dep",
@@ -512,26 +492,24 @@
arch: { arm64: { static_libs: ["static_dep4"] } },
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- implementation_deps = [":static_dep"] + select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "implementation_deps": `[":static_dep"] + select({
"//build/bazel/platforms/arch:arm64": [":static_dep4"],
"//conditions:default": [],
}) + select({
"//build/bazel/platforms/os:android": [":static_dep3"],
"//conditions:default": [],
- }),
- whole_archive_deps = [":static_dep2"],
-)`},
+ })`,
+ "whole_archive_deps": `[":static_dep2"]`,
+ }),
+ },
})
}
func TestCcLibraryStaticSimpleExcludeSrcs(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static simple exclude_srcs",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static simple exclude_srcs",
filesystem: map[string]string{
"common.c": "",
"foo-a.c": "",
@@ -544,22 +522,20 @@
exclude_srcs: ["foo-excluded.c"],
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- srcs_c = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "srcs_c": `[
"common.c",
"foo-a.c",
- ],
-)`},
+ ]`,
+ }),
+ },
})
}
func TestCcLibraryStaticOneArchSrcs(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static one arch specific srcs",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static one arch specific srcs",
filesystem: map[string]string{
"common.c": "",
"foo-arm.c": "",
@@ -571,22 +547,20 @@
arch: { arm: { srcs: ["foo-arm.c"] } },
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- srcs_c = ["common.c"] + select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "srcs_c": `["common.c"] + select({
"//build/bazel/platforms/arch:arm": ["foo-arm.c"],
"//conditions:default": [],
- }),
-)`},
+ })`,
+ }),
+ },
})
}
func TestCcLibraryStaticOneArchSrcsExcludeSrcs(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static one arch specific srcs and exclude_srcs",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static one arch specific srcs and exclude_srcs",
filesystem: map[string]string{
"common.c": "",
"for-arm.c": "",
@@ -603,22 +577,20 @@
},
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- srcs_c = ["common.c"] + select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "srcs_c": `["common.c"] + select({
"//build/bazel/platforms/arch:arm": ["for-arm.c"],
"//conditions:default": ["not-for-arm.c"],
- }),
-)`},
+ })`,
+ }),
+ },
})
}
func TestCcLibraryStaticTwoArchExcludeSrcs(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static arch specific exclude_srcs for 2 architectures",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static arch specific exclude_srcs for 2 architectures",
filesystem: map[string]string{
"common.c": "",
"for-arm.c": "",
@@ -637,9 +609,9 @@
},
include_build_directory: false,
} `,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- srcs_c = ["common.c"] + select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "srcs_c": `["common.c"] + select({
"//build/bazel/platforms/arch:arm": [
"not-for-x86.c",
"for-arm.c",
@@ -652,16 +624,15 @@
"not-for-arm.c",
"not-for-x86.c",
],
- }),
-)`},
+ })`,
+ }),
+ },
})
}
+
func TestCcLibraryStaticFourArchExcludeSrcs(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static arch specific exclude_srcs for 4 architectures",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static arch specific exclude_srcs for 4 architectures",
filesystem: map[string]string{
"common.c": "",
"for-arm.c": "",
@@ -687,9 +658,9 @@
},
include_build_directory: false,
} `,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- srcs_c = ["common.c"] + select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "srcs_c": `["common.c"] + select({
"//build/bazel/platforms/arch:arm": [
"not-for-arm64.c",
"not-for-x86.c",
@@ -720,17 +691,15 @@
"not-for-x86.c",
"not-for-x86_64.c",
],
- }),
-)`},
+ })`,
+ }),
+ },
})
}
func TestCcLibraryStaticOneArchEmpty(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static one arch empty",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static one arch empty",
filesystem: map[string]string{
"common.cc": "",
"foo-no-arm.cc": "",
@@ -746,22 +715,20 @@
},
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- srcs = ["common.cc"] + select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "srcs": `["common.cc"] + select({
"//build/bazel/platforms/arch:arm": [],
"//conditions:default": ["foo-no-arm.cc"],
- }),
-)`},
+ })`,
+ }),
+ },
})
}
func TestCcLibraryStaticOneArchEmptyOtherSet(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static one arch empty other set",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static one arch empty other set",
filesystem: map[string]string{
"common.cc": "",
"foo-no-arm.cc": "",
@@ -779,27 +746,25 @@
},
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- srcs = ["common.cc"] + select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "srcs": `["common.cc"] + select({
"//build/bazel/platforms/arch:arm": [],
"//build/bazel/platforms/arch:x86": [
"foo-no-arm.cc",
"x86-only.cc",
],
"//conditions:default": ["foo-no-arm.cc"],
- }),
-)`},
+ })`,
+ }),
+ },
})
}
func TestCcLibraryStaticMultipleDepSameName(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static multiple dep same name panic",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- filesystem: map[string]string{},
+ description: "cc_library_static multiple dep same name panic",
+ filesystem: map[string]string{},
blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "static_dep",
@@ -810,19 +775,17 @@
static_libs: ["static_dep", "static_dep"],
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- implementation_deps = [":static_dep"],
-)`},
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "implementation_deps": `[":static_dep"]`,
+ }),
+ },
})
}
func TestCcLibraryStaticOneMultilibSrcsExcludeSrcs(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static 1 multilib srcs and exclude_srcs",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static 1 multilib srcs and exclude_srcs",
filesystem: map[string]string{
"common.c": "",
"for-lib32.c": "",
@@ -837,23 +800,21 @@
},
include_build_directory: false,
} `,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- srcs_c = ["common.c"] + select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "srcs_c": `["common.c"] + select({
"//build/bazel/platforms/arch:arm": ["for-lib32.c"],
"//build/bazel/platforms/arch:x86": ["for-lib32.c"],
"//conditions:default": ["not-for-lib32.c"],
- }),
-)`},
+ })`,
+ }),
+ },
})
}
func TestCcLibraryStaticTwoMultilibSrcsExcludeSrcs(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static 2 multilib srcs and exclude_srcs",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static 2 multilib srcs and exclude_srcs",
filesystem: map[string]string{
"common.c": "",
"for-lib32.c": "",
@@ -863,7 +824,7 @@
},
blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
- name: "foo_static2",
+ name: "foo_static",
srcs: ["common.c", "not-for-*.c"],
multilib: {
lib32: { srcs: ["for-lib32.c"], exclude_srcs: ["not-for-lib32.c"] },
@@ -871,9 +832,9 @@
},
include_build_directory: false,
} `,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static2",
- srcs_c = ["common.c"] + select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "srcs_c": `["common.c"] + select({
"//build/bazel/platforms/arch:arm": [
"not-for-lib64.c",
"for-lib32.c",
@@ -894,17 +855,15 @@
"not-for-lib32.c",
"not-for-lib64.c",
],
- }),
-)`},
+ })`,
+ }),
+ },
})
}
func TestCcLibrarySTaticArchMultilibSrcsExcludeSrcs(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static arch and multilib srcs and exclude_srcs",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static arch and multilib srcs and exclude_srcs",
filesystem: map[string]string{
"common.c": "",
"for-arm.c": "",
@@ -923,7 +882,7 @@
},
blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
- name: "foo_static3",
+ name: "foo_static",
srcs: ["common.c", "not-for-*.c"],
exclude_srcs: ["not-for-everything.c"],
arch: {
@@ -938,9 +897,9 @@
},
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static3",
- srcs_c = ["common.c"] + select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "srcs_c": `["common.c"] + select({
"//build/bazel/platforms/arch:arm": [
"not-for-arm64.c",
"not-for-lib64.c",
@@ -981,25 +940,25 @@
"not-for-x86.c",
"not-for-x86_64.c",
],
- }),
-)`},
+ })`,
+ }),
+ },
})
}
func TestCcLibraryStaticGeneratedHeadersAllPartitions(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
blueprint: soongCcLibraryStaticPreamble + `
genrule {
name: "generated_hdr",
cmd: "nothing to see here",
+ bazel_module: { bp2build_available: false },
}
genrule {
name: "export_generated_hdr",
cmd: "nothing to see here",
+ bazel_module: { bp2build_available: false },
}
cc_library_static {
@@ -1009,137 +968,109 @@
export_generated_headers: ["export_generated_hdr"],
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- hdrs = [":export_generated_hdr"],
- srcs = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "export_includes": `["."]`,
+ "local_includes": `["."]`,
+ "hdrs": `[":export_generated_hdr"]`,
+ "srcs": `[
"cpp_src.cpp",
":generated_hdr",
- ],
- srcs_as = [
+ ]`,
+ "srcs_as": `[
"as_src.S",
":generated_hdr",
- ],
- srcs_c = [
+ ]`,
+ "srcs_c": `[
"c_src.c",
":generated_hdr",
- ],
-)`},
+ ]`,
+ }),
+ },
})
}
func TestCcLibraryStaticArchSrcsExcludeSrcsGeneratedFiles(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static arch srcs/exclude_srcs with generated files",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static arch srcs/exclude_srcs with generated files",
filesystem: map[string]string{
"common.cpp": "",
"for-x86.cpp": "",
"not-for-x86.cpp": "",
"not-for-everything.cpp": "",
- "dep/Android.bp": `
-genrule {
- name: "generated_src_other_pkg",
- cmd: "nothing to see here",
-}
-
-genrule {
- name: "generated_hdr_other_pkg",
- cmd: "nothing to see here",
-}
-
-genrule {
- name: "generated_hdr_other_pkg_x86",
- cmd: "nothing to see here",
-}
-
-genrule {
- name: "generated_hdr_other_pkg_android",
- cmd: "nothing to see here",
-}`,
+ "dep/Android.bp": simpleModuleDoNotConvertBp2build("genrule", "generated_src_other_pkg") +
+ simpleModuleDoNotConvertBp2build("genrule", "generated_hdr_other_pkg") +
+ simpleModuleDoNotConvertBp2build("genrule", "generated_src_other_pkg_x86") +
+ simpleModuleDoNotConvertBp2build("genrule", "generated_hdr_other_pkg_x86") +
+ simpleModuleDoNotConvertBp2build("genrule", "generated_hdr_other_pkg_android"),
},
- blueprint: soongCcLibraryStaticPreamble + `
-genrule {
- name: "generated_src",
- cmd: "nothing to see here",
-}
-
-genrule {
- name: "generated_src_not_x86",
- cmd: "nothing to see here",
-}
-
-genrule {
- name: "generated_src_android",
- cmd: "nothing to see here",
-}
-
-genrule {
- name: "generated_hdr",
- cmd: "nothing to see here",
-}
-
+ blueprint: soongCcLibraryStaticPreamble +
+ simpleModuleDoNotConvertBp2build("genrule", "generated_src") +
+ simpleModuleDoNotConvertBp2build("genrule", "generated_src_not_x86") +
+ simpleModuleDoNotConvertBp2build("genrule", "generated_src_android") +
+ simpleModuleDoNotConvertBp2build("genrule", "generated_hdr") + `
cc_library_static {
- name: "foo_static3",
+ name: "foo_static",
srcs: ["common.cpp", "not-for-*.cpp"],
exclude_srcs: ["not-for-everything.cpp"],
generated_sources: ["generated_src", "generated_src_other_pkg", "generated_src_not_x86"],
generated_headers: ["generated_hdr", "generated_hdr_other_pkg"],
+ export_generated_headers: ["generated_hdr_other_pkg"],
arch: {
x86: {
srcs: ["for-x86.cpp"],
exclude_srcs: ["not-for-x86.cpp"],
generated_headers: ["generated_hdr_other_pkg_x86"],
exclude_generated_sources: ["generated_src_not_x86"],
+ export_generated_headers: ["generated_hdr_other_pkg_x86"],
},
},
target: {
android: {
generated_sources: ["generated_src_android"],
generated_headers: ["generated_hdr_other_pkg_android"],
+ export_generated_headers: ["generated_hdr_other_pkg_android"],
},
},
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static3",
- srcs = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "srcs": `[
"common.cpp",
":generated_src",
"//dep:generated_src_other_pkg",
":generated_hdr",
- "//dep:generated_hdr_other_pkg",
] + select({
- "//build/bazel/platforms/arch:x86": [
- "for-x86.cpp",
- "//dep:generated_hdr_other_pkg_x86",
- ],
+ "//build/bazel/platforms/arch:x86": ["for-x86.cpp"],
"//conditions:default": [
"not-for-x86.cpp",
":generated_src_not_x86",
],
}) + select({
- "//build/bazel/platforms/os:android": [
- ":generated_src_android",
- "//dep:generated_hdr_other_pkg_android",
- ],
+ "//build/bazel/platforms/os:android": [":generated_src_android"],
"//conditions:default": [],
- }),
-)`},
+ })`,
+ "hdrs": `["//dep:generated_hdr_other_pkg"] + select({
+ "//build/bazel/platforms/arch:x86": ["//dep:generated_hdr_other_pkg_x86"],
+ "//conditions:default": [],
+ }) + select({
+ "//build/bazel/platforms/os:android": ["//dep:generated_hdr_other_pkg_android"],
+ "//conditions:default": [],
+ })`,
+ "local_includes": `["."]`,
+ "export_absolute_includes": `["dep"]`,
+ }),
+ },
})
}
func TestCcLibraryStaticGetTargetProperties(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static complex GetTargetProperties",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static complex GetTargetProperties",
blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
@@ -1168,9 +1099,9 @@
},
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- srcs_c = select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "srcs_c": `select({
"//build/bazel/platforms/os:android": ["android_src.c"],
"//conditions:default": [],
}) + select({
@@ -1181,17 +1112,15 @@
"//build/bazel/platforms/os_arch:linux_bionic_arm64": ["linux_bionic_arm64_src.c"],
"//build/bazel/platforms/os_arch:linux_bionic_x86_64": ["linux_bionic_x86_64_src.c"],
"//conditions:default": [],
- }),
-)`},
+ })`,
+ }),
+ },
})
}
func TestCcLibraryStaticProductVariableSelects(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static product variable selects",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static product variable selects",
blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
@@ -1209,9 +1138,9 @@
},
include_build_directory: false,
} `,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- copts = select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "copts": `select({
"//build/bazel/product_variables:binder32bit": ["-Wbinder32bit"],
"//conditions:default": [],
}) + select({
@@ -1220,19 +1149,17 @@
}) + select({
"//build/bazel/product_variables:malloc_zero_contents": ["-Wmalloc_zero_contents"],
"//conditions:default": [],
- }),
- srcs_c = ["common.c"],
-)`},
+ })`,
+ "srcs_c": `["common.c"]`,
+ }),
+ },
})
}
func TestCcLibraryStaticProductVariableArchSpecificSelects(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static arch-specific product variable selects",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- filesystem: map[string]string{},
+ description: "cc_library_static arch-specific product variable selects",
+ filesystem: map[string]string{},
blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
@@ -1271,9 +1198,9 @@
},
include_build_directory: false,
} `,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- copts = select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "copts": `select({
"//build/bazel/product_variables:malloc_not_svelte": ["-Wmalloc_not_svelte"],
"//conditions:default": [],
}) + select({
@@ -1288,19 +1215,17 @@
}) + select({
"//build/bazel/product_variables:malloc_not_svelte-x86": ["-Wlib32_malloc_not_svelte"],
"//conditions:default": [],
- }),
- srcs_c = ["common.c"],
-)`},
+ })`,
+ "srcs_c": `["common.c"]`,
+ }),
+ },
})
}
func TestCcLibraryStaticProductVariableStringReplacement(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static product variable string replacement",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- filesystem: map[string]string{},
+ description: "cc_library_static product variable string replacement",
+ filesystem: map[string]string{},
blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
@@ -1312,23 +1237,21 @@
},
include_build_directory: false,
} `,
- expectedBazelTargets: []string{`cc_library_static(
- name = "foo_static",
- asflags = select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+ "asflags": `select({
"//build/bazel/product_variables:platform_sdk_version": ["-DPLATFORM_SDK_VERSION=$(Platform_sdk_version)"],
"//conditions:default": [],
- }),
- srcs_as = ["common.S"],
-)`},
+ })`,
+ "srcs_as": `["common.S"]`,
+ }),
+ },
})
}
func TestStaticLibrary_SystemSharedLibsRootEmpty(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static system_shared_lib empty root",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static system_shared_lib empty root",
blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "root_empty",
@@ -1336,19 +1259,17 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "root_empty",
- system_dynamic_deps = [],
-)`},
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "root_empty", attrNameToString{
+ "system_dynamic_deps": `[]`,
+ }),
+ },
})
}
func TestStaticLibrary_SystemSharedLibsStaticEmpty(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static system_shared_lib empty static default",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static system_shared_lib empty static default",
blueprint: soongCcLibraryStaticPreamble + `
cc_defaults {
name: "static_empty_defaults",
@@ -1362,19 +1283,17 @@
defaults: ["static_empty_defaults"],
}
`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "static_empty",
- system_dynamic_deps = [],
-)`},
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "static_empty", attrNameToString{
+ "system_dynamic_deps": `[]`,
+ }),
+ },
})
}
func TestStaticLibrary_SystemSharedLibsBionicEmpty(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static system_shared_lib empty for bionic variant",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static system_shared_lib empty for bionic variant",
blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "target_bionic_empty",
@@ -1386,10 +1305,11 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "target_bionic_empty",
- system_dynamic_deps = [],
-)`},
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "target_bionic_empty", attrNameToString{
+ "system_dynamic_deps": `[]`,
+ }),
+ },
})
}
@@ -1399,10 +1319,7 @@
// only for linux_bionic, but `android` had `["libc", "libdl", "libm"].
// b/195791252 tracks the fix.
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static system_shared_lib empty for linux_bionic variant",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ description: "cc_library_static system_shared_lib empty for linux_bionic variant",
blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "target_linux_bionic_empty",
@@ -1414,22 +1331,19 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "target_linux_bionic_empty",
- system_dynamic_deps = [],
-)`},
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "target_linux_bionic_empty", attrNameToString{
+ "system_dynamic_deps": `[]`,
+ }),
+ },
})
}
func TestStaticLibrary_SystemSharedLibsBionic(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static system_shared_libs set for bionic variant",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- blueprint: soongCcLibraryStaticPreamble + `
-cc_library{name: "libc"}
-
+ description: "cc_library_static system_shared_libs set for bionic variant",
+ blueprint: soongCcLibraryStaticPreamble +
+ simpleModuleDoNotConvertBp2build("cc_library", "libc") + `
cc_library_static {
name: "target_bionic",
target: {
@@ -1440,27 +1354,24 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "target_bionic",
- system_dynamic_deps = select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "target_bionic", attrNameToString{
+ "system_dynamic_deps": `select({
"//build/bazel/platforms/os:android": [":libc"],
"//build/bazel/platforms/os:linux_bionic": [":libc"],
"//conditions:default": [],
- }),
-)`},
+ })`,
+ }),
+ },
})
}
func TestStaticLibrary_SystemSharedLibsLinuxRootAndLinuxBionic(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
- description: "cc_library_static system_shared_libs set for root and linux_bionic variant",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- blueprint: soongCcLibraryStaticPreamble + `
-cc_library{name: "libc"}
-cc_library{name: "libm"}
-
+ description: "cc_library_static system_shared_libs set for root and linux_bionic variant",
+ blueprint: soongCcLibraryStaticPreamble +
+ simpleModuleDoNotConvertBp2build("cc_library", "libc") +
+ simpleModuleDoNotConvertBp2build("cc_library", "libm") + `
cc_library_static {
name: "target_linux_bionic",
system_shared_libs: ["libc"],
@@ -1472,12 +1383,118 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_library_static(
- name = "target_linux_bionic",
- system_dynamic_deps = [":libc"] + select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "target_linux_bionic", attrNameToString{
+ "system_dynamic_deps": `[":libc"] + select({
"//build/bazel/platforms/os:linux_bionic": [":libm"],
"//conditions:default": [],
- }),
-)`},
+ })`,
+ }),
+ },
+ })
+}
+
+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 {
+ name: "foo",
+ srcs: ["foo.proto"],
+ proto: {
+ canonical_path_from_root: false,
+ export_proto_headers: true,
+ },
+ include_build_directory: false,
+}`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("proto_library", "foo_proto", attrNameToString{
+ "srcs": `["foo.proto"]`,
+ }), makeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", attrNameToString{
+ "deps": `[":foo_proto"]`,
+ }), makeBazelTarget("cc_library_static", "foo", attrNameToString{
+ "deps": `[":libprotobuf-cpp-lite"]`,
+ "whole_archive_deps": `[":foo_cc_proto_lite"]`,
+ }),
+ },
+ })
+}
+
+func TestCcLibraryStaticUseVersionLib(t *testing.T) {
+ runCcLibraryStaticTestCase(t, bp2buildTestCase{
+ blueprint: soongCcProtoPreamble + `cc_library_static {
+ name: "foo",
+ use_version_lib: true,
+ include_build_directory: false,
+}`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo", attrNameToString{
+ "use_version_lib": "True",
+ }),
+ },
+ })
+}
+
+func TestCcLibraryStaticStdInFlags(t *testing.T) {
+ runCcLibraryStaticTestCase(t, bp2buildTestCase{
+ blueprint: soongCcProtoPreamble + `cc_library_static {
+ name: "foo",
+ cflags: ["-std=candcpp"],
+ conlyflags: ["-std=conly"],
+ cppflags: ["-std=cpp"],
+ include_build_directory: false,
+}`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_library_static", "foo", attrNameToString{
+ "conlyflags": `["-std=conly"]`,
+ "cppflags": `["-std=cpp"]`,
+ }),
+ },
})
}
diff --git a/bp2build/cc_object_conversion_test.go b/bp2build/cc_object_conversion_test.go
index c4b276a..0a6c317 100644
--- a/bp2build/cc_object_conversion_test.go
+++ b/bp2build/cc_object_conversion_test.go
@@ -28,15 +28,14 @@
func runCcObjectTestCase(t *testing.T, tc bp2buildTestCase) {
t.Helper()
+ (&tc).moduleTypeUnderTest = "cc_object"
+ (&tc).moduleTypeUnderTestFactory = cc.ObjectFactory
runBp2BuildTestCase(t, registerCcObjectModuleTypes, tc)
}
func TestCcObjectSimple(t *testing.T) {
runCcObjectTestCase(t, bp2buildTestCase{
- description: "simple cc_object generates cc_object with include header dep",
- moduleTypeUnderTest: "cc_object",
- moduleTypeUnderTestFactory: cc.ObjectFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
+ description: "simple cc_object generates cc_object with include header dep",
filesystem: map[string]string{
"a/b/foo.h": "",
"a/b/bar.h": "",
@@ -58,30 +57,27 @@
exclude_srcs: ["a/b/exclude.c"],
}
`,
- expectedBazelTargets: []string{`cc_object(
- name = "foo",
- copts = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_object", "foo", attrNameToString{
+ "copts": `[
"-fno-addrsig",
"-Wno-gcc-compat",
"-Wall",
"-Werror",
- ],
- local_includes = [
+ ]`,
+ "local_includes": `[
"include",
".",
- ],
- srcs = ["a/b/c.c"],
- system_dynamic_deps = [],
-)`,
+ ]`,
+ "srcs": `["a/b/c.c"]`,
+ "system_dynamic_deps": `[]`,
+ }),
},
})
}
func TestCcObjectDefaults(t *testing.T) {
runCcObjectTestCase(t, bp2buildTestCase{
- moduleTypeUnderTest: "cc_object",
- moduleTypeUnderTestFactory: cc.ObjectFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
blueprint: `cc_object {
name: "foo",
system_shared_libs: [],
@@ -101,33 +97,26 @@
cc_defaults {
name: "foo_bar_defaults",
cflags: [
- "-Wno-gcc-compat",
- "-Wall",
"-Werror",
],
}
`,
- expectedBazelTargets: []string{`cc_object(
- name = "foo",
- copts = [
- "-Wno-gcc-compat",
- "-Wall",
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_object", "foo", attrNameToString{
+ "copts": `[
"-Werror",
"-fno-addrsig",
- ],
- local_includes = ["."],
- srcs = ["a/b/c.c"],
- system_dynamic_deps = [],
-)`,
+ ]`,
+ "local_includes": `["."]`,
+ "srcs": `["a/b/c.c"]`,
+ "system_dynamic_deps": `[]`,
+ }),
}})
}
func TestCcObjectCcObjetDepsInObjs(t *testing.T) {
runCcObjectTestCase(t, bp2buildTestCase{
- description: "cc_object with cc_object deps in objs props",
- moduleTypeUnderTest: "cc_object",
- moduleTypeUnderTestFactory: cc.ObjectFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
+ description: "cc_object with cc_object deps in objs props",
filesystem: map[string]string{
"a/b/c.c": "",
"x/y/z.c": "",
@@ -147,28 +136,24 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_object(
- name = "bar",
- copts = ["-fno-addrsig"],
- srcs = ["x/y/z.c"],
- system_dynamic_deps = [],
-)`, `cc_object(
- name = "foo",
- copts = ["-fno-addrsig"],
- deps = [":bar"],
- srcs = ["a/b/c.c"],
- system_dynamic_deps = [],
-)`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_object", "bar", attrNameToString{
+ "copts": `["-fno-addrsig"]`,
+ "srcs": `["x/y/z.c"]`,
+ "system_dynamic_deps": `[]`,
+ }), makeBazelTarget("cc_object", "foo", attrNameToString{
+ "copts": `["-fno-addrsig"]`,
+ "deps": `[":bar"]`,
+ "srcs": `["a/b/c.c"]`,
+ "system_dynamic_deps": `[]`,
+ }),
},
})
}
func TestCcObjectIncludeBuildDirFalse(t *testing.T) {
runCcObjectTestCase(t, bp2buildTestCase{
- description: "cc_object with include_build_dir: false",
- moduleTypeUnderTest: "cc_object",
- moduleTypeUnderTestFactory: cc.ObjectFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
+ description: "cc_object with include_build_dir: false",
filesystem: map[string]string{
"a/b/c.c": "",
"x/y/z.c": "",
@@ -180,22 +165,19 @@
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_object(
- name = "foo",
- copts = ["-fno-addrsig"],
- srcs = ["a/b/c.c"],
- system_dynamic_deps = [],
-)`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_object", "foo", attrNameToString{
+ "copts": `["-fno-addrsig"]`,
+ "srcs": `["a/b/c.c"]`,
+ "system_dynamic_deps": `[]`,
+ }),
},
})
}
func TestCcObjectProductVariable(t *testing.T) {
runCcObjectTestCase(t, bp2buildTestCase{
- description: "cc_object with product variable",
- moduleTypeUnderTest: "cc_object",
- moduleTypeUnderTestFactory: cc.ObjectFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
+ description: "cc_object with product variable",
blueprint: `cc_object {
name: "foo",
system_shared_libs: [],
@@ -208,26 +190,23 @@
srcs: ["src.S"],
}
`,
- expectedBazelTargets: []string{`cc_object(
- name = "foo",
- asflags = select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("cc_object", "foo", attrNameToString{
+ "asflags": `select({
"//build/bazel/product_variables:platform_sdk_version": ["-DPLATFORM_SDK_VERSION=$(Platform_sdk_version)"],
"//conditions:default": [],
- }),
- copts = ["-fno-addrsig"],
- srcs_as = ["src.S"],
- system_dynamic_deps = [],
-)`,
+ })`,
+ "copts": `["-fno-addrsig"]`,
+ "srcs_as": `["src.S"]`,
+ "system_dynamic_deps": `[]`,
+ }),
},
})
}
func TestCcObjectCflagsOneArch(t *testing.T) {
runCcObjectTestCase(t, bp2buildTestCase{
- description: "cc_object setting cflags for one arch",
- moduleTypeUnderTest: "cc_object",
- moduleTypeUnderTestFactory: cc.ObjectFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
+ description: "cc_object setting cflags for one arch",
blueprint: `cc_object {
name: "foo",
system_shared_libs: [],
@@ -244,28 +223,24 @@
}
`,
expectedBazelTargets: []string{
- `cc_object(
- name = "foo",
- copts = ["-fno-addrsig"] + select({
+ makeBazelTarget("cc_object", "foo", attrNameToString{
+ "copts": `["-fno-addrsig"] + select({
"//build/bazel/platforms/arch:x86": ["-fPIC"],
"//conditions:default": [],
- }),
- srcs = ["a.cpp"] + select({
+ })`,
+ "srcs": `["a.cpp"] + select({
"//build/bazel/platforms/arch:arm": ["arch/arm/file.cpp"],
"//conditions:default": [],
- }),
- system_dynamic_deps = [],
-)`,
+ })`,
+ "system_dynamic_deps": `[]`,
+ }),
},
})
}
func TestCcObjectCflagsFourArch(t *testing.T) {
runCcObjectTestCase(t, bp2buildTestCase{
- description: "cc_object setting cflags for 4 architectures",
- moduleTypeUnderTest: "cc_object",
- moduleTypeUnderTestFactory: cc.ObjectFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
+ description: "cc_object setting cflags for 4 architectures",
blueprint: `cc_object {
name: "foo",
system_shared_libs: [],
@@ -292,34 +267,30 @@
}
`,
expectedBazelTargets: []string{
- `cc_object(
- name = "foo",
- copts = ["-fno-addrsig"] + select({
+ makeBazelTarget("cc_object", "foo", attrNameToString{
+ "copts": `["-fno-addrsig"] + select({
"//build/bazel/platforms/arch:arm": ["-Wall"],
"//build/bazel/platforms/arch:arm64": ["-Wall"],
"//build/bazel/platforms/arch:x86": ["-fPIC"],
"//build/bazel/platforms/arch:x86_64": ["-fPIC"],
"//conditions:default": [],
- }),
- srcs = ["base.cpp"] + select({
+ })`,
+ "srcs": `["base.cpp"] + select({
"//build/bazel/platforms/arch:arm": ["arm.cpp"],
"//build/bazel/platforms/arch:arm64": ["arm64.cpp"],
"//build/bazel/platforms/arch:x86": ["x86.cpp"],
"//build/bazel/platforms/arch:x86_64": ["x86_64.cpp"],
"//conditions:default": [],
- }),
- system_dynamic_deps = [],
-)`,
+ })`,
+ "system_dynamic_deps": `[]`,
+ }),
},
})
}
func TestCcObjectLinkerScript(t *testing.T) {
runCcObjectTestCase(t, bp2buildTestCase{
- description: "cc_object setting linker_script",
- moduleTypeUnderTest: "cc_object",
- moduleTypeUnderTestFactory: cc.ObjectFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
+ description: "cc_object setting linker_script",
blueprint: `cc_object {
name: "foo",
srcs: ["base.cpp"],
@@ -328,22 +299,18 @@
}
`,
expectedBazelTargets: []string{
- `cc_object(
- name = "foo",
- copts = ["-fno-addrsig"],
- linker_script = "bunny.lds",
- srcs = ["base.cpp"],
-)`,
+ makeBazelTarget("cc_object", "foo", attrNameToString{
+ "copts": `["-fno-addrsig"]`,
+ "linker_script": `"bunny.lds"`,
+ "srcs": `["base.cpp"]`,
+ }),
},
})
}
func TestCcObjectDepsAndLinkerScriptSelects(t *testing.T) {
runCcObjectTestCase(t, bp2buildTestCase{
- description: "cc_object setting deps and linker_script across archs",
- moduleTypeUnderTest: "cc_object",
- moduleTypeUnderTestFactory: cc.ObjectFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
+ description: "cc_object setting deps and linker_script across archs",
blueprint: `cc_object {
name: "foo",
srcs: ["base.cpp"],
@@ -389,33 +356,29 @@
}
`,
expectedBazelTargets: []string{
- `cc_object(
- name = "foo",
- copts = ["-fno-addrsig"],
- deps = select({
+ makeBazelTarget("cc_object", "foo", attrNameToString{
+ "copts": `["-fno-addrsig"]`,
+ "deps": `select({
"//build/bazel/platforms/arch:arm": [":arm_obj"],
"//build/bazel/platforms/arch:x86": [":x86_obj"],
"//build/bazel/platforms/arch:x86_64": [":x86_64_obj"],
"//conditions:default": [],
- }),
- linker_script = select({
+ })`,
+ "linker_script": `select({
"//build/bazel/platforms/arch:arm": "arm.lds",
"//build/bazel/platforms/arch:x86": "x86.lds",
"//build/bazel/platforms/arch:x86_64": "x86_64.lds",
"//conditions:default": None,
- }),
- srcs = ["base.cpp"],
-)`,
+ })`,
+ "srcs": `["base.cpp"]`,
+ }),
},
})
}
func TestCcObjectSelectOnLinuxAndBionicArchs(t *testing.T) {
runCcObjectTestCase(t, bp2buildTestCase{
- description: "cc_object setting srcs based on linux and bionic archs",
- moduleTypeUnderTest: "cc_object",
- moduleTypeUnderTestFactory: cc.ObjectFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
+ description: "cc_object setting srcs based on linux and bionic archs",
blueprint: `cc_object {
name: "foo",
srcs: ["base.cpp"],
@@ -434,10 +397,9 @@
}
`,
expectedBazelTargets: []string{
- `cc_object(
- name = "foo",
- copts = ["-fno-addrsig"],
- srcs = ["base.cpp"] + select({
+ makeBazelTarget("cc_object", "foo", attrNameToString{
+ "copts": `["-fno-addrsig"]`,
+ "srcs": `["base.cpp"] + select({
"//build/bazel/platforms/os_arch:android_arm64": [
"linux_arm64.cpp",
"bionic_arm64.cpp",
@@ -450,8 +412,8 @@
"//build/bazel/platforms/os_arch:linux_glibc_x86": ["linux_x86.cpp"],
"//build/bazel/platforms/os_arch:linux_musl_x86": ["linux_x86.cpp"],
"//conditions:default": [],
- }),
-)`,
+ })`,
+ }),
},
})
}
diff --git a/bp2build/cc_prebuilt_library_shared_test.go b/bp2build/cc_prebuilt_library_shared_test.go
index 97545c8..ef2fddc 100644
--- a/bp2build/cc_prebuilt_library_shared_test.go
+++ b/bp2build/cc_prebuilt_library_shared_test.go
@@ -9,10 +9,9 @@
func TestSharedPrebuiltLibrary(t *testing.T) {
runBp2BuildTestCaseSimple(t,
bp2buildTestCase{
- description: "prebuilt library shared simple",
- moduleTypeUnderTest: "cc_prebuilt_library_shared",
- moduleTypeUnderTestFactory: cc.PrebuiltSharedLibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.PrebuiltLibrarySharedBp2Build,
+ description: "prebuilt library shared simple",
+ moduleTypeUnderTest: "cc_prebuilt_library_shared",
+ moduleTypeUnderTestFactory: cc.PrebuiltSharedLibraryFactory,
filesystem: map[string]string{
"libf.so": "",
},
@@ -23,10 +22,9 @@
bazel_module: { bp2build_available: true },
}`,
expectedBazelTargets: []string{
- `prebuilt_library_shared(
- name = "libtest",
- shared_library = "libf.so",
-)`,
+ makeBazelTarget("prebuilt_library_shared", "libtest", attrNameToString{
+ "shared_library": `"libf.so"`,
+ }),
},
})
}
@@ -34,10 +32,9 @@
func TestSharedPrebuiltLibraryWithArchVariance(t *testing.T) {
runBp2BuildTestCaseSimple(t,
bp2buildTestCase{
- description: "prebuilt library shared with arch variance",
- moduleTypeUnderTest: "cc_prebuilt_library_shared",
- moduleTypeUnderTestFactory: cc.PrebuiltSharedLibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.PrebuiltLibrarySharedBp2Build,
+ description: "prebuilt library shared with arch variance",
+ moduleTypeUnderTest: "cc_prebuilt_library_shared",
+ moduleTypeUnderTestFactory: cc.PrebuiltSharedLibraryFactory,
filesystem: map[string]string{
"libf.so": "",
"libg.so": "",
@@ -52,14 +49,13 @@
bazel_module: { bp2build_available: true },
}`,
expectedBazelTargets: []string{
- `prebuilt_library_shared(
- name = "libtest",
- shared_library = select({
+ makeBazelTarget("prebuilt_library_shared", "libtest", attrNameToString{
+ "shared_library": `select({
"//build/bazel/platforms/arch:arm": "libg.so",
"//build/bazel/platforms/arch:arm64": "libf.so",
"//conditions:default": None,
- }),
-)`,
+ })`,
+ }),
},
})
}
diff --git a/bp2build/configurability.go b/bp2build/configurability.go
index 0bcf91d..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); use {
+ if use, value := labelListSelectValue(selectKey, labels, emitEmptyList); use {
archSelects[selectKey] = value
}
}
@@ -107,8 +110,8 @@
return value, ret
}
-func labelListSelectValue(selectKey string, list bazel.LabelList) (bool, reflect.Value) {
- if selectKey == bazel.ConditionsDefaultSelectKey || len(list.Includes) > 0 {
+func labelListSelectValue(selectKey string, list bazel.LabelList, emitEmptyList bool) (bool, reflect.Value) {
+ if selectKey == bazel.ConditionsDefaultSelectKey || emitEmptyList || len(list.Includes) > 0 {
return true, reflect.ValueOf(list.Includes)
} else if len(list.Excludes) > 0 {
// if there is still an excludes -- we need to have an empty list for this select & use the
@@ -129,6 +132,7 @@
var value reflect.Value
var configurableAttrs []selects
var defaultSelectValue *string
+ var emitZeroValues bool
// If true, print the default attribute value, even if the attribute is zero.
shouldPrintDefault := false
switch list := v.(type) {
@@ -137,14 +141,21 @@
defaultSelectValue = &emptyBazelList
case bazel.LabelListAttribute:
value, configurableAttrs = getLabelListValues(list)
+ emitZeroValues = list.EmitEmptyList
defaultSelectValue = &emptyBazelList
if list.ForceSpecifyEmptyList && (!value.IsNil() || list.HasConfigurableValues()) {
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:
@@ -154,7 +165,7 @@
var err error
ret := ""
if value.Kind() != reflect.Invalid {
- s, err := prettyPrint(value, indent)
+ s, err := prettyPrint(value, indent, false) // never emit zero values for the base value
if err != nil {
return ret, err
}
@@ -163,7 +174,7 @@
}
// Convenience function to append selects components to an attribute value.
appendSelects := func(selectsData selects, defaultValue *string, s string) (string, error) {
- selectMap, err := prettyPrintSelectMap(selectsData, defaultValue, indent)
+ selectMap, err := prettyPrintSelectMap(selectsData, defaultValue, indent, emitZeroValues)
if err != nil {
return "", err
}
@@ -190,7 +201,7 @@
// prettyPrintSelectMap converts a map of select keys to reflected Values as a generic way
// to construct a select map for any kind of attribute type.
-func prettyPrintSelectMap(selectMap map[string]reflect.Value, defaultValue *string, indent int) (string, error) {
+func prettyPrintSelectMap(selectMap map[string]reflect.Value, defaultValue *string, indent int, emitZeroValues bool) (string, error) {
if selectMap == nil {
return "", nil
}
@@ -202,11 +213,12 @@
continue
}
value := selectMap[selectKey]
- if isZero(value) {
- // 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)
+ s, err := prettyPrintSelectEntry(value, selectKey, indent, true)
if err != nil {
return "", err
}
@@ -227,7 +239,7 @@
ret += selects
// Handle the default condition
- s, err := prettyPrintSelectEntry(selectMap[bazel.ConditionsDefaultSelectKey], bazel.ConditionsDefaultSelectKey, indent)
+ s, err := prettyPrintSelectEntry(selectMap[bazel.ConditionsDefaultSelectKey], bazel.ConditionsDefaultSelectKey, indent, emitZeroValues)
if err != nil {
return "", err
}
@@ -249,9 +261,9 @@
// prettyPrintSelectEntry converts a reflect.Value into an entry in a select map
// with a provided key.
-func prettyPrintSelectEntry(value reflect.Value, key string, indent int) (string, error) {
+func prettyPrintSelectEntry(value reflect.Value, key string, indent int, emitZeroValues bool) (string, error) {
s := makeIndent(indent + 1)
- v, err := prettyPrint(value, indent+1)
+ v, err := prettyPrint(value, indent+1, emitZeroValues)
if err != nil {
return "", err
}
diff --git a/bp2build/conversion.go b/bp2build/conversion.go
index 944cb83..81a4b26 100644
--- a/bp2build/conversion.go
+++ b/bp2build/conversion.go
@@ -25,6 +25,8 @@
files = append(files, newFile("metrics", "converted_modules.txt", strings.Join(metrics.convertedModules, "\n")))
+ files = append(files, newFile("product_config", "soong_config_variables.bzl", cfg.Bp2buildSoongConfigDefinitions.String()))
+
return files
}
diff --git a/bp2build/conversion_test.go b/bp2build/conversion_test.go
index d09238a..3e6d9e6 100644
--- a/bp2build/conversion_test.go
+++ b/bp2build/conversion_test.go
@@ -82,7 +82,8 @@
}
func TestCreateBazelFiles_Bp2Build_CreatesDefaultFiles(t *testing.T) {
- files := CreateSoongInjectionFiles(android.Config{}, CodegenMetrics{})
+ testConfig := android.TestConfig("", make(map[string]string), "", make(map[string][]byte))
+ files := CreateSoongInjectionFiles(testConfig, CodegenMetrics{})
expectedFilePaths := []bazelFilepath{
{
@@ -97,6 +98,10 @@
dir: "metrics",
basename: "converted_modules.txt",
},
+ {
+ dir: "product_config",
+ basename: "soong_config_variables.bzl",
+ },
}
if len(files) != len(expectedFilePaths) {
diff --git a/bp2build/filegroup_conversion_test.go b/bp2build/filegroup_conversion_test.go
index ad99236..b43cf53 100644
--- a/bp2build/filegroup_conversion_test.go
+++ b/bp2build/filegroup_conversion_test.go
@@ -23,6 +23,8 @@
func runFilegroupTestCase(t *testing.T, tc bp2buildTestCase) {
t.Helper()
+ (&tc).moduleTypeUnderTest = "filegroup"
+ (&tc).moduleTypeUnderTestFactory = android.FileGroupFactory
runBp2BuildTestCase(t, registerFilegroupModuleTypes, tc)
}
@@ -30,11 +32,8 @@
func TestFilegroupSameNameAsFile_OneFile(t *testing.T) {
runFilegroupTestCase(t, bp2buildTestCase{
- description: "filegroup - same name as file, with one file",
- moduleTypeUnderTest: "filegroup",
- moduleTypeUnderTestFactory: android.FileGroupFactory,
- moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
- filesystem: map[string]string{},
+ description: "filegroup - same name as file, with one file",
+ filesystem: map[string]string{},
blueprint: `
filegroup {
name: "foo",
@@ -46,11 +45,8 @@
func TestFilegroupSameNameAsFile_MultipleFiles(t *testing.T) {
runFilegroupTestCase(t, bp2buildTestCase{
- description: "filegroup - same name as file, with multiple files",
- moduleTypeUnderTest: "filegroup",
- moduleTypeUnderTestFactory: android.FileGroupFactory,
- moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
- filesystem: map[string]string{},
+ description: "filegroup - same name as file, with multiple files",
+ filesystem: map[string]string{},
blueprint: `
filegroup {
name: "foo",
diff --git a/bp2build/genrule_conversion_test.go b/bp2build/genrule_conversion_test.go
index f3bc1ba..fd631a5 100644
--- a/bp2build/genrule_conversion_test.go
+++ b/bp2build/genrule_conversion_test.go
@@ -17,10 +17,20 @@
import (
"android/soong/android"
"android/soong/genrule"
- "strings"
"testing"
)
+func registerGenruleModuleTypes(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("genrule_defaults", func() android.Module { return genrule.DefaultsFactory() })
+}
+
+func runGenruleTestCase(t *testing.T, tc bp2buildTestCase) {
+ t.Helper()
+ (&tc).moduleTypeUnderTest = "genrule"
+ (&tc).moduleTypeUnderTestFactory = genrule.GenRuleFactory
+ runBp2BuildTestCase(t, registerGenruleModuleTypes, tc)
+}
+
func TestGenruleBp2Build(t *testing.T) {
otherGenruleBp := map[string]string{
"other/Android.bp": `genrule {
@@ -39,10 +49,7 @@
testCases := []bp2buildTestCase{
{
- description: "genrule with command line variable replacements",
- moduleTypeUnderTest: "genrule",
- moduleTypeUnderTestFactory: genrule.GenRuleFactory,
- moduleTypeUnderTestBp2BuildMutator: genrule.GenruleBp2Build,
+ description: "genrule with command line variable replacements",
blueprint: `genrule {
name: "foo.tool",
out: ["foo_tool.out"],
@@ -60,26 +67,21 @@
bazel_module: { bp2build_available: true },
}`,
expectedBazelTargets: []string{
- `genrule(
- name = "foo",
- cmd = "$(location :foo.tool) --genDir=$(GENDIR) arg $(SRCS) $(OUTS)",
- outs = ["foo.out"],
- srcs = ["foo.in"],
- tools = [":foo.tool"],
-)`,
- `genrule(
- name = "foo.tool",
- cmd = "cp $(SRCS) $(OUTS)",
- outs = ["foo_tool.out"],
- srcs = ["foo_tool.in"],
-)`,
+ makeBazelTarget("genrule", "foo", attrNameToString{
+ "cmd": `"$(location :foo.tool) --genDir=$(GENDIR) arg $(SRCS) $(OUTS)"`,
+ "outs": `["foo.out"]`,
+ "srcs": `["foo.in"]`,
+ "tools": `[":foo.tool"]`,
+ }),
+ makeBazelTarget("genrule", "foo.tool", attrNameToString{
+ "cmd": `"cp $(SRCS) $(OUTS)"`,
+ "outs": `["foo_tool.out"]`,
+ "srcs": `["foo_tool.in"]`,
+ }),
},
},
{
- description: "genrule using $(locations :label)",
- moduleTypeUnderTest: "genrule",
- moduleTypeUnderTestFactory: genrule.GenRuleFactory,
- moduleTypeUnderTestBp2BuildMutator: genrule.GenruleBp2Build,
+ description: "genrule using $(locations :label)",
blueprint: `genrule {
name: "foo.tools",
out: ["foo_tool.out", "foo_tool2.out"],
@@ -96,29 +98,25 @@
cmd: "$(locations :foo.tools) -s $(out) $(in)",
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`genrule(
- name = "foo",
- cmd = "$(locations :foo.tools) -s $(OUTS) $(SRCS)",
- outs = ["foo.out"],
- srcs = ["foo.in"],
- tools = [":foo.tools"],
-)`,
- `genrule(
- name = "foo.tools",
- cmd = "cp $(SRCS) $(OUTS)",
- outs = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("genrule", "foo", attrNameToString{
+ "cmd": `"$(locations :foo.tools) -s $(OUTS) $(SRCS)"`,
+ "outs": `["foo.out"]`,
+ "srcs": `["foo.in"]`,
+ "tools": `[":foo.tools"]`,
+ }),
+ makeBazelTarget("genrule", "foo.tools", attrNameToString{
+ "cmd": `"cp $(SRCS) $(OUTS)"`,
+ "outs": `[
"foo_tool.out",
"foo_tool2.out",
- ],
- srcs = ["foo_tool.in"],
-)`,
+ ]`,
+ "srcs": `["foo_tool.in"]`,
+ }),
},
},
{
- description: "genrule using $(locations //absolute:label)",
- moduleTypeUnderTest: "genrule",
- moduleTypeUnderTestFactory: genrule.GenRuleFactory,
- moduleTypeUnderTestBp2BuildMutator: genrule.GenruleBp2Build,
+ description: "genrule using $(locations //absolute:label)",
blueprint: `genrule {
name: "foo",
out: ["foo.out"],
@@ -127,21 +125,18 @@
cmd: "$(locations :foo.tool) -s $(out) $(in)",
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`genrule(
- name = "foo",
- cmd = "$(locations //other:foo.tool) -s $(OUTS) $(SRCS)",
- outs = ["foo.out"],
- srcs = ["foo.in"],
- tools = ["//other:foo.tool"],
-)`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("genrule", "foo", attrNameToString{
+ "cmd": `"$(locations //other:foo.tool) -s $(OUTS) $(SRCS)"`,
+ "outs": `["foo.out"]`,
+ "srcs": `["foo.in"]`,
+ "tools": `["//other:foo.tool"]`,
+ }),
},
filesystem: otherGenruleBp,
},
{
- description: "genrule srcs using $(locations //absolute:label)",
- moduleTypeUnderTest: "genrule",
- moduleTypeUnderTestFactory: genrule.GenRuleFactory,
- moduleTypeUnderTestBp2BuildMutator: genrule.GenruleBp2Build,
+ description: "genrule srcs using $(locations //absolute:label)",
blueprint: `genrule {
name: "foo",
out: ["foo.out"],
@@ -150,21 +145,18 @@
cmd: "$(locations :foo.tool) -s $(out) $(location :other.tool)",
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`genrule(
- name = "foo",
- cmd = "$(locations //other:foo.tool) -s $(OUTS) $(location //other:other.tool)",
- outs = ["foo.out"],
- srcs = ["//other:other.tool"],
- tools = ["//other:foo.tool"],
-)`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("genrule", "foo", attrNameToString{
+ "cmd": `"$(locations //other:foo.tool) -s $(OUTS) $(location //other:other.tool)"`,
+ "outs": `["foo.out"]`,
+ "srcs": `["//other:other.tool"]`,
+ "tools": `["//other:foo.tool"]`,
+ }),
},
filesystem: otherGenruleBp,
},
{
- description: "genrule using $(location) label should substitute first tool label automatically",
- moduleTypeUnderTest: "genrule",
- moduleTypeUnderTestFactory: genrule.GenRuleFactory,
- moduleTypeUnderTestBp2BuildMutator: genrule.GenruleBp2Build,
+ description: "genrule using $(location) label should substitute first tool label automatically",
blueprint: `genrule {
name: "foo",
out: ["foo.out"],
@@ -173,24 +165,21 @@
cmd: "$(location) -s $(out) $(in)",
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`genrule(
- name = "foo",
- cmd = "$(location //other:foo.tool) -s $(OUTS) $(SRCS)",
- outs = ["foo.out"],
- srcs = ["foo.in"],
- tools = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("genrule", "foo", attrNameToString{
+ "cmd": `"$(location //other:foo.tool) -s $(OUTS) $(SRCS)"`,
+ "outs": `["foo.out"]`,
+ "srcs": `["foo.in"]`,
+ "tools": `[
"//other:foo.tool",
"//other:other.tool",
- ],
-)`,
+ ]`,
+ }),
},
filesystem: otherGenruleBp,
},
{
- description: "genrule using $(locations) label should substitute first tool label automatically",
- moduleTypeUnderTest: "genrule",
- moduleTypeUnderTestFactory: genrule.GenRuleFactory,
- moduleTypeUnderTestBp2BuildMutator: genrule.GenruleBp2Build,
+ description: "genrule using $(locations) label should substitute first tool label automatically",
blueprint: `genrule {
name: "foo",
out: ["foo.out"],
@@ -199,24 +188,21 @@
cmd: "$(locations) -s $(out) $(in)",
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`genrule(
- name = "foo",
- cmd = "$(locations //other:foo.tool) -s $(OUTS) $(SRCS)",
- outs = ["foo.out"],
- srcs = ["foo.in"],
- tools = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("genrule", "foo", attrNameToString{
+ "cmd": `"$(locations //other:foo.tool) -s $(OUTS) $(SRCS)"`,
+ "outs": `["foo.out"]`,
+ "srcs": `["foo.in"]`,
+ "tools": `[
"//other:foo.tool",
"//other:other.tool",
- ],
-)`,
+ ]`,
+ }),
},
filesystem: otherGenruleBp,
},
{
- description: "genrule without tools or tool_files can convert successfully",
- moduleTypeUnderTest: "genrule",
- moduleTypeUnderTestFactory: genrule.GenRuleFactory,
- moduleTypeUnderTestBp2BuildMutator: genrule.GenruleBp2Build,
+ description: "genrule without tools or tool_files can convert successfully",
blueprint: `genrule {
name: "foo",
out: ["foo.out"],
@@ -224,85 +210,28 @@
cmd: "cp $(in) $(out)",
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`genrule(
- name = "foo",
- cmd = "cp $(SRCS) $(OUTS)",
- outs = ["foo.out"],
- srcs = ["foo.in"],
-)`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("genrule", "foo", attrNameToString{
+ "cmd": `"cp $(SRCS) $(OUTS)"`,
+ "outs": `["foo.out"]`,
+ "srcs": `["foo.in"]`,
+ }),
},
},
}
- dir := "."
for _, testCase := range testCases {
- fs := make(map[string][]byte)
- toParse := []string{
- "Android.bp",
- }
- for f, content := range testCase.filesystem {
- if strings.HasSuffix(f, "Android.bp") {
- toParse = append(toParse, f)
- }
- fs[f] = []byte(content)
- }
- config := android.TestConfig(buildDir, nil, testCase.blueprint, fs)
- ctx := android.NewTestContext(config)
- ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
- ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator)
- ctx.RegisterForBazelConversion()
-
- _, errs := ctx.ParseFileList(dir, toParse)
- if errored(t, testCase, errs) {
- continue
- }
- _, errs = ctx.ResolveDependencies(config)
- if errored(t, testCase, errs) {
- continue
- }
-
- checkDir := dir
- if testCase.dir != "" {
- checkDir = testCase.dir
- }
-
- codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
- bazelTargets, err := generateBazelTargetsForDir(codegenCtx, checkDir)
- android.FailIfErrored(t, err)
- if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount {
- t.Errorf("%s: Expected %d bazel target, got %d", testCase.description, expectedCount, actualCount)
- } else {
- for i, target := range bazelTargets {
- if w, g := testCase.expectedBazelTargets[i], target.content; w != g {
- t.Errorf(
- "%s: Expected generated Bazel target to be '%s', got '%s'",
- testCase.description,
- w,
- g,
- )
- }
- }
- }
+ t.Run(testCase.description, func(t *testing.T) {
+ runGenruleTestCase(t, testCase)
+ })
}
}
func TestBp2BuildInlinesDefaults(t *testing.T) {
- testCases := []struct {
- moduleTypesUnderTest map[string]android.ModuleFactory
- bp2buildMutatorsUnderTest map[string]bp2buildMutator
- bp string
- expectedBazelTarget string
- description string
- }{
+ testCases := []bp2buildTestCase{
{
- moduleTypesUnderTest: map[string]android.ModuleFactory{
- "genrule": genrule.GenRuleFactory,
- "genrule_defaults": func() android.Module { return genrule.DefaultsFactory() },
- },
- bp2buildMutatorsUnderTest: map[string]bp2buildMutator{
- "genrule": genrule.GenruleBp2Build,
- },
- bp: `genrule_defaults {
+ description: "genrule applies properties from a genrule_defaults dependency if not specified",
+ blueprint: `genrule_defaults {
name: "gen_defaults",
cmd: "do-something $(in) $(out)",
}
@@ -314,23 +243,17 @@
bazel_module: { bp2build_available: true },
}
`,
- expectedBazelTarget: `genrule(
- name = "gen",
- cmd = "do-something $(SRCS) $(OUTS)",
- outs = ["out"],
- srcs = ["in1"],
-)`,
- description: "genrule applies properties from a genrule_defaults dependency if not specified",
+ expectedBazelTargets: []string{
+ makeBazelTarget("genrule", "gen", attrNameToString{
+ "cmd": `"do-something $(SRCS) $(OUTS)"`,
+ "outs": `["out"]`,
+ "srcs": `["in1"]`,
+ }),
+ },
},
{
- moduleTypesUnderTest: map[string]android.ModuleFactory{
- "genrule": genrule.GenRuleFactory,
- "genrule_defaults": func() android.Module { return genrule.DefaultsFactory() },
- },
- bp2buildMutatorsUnderTest: map[string]bp2buildMutator{
- "genrule": genrule.GenruleBp2Build,
- },
- bp: `genrule_defaults {
+ description: "genrule does merges properties from a genrule_defaults dependency, latest-first",
+ blueprint: `genrule_defaults {
name: "gen_defaults",
out: ["out-from-defaults"],
srcs: ["in-from-defaults"],
@@ -345,29 +268,23 @@
bazel_module: { bp2build_available: true },
}
`,
- expectedBazelTarget: `genrule(
- name = "gen",
- cmd = "do-something $(SRCS) $(OUTS)",
- outs = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("genrule", "gen", attrNameToString{
+ "cmd": `"do-something $(SRCS) $(OUTS)"`,
+ "outs": `[
"out-from-defaults",
"out",
- ],
- srcs = [
+ ]`,
+ "srcs": `[
"in-from-defaults",
"in1",
- ],
-)`,
- description: "genrule does merges properties from a genrule_defaults dependency, latest-first",
+ ]`,
+ }),
+ },
},
{
- moduleTypesUnderTest: map[string]android.ModuleFactory{
- "genrule": genrule.GenRuleFactory,
- "genrule_defaults": func() android.Module { return genrule.DefaultsFactory() },
- },
- bp2buildMutatorsUnderTest: map[string]bp2buildMutator{
- "genrule": genrule.GenruleBp2Build,
- },
- bp: `genrule_defaults {
+ description: "genrule applies properties from list of genrule_defaults",
+ blueprint: `genrule_defaults {
name: "gen_defaults1",
cmd: "cp $(in) $(out)",
}
@@ -384,23 +301,17 @@
bazel_module: { bp2build_available: true },
}
`,
- expectedBazelTarget: `genrule(
- name = "gen",
- cmd = "cp $(SRCS) $(OUTS)",
- outs = ["out"],
- srcs = ["in1"],
-)`,
- description: "genrule applies properties from list of genrule_defaults",
+ expectedBazelTargets: []string{
+ makeBazelTarget("genrule", "gen", attrNameToString{
+ "cmd": `"cp $(SRCS) $(OUTS)"`,
+ "outs": `["out"]`,
+ "srcs": `["in1"]`,
+ }),
+ },
},
{
- moduleTypesUnderTest: map[string]android.ModuleFactory{
- "genrule": genrule.GenRuleFactory,
- "genrule_defaults": func() android.Module { return genrule.DefaultsFactory() },
- },
- bp2buildMutatorsUnderTest: map[string]bp2buildMutator{
- "genrule": genrule.GenruleBp2Build,
- },
- bp: `genrule_defaults {
+ description: "genrule applies properties from genrule_defaults transitively",
+ blueprint: `genrule_defaults {
name: "gen_defaults1",
defaults: ["gen_defaults2"],
cmd: "cmd1 $(in) $(out)", // overrides gen_defaults2's cmd property value.
@@ -427,55 +338,26 @@
bazel_module: { bp2build_available: true },
}
`,
- expectedBazelTarget: `genrule(
- name = "gen",
- cmd = "cmd1 $(SRCS) $(OUTS)",
- outs = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("genrule", "gen", attrNameToString{
+ "cmd": `"cmd1 $(SRCS) $(OUTS)"`,
+ "outs": `[
"out-from-3",
"out-from-2",
"out",
- ],
- srcs = [
+ ]`,
+ "srcs": `[
"srcs-from-3",
"in1",
- ],
-)`,
- description: "genrule applies properties from genrule_defaults transitively",
+ ]`,
+ }),
+ },
},
}
- dir := "."
for _, testCase := range testCases {
- config := android.TestConfig(buildDir, nil, testCase.bp, nil)
- ctx := android.NewTestContext(config)
- for m, factory := range testCase.moduleTypesUnderTest {
- ctx.RegisterModuleType(m, factory)
- }
- for mutator, f := range testCase.bp2buildMutatorsUnderTest {
- ctx.RegisterBp2BuildMutator(mutator, f)
- }
- ctx.RegisterForBazelConversion()
-
- _, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
- android.FailIfErrored(t, errs)
- _, errs = ctx.ResolveDependencies(config)
- android.FailIfErrored(t, errs)
-
- codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
- bazelTargets, err := generateBazelTargetsForDir(codegenCtx, dir)
- android.FailIfErrored(t, err)
- if actualCount := len(bazelTargets); actualCount != 1 {
- t.Fatalf("%s: Expected 1 bazel target, got %d", testCase.description, actualCount)
- }
-
- actualBazelTarget := bazelTargets[0]
- if actualBazelTarget.content != testCase.expectedBazelTarget {
- t.Errorf(
- "%s: Expected generated Bazel target to be '%s', got '%s'",
- testCase.description,
- testCase.expectedBazelTarget,
- actualBazelTarget.content,
- )
- }
+ t.Run(testCase.description, func(t *testing.T) {
+ runGenruleTestCase(t, testCase)
+ })
}
}
diff --git a/bp2build/java_binary_host_conversion_test.go b/bp2build/java_binary_host_conversion_test.go
new file mode 100644
index 0000000..96b8958
--- /dev/null
+++ b/bp2build/java_binary_host_conversion_test.go
@@ -0,0 +1,63 @@
+// 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 bp2build
+
+import (
+ "testing"
+
+ "android/soong/android"
+ "android/soong/cc"
+ "android/soong/java"
+)
+
+func runJavaBinaryHostTestCase(t *testing.T, tc bp2buildTestCase) {
+ t.Helper()
+ (&tc).moduleTypeUnderTest = "java_binary_host"
+ (&tc).moduleTypeUnderTestFactory = java.BinaryHostFactory
+ runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("cc_library_host_shared", cc.LibraryHostSharedFactory)
+ }, tc)
+}
+
+var fs = map[string]string{
+ "test.mf": "Main-Class: com.android.test.MainClass",
+ "other/Android.bp": `cc_library_host_shared {
+ name: "jni-lib-1",
+ stl: "none",
+}`,
+}
+
+func TestJavaBinaryHost(t *testing.T) {
+ runJavaBinaryHostTestCase(t, bp2buildTestCase{
+ description: "java_binary_host with srcs, exclude_srcs, jni_libs and manifest.",
+ filesystem: fs,
+ blueprint: `java_binary_host {
+ name: "java-binary-host-1",
+ srcs: ["a.java", "b.java"],
+ exclude_srcs: ["b.java"],
+ manifest: "test.mf",
+ jni_libs: ["jni-lib-1"],
+ bazel_module: { bp2build_available: true },
+}`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("java_binary", "java-binary-host-1", attrNameToString{
+ "srcs": `["a.java"]`,
+ "main_class": `"com.android.test.MainClass"`,
+ "deps": `["//other:jni-lib-1"]`,
+ "jvm_flags": `["-Djava.library.path=$${RUNPATH}other"]`,
+ }),
+ },
+ })
+}
diff --git a/bp2build/java_library_conversion_test.go b/bp2build/java_library_conversion_test.go
new file mode 100644
index 0000000..5c65ec2
--- /dev/null
+++ b/bp2build/java_library_conversion_test.go
@@ -0,0 +1,57 @@
+// 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 bp2build
+
+import (
+ "testing"
+
+ "android/soong/android"
+ "android/soong/java"
+)
+
+func runJavaLibraryTestCase(t *testing.T, tc bp2buildTestCase) {
+ t.Helper()
+ (&tc).moduleTypeUnderTest = "java_library"
+ (&tc).moduleTypeUnderTestFactory = java.LibraryFactory
+ runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc)
+}
+
+func TestJavaLibrary(t *testing.T) {
+ runJavaLibraryTestCase(t, bp2buildTestCase{
+ description: "java_library with srcs, exclude_srcs and libs",
+ blueprint: `java_library {
+ name: "java-lib-1",
+ srcs: ["a.java", "b.java"],
+ exclude_srcs: ["b.java"],
+ libs: ["java-lib-2"],
+ bazel_module: { bp2build_available: true },
+}
+
+java_library {
+ name: "java-lib-2",
+ srcs: ["b.java"],
+ bazel_module: { bp2build_available: true },
+}`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("java_library", "java-lib-1", attrNameToString{
+ "srcs": `["a.java"]`,
+ "deps": `[":java-lib-2"]`,
+ }),
+ makeBazelTarget("java_library", "java-lib-2", attrNameToString{
+ "srcs": `["b.java"]`,
+ }),
+ },
+ })
+}
diff --git a/bp2build/java_library_host_conversion_test.go b/bp2build/java_library_host_conversion_test.go
new file mode 100644
index 0000000..6ac82db
--- /dev/null
+++ b/bp2build/java_library_host_conversion_test.go
@@ -0,0 +1,57 @@
+// 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 bp2build
+
+import (
+ "testing"
+
+ "android/soong/android"
+ "android/soong/java"
+)
+
+func runJavaLibraryHostTestCase(t *testing.T, tc bp2buildTestCase) {
+ t.Helper()
+ (&tc).moduleTypeUnderTest = "java_library_host"
+ (&tc).moduleTypeUnderTestFactory = java.LibraryHostFactory
+ runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc)
+}
+
+func TestJavaLibraryHost(t *testing.T) {
+ runJavaLibraryHostTestCase(t, bp2buildTestCase{
+ description: "java_library_host with srcs, exclude_srcs and libs",
+ blueprint: `java_library_host {
+ name: "java-lib-host-1",
+ srcs: ["a.java", "b.java"],
+ exclude_srcs: ["b.java"],
+ libs: ["java-lib-host-2"],
+ bazel_module: { bp2build_available: true },
+}
+
+java_library_host {
+ name: "java-lib-host-2",
+ srcs: ["c.java"],
+ bazel_module: { bp2build_available: true },
+}`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("java_library", "java-lib-host-1", attrNameToString{
+ "srcs": `["a.java"]`,
+ "deps": `[":java-lib-host-2"]`,
+ }),
+ makeBazelTarget("java_library", "java-lib-host-2", attrNameToString{
+ "srcs": `["c.java"]`,
+ }),
+ },
+ })
+}
diff --git a/bp2build/metrics.go b/bp2build/metrics.go
index 1cc4143..68ac544 100644
--- a/bp2build/metrics.go
+++ b/bp2build/metrics.go
@@ -1,41 +1,61 @@
package bp2build
import (
- "android/soong/android"
"fmt"
+ "os"
+ "path/filepath"
"strings"
+
+ "android/soong/android"
+ "android/soong/shared"
+ "android/soong/ui/metrics/bp2build_metrics_proto"
)
// Simple metrics struct to collect information about a Blueprint to BUILD
// conversion process.
type CodegenMetrics struct {
// Total number of Soong modules converted to generated targets
- generatedModuleCount int
+ generatedModuleCount uint64
// Total number of Soong modules converted to handcrafted targets
- handCraftedModuleCount int
+ handCraftedModuleCount uint64
// Total number of unconverted Soong modules
- unconvertedModuleCount int
+ unconvertedModuleCount uint64
// Counts of generated Bazel targets per Bazel rule class
- ruleClassCount map[string]int
+ ruleClassCount map[string]uint64
+ // List of modules with unconverted deps
+ // NOTE: NOT in the .proto
moduleWithUnconvertedDepsMsgs []string
+ // List of converted modules
convertedModules []string
}
+// Serialize returns the protoized version of CodegenMetrics: bp2build_metrics_proto.Bp2BuildMetrics
+func (metrics *CodegenMetrics) Serialize() bp2build_metrics_proto.Bp2BuildMetrics {
+ return bp2build_metrics_proto.Bp2BuildMetrics{
+ GeneratedModuleCount: metrics.generatedModuleCount,
+ HandCraftedModuleCount: metrics.handCraftedModuleCount,
+ UnconvertedModuleCount: metrics.unconvertedModuleCount,
+ RuleClassCount: metrics.ruleClassCount,
+ ConvertedModules: metrics.convertedModules,
+ }
+}
+
// Print the codegen metrics to stdout.
func (metrics *CodegenMetrics) Print() {
- generatedTargetCount := 0
+ generatedTargetCount := uint64(0)
for _, ruleClass := range android.SortedStringKeys(metrics.ruleClassCount) {
count := metrics.ruleClassCount[ruleClass]
fmt.Printf("[bp2build] %s: %d targets\n", ruleClass, count)
generatedTargetCount += count
}
fmt.Printf(
- "[bp2build] Generated %d total BUILD targets and included %d handcrafted BUILD targets from %d Android.bp modules.\n With %d modules with 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.\n%d converted modules have unconverted deps: \n\t%s",
+ metrics.generatedModuleCount,
generatedTargetCount,
metrics.handCraftedModuleCount,
metrics.TotalModuleCount(),
@@ -43,6 +63,40 @@
strings.Join(metrics.moduleWithUnconvertedDepsMsgs, "\n\t"))
}
+const bp2buildMetricsFilename = "bp2build_metrics.pb"
+
+// fail prints $PWD to stderr, followed by the given printf string and args (vals),
+// then the given alert, and then exits with 1 for failure
+func fail(err error, alertFmt string, vals ...interface{}) {
+ cwd, wderr := os.Getwd()
+ if wderr != nil {
+ cwd = "FAILED TO GET $PWD: " + wderr.Error()
+ }
+ fmt.Fprintf(os.Stderr, "\nIn "+cwd+":\n"+alertFmt+"\n"+err.Error()+"\n", vals...)
+ os.Exit(1)
+}
+
+// Write the bp2build-protoized codegen metrics into the given directory
+func (metrics *CodegenMetrics) Write(dir string) {
+ if _, err := os.Stat(dir); os.IsNotExist(err) {
+ // The metrics dir doesn't already exist, so create it (and parents)
+ if err := os.MkdirAll(dir, 0755); err != nil { // rx for all; w for user
+ fail(err, "Failed to `mkdir -p` %s", dir)
+ }
+ } else if err != nil {
+ fail(err, "Failed to `stat` %s", dir)
+ }
+ metricsFile := filepath.Join(dir, bp2buildMetricsFilename)
+ if err := metrics.dump(metricsFile); err != nil {
+ fail(err, "Error outputting %s", metricsFile)
+ }
+ if _, err := os.Stat(metricsFile); err != nil {
+ fail(err, "MISSING BP2BUILD METRICS OUTPUT: Failed to `stat` %s", metricsFile)
+ } else {
+ fmt.Printf("\nWrote bp2build metrics to: %s\n", metricsFile)
+ }
+}
+
func (metrics *CodegenMetrics) IncrementRuleClassCount(ruleClass string) {
metrics.ruleClassCount[ruleClass] += 1
}
@@ -51,12 +105,18 @@
metrics.unconvertedModuleCount += 1
}
-func (metrics *CodegenMetrics) TotalModuleCount() int {
+func (metrics *CodegenMetrics) TotalModuleCount() uint64 {
return metrics.handCraftedModuleCount +
metrics.generatedModuleCount +
metrics.unconvertedModuleCount
}
+// Dump serializes the metrics to the given filename
+func (metrics *CodegenMetrics) dump(filename string) (err error) {
+ ser := metrics.Serialize()
+ return shared.Save(&ser, filename)
+}
+
type ConversionType int
const (
diff --git a/bp2build/performance_test.go b/bp2build/performance_test.go
index 3283952..c4bbae2 100644
--- a/bp2build/performance_test.go
+++ b/bp2build/performance_test.go
@@ -29,6 +29,10 @@
"testing"
)
+const (
+ performance_test_dir = "."
+)
+
func genCustomModule(i int, convert bool) string {
var conversionString string
if convert {
@@ -76,34 +80,83 @@
return strings.Join(bp, "\n\n")
}
+type testConfig struct {
+ config android.Config
+ ctx *android.TestContext
+ codegenCtx *CodegenContext
+}
+
+func (tc testConfig) parse() []error {
+ _, errs := tc.ctx.ParseFileList(performance_test_dir, []string{"Android.bp"})
+ return errs
+}
+
+func (tc testConfig) resolveDependencies() []error {
+ _, errs := tc.ctx.ResolveDependencies(tc.config)
+ return errs
+}
+
+func (tc testConfig) convert() {
+ generateBazelTargetsForDir(tc.codegenCtx, performance_test_dir)
+}
+
+func setup(builddir string, tcSize float64) testConfig {
+ config := android.TestConfig(buildDir, nil, genCustomModuleBp(tcSize), nil)
+ ctx := android.NewTestContext(config)
+
+ registerCustomModuleForBp2buildConversion(ctx)
+ codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
+ return testConfig{
+ config,
+ ctx,
+ codegenCtx,
+ }
+}
+
var pctToConvert = []float64{0.0, 0.01, 0.05, 0.10, 0.25, 0.5, 0.75, 1.0}
+// This is not intended to test performance, but to verify performance infra continues to work
+func TestConvertManyModulesFull(t *testing.T) {
+ for _, tcSize := range pctToConvert {
+
+ t.Run(fmt.Sprintf("pctConverted %f", tcSize), func(t *testing.T) {
+ testConfig := setup(buildDir, tcSize)
+
+ errs := testConfig.parse()
+ if len(errs) > 0 {
+ t.Fatalf("Unexpected errors: %s", errs)
+ }
+
+ errs = testConfig.resolveDependencies()
+ if len(errs) > 0 {
+ t.Fatalf("Unexpected errors: %s", errs)
+ }
+
+ testConfig.convert()
+ })
+ }
+}
+
func BenchmarkManyModulesFull(b *testing.B) {
- dir := "."
for _, tcSize := range pctToConvert {
b.Run(fmt.Sprintf("pctConverted %f", tcSize), func(b *testing.B) {
for n := 0; n < b.N; n++ {
b.StopTimer()
- // setup we don't want to measure
- config := android.TestConfig(buildDir, nil, genCustomModuleBp(tcSize), nil)
- ctx := android.NewTestContext(config)
-
- registerCustomModuleForBp2buildConversion(ctx)
- codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
+ testConfig := setup(buildDir, tcSize)
b.StartTimer()
- _, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
+ errs := testConfig.parse()
if len(errs) > 0 {
b.Fatalf("Unexpected errors: %s", errs)
}
- _, errs = ctx.ResolveDependencies(config)
+ errs = testConfig.resolveDependencies()
if len(errs) > 0 {
b.Fatalf("Unexpected errors: %s", errs)
}
- generateBazelTargetsForDir(codegenCtx, dir)
+ testConfig.convert()
b.StopTimer()
}
})
@@ -111,63 +164,53 @@
}
func BenchmarkManyModulesResolveDependencies(b *testing.B) {
- dir := "."
for _, tcSize := range pctToConvert {
b.Run(fmt.Sprintf("pctConverted %f", tcSize), func(b *testing.B) {
for n := 0; n < b.N; n++ {
b.StopTimer()
// setup we don't want to measure
- config := android.TestConfig(buildDir, nil, genCustomModuleBp(tcSize), nil)
- ctx := android.NewTestContext(config)
+ testConfig := setup(buildDir, tcSize)
- registerCustomModuleForBp2buildConversion(ctx)
- codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
-
- _, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
+ errs := testConfig.parse()
if len(errs) > 0 {
b.Fatalf("Unexpected errors: %s", errs)
}
b.StartTimer()
- _, errs = ctx.ResolveDependencies(config)
+ errs = testConfig.resolveDependencies()
b.StopTimer()
if len(errs) > 0 {
b.Fatalf("Unexpected errors: %s", errs)
}
- generateBazelTargetsForDir(codegenCtx, dir)
+ testConfig.convert()
}
})
}
}
func BenchmarkManyModulesGenerateBazelTargetsForDir(b *testing.B) {
- dir := "."
for _, tcSize := range pctToConvert {
b.Run(fmt.Sprintf("pctConverted %f", tcSize), func(b *testing.B) {
for n := 0; n < b.N; n++ {
b.StopTimer()
// setup we don't want to measure
- config := android.TestConfig(buildDir, nil, genCustomModuleBp(tcSize), nil)
- ctx := android.NewTestContext(config)
+ testConfig := setup(buildDir, tcSize)
- registerCustomModuleForBp2buildConversion(ctx)
- codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
-
- _, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
+ errs := testConfig.parse()
if len(errs) > 0 {
b.Fatalf("Unexpected errors: %s", errs)
}
- _, errs = ctx.ResolveDependencies(config)
+ errs = testConfig.resolveDependencies()
if len(errs) > 0 {
b.Fatalf("Unexpected errors: %s", errs)
}
b.StartTimer()
- generateBazelTargetsForDir(codegenCtx, dir)
+ testConfig.convert()
b.StopTimer()
}
})
diff --git a/bp2build/prebuilt_etc_conversion_test.go b/bp2build/prebuilt_etc_conversion_test.go
index 62e407b..3a5d5bb 100644
--- a/bp2build/prebuilt_etc_conversion_test.go
+++ b/bp2build/prebuilt_etc_conversion_test.go
@@ -23,6 +23,8 @@
func runPrebuiltEtcTestCase(t *testing.T, tc bp2buildTestCase) {
t.Helper()
+ (&tc).moduleTypeUnderTest = "prebuilt_etc"
+ (&tc).moduleTypeUnderTestFactory = etc.PrebuiltEtcFactory
runBp2BuildTestCase(t, registerPrebuiltEtcModuleTypes, tc)
}
@@ -31,11 +33,8 @@
func TestPrebuiltEtcSimple(t *testing.T) {
runPrebuiltEtcTestCase(t, bp2buildTestCase{
- description: "prebuilt_etc - simple example",
- moduleTypeUnderTest: "prebuilt_etc",
- moduleTypeUnderTestFactory: etc.PrebuiltEtcFactory,
- moduleTypeUnderTestBp2BuildMutator: etc.PrebuiltEtcBp2Build,
- filesystem: map[string]string{},
+ description: "prebuilt_etc - simple example",
+ filesystem: map[string]string{},
blueprint: `
prebuilt_etc {
name: "apex_tz_version",
@@ -45,22 +44,19 @@
installable: false,
}
`,
- expectedBazelTargets: []string{`prebuilt_etc(
- name = "apex_tz_version",
- filename = "tz_version",
- installable = False,
- src = "version/tz_version",
- sub_dir = "tz",
-)`}})
+ expectedBazelTargets: []string{
+ makeBazelTarget("prebuilt_etc", "apex_tz_version", attrNameToString{
+ "filename": `"tz_version"`,
+ "installable": `False`,
+ "src": `"version/tz_version"`,
+ "sub_dir": `"tz"`,
+ })}})
}
func TestPrebuiltEtcArchVariant(t *testing.T) {
runPrebuiltEtcTestCase(t, bp2buildTestCase{
- description: "prebuilt_etc - simple example",
- moduleTypeUnderTest: "prebuilt_etc",
- moduleTypeUnderTestFactory: etc.PrebuiltEtcFactory,
- moduleTypeUnderTestBp2BuildMutator: etc.PrebuiltEtcBp2Build,
- filesystem: map[string]string{},
+ description: "prebuilt_etc - arch variant",
+ filesystem: map[string]string{},
blueprint: `
prebuilt_etc {
name: "apex_tz_version",
@@ -78,15 +74,57 @@
}
}
`,
- expectedBazelTargets: []string{`prebuilt_etc(
- name = "apex_tz_version",
- filename = "tz_version",
- installable = False,
- src = select({
+ expectedBazelTargets: []string{
+ makeBazelTarget("prebuilt_etc", "apex_tz_version", attrNameToString{
+ "filename": `"tz_version"`,
+ "installable": `False`,
+ "src": `select({
"//build/bazel/platforms/arch:arm": "arm",
"//build/bazel/platforms/arch:arm64": "arm64",
"//conditions:default": "version/tz_version",
- }),
- sub_dir = "tz",
-)`}})
+ })`,
+ "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/python_binary_conversion_test.go b/bp2build/python_binary_conversion_test.go
index 5b4829e..40c8ba1 100644
--- a/bp2build/python_binary_conversion_test.go
+++ b/bp2build/python_binary_conversion_test.go
@@ -7,7 +7,8 @@
"android/soong/python"
)
-func runBp2BuildTestCaseWithLibs(t *testing.T, tc bp2buildTestCase) {
+func runBp2BuildTestCaseWithPythonLibraries(t *testing.T, tc bp2buildTestCase) {
+ t.Helper()
runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {
ctx.RegisterModuleType("python_library", python.PythonLibraryFactory)
ctx.RegisterModuleType("python_library_host", python.PythonLibraryHostFactory)
@@ -15,11 +16,10 @@
}
func TestPythonBinaryHostSimple(t *testing.T) {
- runBp2BuildTestCaseWithLibs(t, bp2buildTestCase{
- description: "simple python_binary_host converts to a native py_binary",
- moduleTypeUnderTest: "python_binary_host",
- moduleTypeUnderTestFactory: python.PythonBinaryHostFactory,
- moduleTypeUnderTestBp2BuildMutator: python.PythonBinaryBp2Build,
+ runBp2BuildTestCaseWithPythonLibraries(t, bp2buildTestCase{
+ description: "simple python_binary_host converts to a native py_binary",
+ moduleTypeUnderTest: "python_binary_host",
+ moduleTypeUnderTestFactory: python.PythonBinaryHostFactory,
filesystem: map[string]string{
"a.py": "",
"b/c.py": "",
@@ -39,29 +39,28 @@
python_library_host {
name: "bar",
srcs: ["b/e.py"],
- bazel_module: { bp2build_available: true },
+ bazel_module: { bp2build_available: false },
}`,
- expectedBazelTargets: []string{`py_binary(
- name = "foo",
- data = ["files/data.txt"],
- deps = [":bar"],
- main = "a.py",
- srcs = [
+ expectedBazelTargets: []string{
+ makeBazelTarget("py_binary", "foo", attrNameToString{
+ "data": `["files/data.txt"]`,
+ "deps": `[":bar"]`,
+ "main": `"a.py"`,
+ "srcs": `[
"a.py",
"b/c.py",
"b/d.py",
- ],
-)`,
+ ]`,
+ }),
},
})
}
func TestPythonBinaryHostPy2(t *testing.T) {
runBp2BuildTestCaseSimple(t, bp2buildTestCase{
- description: "py2 python_binary_host",
- moduleTypeUnderTest: "python_binary_host",
- moduleTypeUnderTestFactory: python.PythonBinaryHostFactory,
- moduleTypeUnderTestBp2BuildMutator: python.PythonBinaryBp2Build,
+ description: "py2 python_binary_host",
+ moduleTypeUnderTest: "python_binary_host",
+ moduleTypeUnderTestFactory: python.PythonBinaryHostFactory,
blueprint: `python_binary_host {
name: "foo",
srcs: ["a.py"],
@@ -77,21 +76,20 @@
bazel_module: { bp2build_available: true },
}
`,
- expectedBazelTargets: []string{`py_binary(
- name = "foo",
- python_version = "PY2",
- srcs = ["a.py"],
-)`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("py_binary", "foo", attrNameToString{
+ "python_version": `"PY2"`,
+ "srcs": `["a.py"]`,
+ }),
},
})
}
func TestPythonBinaryHostPy3(t *testing.T) {
runBp2BuildTestCaseSimple(t, bp2buildTestCase{
- description: "py3 python_binary_host",
- moduleTypeUnderTest: "python_binary_host",
- moduleTypeUnderTestFactory: python.PythonBinaryHostFactory,
- moduleTypeUnderTestBp2BuildMutator: python.PythonBinaryBp2Build,
+ description: "py3 python_binary_host",
+ moduleTypeUnderTest: "python_binary_host",
+ moduleTypeUnderTestFactory: python.PythonBinaryHostFactory,
blueprint: `python_binary_host {
name: "foo",
srcs: ["a.py"],
@@ -109,20 +107,18 @@
`,
expectedBazelTargets: []string{
// python_version is PY3 by default.
- `py_binary(
- name = "foo",
- srcs = ["a.py"],
-)`,
+ makeBazelTarget("py_binary", "foo", attrNameToString{
+ "srcs": `["a.py"]`,
+ }),
},
})
}
func TestPythonBinaryHostArchVariance(t *testing.T) {
runBp2BuildTestCaseSimple(t, bp2buildTestCase{
- description: "test arch variants",
- moduleTypeUnderTest: "python_binary_host",
- moduleTypeUnderTestFactory: python.PythonBinaryHostFactory,
- moduleTypeUnderTestBp2BuildMutator: python.PythonBinaryBp2Build,
+ description: "test arch variants",
+ moduleTypeUnderTest: "python_binary_host",
+ moduleTypeUnderTestFactory: python.PythonBinaryHostFactory,
filesystem: map[string]string{
"dir/arm.py": "",
"dir/x86.py": "",
@@ -139,14 +135,13 @@
},
}`,
expectedBazelTargets: []string{
- `py_binary(
- name = "foo-arm",
- srcs = select({
+ makeBazelTarget("py_binary", "foo-arm", attrNameToString{
+ "srcs": `select({
"//build/bazel/platforms/arch:arm": ["arm.py"],
"//build/bazel/platforms/arch:x86": ["x86.py"],
"//conditions:default": [],
- }),
-)`,
+ })`,
+ }),
},
})
}
diff --git a/bp2build/python_library_conversion_test.go b/bp2build/python_library_conversion_test.go
index 7f983ad..6b26105 100644
--- a/bp2build/python_library_conversion_test.go
+++ b/bp2build/python_library_conversion_test.go
@@ -11,38 +11,47 @@
// TODO(alexmarquez): Should be lifted into a generic Bp2Build file
type PythonLibBp2Build func(ctx android.TopDownMutatorContext)
-func TestPythonLibrary(t *testing.T) {
- testPythonLib(t, "python_library",
- python.PythonLibraryFactory, python.PythonLibraryBp2Build,
- func(ctx android.RegistrationContext) {})
-}
-
-func TestPythonLibraryHost(t *testing.T) {
- testPythonLib(t, "python_library_host",
- python.PythonLibraryHostFactory, python.PythonLibraryHostBp2Build,
- func(ctx android.RegistrationContext) {
- ctx.RegisterModuleType("python_library", python.PythonLibraryFactory)
- })
-}
-
-func testPythonLib(t *testing.T, modType string,
- factory android.ModuleFactory, mutator PythonLibBp2Build,
- registration func(ctx android.RegistrationContext)) {
+func runPythonLibraryTestCase(t *testing.T, tc bp2buildTestCase) {
t.Helper()
- // Simple
- runBp2BuildTestCase(t, registration, bp2buildTestCase{
- description: fmt.Sprintf("simple %s converts to a native py_library", modType),
- moduleTypeUnderTest: modType,
- moduleTypeUnderTestFactory: factory,
- moduleTypeUnderTestBp2BuildMutator: mutator,
- filesystem: map[string]string{
- "a.py": "",
- "b/c.py": "",
- "b/d.py": "",
- "b/e.py": "",
- "files/data.txt": "",
- },
- blueprint: fmt.Sprintf(`%s {
+ testCase := tc
+ testCase.description = fmt.Sprintf(testCase.description, "python_library")
+ testCase.blueprint = fmt.Sprintf(testCase.blueprint, "python_library")
+ testCase.moduleTypeUnderTest = "python_library"
+ testCase.moduleTypeUnderTestFactory = python.PythonLibraryFactory
+ runBp2BuildTestCaseSimple(t, testCase)
+}
+
+func runPythonLibraryHostTestCase(t *testing.T, tc bp2buildTestCase) {
+ t.Helper()
+ testCase := tc
+ testCase.description = fmt.Sprintf(testCase.description, "python_library_host")
+ testCase.blueprint = fmt.Sprintf(testCase.blueprint, "python_library_host")
+ testCase.moduleTypeUnderTest = "python_library_host"
+ testCase.moduleTypeUnderTestFactory = python.PythonLibraryHostFactory
+ runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("python_library", python.PythonLibraryFactory)
+ },
+ testCase)
+}
+
+func runPythonLibraryTestCases(t *testing.T, tc bp2buildTestCase) {
+ t.Helper()
+ runPythonLibraryTestCase(t, tc)
+ runPythonLibraryHostTestCase(t, tc)
+}
+
+func TestSimplePythonLib(t *testing.T) {
+ testCases := []bp2buildTestCase{
+ {
+ description: "simple %s converts to a native py_library",
+ filesystem: map[string]string{
+ "a.py": "",
+ "b/c.py": "",
+ "b/d.py": "",
+ "b/e.py": "",
+ "files/data.txt": "",
+ },
+ blueprint: `%s {
name: "foo",
srcs: ["**/*.py"],
exclude_srcs: ["b/e.py"],
@@ -54,28 +63,23 @@
name: "bar",
srcs: ["b/e.py"],
bazel_module: { bp2build_available: false },
- }`, modType),
- expectedBazelTargets: []string{`py_library(
- name = "foo",
- data = ["files/data.txt"],
- deps = [":bar"],
- srcs = [
+ }`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("py_library", "foo", attrNameToString{
+ "data": `["files/data.txt"]`,
+ "deps": `[":bar"]`,
+ "srcs": `[
"a.py",
"b/c.py",
"b/d.py",
- ],
- srcs_version = "PY3",
-)`,
+ ]`,
+ "srcs_version": `"PY3"`,
+ }),
+ },
},
- })
-
- // PY2
- runBp2BuildTestCaseSimple(t, bp2buildTestCase{
- description: fmt.Sprintf("py2 %s converts to a native py_library", modType),
- moduleTypeUnderTest: modType,
- moduleTypeUnderTestFactory: factory,
- moduleTypeUnderTestBp2BuildMutator: mutator,
- blueprint: fmt.Sprintf(`%s {
+ {
+ description: "py2 %s converts to a native py_library",
+ blueprint: `%s {
name: "foo",
srcs: ["a.py"],
version: {
@@ -88,22 +92,17 @@
},
bazel_module: { bp2build_available: true },
-}`, modType),
- expectedBazelTargets: []string{`py_library(
- name = "foo",
- srcs = ["a.py"],
- srcs_version = "PY2",
-)`,
+}`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("py_library", "foo", attrNameToString{
+ "srcs": `["a.py"]`,
+ "srcs_version": `"PY2"`,
+ }),
+ },
},
- })
-
- // PY3
- runBp2BuildTestCaseSimple(t, bp2buildTestCase{
- description: fmt.Sprintf("py3 %s converts to a native py_library", modType),
- moduleTypeUnderTest: modType,
- moduleTypeUnderTestFactory: factory,
- moduleTypeUnderTestBp2BuildMutator: mutator,
- blueprint: fmt.Sprintf(`%s {
+ {
+ description: "py3 %s converts to a native py_library",
+ blueprint: `%s {
name: "foo",
srcs: ["a.py"],
version: {
@@ -116,22 +115,17 @@
},
bazel_module: { bp2build_available: true },
-}`, modType),
- expectedBazelTargets: []string{`py_library(
- name = "foo",
- srcs = ["a.py"],
- srcs_version = "PY3",
-)`,
+}`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("py_library", "foo", attrNameToString{
+ "srcs": `["a.py"]`,
+ "srcs_version": `"PY3"`,
+ }),
+ },
},
- })
-
- // Both
- runBp2BuildTestCaseSimple(t, bp2buildTestCase{
- description: fmt.Sprintf("py2&3 %s converts to a native py_library", modType),
- moduleTypeUnderTest: modType,
- moduleTypeUnderTestFactory: factory,
- moduleTypeUnderTestBp2BuildMutator: mutator,
- blueprint: fmt.Sprintf(`%s {
+ {
+ description: "py2&3 %s converts to a native py_library",
+ blueprint: `%s {
name: "foo",
srcs: ["a.py"],
version: {
@@ -144,44 +138,31 @@
},
bazel_module: { bp2build_available: true },
-}`, modType),
- expectedBazelTargets: []string{
- // srcs_version is PY2ANDPY3 by default.
- `py_library(
- name = "foo",
- srcs = ["a.py"],
-)`,
+}`,
+ expectedBazelTargets: []string{
+ // srcs_version is PY2ANDPY3 by default.
+ makeBazelTarget("py_library", "foo", attrNameToString{
+ "srcs": `["a.py"]`,
+ }),
+ },
},
- })
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.description, func(t *testing.T) {
+ runPythonLibraryTestCases(t, tc)
+ })
+ }
}
-func TestPythonLibraryArchVariance(t *testing.T) {
- testPythonArchVariance(t, "python_library", "py_library",
- python.PythonLibraryFactory, python.PythonLibraryBp2Build,
- func(ctx android.RegistrationContext) {})
-}
-
-func TestPythonLibraryHostArchVariance(t *testing.T) {
- testPythonArchVariance(t, "python_library_host", "py_library",
- python.PythonLibraryHostFactory, python.PythonLibraryHostBp2Build,
- func(ctx android.RegistrationContext) {})
-}
-
-// TODO: refactor python_binary_conversion_test to use this
-func testPythonArchVariance(t *testing.T, modType, bazelTarget string,
- factory android.ModuleFactory, mutator PythonLibBp2Build,
- registration func(ctx android.RegistrationContext)) {
- t.Helper()
- runBp2BuildTestCase(t, registration, bp2buildTestCase{
- description: fmt.Sprintf("test %s arch variants", modType),
- moduleTypeUnderTest: modType,
- moduleTypeUnderTestFactory: factory,
- moduleTypeUnderTestBp2BuildMutator: mutator,
+func TestPythonArchVariance(t *testing.T) {
+ runPythonLibraryTestCases(t, bp2buildTestCase{
+ description: "test %s arch variants",
filesystem: map[string]string{
"dir/arm.py": "",
"dir/x86.py": "",
},
- blueprint: fmt.Sprintf(`%s {
+ blueprint: `%s {
name: "foo",
arch: {
arm: {
@@ -191,17 +172,16 @@
srcs: ["x86.py"],
},
},
- }`, modType),
+ }`,
expectedBazelTargets: []string{
- fmt.Sprintf(`%s(
- name = "foo",
- srcs = select({
+ makeBazelTarget("py_library", "foo", attrNameToString{
+ "srcs": `select({
"//build/bazel/platforms/arch:arm": ["arm.py"],
"//build/bazel/platforms/arch:x86": ["x86.py"],
"//conditions:default": [],
- }),
- srcs_version = "PY3",
-)`, bazelTarget),
+ })`,
+ "srcs_version": `"PY3"`,
+ }),
},
})
}
diff --git a/bp2build/sh_conversion_test.go b/bp2build/sh_conversion_test.go
index 82e0a14..ac89087 100644
--- a/bp2build/sh_conversion_test.go
+++ b/bp2build/sh_conversion_test.go
@@ -55,18 +55,38 @@
func TestShBinarySimple(t *testing.T) {
runShBinaryTestCase(t, bp2buildTestCase{
- description: "sh_binary test",
- moduleTypeUnderTest: "sh_binary",
- moduleTypeUnderTestFactory: sh.ShBinaryFactory,
- moduleTypeUnderTestBp2BuildMutator: sh.ShBinaryBp2Build,
+ description: "sh_binary test",
+ moduleTypeUnderTest: "sh_binary",
+ moduleTypeUnderTestFactory: sh.ShBinaryFactory,
+ blueprint: `sh_binary {
+ name: "foo",
+ src: "foo.sh",
+ filename: "foo.exe",
+ sub_dir: "sub",
+ bazel_module: { bp2build_available: true },
+}`,
+ expectedBazelTargets: []string{
+ makeBazelTarget("sh_binary", "foo", attrNameToString{
+ "srcs": `["foo.sh"]`,
+ "filename": `"foo.exe"`,
+ "sub_dir": `"sub"`,
+ })},
+ })
+}
+
+func TestShBinaryDefaults(t *testing.T) {
+ runShBinaryTestCase(t, bp2buildTestCase{
+ description: "sh_binary test",
+ moduleTypeUnderTest: "sh_binary",
+ moduleTypeUnderTestFactory: sh.ShBinaryFactory,
blueprint: `sh_binary {
name: "foo",
src: "foo.sh",
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`sh_binary(
- name = "foo",
- srcs = ["foo.sh"],
-)`},
+ expectedBazelTargets: []string{
+ makeBazelTarget("sh_binary", "foo", attrNameToString{
+ "srcs": `["foo.sh"]`,
+ })},
})
}
diff --git a/bp2build/soong_config_module_type_conversion_test.go b/bp2build/soong_config_module_type_conversion_test.go
new file mode 100644
index 0000000..f1489aa
--- /dev/null
+++ b/bp2build/soong_config_module_type_conversion_test.go
@@ -0,0 +1,836 @@
+// 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 bp2build
+
+import (
+ "android/soong/android"
+ "android/soong/cc"
+ "testing"
+)
+
+func runSoongConfigModuleTypeTest(t *testing.T, tc bp2buildTestCase) {
+ t.Helper()
+ runBp2BuildTestCase(t, registerSoongConfigModuleTypes, tc)
+}
+
+func registerSoongConfigModuleTypes(ctx android.RegistrationContext) {
+ cc.RegisterCCBuildComponents(ctx)
+
+ ctx.RegisterModuleType("soong_config_module_type_import", android.SoongConfigModuleTypeImportFactory)
+ ctx.RegisterModuleType("soong_config_module_type", android.SoongConfigModuleTypeFactory)
+ ctx.RegisterModuleType("soong_config_string_variable", android.SoongConfigStringVariableDummyFactory)
+ ctx.RegisterModuleType("soong_config_bool_variable", android.SoongConfigBoolVariableDummyFactory)
+
+ ctx.RegisterModuleType("cc_library", cc.LibraryFactory)
+}
+
+func TestSoongConfigModuleType(t *testing.T) {
+ bp := `
+soong_config_module_type {
+ name: "custom_cc_library_static",
+ module_type: "cc_library_static",
+ config_namespace: "acme",
+ bool_variables: ["feature1"],
+ properties: ["cflags"],
+}
+
+custom_cc_library_static {
+ name: "foo",
+ bazel_module: { bp2build_available: true },
+ soong_config_variables: {
+ feature1: {
+ conditions_default: {
+ cflags: ["-DDEFAULT1"],
+ },
+ cflags: ["-DFEATURE1"],
+ },
+ },
+}
+`
+
+ runSoongConfigModuleTypeTest(t, bp2buildTestCase{
+ description: "soong config variables - soong_config_module_type is supported in bp2build",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ blueprint: bp,
+ expectedBazelTargets: []string{`cc_library_static(
+ name = "foo",
+ copts = select({
+ "//build/bazel/product_variables:acme__feature1__enabled": ["-DFEATURE1"],
+ "//conditions:default": ["-DDEFAULT1"],
+ }),
+ local_includes = ["."],
+)`}})
+}
+
+func TestSoongConfigModuleTypeImport(t *testing.T) {
+ configBp := `
+soong_config_module_type {
+ name: "custom_cc_library_static",
+ module_type: "cc_library_static",
+ config_namespace: "acme",
+ bool_variables: ["feature1"],
+ properties: ["cflags"],
+}
+`
+ bp := `
+soong_config_module_type_import {
+ from: "foo/bar/SoongConfig.bp",
+ module_types: ["custom_cc_library_static"],
+}
+
+custom_cc_library_static {
+ name: "foo",
+ bazel_module: { bp2build_available: true },
+ soong_config_variables: {
+ feature1: {
+ conditions_default: {
+ cflags: ["-DDEFAULT1"],
+ },
+ cflags: ["-DFEATURE1"],
+ },
+ },
+}
+`
+
+ runSoongConfigModuleTypeTest(t, bp2buildTestCase{
+ description: "soong config variables - soong_config_module_type_import is supported in bp2build",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ filesystem: map[string]string{
+ "foo/bar/SoongConfig.bp": configBp,
+ },
+ blueprint: bp,
+ expectedBazelTargets: []string{`cc_library_static(
+ name = "foo",
+ copts = select({
+ "//build/bazel/product_variables:acme__feature1__enabled": ["-DFEATURE1"],
+ "//conditions:default": ["-DDEFAULT1"],
+ }),
+ local_includes = ["."],
+)`}})
+}
+
+func TestSoongConfigModuleType_StringVar(t *testing.T) {
+ bp := `
+soong_config_string_variable {
+ name: "board",
+ values: ["soc_a", "soc_b", "soc_c"],
+}
+
+soong_config_module_type {
+ name: "custom_cc_library_static",
+ module_type: "cc_library_static",
+ config_namespace: "acme",
+ variables: ["board"],
+ properties: ["cflags"],
+}
+
+custom_cc_library_static {
+ name: "foo",
+ bazel_module: { bp2build_available: true },
+ soong_config_variables: {
+ board: {
+ soc_a: {
+ cflags: ["-DSOC_A"],
+ },
+ soc_b: {
+ cflags: ["-DSOC_B"],
+ },
+ soc_c: {},
+ conditions_default: {
+ cflags: ["-DSOC_DEFAULT"]
+ },
+ },
+ },
+}
+`
+
+ runSoongConfigModuleTypeTest(t, bp2buildTestCase{
+ description: "soong config variables - generates selects for string vars",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ blueprint: bp,
+ expectedBazelTargets: []string{`cc_library_static(
+ name = "foo",
+ copts = select({
+ "//build/bazel/product_variables:acme__board__soc_a": ["-DSOC_A"],
+ "//build/bazel/product_variables:acme__board__soc_b": ["-DSOC_B"],
+ "//conditions:default": ["-DSOC_DEFAULT"],
+ }),
+ local_includes = ["."],
+)`}})
+}
+
+func TestSoongConfigModuleType_StringAndBoolVar(t *testing.T) {
+ bp := `
+soong_config_bool_variable {
+ name: "feature1",
+}
+
+soong_config_bool_variable {
+ name: "feature2",
+}
+
+soong_config_string_variable {
+ name: "board",
+ values: ["soc_a", "soc_b", "soc_c"],
+}
+
+soong_config_module_type {
+ name: "custom_cc_library_static",
+ module_type: "cc_library_static",
+ config_namespace: "acme",
+ variables: ["feature1", "feature2", "board"],
+ properties: ["cflags"],
+}
+
+custom_cc_library_static {
+ name: "foo",
+ bazel_module: { bp2build_available: true },
+ soong_config_variables: {
+ feature1: {
+ conditions_default: {
+ cflags: ["-DDEFAULT1"],
+ },
+ cflags: ["-DFEATURE1"],
+ },
+ feature2: {
+ cflags: ["-DFEATURE2"],
+ conditions_default: {
+ cflags: ["-DDEFAULT2"],
+ },
+ },
+ board: {
+ soc_a: {
+ cflags: ["-DSOC_A"],
+ },
+ soc_b: {
+ cflags: ["-DSOC_B"],
+ },
+ soc_c: {},
+ conditions_default: {
+ cflags: ["-DSOC_DEFAULT"]
+ },
+ },
+ },
+}`
+
+ runSoongConfigModuleTypeTest(t, bp2buildTestCase{
+ description: "soong config variables - generates selects for multiple variable types",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ blueprint: bp,
+ expectedBazelTargets: []string{`cc_library_static(
+ name = "foo",
+ copts = select({
+ "//build/bazel/product_variables:acme__board__soc_a": ["-DSOC_A"],
+ "//build/bazel/product_variables:acme__board__soc_b": ["-DSOC_B"],
+ "//conditions:default": ["-DSOC_DEFAULT"],
+ }) + select({
+ "//build/bazel/product_variables:acme__feature1__enabled": ["-DFEATURE1"],
+ "//conditions:default": ["-DDEFAULT1"],
+ }) + select({
+ "//build/bazel/product_variables:acme__feature2__enabled": ["-DFEATURE2"],
+ "//conditions:default": ["-DDEFAULT2"],
+ }),
+ local_includes = ["."],
+)`}})
+}
+
+func TestSoongConfigModuleType_StringVar_LabelListDeps(t *testing.T) {
+ bp := `
+soong_config_string_variable {
+ name: "board",
+ values: ["soc_a", "soc_b", "soc_c"],
+}
+
+soong_config_module_type {
+ name: "custom_cc_library_static",
+ module_type: "cc_library_static",
+ config_namespace: "acme",
+ variables: ["board"],
+ properties: ["cflags", "static_libs"],
+}
+
+custom_cc_library_static {
+ name: "foo",
+ bazel_module: { bp2build_available: true },
+ soong_config_variables: {
+ board: {
+ soc_a: {
+ cflags: ["-DSOC_A"],
+ static_libs: ["soc_a_dep"],
+ },
+ soc_b: {
+ cflags: ["-DSOC_B"],
+ static_libs: ["soc_b_dep"],
+ },
+ soc_c: {},
+ conditions_default: {
+ cflags: ["-DSOC_DEFAULT"],
+ static_libs: ["soc_default_static_dep"],
+ },
+ },
+ },
+}`
+
+ otherDeps := `
+cc_library_static { name: "soc_a_dep", bazel_module: { bp2build_available: false } }
+cc_library_static { name: "soc_b_dep", bazel_module: { bp2build_available: false } }
+cc_library_static { name: "soc_default_static_dep", bazel_module: { bp2build_available: false } }
+`
+
+ runSoongConfigModuleTypeTest(t, bp2buildTestCase{
+ description: "soong config variables - generates selects for label list attributes",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ blueprint: bp,
+ filesystem: map[string]string{
+ "foo/bar/Android.bp": otherDeps,
+ },
+ expectedBazelTargets: []string{`cc_library_static(
+ name = "foo",
+ copts = select({
+ "//build/bazel/product_variables:acme__board__soc_a": ["-DSOC_A"],
+ "//build/bazel/product_variables:acme__board__soc_b": ["-DSOC_B"],
+ "//conditions:default": ["-DSOC_DEFAULT"],
+ }),
+ implementation_deps = select({
+ "//build/bazel/product_variables:acme__board__soc_a": ["//foo/bar:soc_a_dep"],
+ "//build/bazel/product_variables:acme__board__soc_b": ["//foo/bar:soc_b_dep"],
+ "//conditions:default": ["//foo/bar:soc_default_static_dep"],
+ }),
+ local_includes = ["."],
+)`}})
+}
+
+func TestSoongConfigModuleType_Defaults_SingleNamespace(t *testing.T) {
+ bp := `
+soong_config_module_type {
+ name: "vendor_foo_cc_defaults",
+ module_type: "cc_defaults",
+ config_namespace: "vendor_foo",
+ bool_variables: ["feature"],
+ properties: ["cflags", "cppflags"],
+}
+
+vendor_foo_cc_defaults {
+ name: "foo_defaults_1",
+ soong_config_variables: {
+ feature: {
+ cflags: ["-cflag_feature_1"],
+ conditions_default: {
+ cflags: ["-cflag_default_1"],
+ },
+ },
+ },
+}
+
+vendor_foo_cc_defaults {
+ name: "foo_defaults_2",
+ defaults: ["foo_defaults_1"],
+ soong_config_variables: {
+ feature: {
+ cflags: ["-cflag_feature_2"],
+ conditions_default: {
+ cflags: ["-cflag_default_2"],
+ },
+ },
+ },
+}
+
+cc_library_static {
+ name: "lib",
+ defaults: ["foo_defaults_2"],
+ bazel_module: { bp2build_available: true },
+}
+`
+
+ runSoongConfigModuleTypeTest(t, bp2buildTestCase{
+ description: "soong config variables - defaults with a single namespace",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ blueprint: bp,
+ expectedBazelTargets: []string{`cc_library_static(
+ name = "lib",
+ copts = select({
+ "//build/bazel/product_variables:vendor_foo__feature__enabled": [
+ "-cflag_feature_2",
+ "-cflag_feature_1",
+ ],
+ "//conditions:default": [
+ "-cflag_default_2",
+ "-cflag_default_1",
+ ],
+ }),
+ local_includes = ["."],
+)`}})
+}
+
+func TestSoongConfigModuleType_MultipleDefaults_SingleNamespace(t *testing.T) {
+ bp := `
+soong_config_module_type {
+ name: "foo_cc_defaults",
+ module_type: "cc_defaults",
+ config_namespace: "acme",
+ bool_variables: ["feature"],
+ properties: ["cflags"],
+}
+
+soong_config_module_type {
+ name: "bar_cc_defaults",
+ module_type: "cc_defaults",
+ config_namespace: "acme",
+ bool_variables: ["feature"],
+ properties: ["cflags", "asflags"],
+}
+
+foo_cc_defaults {
+ name: "foo_defaults",
+ soong_config_variables: {
+ feature: {
+ cflags: ["-cflag_foo"],
+ conditions_default: {
+ cflags: ["-cflag_default_foo"],
+ },
+ },
+ },
+}
+
+bar_cc_defaults {
+ name: "bar_defaults",
+ srcs: ["file.S"],
+ soong_config_variables: {
+ feature: {
+ cflags: ["-cflag_bar"],
+ asflags: ["-asflag_bar"],
+ conditions_default: {
+ asflags: ["-asflag_default_bar"],
+ cflags: ["-cflag_default_bar"],
+ },
+ },
+ },
+}
+
+cc_library_static {
+ name: "lib",
+ defaults: ["foo_defaults", "bar_defaults"],
+ bazel_module: { bp2build_available: true },
+}
+
+cc_library_static {
+ name: "lib2",
+ defaults: ["bar_defaults", "foo_defaults"],
+ bazel_module: { bp2build_available: true },
+}
+`
+
+ runSoongConfigModuleTypeTest(t, bp2buildTestCase{
+ description: "soong config variables - multiple defaults with a single namespace",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ blueprint: bp,
+ expectedBazelTargets: []string{`cc_library_static(
+ name = "lib",
+ asflags = select({
+ "//build/bazel/product_variables:acme__feature__enabled": ["-asflag_bar"],
+ "//conditions:default": ["-asflag_default_bar"],
+ }),
+ copts = select({
+ "//build/bazel/product_variables:acme__feature__enabled": [
+ "-cflag_foo",
+ "-cflag_bar",
+ ],
+ "//conditions:default": [
+ "-cflag_default_foo",
+ "-cflag_default_bar",
+ ],
+ }),
+ local_includes = ["."],
+ srcs_as = ["file.S"],
+)`,
+ `cc_library_static(
+ name = "lib2",
+ asflags = select({
+ "//build/bazel/product_variables:acme__feature__enabled": ["-asflag_bar"],
+ "//conditions:default": ["-asflag_default_bar"],
+ }),
+ copts = select({
+ "//build/bazel/product_variables:acme__feature__enabled": [
+ "-cflag_bar",
+ "-cflag_foo",
+ ],
+ "//conditions:default": [
+ "-cflag_default_bar",
+ "-cflag_default_foo",
+ ],
+ }),
+ local_includes = ["."],
+ srcs_as = ["file.S"],
+)`}})
+}
+
+func TestSoongConfigModuleType_Defaults_MultipleNamespaces(t *testing.T) {
+ bp := `
+soong_config_module_type {
+ name: "vendor_foo_cc_defaults",
+ module_type: "cc_defaults",
+ config_namespace: "vendor_foo",
+ bool_variables: ["feature"],
+ properties: ["cflags"],
+}
+
+soong_config_module_type {
+ name: "vendor_bar_cc_defaults",
+ module_type: "cc_defaults",
+ config_namespace: "vendor_bar",
+ bool_variables: ["feature"],
+ properties: ["cflags"],
+}
+
+soong_config_module_type {
+ name: "vendor_qux_cc_defaults",
+ module_type: "cc_defaults",
+ config_namespace: "vendor_qux",
+ bool_variables: ["feature"],
+ properties: ["cflags"],
+}
+
+vendor_foo_cc_defaults {
+ name: "foo_defaults",
+ soong_config_variables: {
+ feature: {
+ cflags: ["-DVENDOR_FOO_FEATURE"],
+ conditions_default: {
+ cflags: ["-DVENDOR_FOO_DEFAULT"],
+ },
+ },
+ },
+}
+
+vendor_bar_cc_defaults {
+ name: "bar_defaults",
+ soong_config_variables: {
+ feature: {
+ cflags: ["-DVENDOR_BAR_FEATURE"],
+ conditions_default: {
+ cflags: ["-DVENDOR_BAR_DEFAULT"],
+ },
+ },
+ },
+}
+
+vendor_qux_cc_defaults {
+ name: "qux_defaults",
+ defaults: ["bar_defaults"],
+ soong_config_variables: {
+ feature: {
+ cflags: ["-DVENDOR_QUX_FEATURE"],
+ conditions_default: {
+ cflags: ["-DVENDOR_QUX_DEFAULT"],
+ },
+ },
+ },
+}
+
+cc_library_static {
+ name: "lib",
+ defaults: ["foo_defaults", "qux_defaults"],
+ bazel_module: { bp2build_available: true },
+}
+`
+
+ runSoongConfigModuleTypeTest(t, bp2buildTestCase{
+ description: "soong config variables - defaults with multiple namespaces",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ blueprint: bp,
+ expectedBazelTargets: []string{`cc_library_static(
+ name = "lib",
+ copts = select({
+ "//build/bazel/product_variables:vendor_bar__feature__enabled": ["-DVENDOR_BAR_FEATURE"],
+ "//conditions:default": ["-DVENDOR_BAR_DEFAULT"],
+ }) + select({
+ "//build/bazel/product_variables:vendor_foo__feature__enabled": ["-DVENDOR_FOO_FEATURE"],
+ "//conditions:default": ["-DVENDOR_FOO_DEFAULT"],
+ }) + select({
+ "//build/bazel/product_variables:vendor_qux__feature__enabled": ["-DVENDOR_QUX_FEATURE"],
+ "//conditions:default": ["-DVENDOR_QUX_DEFAULT"],
+ }),
+ local_includes = ["."],
+)`}})
+}
+
+func TestSoongConfigModuleType_Defaults(t *testing.T) {
+ bp := `
+soong_config_string_variable {
+ name: "library_linking_strategy",
+ values: [
+ "prefer_static",
+ ],
+}
+
+soong_config_module_type {
+ name: "library_linking_strategy_cc_defaults",
+ module_type: "cc_defaults",
+ config_namespace: "ANDROID",
+ variables: ["library_linking_strategy"],
+ properties: [
+ "shared_libs",
+ "static_libs",
+ ],
+}
+
+library_linking_strategy_cc_defaults {
+ name: "library_linking_strategy_lib_a_defaults",
+ soong_config_variables: {
+ library_linking_strategy: {
+ prefer_static: {
+ static_libs: [
+ "lib_a",
+ ],
+ },
+ conditions_default: {
+ shared_libs: [
+ "lib_a",
+ ],
+ },
+ },
+ },
+}
+
+library_linking_strategy_cc_defaults {
+ name: "library_linking_strategy_merged_defaults",
+ defaults: ["library_linking_strategy_lib_a_defaults"],
+ soong_config_variables: {
+ library_linking_strategy: {
+ prefer_static: {
+ static_libs: [
+ "lib_b",
+ ],
+ },
+ conditions_default: {
+ shared_libs: [
+ "lib_b",
+ ],
+ },
+ },
+ },
+}
+
+cc_binary {
+ name: "library_linking_strategy_sample_binary",
+ srcs: ["library_linking_strategy.cc"],
+ defaults: ["library_linking_strategy_merged_defaults"],
+}`
+
+ otherDeps := `
+cc_library { name: "lib_a", bazel_module: { bp2build_available: false } }
+cc_library { name: "lib_b", bazel_module: { bp2build_available: false } }
+cc_library { name: "lib_default", bazel_module: { bp2build_available: false } }
+`
+
+ runSoongConfigModuleTypeTest(t, bp2buildTestCase{
+ description: "soong config variables - generates selects for library_linking_strategy",
+ moduleTypeUnderTest: "cc_binary",
+ moduleTypeUnderTestFactory: cc.BinaryFactory,
+ blueprint: bp,
+ filesystem: map[string]string{
+ "foo/bar/Android.bp": otherDeps,
+ },
+ expectedBazelTargets: []string{`cc_binary(
+ name = "library_linking_strategy_sample_binary",
+ deps = select({
+ "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": [
+ "//foo/bar:lib_b_bp2build_cc_library_static",
+ "//foo/bar:lib_a_bp2build_cc_library_static",
+ ],
+ "//conditions:default": [],
+ }),
+ dynamic_deps = select({
+ "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": [],
+ "//conditions:default": [
+ "//foo/bar:lib_b",
+ "//foo/bar:lib_a",
+ ],
+ }),
+ local_includes = ["."],
+ srcs = ["library_linking_strategy.cc"],
+)`}})
+}
+
+func TestSoongConfigModuleType_Defaults_Another(t *testing.T) {
+ bp := `
+soong_config_string_variable {
+ name: "library_linking_strategy",
+ values: [
+ "prefer_static",
+ ],
+}
+
+soong_config_module_type {
+ name: "library_linking_strategy_cc_defaults",
+ module_type: "cc_defaults",
+ config_namespace: "ANDROID",
+ variables: ["library_linking_strategy"],
+ properties: [
+ "shared_libs",
+ "static_libs",
+ ],
+}
+
+library_linking_strategy_cc_defaults {
+ name: "library_linking_strategy_sample_defaults",
+ soong_config_variables: {
+ library_linking_strategy: {
+ prefer_static: {
+ static_libs: [
+ "lib_a",
+ "lib_b",
+ ],
+ },
+ conditions_default: {
+ shared_libs: [
+ "lib_a",
+ "lib_b",
+ ],
+ },
+ },
+ },
+}
+
+cc_binary {
+ name: "library_linking_strategy_sample_binary",
+ srcs: ["library_linking_strategy.cc"],
+ defaults: ["library_linking_strategy_sample_defaults"],
+}`
+
+ otherDeps := `
+cc_library { name: "lib_a", bazel_module: { bp2build_available: false } }
+cc_library { name: "lib_b", bazel_module: { bp2build_available: false } }
+`
+
+ runSoongConfigModuleTypeTest(t, bp2buildTestCase{
+ description: "soong config variables - generates selects for library_linking_strategy",
+ moduleTypeUnderTest: "cc_binary",
+ moduleTypeUnderTestFactory: cc.BinaryFactory,
+ blueprint: bp,
+ filesystem: map[string]string{
+ "foo/bar/Android.bp": otherDeps,
+ },
+ expectedBazelTargets: []string{`cc_binary(
+ name = "library_linking_strategy_sample_binary",
+ deps = select({
+ "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": [
+ "//foo/bar:lib_a_bp2build_cc_library_static",
+ "//foo/bar:lib_b_bp2build_cc_library_static",
+ ],
+ "//conditions:default": [],
+ }),
+ dynamic_deps = select({
+ "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": [],
+ "//conditions:default": [
+ "//foo/bar:lib_a",
+ "//foo/bar:lib_b",
+ ],
+ }),
+ local_includes = ["."],
+ srcs = ["library_linking_strategy.cc"],
+)`}})
+}
+
+func TestSoongConfigModuleType_Defaults_UnusedProps(t *testing.T) {
+ bp := `
+soong_config_string_variable {
+ name: "alphabet",
+ values: [
+ "a",
+ "b",
+ "c", // unused
+ ],
+}
+
+soong_config_module_type {
+ name: "alphabet_cc_defaults",
+ module_type: "cc_defaults",
+ config_namespace: "ANDROID",
+ variables: ["alphabet"],
+ properties: [
+ "cflags", // unused
+ "shared_libs",
+ "static_libs",
+ ],
+}
+
+alphabet_cc_defaults {
+ name: "alphabet_sample_cc_defaults",
+ soong_config_variables: {
+ alphabet: {
+ a: {
+ shared_libs: [
+ "lib_a",
+ ],
+ },
+ b: {
+ shared_libs: [
+ "lib_b",
+ ],
+ },
+ conditions_default: {
+ static_libs: [
+ "lib_default",
+ ],
+ },
+ },
+ },
+}
+
+cc_binary {
+ name: "alphabet_binary",
+ srcs: ["main.cc"],
+ defaults: ["alphabet_sample_cc_defaults"],
+}`
+
+ otherDeps := `
+cc_library { name: "lib_a", bazel_module: { bp2build_available: false } }
+cc_library { name: "lib_b", bazel_module: { bp2build_available: false } }
+cc_library { name: "lib_default", bazel_module: { bp2build_available: false } }
+`
+
+ runSoongConfigModuleTypeTest(t, bp2buildTestCase{
+ description: "soong config variables - generates selects for library_linking_strategy",
+ moduleTypeUnderTest: "cc_binary",
+ moduleTypeUnderTestFactory: cc.BinaryFactory,
+ blueprint: bp,
+ filesystem: map[string]string{
+ "foo/bar/Android.bp": otherDeps,
+ },
+ expectedBazelTargets: []string{`cc_binary(
+ name = "alphabet_binary",
+ deps = select({
+ "//build/bazel/product_variables:android__alphabet__a": [],
+ "//build/bazel/product_variables:android__alphabet__b": [],
+ "//conditions:default": ["//foo/bar:lib_default_bp2build_cc_library_static"],
+ }),
+ dynamic_deps = select({
+ "//build/bazel/product_variables:android__alphabet__a": ["//foo/bar:lib_a"],
+ "//build/bazel/product_variables:android__alphabet__b": ["//foo/bar:lib_b"],
+ "//conditions:default": [],
+ }),
+ local_includes = ["."],
+ srcs = ["main.cc"],
+)`}})
+}
diff --git a/bp2build/testing.go b/bp2build/testing.go
index 7c2f43a..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
}
@@ -74,16 +74,15 @@
}
type bp2buildTestCase struct {
- description string
- moduleTypeUnderTest string
- moduleTypeUnderTestFactory android.ModuleFactory
- moduleTypeUnderTestBp2BuildMutator func(android.TopDownMutatorContext)
- blueprint string
- expectedBazelTargets []string
- filesystem map[string]string
- dir string
- expectedErr error
- unconvertedDepsMode unconvertedDepsMode
+ description string
+ moduleTypeUnderTest string
+ moduleTypeUnderTestFactory android.ModuleFactory
+ blueprint string
+ expectedBazelTargets []string
+ filesystem map[string]string
+ dir string
+ expectedErr error
+ unconvertedDepsMode unconvertedDepsMode
}
func runBp2BuildTestCase(t *testing.T, registerModuleTypes func(ctx android.RegistrationContext), tc bp2buildTestCase) {
@@ -105,7 +104,6 @@
registerModuleTypes(ctx)
ctx.RegisterModuleType(tc.moduleTypeUnderTest, tc.moduleTypeUnderTestFactory)
ctx.RegisterBp2BuildConfig(bp2buildConfig)
- ctx.RegisterBp2BuildMutator(tc.moduleTypeUnderTest, tc.moduleTypeUnderTestBp2BuildMutator)
ctx.RegisterForBazelConversion()
_, parseErrs := ctx.ParseFileList(dir, toParse)
@@ -129,14 +127,18 @@
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)
}
if actualCount, expectedCount := len(bazelTargets), len(tc.expectedBazelTargets); actualCount != expectedCount {
- t.Errorf("%s: Expected %d bazel target, got `%d``",
- tc.description, expectedCount, actualCount)
+ t.Errorf("%s: Expected %d bazel target (%s), got `%d`` (%s)",
+ tc.description, expectedCount, tc.expectedBazelTargets, actualCount, bazelTargets)
} else {
for i, target := range bazelTargets {
if w, g := tc.expectedBazelTargets[i], target.content; w != g {
@@ -149,15 +151,15 @@
}
type nestedProps struct {
- Nested_prop string
+ Nested_prop *string
}
type EmbeddedProps struct {
- Embedded_prop string
+ Embedded_prop *string
}
type OtherEmbeddedProps struct {
- Other_embedded_prop string
+ Other_embedded_prop *string
}
type customProps struct {
@@ -178,6 +180,9 @@
Arch_paths []string `android:"path,arch_variant"`
Arch_paths_exclude []string `android:"path,arch_variant"`
+
+ // Prop used to indicate this conversion should be 1 module -> multiple targets
+ One_to_many_prop *bool
}
type customModule struct {
@@ -262,86 +267,80 @@
}
type EmbeddedAttr struct {
- Embedded_attr string
+ Embedded_attr *string
}
type OtherEmbeddedAttr struct {
- Other_embedded_attr string
+ Other_embedded_attr *string
}
type customBazelModuleAttributes struct {
EmbeddedAttr
*OtherEmbeddedAttr
- String_prop string
+ String_ptr_prop *string
String_list_prop []string
Arch_paths bazel.LabelListAttribute
}
-func customBp2BuildMutator(ctx android.TopDownMutatorContext) {
- if m, ok := ctx.Module().(*customModule); ok {
- if !m.ConvertWithBp2build(ctx) {
- return
- }
+func (m *customModule) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
+ paths := bazel.LabelListAttribute{}
- paths := bazel.LabelListAttribute{}
+ if p := m.props.One_to_many_prop; p != nil && *p {
+ customBp2buildOneToMany(ctx, m)
+ return
+ }
- for axis, configToProps := range m.GetArchVariantProperties(ctx, &customProps{}) {
- for config, props := range configToProps {
- if archProps, ok := props.(*customProps); ok && archProps.Arch_paths != nil {
- paths.SetSelectValue(axis, config, android.BazelLabelForModuleSrcExcludes(ctx, archProps.Arch_paths, archProps.Arch_paths_exclude))
- }
+ for axis, configToProps := range m.GetArchVariantProperties(ctx, &customProps{}) {
+ for config, props := range configToProps {
+ if archProps, ok := props.(*customProps); ok && archProps.Arch_paths != nil {
+ paths.SetSelectValue(axis, config, android.BazelLabelForModuleSrcExcludes(ctx, archProps.Arch_paths, archProps.Arch_paths_exclude))
}
}
-
- paths.ResolveExcludes()
-
- attrs := &customBazelModuleAttributes{
- String_prop: m.props.String_prop,
- String_list_prop: m.props.String_list_prop,
- Arch_paths: paths,
- }
- attrs.Embedded_attr = m.props.Embedded_prop
- if m.props.OtherEmbeddedProps != nil {
- attrs.OtherEmbeddedAttr = &OtherEmbeddedAttr{Other_embedded_attr: m.props.OtherEmbeddedProps.Other_embedded_prop}
- }
-
- props := bazel.BazelTargetModuleProperties{
- Rule_class: "custom",
- }
-
- ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
}
+
+ paths.ResolveExcludes()
+
+ attrs := &customBazelModuleAttributes{
+ String_ptr_prop: m.props.String_ptr_prop,
+ String_list_prop: m.props.String_list_prop,
+ Arch_paths: paths,
+ }
+ attrs.Embedded_attr = m.props.Embedded_prop
+ if m.props.OtherEmbeddedProps != nil {
+ attrs.OtherEmbeddedAttr = &OtherEmbeddedAttr{Other_embedded_attr: m.props.OtherEmbeddedProps.Other_embedded_prop}
+ }
+
+ props := bazel.BazelTargetModuleProperties{
+ Rule_class: "custom",
+ }
+
+ ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
}
// A bp2build mutator that uses load statements and creates a 1:M mapping from
// module to target.
-func customBp2BuildMutatorFromStarlark(ctx android.TopDownMutatorContext) {
- if m, ok := ctx.Module().(*customModule); ok {
- if !m.ConvertWithBp2build(ctx) {
- return
- }
+func customBp2buildOneToMany(ctx android.TopDownMutatorContext, m *customModule) {
- baseName := m.Name()
- attrs := &customBazelModuleAttributes{}
+ baseName := m.Name()
+ attrs := &customBazelModuleAttributes{}
- myLibraryProps := bazel.BazelTargetModuleProperties{
- Rule_class: "my_library",
- Bzl_load_location: "//build/bazel/rules:rules.bzl",
- }
- ctx.CreateBazelTargetModule(myLibraryProps, android.CommonAttributes{Name: baseName}, attrs)
-
- protoLibraryProps := bazel.BazelTargetModuleProperties{
- Rule_class: "proto_library",
- Bzl_load_location: "//build/bazel/rules:proto.bzl",
- }
- ctx.CreateBazelTargetModule(protoLibraryProps, android.CommonAttributes{Name: baseName + "_proto_library_deps"}, attrs)
-
- myProtoLibraryProps := bazel.BazelTargetModuleProperties{
- Rule_class: "my_proto_library",
- Bzl_load_location: "//build/bazel/rules:proto.bzl",
- }
- ctx.CreateBazelTargetModule(myProtoLibraryProps, android.CommonAttributes{Name: baseName + "_my_proto_library_deps"}, attrs)
+ myLibraryProps := bazel.BazelTargetModuleProperties{
+ Rule_class: "my_library",
+ Bzl_load_location: "//build/bazel/rules:rules.bzl",
}
+ ctx.CreateBazelTargetModule(myLibraryProps, android.CommonAttributes{Name: baseName}, attrs)
+
+ protoLibraryProps := bazel.BazelTargetModuleProperties{
+ Rule_class: "proto_library",
+ Bzl_load_location: "//build/bazel/rules:proto.bzl",
+ }
+ ctx.CreateBazelTargetModule(protoLibraryProps, android.CommonAttributes{Name: baseName + "_proto_library_deps"}, attrs)
+
+ myProtoLibraryProps := bazel.BazelTargetModuleProperties{
+ Rule_class: "my_proto_library",
+ Bzl_load_location: "//build/bazel/rules:proto.bzl",
+ }
+ ctx.CreateBazelTargetModule(myProtoLibraryProps, android.CommonAttributes{Name: baseName + "_my_proto_library_deps"}, attrs)
}
// Helper method for tests to easily access the targets in a dir.
@@ -353,7 +352,6 @@
func registerCustomModuleForBp2buildConversion(ctx *android.TestContext) {
ctx.RegisterModuleType("custom", customModuleFactory)
- ctx.RegisterBp2BuildMutator("custom", customBp2BuildMutator)
ctx.RegisterForBazelConversion()
}
@@ -364,3 +362,16 @@
bazel_module: { bp2build_available: false },
}`, typ, name)
}
+
+type attrNameToString map[string]string
+
+func makeBazelTarget(typ, name string, attrs attrNameToString) string {
+ attrStrings := make([]string, 0, len(attrs)+1)
+ attrStrings = append(attrStrings, fmt.Sprintf(` name = "%s",`, name))
+ for _, k := range android.SortedStringKeys(attrs) {
+ attrStrings = append(attrStrings, fmt.Sprintf(" %s = %s,", k, attrs[k]))
+ }
+ return fmt.Sprintf(`%s(
+%s
+)`, typ, strings.Join(attrStrings, "\n"))
+}
diff --git a/bpf/bpf.go b/bpf/bpf.go
index fa1a84d..9f0c86c 100644
--- a/bpf/bpf.go
+++ b/bpf/bpf.go
@@ -83,9 +83,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(),
}
diff --git a/bpfix/Android.bp b/bpfix/Android.bp
index 345dbd0..a72d9b4 100644
--- a/bpfix/Android.bp
+++ b/bpfix/Android.bp
@@ -52,5 +52,6 @@
],
deps: [
"blueprint-parser",
+ "blueprint-pathtools",
],
}
diff --git a/bpfix/bpfix/bpfix.go b/bpfix/bpfix/bpfix.go
index a608630..b683472 100644
--- a/bpfix/bpfix/bpfix.go
+++ b/bpfix/bpfix/bpfix.go
@@ -19,12 +19,18 @@
import (
"bytes"
"errors"
+ "flag"
"fmt"
"io"
+ "io/ioutil"
+ "os"
"path/filepath"
+ "reflect"
+ "sort"
"strings"
"github.com/google/blueprint/parser"
+ "github.com/google/blueprint/pathtools"
)
// Reformat takes a blueprint file as a string and returns a formatted version
@@ -137,11 +143,35 @@
Fix: runPatchListMod(removeObsoleteProperty("sanitize.scudo")),
},
{
+ Name: "removeAndroidLicenseKinds",
+ Fix: runPatchListMod(removeIncorrectProperties("android_license_kinds")),
+ },
+ {
+ Name: "removeAndroidLicenseConditions",
+ Fix: runPatchListMod(removeIncorrectProperties("android_license_conditions")),
+ },
+ {
+ Name: "removeAndroidLicenseFiles",
+ Fix: runPatchListMod(removeIncorrectProperties("android_license_files")),
+ },
+ {
Name: "formatFlagProperties",
Fix: runPatchListMod(formatFlagProperties),
},
}
+// for fix that only need to run once
+var fixStepsOnce = []FixStep{
+ {
+ Name: "haveSameLicense",
+ Fix: haveSameLicense,
+ },
+ {
+ Name: "rewriteLicenseProperties",
+ Fix: runPatchListMod(rewriteLicenseProperty(nil, "")),
+ },
+}
+
func NewFixRequest() FixRequest {
return FixRequest{}
}
@@ -196,6 +226,16 @@
return nil, err
}
+ // run fix that is expected to run once first
+ configOnce := NewFixRequest()
+ configOnce.steps = append(configOnce.steps, fixStepsOnce...)
+ if len(configOnce.steps) > 0 {
+ err = f.fixTreeOnce(configOnce)
+ if err != nil {
+ return nil, err
+ }
+ }
+
maxNumIterations := 20
i := 0
for {
@@ -601,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:,
@@ -1413,3 +1453,342 @@
}
return nil
}
+
+func rewriteLicenseProperty(fs pathtools.FileSystem, relativePath string) patchListModFunction {
+ return func(mod *parser.Module, buf []byte, patchList *parser.PatchList) error {
+ return rewriteLicenseProperties(mod, patchList, fs, relativePath)
+ }
+}
+
+// rewrite the "android_license_kinds" and "android_license_files" properties to a package module
+// (and a license module when needed).
+func rewriteLicenseProperties(mod *parser.Module, patchList *parser.PatchList, fs pathtools.FileSystem,
+ relativePath string) error {
+ // if a package module has been added, no more action is needed.
+ for _, patch := range *patchList {
+ if strings.Contains(patch.Replacement, "package {") {
+ return nil
+ }
+ }
+
+ // initial the fs
+ if fs == nil {
+ fs = pathtools.NewOsFs(os.Getenv("ANDROID_BUILD_TOP"))
+ }
+
+ // initial the relativePath
+ if len(relativePath) == 0 {
+ relativePath = getModuleRelativePath()
+ }
+ // validate the relativePath
+ 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 %q", relativePath)
+ }
+
+ licenseKindsPropertyName := "android_license_kinds"
+ licenseFilesPropertyName := "android_license_files"
+
+ androidBpFileErr := "// Error: No Android.bp file is found at path\n" +
+ "// %s\n" +
+ "// Please add one there with the needed license module first.\n" +
+ "// Then reset the default_applicable_licenses property below with the license module name.\n"
+ licenseModuleErr := "// Error: Cannot get the name of the license module in the\n" +
+ "// %s file.\n" +
+ "// If no such license module exists, please add one there first.\n" +
+ "// Then reset the default_applicable_licenses property below with the license module name.\n"
+
+ defaultApplicableLicense := "Android-Apache-2.0"
+ var licenseModuleName, licensePatch string
+ var hasFileInParentDir bool
+
+ // when LOCAL_NOTICE_FILE is not empty
+ if hasNonEmptyLiteralListProperty(mod, licenseFilesPropertyName) {
+ hasFileInParentDir = hasValueStartWithTwoDotsLiteralList(mod, licenseFilesPropertyName)
+ // if have LOCAL_NOTICE_FILE outside the current directory, need to find and refer to the license
+ // module in the LOCAL_NOTICE_FILE location directly and no new license module needs to be created
+ if hasFileInParentDir {
+ bpPath, ok := getPathFromProperty(mod, licenseFilesPropertyName, fs, relativePath)
+ if !ok {
+ bpDir, err := getDirFromProperty(mod, licenseFilesPropertyName, fs, relativePath)
+ if err != nil {
+ return err
+ }
+ licensePatch += fmt.Sprintf(androidBpFileErr, bpDir)
+ defaultApplicableLicense = ""
+ } else {
+ licenseModuleName, _ = getModuleName(bpPath, "license", fs)
+ if len(licenseModuleName) == 0 {
+ licensePatch += fmt.Sprintf(licenseModuleErr, bpPath)
+ }
+ defaultApplicableLicense = licenseModuleName
+ }
+ } else {
+ // if have LOCAL_NOTICE_FILE in the current directory, need to create a new license module
+ if len(relativePath) == 0 {
+ return fmt.Errorf("Cannot obtain the relative path of the Android.mk file")
+ }
+ licenseModuleName = strings.Replace(relativePath, "/", "_", -1) + "_license"
+ defaultApplicableLicense = licenseModuleName
+ }
+ }
+
+ //add the package module
+ if hasNonEmptyLiteralListProperty(mod, licenseKindsPropertyName) {
+ licensePatch += "package {\n" +
+ " // See: http://go/android-license-faq\n" +
+ " default_applicable_licenses: [\n" +
+ " \"" + defaultApplicableLicense + "\",\n" +
+ " ],\n" +
+ "}\n" +
+ "\n"
+ }
+
+ // append the license module when necessary
+ // when LOCAL_NOTICE_FILE is not empty and in the current directory, create a new license module
+ // otherwise, use the above default license directly
+ if hasNonEmptyLiteralListProperty(mod, licenseFilesPropertyName) && !hasFileInParentDir {
+ licenseKinds, err := mergeLiteralListPropertyValue(mod, licenseKindsPropertyName)
+ if err != nil {
+ return err
+ }
+ licenseFiles, err := mergeLiteralListPropertyValue(mod, licenseFilesPropertyName)
+ if err != nil {
+ return err
+ }
+ licensePatch += "license {\n" +
+ " name: \"" + licenseModuleName + "\",\n" +
+ " visibility: [\":__subpackages__\"],\n" +
+ " license_kinds: [\n" +
+ licenseKinds +
+ " ],\n" +
+ " license_text: [\n" +
+ licenseFiles +
+ " ],\n" +
+ "}\n" +
+ "\n"
+ }
+
+ // add to the patchList
+ pos := mod.Pos().Offset
+ err := patchList.Add(pos, pos, licensePatch)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+// merge the string vaules in a list property of a module into one string with expected format
+func mergeLiteralListPropertyValue(mod *parser.Module, property string) (s string, err error) {
+ listValue, ok := getLiteralListPropertyValue(mod, property)
+ if !ok {
+ // if do not find
+ return "", fmt.Errorf("Cannot retrieve the %s.%s field", mod.Type, property)
+ }
+ for i := 0; i < len(listValue); i++ {
+ s += " \"" + listValue[i] + "\",\n"
+ }
+ return s, nil
+}
+
+// check whether a string list property has any value starting with `../`
+func hasValueStartWithTwoDotsLiteralList(mod *parser.Module, property string) bool {
+ listValue, ok := getLiteralListPropertyValue(mod, property)
+ if ok {
+ for i := 0; i < len(listValue); i++ {
+ if strings.HasPrefix(listValue[i], "../") {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// get the relative path from ANDROID_BUILD_TOP to the Android.mk file to be converted
+func getModuleRelativePath() string {
+ // get the absolute path of the top of the tree
+ rootPath := os.Getenv("ANDROID_BUILD_TOP")
+ // get the absolute path of the `Android.mk` file to be converted
+ absPath := getModuleAbsolutePath()
+ // get the relative path of the `Android.mk` file to top of the tree
+ relModulePath, err := filepath.Rel(rootPath, absPath)
+ if err != nil {
+ return ""
+ }
+ return relModulePath
+}
+
+// get the absolute path of the Android.mk file to be converted
+func getModuleAbsolutePath() string {
+ // get the absolute path at where the `androidmk` commend is executed
+ curAbsPath, err := filepath.Abs(".")
+ if err != nil {
+ return ""
+ }
+ // the argument for the `androidmk` command could be
+ // 1. "./a/b/c/Android.mk"; 2. "a/b/c/Android.mk"; 3. "Android.mk"
+ argPath := flag.Arg(0)
+ if strings.HasPrefix(argPath, "./") {
+ argPath = strings.TrimPrefix(argPath, ".")
+ }
+ argPath = strings.TrimSuffix(argPath, "Android.mk")
+ if strings.HasSuffix(argPath, "/") {
+ argPath = strings.TrimSuffix(argPath, "/")
+ }
+ if len(argPath) > 0 && !strings.HasPrefix(argPath, "/") {
+ argPath = "/" + argPath
+ }
+ // get the absolute path of the `Android.mk` file to be converted
+ absPath := curAbsPath + argPath
+ return absPath
+}
+
+// check whether a file exists in a filesystem
+func hasFile(path string, fs pathtools.FileSystem) bool {
+ ok, _, _ := fs.Exists(path)
+ return ok
+}
+
+// get the directory where an `Android.bp` file and the property files are expected to locate
+func getDirFromProperty(mod *parser.Module, property string, fs pathtools.FileSystem, relativePath string) (string, error) {
+ listValue, ok := getLiteralListPropertyValue(mod, property)
+ if !ok {
+ // if do not find
+ return "", fmt.Errorf("Cannot retrieve the %s.%s property", mod.Type, property)
+ }
+ if len(listValue) == 0 {
+ // 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 %q", relativePath)
+ }
+ path := relativePath
+ for {
+ if !strings.HasPrefix(listValue[0], "../") {
+ break
+ }
+ path = filepath.Dir(path)
+ listValue[0] = strings.TrimPrefix(listValue[0], "../")
+ }
+ _, isDir, _ = fs.Exists(path)
+ if !isDir {
+ return "", fmt.Errorf("Cannot find the path %q", path)
+ }
+ return path, nil
+}
+
+// get the path of the `Android.bp` file at the expected location where the property files locate
+func getPathFromProperty(mod *parser.Module, property string, fs pathtools.FileSystem, relativePath string) (string, bool) {
+ dir, err := getDirFromProperty(mod, property, fs, relativePath)
+ if err != nil {
+ return "", false
+ }
+ ok := hasFile(dir+"/Android.bp", fs)
+ if !ok {
+ return "", false
+ }
+ return dir + "/Android.bp", true
+}
+
+// parse an Android.bp file to get the name of the first module with type of moduleType
+func getModuleName(path string, moduleType string, fs pathtools.FileSystem) (string, error) {
+ tree, err := parserPath(path, fs)
+ if err != nil {
+ return "", err
+ }
+ for _, def := range tree.Defs {
+ mod, ok := def.(*parser.Module)
+ if !ok || mod.Type != moduleType {
+ continue
+ }
+ prop, ok := mod.GetProperty("name")
+ if !ok {
+ return "", fmt.Errorf("Cannot get the %s."+"name property", mod.Type)
+ }
+ propVal, ok := prop.Value.(*parser.String)
+ if ok {
+ return propVal.Value, nil
+ }
+ }
+ return "", fmt.Errorf("Cannot find the value of the %s."+"name property", moduleType)
+}
+
+// parse an Android.bp file with the specific path
+func parserPath(path string, fs pathtools.FileSystem) (tree *parser.File, err error) {
+ f, err := fs.Open(path)
+ if err != nil {
+ return tree, err
+ }
+ defer f.Close()
+ fileContent, _ := ioutil.ReadAll(f)
+ tree, err = parse(path, bytes.NewBufferString(string(fileContent)))
+ if err != nil {
+ return tree, err
+ }
+ return tree, nil
+}
+
+// remove the incorrect property that Soong does not support
+func removeIncorrectProperties(propName string) patchListModFunction {
+ return removeObsoleteProperty(propName)
+}
+
+// the modules on the same Android.mk file are expected to have the same license
+func haveSameLicense(f *Fixer) error {
+ androidLicenseProperties := []string{
+ "android_license_kinds",
+ "android_license_conditions",
+ "android_license_files",
+ }
+
+ var prevModuleName string
+ var prevLicenseKindsVals, prevLicenseConditionsVals, prevLicenseFilesVals []string
+ prevLicenseVals := [][]string{
+ prevLicenseKindsVals,
+ prevLicenseConditionsVals,
+ prevLicenseFilesVals,
+ }
+
+ for _, def := range f.tree.Defs {
+ mod, ok := def.(*parser.Module)
+ if !ok {
+ continue
+ }
+ for idx, property := range androidLicenseProperties {
+ curModuleName, ok := getLiteralStringPropertyValue(mod, "name")
+ // some modules in the existing test cases in the androidmk_test.go do not have name property
+ hasNameProperty := hasProperty(mod, "name")
+ if hasNameProperty && (!ok || len(curModuleName) == 0) {
+ return fmt.Errorf("Cannot retrieve the name property of a module of %s type.", mod.Type)
+ }
+ curVals, ok := getLiteralListPropertyValue(mod, property)
+ // some modules in the existing test cases in the androidmk_test.go do not have license-related property
+ hasLicenseProperty := hasProperty(mod, property)
+ if hasLicenseProperty && (!ok || len(curVals) == 0) {
+ // if do not find the property, or no value is found for the property
+ return fmt.Errorf("Cannot retrieve the %s.%s property", mod.Type, property)
+ }
+ if len(prevLicenseVals[idx]) > 0 {
+ if !reflect.DeepEqual(prevLicenseVals[idx], curVals) {
+ return fmt.Errorf("Modules %s and %s are expected to have the same %s property.",
+ prevModuleName, curModuleName, property)
+ }
+ }
+ sort.Strings(curVals)
+ prevLicenseVals[idx] = curVals
+ prevModuleName = curModuleName
+ }
+ }
+ return nil
+}
+
+func hasProperty(mod *parser.Module, propName string) bool {
+ _, ok := mod.GetProperty(propName)
+ return ok
+}
diff --git a/bpfix/bpfix/bpfix_test.go b/bpfix/bpfix/bpfix_test.go
index d8772c1..69f5967 100644
--- a/bpfix/bpfix/bpfix_test.go
+++ b/bpfix/bpfix/bpfix_test.go
@@ -25,6 +25,7 @@
"reflect"
"github.com/google/blueprint/parser"
+ "github.com/google/blueprint/pathtools"
)
// TODO(jeffrygaston) remove this when position is removed from ParseNode (in b/38325146) and we can directly do reflect.DeepEqual
@@ -125,34 +126,103 @@
implFilterListTest(t, []string{}, []string{}, []string{})
}
-func runPass(t *testing.T, in, out string, innerTest func(*Fixer) error) {
- expected, err := Reformat(out)
+func checkError(t *testing.T, in, expectedErr string, innerTest func(*Fixer) error) {
+ expected := preProcessOutErr(expectedErr)
+ runTestOnce(t, in, expected, innerTest)
+}
+
+func runTestOnce(t *testing.T, in, expected string, innerTest func(*Fixer) error) {
+ fixer, err := preProcessIn(in)
if err != nil {
t.Fatal(err)
}
+ out, err := runFixerOnce(fixer, innerTest)
+ if err != nil {
+ out = err.Error()
+ }
+
+ compareResult := compareOutExpected(in, out, expected)
+ if len(compareResult) > 0 {
+ t.Errorf(compareResult)
+ }
+}
+
+func preProcessOutErr(expectedErr string) string {
+ expected := strings.TrimSpace(expectedErr)
+ return expected
+}
+
+func preProcessOut(out string) (expected string, err error) {
+ expected, err = Reformat(out)
+ if err != nil {
+ return expected, err
+ }
+ return expected, nil
+}
+
+func preProcessIn(in string) (fixer *Fixer, err error) {
in, err = Reformat(in)
if err != nil {
- t.Fatal(err)
+ return fixer, err
}
tree, errs := parser.Parse("<testcase>", bytes.NewBufferString(in), parser.NewScope(nil))
if errs != nil {
- t.Fatal(errs)
+ return fixer, err
}
- fixer := NewFixer(tree)
+ fixer = NewFixer(tree)
+
+ return fixer, nil
+}
+
+func runFixerOnce(fixer *Fixer, innerTest func(*Fixer) error) (string, error) {
+ err := innerTest(fixer)
+ if err != nil {
+ return "", err
+ }
+
+ out, err := parser.Print(fixer.tree)
+ if err != nil {
+ return "", err
+ }
+ return string(out), nil
+}
+
+func compareOutExpected(in, out, expected string) string {
+ if out != expected {
+ return fmt.Sprintf("output didn't match:\ninput:\n%s\n\nexpected:\n%s\ngot:\n%s\n",
+ in, expected, out)
+ }
+ return ""
+}
+
+func runPassOnce(t *testing.T, in, out string, innerTest func(*Fixer) error) {
+ expected, err := preProcessOut(out)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ runTestOnce(t, in, expected, innerTest)
+}
+
+func runPass(t *testing.T, in, out string, innerTest func(*Fixer) error) {
+ expected, err := preProcessOut(out)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ fixer, err := preProcessIn(in)
+ if err != nil {
+ t.Fatal(err)
+ }
got := ""
prev := "foo"
passes := 0
for got != prev && passes < 10 {
- err := innerTest(fixer)
- if err != nil {
- t.Fatal(err)
- }
-
- out, err := parser.Print(fixer.tree)
+ out, err = runFixerOnce(fixer, innerTest)
if err != nil {
t.Fatal(err)
}
@@ -162,9 +232,9 @@
passes++
}
- if got != expected {
- t.Errorf("output didn't match:\ninput:\n%s\n\nexpected:\n%s\ngot:\n%s\n",
- in, expected, got)
+ compareResult := compareOutExpected(in, out, expected)
+ if len(compareResult) > 0 {
+ t.Errorf(compareResult)
}
}
@@ -754,7 +824,7 @@
out: `prebuilt_etc {
name: "foo",
src: "bar",
- relative_install_dir: "baz",
+ relative_install_path: "baz",
}
`,
},
@@ -1608,3 +1678,348 @@
})
}
}
+
+func TestRewriteLicenseProperty(t *testing.T) {
+ mockFs := pathtools.MockFs(map[string][]byte{
+ "a/b/c/d/Android.mk": []byte("this is not important."),
+ "a/b/LicenseFile1": []byte("LicenseFile1"),
+ "a/b/LicenseFile2": []byte("LicenseFile2"),
+ "a/b/Android.bp": []byte("license {\n\tname: \"reuse_a_b_license\",\n}\n"),
+ })
+ relativePath := "a/b/c/d"
+ relativePathErr := "a/b/c"
+ tests := []struct {
+ name string
+ in string
+ fs pathtools.FileSystem
+ path string
+ out string
+ }{
+ {
+ name: "license rewriting with one module",
+ in: `
+ android_test {
+ name: "foo",
+ android_license_kinds: ["license_kind"],
+ android_license_conditions: ["license_notice"],
+ }
+ `,
+ out: `
+ package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: [
+ "Android-Apache-2.0",
+ ],
+ }
+
+ android_test {
+ name: "foo",
+ android_license_kinds: ["license_kind"],
+ android_license_conditions: ["license_notice"],
+ }
+ `,
+ },
+ {
+ name: "license rewriting with two modules",
+ in: `
+ android_test {
+ name: "foo1",
+ android_license_kinds: ["license_kind1"],
+ android_license_conditions: ["license_notice1"],
+ }
+
+ android_test {
+ name: "foo2",
+ android_license_kinds: ["license_kind2"],
+ android_license_conditions: ["license_notice2"],
+ }
+ `,
+ out: `
+ package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: [
+ "Android-Apache-2.0",
+ ],
+ }
+
+ android_test {
+ name: "foo1",
+ android_license_kinds: ["license_kind1"],
+ android_license_conditions: ["license_notice1"],
+ }
+
+ android_test {
+ name: "foo2",
+ android_license_kinds: ["license_kind2"],
+ android_license_conditions: ["license_notice2"],
+ }
+ `,
+ },
+ {
+ name: "license rewriting with license files in the current directory",
+ in: `
+ android_test {
+ name: "foo",
+ android_license_kinds: ["license_kind"],
+ android_license_conditions: ["license_notice"],
+ android_license_files: ["LicenseFile1", "LicenseFile2",],
+ }
+ `,
+ fs: mockFs,
+ path: relativePath,
+ out: `
+ package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: [
+ "a_b_c_d_license",
+ ],
+ }
+
+ license {
+ name: "a_b_c_d_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "license_kind",
+ ],
+ license_text: [
+ "LicenseFile1",
+ "LicenseFile2",
+ ],
+ }
+
+ android_test {
+ name: "foo",
+ android_license_kinds: ["license_kind"],
+ android_license_conditions: ["license_notice"],
+ android_license_files: [
+ "LicenseFile1",
+ "LicenseFile2",
+ ],
+ }
+ `,
+ },
+ {
+ name: "license rewriting with license files outside the current directory",
+ in: `
+ android_test {
+ name: "foo",
+ android_license_kinds: ["license_kind"],
+ android_license_conditions: ["license_notice"],
+ android_license_files: ["../../LicenseFile1", "../../LicenseFile2",],
+ }
+ `,
+ fs: mockFs,
+ path: relativePath,
+ out: `
+ package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: [
+ "reuse_a_b_license",
+ ],
+ }
+
+ android_test {
+ name: "foo",
+ android_license_kinds: ["license_kind"],
+ android_license_conditions: ["license_notice"],
+ android_license_files: [
+ "../../LicenseFile1",
+ "../../LicenseFile2",
+ ],
+ }
+ `,
+ },
+ {
+ name: "license rewriting with no Android.bp file in the expected location",
+ in: `
+ android_test {
+ name: "foo",
+ android_license_kinds: ["license_kind"],
+ android_license_conditions: ["license_notice"],
+ android_license_files: ["../../LicenseFile1", "../../LicenseFile2",],
+ }
+ `,
+ fs: pathtools.MockFs(map[string][]byte{
+ "a/b/c/d/Android.mk": []byte("this is not important."),
+ "a/b/LicenseFile1": []byte("LicenseFile1"),
+ "a/b/LicenseFile2": []byte("LicenseFile2"),
+ "a/Android.bp": []byte("license {\n\tname: \"reuse_a_b_license\",\n}\n"),
+ }),
+ path: relativePath,
+ out: `
+ // Error: No Android.bp file is found at path
+ // a/b
+ // Please add one there with the needed license module first.
+ // Then reset the default_applicable_licenses property below with the license module name.
+ package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: [
+ "",
+ ],
+ }
+
+ android_test {
+ name: "foo",
+ android_license_kinds: ["license_kind"],
+ android_license_conditions: ["license_notice"],
+ android_license_files: [
+ "../../LicenseFile1",
+ "../../LicenseFile2",
+ ],
+ }
+ `,
+ },
+ {
+ name: "license rewriting with an Android.bp file without a license module",
+ in: `
+ android_test {
+ name: "foo",
+ android_license_kinds: ["license_kind"],
+ android_license_conditions: ["license_notice"],
+ android_license_files: ["../../LicenseFile1", "../../LicenseFile2",],
+ }
+ `,
+ fs: pathtools.MockFs(map[string][]byte{
+ "a/b/c/d/Android.mk": []byte("this is not important."),
+ "a/b/LicenseFile1": []byte("LicenseFile1"),
+ "a/b/LicenseFile2": []byte("LicenseFile2"),
+ "a/b/Android.bp": []byte("non_license {\n\tname: \"reuse_a_b_license\",\n}\n"),
+ }),
+ path: relativePath,
+ out: `
+ // Error: Cannot get the name of the license module in the
+ // a/b/Android.bp file.
+ // If no such license module exists, please add one there first.
+ // Then reset the default_applicable_licenses property below with the license module name.
+ package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: [
+ "",
+ ],
+ }
+
+ android_test {
+ name: "foo",
+ android_license_kinds: ["license_kind"],
+ android_license_conditions: ["license_notice"],
+ android_license_files: [
+ "../../LicenseFile1",
+ "../../LicenseFile2",
+ ],
+ }
+ `,
+ },
+ }
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ runPassOnce(t, test.in, test.out, runPatchListMod(rewriteLicenseProperty(test.fs, test.path)))
+ })
+ }
+
+ testErrs := []struct {
+ name string
+ in string
+ fs pathtools.FileSystem
+ path string
+ expectedErr string
+ }{
+ {
+ name: "license rewriting with a wrong path",
+ in: `
+ android_test {
+ name: "foo",
+ android_license_kinds: ["license_kind"],
+ android_license_conditions: ["license_notice"],
+ android_license_files: ["../../LicenseFile1", "../../LicenseFile2",],
+ }
+ `,
+ fs: mockFs,
+ path: relativePathErr,
+ expectedErr: `
+ Cannot find an Android.mk file at path "a/b/c"
+ `,
+ },
+ }
+ for _, test := range testErrs {
+ t.Run(test.name, func(t *testing.T) {
+ checkError(t, test.in, test.expectedErr, runPatchListMod(rewriteLicenseProperty(test.fs, test.path)))
+ })
+ }
+}
+
+func TestHaveSameLicense(t *testing.T) {
+ tests := []struct {
+ name string
+ in string
+ out string
+ }{
+ {
+ name: "two modules with the same license",
+ in: `
+ android_test {
+ name: "foo1",
+ android_license_kinds: ["license_kind"],
+ android_license_conditions: ["license_notice"],
+ }
+
+ android_test {
+ name: "foo2",
+ android_license_kinds: ["license_kind"],
+ android_license_conditions: ["license_notice"],
+ }
+ `,
+ out: `
+ android_test {
+ name: "foo1",
+ android_license_kinds: ["license_kind"],
+ android_license_conditions: ["license_notice"],
+ }
+
+ android_test {
+ name: "foo2",
+ android_license_kinds: ["license_kind"],
+ android_license_conditions: ["license_notice"],
+ }
+ `,
+ },
+ }
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ runPassOnce(t, test.in, test.out, func(fixer *Fixer) error {
+ return haveSameLicense(fixer)
+ })
+ })
+ }
+ testErrs := []struct {
+ name string
+ in string
+ expectedErr string
+ }{
+ {
+ name: "two modules will different licenses",
+ in: `
+ android_test {
+ name: "foo1",
+ android_license_kinds: ["license_kind1"],
+ android_license_conditions: ["license_notice1"],
+ }
+
+ android_test {
+ name: "foo2",
+ android_license_kinds: ["license_kind2"],
+ android_license_conditions: ["license_notice2"],
+ }
+ `,
+ expectedErr: `
+ Modules foo1 and foo2 are expected to have the same android_license_kinds property.
+ `,
+ },
+ }
+ for _, test := range testErrs {
+ t.Run(test.name, func(t *testing.T) {
+ checkError(t, test.in, test.expectedErr, func(fixer *Fixer) error {
+ return haveSameLicense(fixer)
+ })
+ })
+ }
+}
diff --git a/build_kzip.bash b/build_kzip.bash
index 5655067..aff2d6d 100755
--- a/build_kzip.bash
+++ b/build_kzip.bash
@@ -61,5 +61,5 @@
# Pack
# TODO(asmundak): this should be done by soong.
declare -r allkzip="$KZIP_NAME.kzip"
-"$out/soong/host/linux-x86/bin/merge_zips" "$DIST_DIR/$allkzip" @<(find "$out" -name '*.kzip')
+"$out/host/linux-x86/bin/merge_zips" "$DIST_DIR/$allkzip" @<(find "$out" -name '*.kzip')
diff --git a/build_test.bash b/build_test.bash
index b039285..b6d00e2 100755
--- a/build_test.bash
+++ b/build_test.bash
@@ -50,7 +50,9 @@
echo
echo "Free disk space:"
-df -h
+# Ignore df errors because it errors out on gvfsd file systems
+# but still displays most of the useful info we need
+df -h || true
echo
echo "Running Bazel smoke test..."
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/androidmk.go b/cc/androidmk.go
index 93283d0..800b58f 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -80,7 +80,7 @@
// to be installed. And this is breaking some older devices (like marlin)
// where system.img is small.
Required: c.Properties.AndroidMkRuntimeLibs,
- Include: "$(BUILD_SYSTEM)/soong_cc_prebuilt.mk",
+ Include: "$(BUILD_SYSTEM)/soong_cc_rust_prebuilt.mk",
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
@@ -263,9 +263,10 @@
library.androidMkWriteExportedFlags(entries)
library.androidMkEntriesWriteAdditionalDependenciesForSourceAbiDiff(entries)
- _, _, ext := android.SplitFileExt(entries.OutputFile.Path().Base())
-
- entries.SetString("LOCAL_BUILT_MODULE_STEM", "$(LOCAL_MODULE)"+ext)
+ if entries.OutputFile.Valid() {
+ _, _, ext := android.SplitFileExt(entries.OutputFile.Path().Base())
+ entries.SetString("LOCAL_BUILT_MODULE_STEM", "$(LOCAL_MODULE)"+ext)
+ }
if library.coverageOutputFile.Valid() {
entries.SetString("LOCAL_PREBUILT_COVERAGE_ARCHIVE", library.coverageOutputFile.String())
@@ -450,14 +451,9 @@
if installer.path == (android.InstallPath{}) {
return
}
- // Soong installation is only supported for host modules. Have Make
- // installation trigger Soong installation.
- if ctx.Target().Os.Class == android.Host {
- entries.OutputFile = android.OptionalPathForPath(installer.path)
- }
entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- path, file := filepath.Split(installer.path.ToMakePath().String())
+ path, file := filepath.Split(installer.path.String())
stem, suffix, _ := android.SplitFileExt(file)
entries.SetString("LOCAL_MODULE_SUFFIX", suffix)
entries.SetString("LOCAL_MODULE_PATH", path)
@@ -536,7 +532,7 @@
c.libraryDecorator.androidMkWriteExportedFlags(entries)
if c.shared() || c.static() {
- path, file := filepath.Split(c.path.ToMakePath().String())
+ path, file := filepath.Split(c.path.String())
stem, suffix, ext := android.SplitFileExt(file)
entries.SetString("LOCAL_BUILT_MODULE_STEM", "$(LOCAL_MODULE)"+ext)
entries.SetString("LOCAL_MODULE_SUFFIX", suffix)
@@ -587,8 +583,8 @@
if p.properties.Check_elf_files != nil {
entries.SetBool("LOCAL_CHECK_ELF_FILES", *p.properties.Check_elf_files)
} else {
- // soong_cc_prebuilt.mk does not include check_elf_file.mk by default
- // because cc_library_shared and cc_binary use soong_cc_prebuilt.mk as well.
+ // soong_cc_rust_prebuilt.mk does not include check_elf_file.mk by default
+ // because cc_library_shared and cc_binary use soong_cc_rust_prebuilt.mk as well.
// In order to turn on prebuilt ABI checker, set `LOCAL_CHECK_ELF_FILES` to
// true if `p.properties.Check_elf_files` is not specified.
entries.SetBool("LOCAL_CHECK_ELF_FILES", true)
diff --git a/cc/binary.go b/cc/binary.go
index a5afb07..b59e762 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -18,6 +18,7 @@
"path/filepath"
"github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
"android/soong/android"
"android/soong/bazel"
@@ -68,13 +69,14 @@
// cc_binary produces a binary that is runnable on a device.
func BinaryFactory() android.Module {
- module, _ := NewBinary(android.HostAndDeviceSupported)
+ module, _ := newBinary(android.HostAndDeviceSupported, true)
return module.Init()
}
// cc_binary_host produces a binary that is runnable on a host.
func BinaryHostFactory() android.Module {
- module, _ := NewBinary(android.HostSupported)
+ module, _ := newBinary(android.HostSupported, true)
+ module.bazelable = true
return module.Init()
}
@@ -192,6 +194,10 @@
// Individual module implementations which comprise a C++ binary should call this function,
// set some fields on the result, and then call the Init function.
func NewBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecorator) {
+ return newBinary(hod, true)
+}
+
+func newBinary(hod android.HostOrDeviceSupported, bazelable bool) (*Module, *binaryDecorator) {
module := newModule(hod, android.MultilibFirst)
binary := &binaryDecorator{
baseLinker: NewBaseLinker(module.sanitize),
@@ -200,6 +206,7 @@
module.compiler = NewBaseCompiler()
module.linker = binary
module.installer = binary
+ module.bazelable = bazelable
// Allow module to be added as member of an sdk/module_exports.
module.sdkMemberTypes = []android.SdkMemberType{
@@ -344,6 +351,12 @@
flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--no-dynamic-linker")
}
+ if ctx.Darwin() && deps.DarwinSecondArchOutput.Valid() {
+ fatOutputFile := outputFile
+ outputFile = android.PathForModuleOut(ctx, "pre-fat", fileName)
+ transformDarwinUniversalBinary(ctx, fatOutputFile, outputFile, deps.DarwinSecondArchOutput.Path())
+ }
+
builderFlags := flagsToBuilderFlags(flags)
stripFlags := flagsToStripFlags(flags)
if binary.stripper.NeedsStrip(ctx) {
@@ -388,7 +401,7 @@
}
}
- var validations android.WritablePaths
+ var validations android.Paths
// Handle host bionic linker symbols.
if ctx.Os() == android.LinuxBionic && !binary.static() {
@@ -411,6 +424,7 @@
linkerDeps = append(linkerDeps, deps.EarlySharedLibsDeps...)
linkerDeps = append(linkerDeps, deps.SharedLibsDeps...)
linkerDeps = append(linkerDeps, deps.LateSharedLibsDeps...)
+ linkerDeps = append(linkerDeps, ndkSharedLibDeps(ctx)...)
}
validations = append(validations, objs.tidyFiles...)
@@ -543,44 +557,18 @@
})
}
-func init() {
- android.RegisterBp2BuildMutator("cc_binary", BinaryBp2build)
- android.RegisterBp2BuildMutator("cc_binary_host", BinaryHostBp2build)
-}
-
-func BinaryBp2build(ctx android.TopDownMutatorContext) {
- binaryBp2build(ctx, "cc_binary")
-}
-
-func BinaryHostBp2build(ctx android.TopDownMutatorContext) {
- binaryBp2build(ctx, "cc_binary_host")
-}
-
-func binaryBp2build(ctx android.TopDownMutatorContext, typ string) {
- m, ok := ctx.Module().(*Module)
- if !ok {
- // Not a cc module
- return
- }
- if !m.ConvertWithBp2build(ctx) {
- return
- }
-
- if ctx.ModuleType() != typ {
- return
- }
-
- 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{})
- }
-
+func binaryBp2build(ctx android.TopDownMutatorContext, m *Module, typ string) {
baseAttrs := bp2BuildParseBaseProps(ctx, m)
+ binaryLinkerAttrs := bp2buildBinaryLinkerProps(ctx, m)
+
+ if proptools.BoolDefault(binaryLinkerAttrs.Linkshared, true) {
+ baseAttrs.implementationDynamicDeps.Add(baseAttrs.protoDependency)
+ } else {
+ baseAttrs.implementationDeps.Add(baseAttrs.protoDependency)
+ }
attrs := &binaryAttributes{
- binaryLinkerAttrs: bp2buildBinaryLinkerProps(ctx, m),
+ binaryLinkerAttrs: binaryLinkerAttrs,
Srcs: baseAttrs.srcs,
Srcs_c: baseAttrs.cSrcs,
@@ -615,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
@@ -660,6 +654,4 @@
Strip stripAttributes
Features bazel.StringListAttribute
-
- Target_compatible_with bazel.StringListAttribute
}
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 1b13854..cc2e60e 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -16,6 +16,7 @@
import (
"fmt"
"path/filepath"
+ "regexp"
"strings"
"android/soong/android"
@@ -27,9 +28,16 @@
)
const (
- cSrcPartition = "c"
- asSrcPartition = "as"
- cppSrcPartition = "cpp"
+ cSrcPartition = "c"
+ asSrcPartition = "as"
+ cppSrcPartition = "cpp"
+ protoSrcPartition = "proto"
+)
+
+var (
+ // ignoring case, checks for proto or protos as an independent word in the name, whether at the
+ // beginning, end, or middle. e.g. "proto.foo", "bar-protos", "baz_proto_srcs" would all match
+ filegroupLikelyProtoPattern = regexp.MustCompile("(?i)(^|[^a-z])proto(s)?([^a-z]|$)")
)
// staticOrSharedAttributes are the Bazel-ified versions of StaticOrSharedProperties --
@@ -41,49 +49,52 @@
Hdrs bazel.LabelListAttribute
Copts bazel.StringListAttribute
- Deps bazel.LabelListAttribute
- Implementation_deps bazel.LabelListAttribute
- Dynamic_deps bazel.LabelListAttribute
- Implementation_dynamic_deps bazel.LabelListAttribute
- Whole_archive_deps bazel.LabelListAttribute
+ Deps bazel.LabelListAttribute
+ Implementation_deps bazel.LabelListAttribute
+ Dynamic_deps bazel.LabelListAttribute
+ Implementation_dynamic_deps bazel.LabelListAttribute
+ Whole_archive_deps bazel.LabelListAttribute
+ Implementation_whole_archive_deps bazel.LabelListAttribute
System_dynamic_deps bazel.LabelListAttribute
+
+ Enabled bazel.BoolAttribute
}
func groupSrcsByExtension(ctx android.BazelConversionPathContext, srcs bazel.LabelListAttribute) bazel.PartitionToLabelListAttribute {
- // Check that a module is a filegroup type named <label>.
- isFilegroupNamed := func(m android.Module, fullLabel string) bool {
- if ctx.OtherModuleType(m) != "filegroup" {
- return false
- }
- labelParts := strings.Split(fullLabel, ":")
- if len(labelParts) > 2 {
- // There should not be more than one colon in a label.
- ctx.ModuleErrorf("%s is not a valid Bazel label for a filegroup", fullLabel)
- }
- return m.Name() == labelParts[len(labelParts)-1]
+ // Check that a module is a filegroup type
+ isFilegroup := func(m blueprint.Module) bool {
+ return ctx.OtherModuleType(m) == "filegroup"
}
// Convert filegroup dependencies into extension-specific filegroups filtered in the filegroup.bzl
// macro.
addSuffixForFilegroup := func(suffix string) bazel.LabelMapper {
- return func(ctx bazel.OtherModuleContext, label string) (string, bool) {
- m, exists := ctx.ModuleFromName(label)
- if !exists {
- return label, false
+ return func(ctx bazel.OtherModuleContext, label bazel.Label) (string, bool) {
+ m, exists := ctx.ModuleFromName(label.OriginalModuleName)
+ labelStr := label.Label
+ if !exists || !isFilegroup(m) {
+ return labelStr, false
}
- aModule, _ := m.(android.Module)
- if !isFilegroupNamed(aModule, label) {
- return label, false
- }
- return label + suffix, true
+ return labelStr + suffix, true
}
}
+ isProtoFilegroup := func(ctx bazel.OtherModuleContext, label bazel.Label) (string, bool) {
+ m, exists := ctx.ModuleFromName(label.OriginalModuleName)
+ labelStr := label.Label
+ if !exists || !isFilegroup(m) {
+ return labelStr, false
+ }
+ likelyProtos := filegroupLikelyProtoPattern.MatchString(label.OriginalModuleName)
+ return labelStr, likelyProtos
+ }
+
// TODO(b/190006308): Handle language detection of sources in a Bazel rule.
partitioned := bazel.PartitionLabelListAttribute(ctx, &srcs, bazel.LabelPartitions{
- cSrcPartition: bazel.LabelPartition{Extensions: []string{".c"}, LabelMapper: addSuffixForFilegroup("_c_srcs")},
- asSrcPartition: bazel.LabelPartition{Extensions: []string{".s", ".S"}, LabelMapper: addSuffixForFilegroup("_as_srcs")},
+ protoSrcPartition: bazel.LabelPartition{Extensions: []string{".proto"}, LabelMapper: isProtoFilegroup},
+ cSrcPartition: bazel.LabelPartition{Extensions: []string{".c"}, LabelMapper: addSuffixForFilegroup("_c_srcs")},
+ asSrcPartition: bazel.LabelPartition{Extensions: []string{".s", ".S"}, LabelMapper: addSuffixForFilegroup("_as_srcs")},
// C++ is the "catch-all" group, and comprises generated sources because we don't
// know the language of these sources until the genrule is executed.
cppSrcPartition: bazel.LabelPartition{Extensions: []string{".cpp", ".cc", ".cxx", ".mm"}, LabelMapper: addSuffixForFilegroup("_cpp_srcs"), Keep_remainder: true},
@@ -153,7 +164,7 @@
attrs := staticOrSharedAttributes{}
setAttrs := func(axis bazel.ConfigurationAxis, config string, props StaticOrSharedProperties) {
- attrs.Copts.SetSelectValue(axis, config, props.Cflags)
+ attrs.Copts.SetSelectValue(axis, config, parseCommandLineFlags(props.Cflags, filterOutStdFlag))
attrs.Srcs.SetSelectValue(axis, config, android.BazelLabelForModuleSrc(ctx, props.Srcs))
attrs.System_dynamic_deps.SetSelectValue(axis, config, bazelLabelForSharedDeps(ctx, props.System_shared_libs))
@@ -166,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
@@ -195,6 +207,11 @@
attrs.Srcs_c = partitionedSrcs[cSrcPartition]
attrs.Srcs_as = partitionedSrcs[asSrcPartition]
+ if !partitionedSrcs[protoSrcPartition].IsEmpty() {
+ // TODO(b/208815215): determine whether this is used and add support if necessary
+ ctx.ModuleErrorf("Migrating static/shared only proto srcs is not currently supported")
+ }
+
return attrs
}
@@ -230,6 +247,8 @@
type baseAttributes struct {
compilerAttributes
linkerAttributes
+
+ protoDependency *bazel.LabelAttribute
}
// Convenience struct to hold all attributes parsed from compiler properties.
@@ -252,15 +271,29 @@
// Not affected by arch variants
stl *string
+ cStd *string
cppStd *string
localIncludes bazel.StringListAttribute
absoluteIncludes bazel.StringListAttribute
+
+ includes BazelIncludes
+
+ protoSrcs bazel.LabelListAttribute
}
-func parseCommandLineFlags(soongFlags []string) []string {
+type filterOutFn func(string) bool
+
+func filterOutStdFlag(flag string) bool {
+ return strings.HasPrefix(flag, "-std=")
+}
+
+func parseCommandLineFlags(soongFlags []string, filterOut filterOutFn) []string {
var result []string
for _, flag := range soongFlags {
+ if filterOut != nil && filterOut(flag) {
+ continue
+ }
// Soong's cflags can contain spaces, like `-include header.h`. For
// Bazel's copts, split them up to be compatible with the
// no_copts_tokenization feature.
@@ -278,8 +311,7 @@
localIncludeDirs := props.Local_include_dirs
if axis == bazel.NoConfigAxis {
- ca.cppStd = bp2buildResolveCppStdValue(props.Cpp_std, props.Gnu_extensions)
-
+ ca.cStd, ca.cppStd = bp2buildResolveCppStdValue(props.C_std, props.Cpp_std, props.Gnu_extensions)
if includeBuildDirectory(props.Include_build_directory) {
localIncludeDirs = append(localIncludeDirs, ".")
}
@@ -288,10 +320,14 @@
ca.absoluteIncludes.SetSelectValue(axis, config, props.Include_dirs)
ca.localIncludes.SetSelectValue(axis, config, localIncludeDirs)
- ca.copts.SetSelectValue(axis, config, parseCommandLineFlags(props.Cflags))
- ca.asFlags.SetSelectValue(axis, config, parseCommandLineFlags(props.Asflags))
- ca.conlyFlags.SetSelectValue(axis, config, parseCommandLineFlags(props.Conlyflags))
- ca.cppFlags.SetSelectValue(axis, config, parseCommandLineFlags(props.Cppflags))
+ // In Soong, cflags occur on the command line before -std=<val> flag, resulting in the value being
+ // overridden. In Bazel we always allow overriding, via flags; however, this can cause
+ // incompatibilities, so we remove "-std=" flags from Cflag properties while leaving it in other
+ // cases.
+ ca.copts.SetSelectValue(axis, config, parseCommandLineFlags(props.Cflags, filterOutStdFlag))
+ ca.asFlags.SetSelectValue(axis, config, parseCommandLineFlags(props.Asflags, nil))
+ ca.conlyFlags.SetSelectValue(axis, config, parseCommandLineFlags(props.Conlyflags, nil))
+ ca.cppFlags.SetSelectValue(axis, config, parseCommandLineFlags(props.Cppflags, nil))
ca.rtti.SetSelectValue(axis, config, props.Rtti)
}
@@ -320,14 +356,14 @@
"CppFlags": &ca.cppFlags,
}
for propName, attr := range productVarPropNameToAttribute {
- if props, exists := productVariableProps[propName]; exists {
- for _, prop := range props {
- flags, ok := prop.Property.([]string)
+ if productConfigProps, exists := productVariableProps[propName]; exists {
+ for productConfigProp, prop := range productConfigProps {
+ flags, ok := prop.([]string)
if !ok {
ctx.ModuleErrorf("Could not convert product variable %s property", proptools.PropertyNameForField(propName))
}
- newFlags, _ := bazel.TryVariableSubstitutions(flags, prop.ProductConfigVariable)
- attr.SetSelectValue(bazel.ProductVariableConfigurationAxis(prop.FullConfig), prop.FullConfig, newFlags)
+ newFlags, _ := bazel.TryVariableSubstitutions(flags, productConfigProp.Name)
+ attr.SetSelectValue(productConfigProp.ConfigurationAxis(), productConfigProp.SelectKey(), newFlags)
}
}
}
@@ -337,6 +373,8 @@
ca.srcs.ResolveExcludes()
partitionedSrcs := groupSrcsByExtension(ctx, ca.srcs)
+ ca.protoSrcs = partitionedSrcs[protoSrcPartition]
+
for p, lla := range partitionedSrcs {
// if there are no sources, there is no need for headers
if lla.IsEmpty() {
@@ -371,28 +409,63 @@
return bazel.AppendBazelLabelLists(allSrcsLabelList, generatedSrcsLabelList), anySrcs
}
-func bp2buildResolveCppStdValue(cpp_std *string, gnu_extensions *bool) *string {
- var cppStd *string
- // If cpp_std is not specified, don't generate it in the
- // BUILD file. For readability purposes, cpp_std and gnu_extensions are
- // combined into a single -std=<version> copt, except in the
- // default case where cpp_std is nil and gnu_extensions is true or unspecified,
- // then the toolchain's default "gnu++17" will be used.
+func bp2buildResolveCppStdValue(c_std *string, cpp_std *string, gnu_extensions *bool) (*string, *string) {
+ var cStdVal, cppStdVal string
+ // If c{,pp}std properties are not specified, don't generate them in the BUILD file.
+ // Defaults are handled by the toolchain definition.
+ // However, if gnu_extensions is false, then the default gnu-to-c version must be specified.
if cpp_std != nil {
- // TODO(b/202491296): Handle C_std.
- // These transformations are shared with compiler.go.
- cppStdVal := parseCppStd(cpp_std)
- _, cppStdVal = maybeReplaceGnuToC(gnu_extensions, "", cppStdVal)
- cppStd = &cppStdVal
+ cppStdVal = parseCppStd(cpp_std)
} else if gnu_extensions != nil && !*gnu_extensions {
- cppStdVal := "c++17"
- cppStd = &cppStdVal
+ cppStdVal = "c++17"
}
- return cppStd
+ if c_std != nil {
+ cStdVal = parseCStd(c_std)
+ } else if gnu_extensions != nil && !*gnu_extensions {
+ cStdVal = "c99"
+ }
+
+ cStdVal, cppStdVal = maybeReplaceGnuToC(gnu_extensions, cStdVal, cppStdVal)
+ var c_std_prop, cpp_std_prop *string
+ if cStdVal != "" {
+ c_std_prop = &cStdVal
+ }
+ if cppStdVal != "" {
+ cpp_std_prop = &cppStdVal
+ }
+
+ return c_std_prop, cpp_std_prop
+}
+
+// packageFromLabel extracts package from a fully-qualified or relative Label and whether the label
+// is fully-qualified.
+// e.g. fully-qualified "//a/b:foo" -> "a/b", true, relative: ":bar" -> ".", false
+func packageFromLabel(label string) (string, bool) {
+ split := strings.Split(label, ":")
+ if len(split) != 2 {
+ return "", false
+ }
+ if split[0] == "" {
+ return ".", false
+ }
+ // remove leading "//"
+ return split[0][2:], true
+}
+
+// includesFromLabelList extracts relative/absolute includes from a bazel.LabelList>
+func includesFromLabelList(labelList bazel.LabelList) (relative, absolute []string) {
+ for _, hdr := range labelList.Includes {
+ if pkg, hasPkg := packageFromLabel(hdr.Label); hasPkg {
+ absolute = append(absolute, pkg)
+ } else if pkg != "" {
+ relative = append(relative, pkg)
+ }
+ }
+ return relative, absolute
}
// bp2BuildParseCompilerProps returns copts, srcs and hdrs and other attributes.
-func bp2BuildParseBaseProps(ctx android.BazelConversionPathContext, module *Module) baseAttributes {
+func bp2BuildParseBaseProps(ctx android.Bp2buildMutatorContext, module *Module) baseAttributes {
archVariantCompilerProps := module.GetArchVariantProperties(ctx, &BaseCompilerProperties{})
archVariantLinkerProps := module.GetArchVariantProperties(ctx, &BaseLinkerProperties{})
@@ -434,6 +507,18 @@
headers := maybePartitionExportedAndImplementationsDeps(ctx, !module.Binary(), allHdrs, exportHdrs, android.BazelLabelForModuleDeps)
implementationHdrs.SetSelectValue(axis, config, headers.implementation)
compilerAttrs.hdrs.SetSelectValue(axis, config, headers.export)
+
+ exportIncludes, exportAbsoluteIncludes := includesFromLabelList(headers.export)
+ compilerAttrs.includes.Includes.SetSelectValue(axis, config, exportIncludes)
+ compilerAttrs.includes.AbsoluteIncludes.SetSelectValue(axis, config, exportAbsoluteIncludes)
+
+ includes, absoluteIncludes := includesFromLabelList(headers.implementation)
+ currAbsoluteIncludes := compilerAttrs.absoluteIncludes.SelectValue(axis, config)
+ currAbsoluteIncludes = android.FirstUniqueStrings(append(currAbsoluteIncludes, absoluteIncludes...))
+ compilerAttrs.absoluteIncludes.SetSelectValue(axis, config, currAbsoluteIncludes)
+ currIncludes := compilerAttrs.localIncludes.SelectValue(axis, config)
+ currIncludes = android.FirstUniqueStrings(append(currIncludes, includes...))
+ compilerAttrs.localIncludes.SetSelectValue(axis, config, currIncludes)
}
}
@@ -446,25 +531,37 @@
(&linkerAttrs).convertProductVariables(ctx, productVariableProps)
(&compilerAttrs).finalize(ctx, implementationHdrs)
- (&linkerAttrs).finalize()
+ (&linkerAttrs).finalize(ctx)
+
+ protoDep := bp2buildProto(ctx, module, compilerAttrs.protoSrcs)
+
+ // bp2buildProto will only set wholeStaticLib or implementationWholeStaticLib, but we don't know
+ // which. This will add the newly generated proto library to the appropriate attribute and nothing
+ // to the other
+ (&linkerAttrs).wholeArchiveDeps.Add(protoDep.wholeStaticLib)
+ (&linkerAttrs).implementationWholeArchiveDeps.Add(protoDep.implementationWholeStaticLib)
return baseAttributes{
compilerAttrs,
linkerAttrs,
+ protoDep.protoDep,
}
}
// 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
- 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
+ useVersionLib bazel.BoolAttribute
linkopts bazel.StringListAttribute
additionalLinkerInputs bazel.LabelListAttribute
stripKeepSymbols bazel.BoolAttribute
@@ -475,6 +572,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
@@ -506,6 +607,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)
@@ -534,6 +646,10 @@
la.linkopts.SetSelectValue(axis, config, linkerFlags)
la.useLibcrt.SetSelectValue(axis, config, props.libCrt())
+ if axis == bazel.NoConfigAxis {
+ la.useVersionLib.SetSelectValue(axis, config, props.Use_version_lib)
+ }
+
// it's very unlikely for nocrt to be arch variant, so bp2build doesn't support it.
if props.crt() != nil {
if axis == bazel.NoConfigAxis {
@@ -587,42 +703,59 @@
if !exists && !excludesExists {
continue
}
- // collect all the configurations that an include or exclude property exists for.
- // we want to iterate all configurations rather than either the include or exclude because for a
- // particular configuration we may have only and include or only an exclude to handle
- configs := make(map[string]bool, len(props)+len(excludeProps))
- for config := range props {
- configs[config] = true
+ // Collect all the configurations that an include or exclude property exists for.
+ // We want to iterate all configurations rather than either the include or exclude because, for a
+ // particular configuration, we may have either only an include or an exclude to handle.
+ productConfigProps := make(map[android.ProductConfigProperty]bool, len(props)+len(excludeProps))
+ for p := range props {
+ productConfigProps[p] = true
}
- for config := range excludeProps {
- configs[config] = true
+ for p := range excludeProps {
+ productConfigProps[p] = true
}
- for config := range configs {
- prop, includesExists := props[config]
- excludesProp, excludesExists := excludeProps[config]
+ for productConfigProp := range productConfigProps {
+ prop, includesExists := props[productConfigProp]
+ excludesProp, excludesExists := excludeProps[productConfigProp]
var includes, excludes []string
var ok bool
// if there was no includes/excludes property, casting fails and that's expected
- if includes, ok = prop.Property.([]string); includesExists && !ok {
+ if includes, ok = prop.([]string); includesExists && !ok {
ctx.ModuleErrorf("Could not convert product variable %s property", name)
}
- if excludes, ok = excludesProp.Property.([]string); excludesExists && !ok {
+ if excludes, ok = excludesProp.([]string); excludesExists && !ok {
ctx.ModuleErrorf("Could not convert product variable %s property", dep.excludesField)
}
- dep.attribute.SetSelectValue(bazel.ProductVariableConfigurationAxis(config), config, dep.depResolutionFunc(ctx, android.FirstUniqueStrings(includes), excludes))
+ dep.attribute.EmitEmptyList = productConfigProp.AlwaysEmit()
+ dep.attribute.SetSelectValue(
+ productConfigProp.ConfigurationAxis(),
+ productConfigProp.SelectKey(),
+ dep.depResolutionFunc(ctx, android.FirstUniqueStrings(includes), excludes),
+ )
}
}
}
-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
@@ -651,13 +784,14 @@
// BazelIncludes contains information about -I and -isystem paths from a module converted to Bazel
// attributes.
type BazelIncludes struct {
- Includes bazel.StringListAttribute
- SystemIncludes bazel.StringListAttribute
+ AbsoluteIncludes bazel.StringListAttribute
+ Includes bazel.StringListAttribute
+ SystemIncludes bazel.StringListAttribute
}
-func bp2BuildParseExportedIncludes(ctx android.BazelConversionPathContext, module *Module) BazelIncludes {
+func bp2BuildParseExportedIncludes(ctx android.BazelConversionPathContext, module *Module, existingIncludes BazelIncludes) BazelIncludes {
libraryDecorator := module.linker.(*libraryDecorator)
- return bp2BuildParseExportedIncludesHelper(ctx, module, libraryDecorator)
+ return bp2BuildParseExportedIncludesHelper(ctx, module, libraryDecorator, &existingIncludes)
}
// Bp2buildParseExportedIncludesForPrebuiltLibrary returns a BazelIncludes with Bazel-ified values
@@ -665,25 +799,31 @@
func Bp2BuildParseExportedIncludesForPrebuiltLibrary(ctx android.BazelConversionPathContext, module *Module) BazelIncludes {
prebuiltLibraryLinker := module.linker.(*prebuiltLibraryLinker)
libraryDecorator := prebuiltLibraryLinker.libraryDecorator
- return bp2BuildParseExportedIncludesHelper(ctx, module, libraryDecorator)
+ return bp2BuildParseExportedIncludesHelper(ctx, module, libraryDecorator, nil)
}
// bp2BuildParseExportedIncludes creates a string list attribute contains the
// exported included directories of a module.
-func bp2BuildParseExportedIncludesHelper(ctx android.BazelConversionPathContext, module *Module, libraryDecorator *libraryDecorator) BazelIncludes {
- exported := BazelIncludes{}
+func bp2BuildParseExportedIncludesHelper(ctx android.BazelConversionPathContext, module *Module, libraryDecorator *libraryDecorator, includes *BazelIncludes) BazelIncludes {
+ var exported BazelIncludes
+ if includes != nil {
+ exported = *includes
+ } else {
+ exported = BazelIncludes{}
+ }
for axis, configToProps := range module.GetArchVariantProperties(ctx, &FlagExporterProperties{}) {
for config, props := range configToProps {
if flagExporterProperties, ok := props.(*FlagExporterProperties); ok {
if len(flagExporterProperties.Export_include_dirs) > 0 {
- exported.Includes.SetSelectValue(axis, config, flagExporterProperties.Export_include_dirs)
+ exported.Includes.SetSelectValue(axis, config, android.FirstUniqueStrings(append(exported.Includes.SelectValue(axis, config), flagExporterProperties.Export_include_dirs...)))
}
if len(flagExporterProperties.Export_system_include_dirs) > 0 {
- exported.SystemIncludes.SetSelectValue(axis, config, flagExporterProperties.Export_system_include_dirs)
+ exported.SystemIncludes.SetSelectValue(axis, config, android.FirstUniqueStrings(append(exported.SystemIncludes.SelectValue(axis, config), flagExporterProperties.Export_system_include_dirs...)))
}
}
}
}
+ exported.AbsoluteIncludes.DeduplicateAxesFromBase()
exported.Includes.DeduplicateAxesFromBase()
exported.SystemIncludes.DeduplicateAxesFromBase()
diff --git a/cc/builder.go b/cc/builder.go
index abd5f1d..fa7f7a3 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -165,6 +165,12 @@
}
}()
+ darwinLipo = pctx.AndroidStaticRule("darwinLipo",
+ blueprint.RuleParams{
+ Command: "${config.MacLipoPath} -create -output $out $in",
+ CommandDeps: []string{"${config.MacLipoPath}"},
+ })
+
_ = pctx.SourcePathVariable("archiveRepackPath", "build/soong/scripts/archive_repack.sh")
// Rule to repack an archive (.a) file with a subset of object files.
@@ -413,7 +419,7 @@
// Objects is a collection of file paths corresponding to outputs for C++ related build statements.
type Objects struct {
objFiles android.Paths
- tidyFiles android.WritablePaths
+ tidyFiles android.Paths
coverageFiles android.Paths
sAbiDumpFiles android.Paths
kytheFiles android.Paths
@@ -422,7 +428,7 @@
func (a Objects) Copy() Objects {
return Objects{
objFiles: append(android.Paths{}, a.objFiles...),
- tidyFiles: append(android.WritablePaths{}, a.tidyFiles...),
+ tidyFiles: append(android.Paths{}, a.tidyFiles...),
coverageFiles: append(android.Paths{}, a.coverageFiles...),
sAbiDumpFiles: append(android.Paths{}, a.sAbiDumpFiles...),
kytheFiles: append(android.Paths{}, a.kytheFiles...),
@@ -451,11 +457,11 @@
// Source files are one-to-one with tidy, coverage, or kythe files, if enabled.
objFiles := make(android.Paths, len(srcFiles))
- var tidyFiles android.WritablePaths
+ var tidyFiles android.Paths
noTidySrcsMap := make(map[android.Path]bool)
var tidyVars string
if flags.tidy {
- tidyFiles = make(android.WritablePaths, 0, len(srcFiles))
+ tidyFiles = make(android.Paths, 0, len(srcFiles))
for _, path := range noTidySrcs {
noTidySrcsMap[path] = true
}
@@ -523,6 +529,14 @@
cppflags += " ${config.NoOverrideGlobalCflags}"
toolingCppflags += " ${config.NoOverrideGlobalCflags}"
+ modulePath := android.PathForModuleSrc(ctx).String()
+ if android.IsThirdPartyPath(modulePath) {
+ cflags += " ${config.NoOverrideExternalGlobalCflags}"
+ toolingCflags += " ${config.NoOverrideExternalGlobalCflags}"
+ cppflags += " ${config.NoOverrideExternalGlobalCflags}"
+ toolingCppflags += " ${config.NoOverrideExternalGlobalCflags}"
+ }
+
// 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>.
@@ -665,7 +679,6 @@
rule = clangTidyRE
}
- ctx.TidyFile(tidyFile)
ctx.Build(pctx, android.BuildParams{
Rule: rule,
Description: "clang-tidy " + srcFile.Rel(),
@@ -719,7 +732,7 @@
// Generate a rule for compiling multiple .o files to a static library (.a)
func transformObjToStaticLib(ctx android.ModuleContext,
objFiles android.Paths, wholeStaticLibs android.Paths,
- flags builderFlags, outputFile android.ModuleOutPath, deps android.Paths, validations android.WritablePaths) {
+ flags builderFlags, outputFile android.ModuleOutPath, deps android.Paths, validations android.Paths) {
arCmd := "${config.ClangBin}/llvm-ar"
arFlags := ""
@@ -734,7 +747,7 @@
Output: outputFile,
Inputs: objFiles,
Implicits: deps,
- Validations: validations.Paths(),
+ Validations: validations,
Args: map[string]string{
"arFlags": "crsPD" + arFlags,
"arCmd": arCmd,
@@ -764,7 +777,7 @@
func transformObjToDynamicBinary(ctx android.ModuleContext,
objFiles, sharedLibs, staticLibs, lateStaticLibs, wholeStaticLibs, deps, crtBegin, crtEnd android.Paths,
groupLate bool, flags builderFlags, outputFile android.WritablePath,
- implicitOutputs android.WritablePaths, validations android.WritablePaths) {
+ implicitOutputs android.WritablePaths, validations android.Paths) {
ldCmd := "${config.ClangBin}/clang++"
@@ -831,7 +844,7 @@
Inputs: objFiles,
Implicits: deps,
OrderOnly: sharedLibs,
- Validations: validations.Paths(),
+ Validations: validations,
Args: args,
})
}
@@ -949,8 +962,7 @@
}
// Generate a rule for extracting a table of contents from a shared library (.so)
-func transformSharedObjectToToc(ctx android.ModuleContext, inputFile android.Path,
- outputFile android.WritablePath, flags builderFlags) {
+func TransformSharedObjectToToc(ctx android.ModuleContext, inputFile android.Path, outputFile android.WritablePath) {
var format string
if ctx.Darwin() {
@@ -1061,6 +1073,15 @@
})
}
+func transformDarwinUniversalBinary(ctx android.ModuleContext, outputFile android.WritablePath, inputFiles ...android.Path) {
+ ctx.Build(pctx, android.BuildParams{
+ Rule: darwinLipo,
+ Description: "lipo " + outputFile.Base(),
+ Output: outputFile,
+ Inputs: inputFiles,
+ })
+}
+
// Registers build statement to zip one or more coverage files.
func transformCoverageFilesToZip(ctx android.ModuleContext,
inputs Objects, baseName string) android.OptionalPath {
diff --git a/cc/cc.go b/cc/cc.go
index 32652c1..72adefd 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()
@@ -167,6 +170,10 @@
// Path to the dynamic linker binary
DynamicLinker android.OptionalPath
+
+ // For Darwin builds, the path to the second architecture's output that should
+ // be combined with this architectures's output into a FAT MachO file.
+ DarwinSecondArchOutput android.OptionalPath
}
// LocalOrGlobalFlags contains flags that need to have values set globally by the build system or locally by the module
@@ -682,6 +689,15 @@
return d.Kind == staticLibraryDependency
}
+func (d libraryDependencyTag) LicenseAnnotations() []android.LicenseAnnotation {
+ if d.shared() {
+ return []android.LicenseAnnotation{android.LicenseAnnotationSharedDependency}
+ }
+ return nil
+}
+
+var _ android.LicenseAnnotationsDependencyTag = libraryDependencyTag{}
+
// InstallDepNeeded returns true for shared libraries so that shared library dependencies of
// binaries or other shared libraries are installed as dependencies.
func (d libraryDependencyTag) InstallDepNeeded() bool {
@@ -773,8 +789,9 @@
Properties BaseProperties
// initialize before calling Init
- hod android.HostOrDeviceSupported
- multilib android.Multilib
+ hod android.HostOrDeviceSupported
+ multilib android.Multilib
+ bazelable bool
// Allowable SdkMemberTypes of this module type.
sdkMemberTypes []android.SdkMemberType
@@ -796,6 +813,7 @@
sabi *sabi
vndkdep *vndkdep
lto *lto
+ afdo *afdo
pgo *pgo
library libraryInterface
@@ -815,6 +833,10 @@
makeLinkType string
// Kythe (source file indexer) paths for this compilation module
kytheFiles android.Paths
+ // Object .o file output paths for this compilation module
+ objFiles android.Paths
+ // Tidy .tidy file output paths for this compilation module
+ tidyFiles android.Paths
// For apex variants, this is set as apex.min_sdk_version
apexSdkVersion android.ApiLevel
@@ -1125,6 +1147,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()...)
}
@@ -1133,7 +1158,9 @@
}
android.InitAndroidArchModule(c, c.hod, c.multilib)
- android.InitBazelModule(c)
+ if c.bazelable {
+ android.InitBazelModule(c)
+ }
android.InitApexModule(c)
android.InitSdkAwareModule(c)
android.InitDefaultableModule(c)
@@ -1600,6 +1627,7 @@
module.sabi = &sabi{}
module.vndkdep = &vndkdep{}
module.lto = <o{}
+ module.afdo = &afdo{}
module.pgo = &pgo{}
return module
}
@@ -1711,11 +1739,19 @@
// Returns true if Bazel was successfully used for the analysis of this module.
func (c *Module) maybeGenerateBazelActions(actx android.ModuleContext) bool {
- bazelModuleLabel := c.GetBazelLabel(actx, c)
+ var bazelModuleLabel string
+ if actx.ModuleType() == "cc_library" && c.static() {
+ // cc_library is a special case in bp2build; two targets are generated -- one for each
+ // of the shared and static variants. The shared variant keeps the module name, but the
+ // static variant uses a different suffixed name.
+ bazelModuleLabel = bazelLabelForStaticModule(actx, c)
+ } else {
+ bazelModuleLabel = c.GetBazelLabel(actx, c)
+ }
bazelActionsUsed := false
// Mixed builds mode is disabled for modules outside of device OS.
// TODO(b/200841190): Support non-device OS in mixed builds.
- if c.MixedBuildsEnabled(actx) && c.bazelHandler != nil && actx.Os().Class == android.Device {
+ if c.MixedBuildsEnabled(actx) && c.bazelHandler != nil {
bazelActionsUsed = c.bazelHandler.GenerateBazelBuildActions(actx, bazelModuleLabel)
}
return bazelActionsUsed
@@ -1787,6 +1823,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)
}
@@ -1825,6 +1864,8 @@
return
}
c.kytheFiles = objs.kytheFiles
+ c.objFiles = objs.objFiles
+ c.tidyFiles = objs.tidyFiles
}
if c.linker != nil {
@@ -1912,6 +1953,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)
}
@@ -2568,6 +2612,11 @@
depName := ctx.OtherModuleName(dep)
depTag := ctx.OtherModuleDependencyTag(dep)
+ if depTag == android.DarwinUniversalVariantTag {
+ depPaths.DarwinSecondArchOutput = dep.(*Module).OutputFile()
+ return
+ }
+
ccDep, ok := dep.(LinkableInterface)
if !ok {
@@ -3151,6 +3200,24 @@
return false
}
+func (c *Module) benchmarkBinary() bool {
+ if b, ok := c.linker.(interface {
+ benchmarkBinary() bool
+ }); ok {
+ return b.benchmarkBinary()
+ }
+ return false
+}
+
+func (c *Module) fuzzBinary() bool {
+ if f, ok := c.linker.(interface {
+ fuzzBinary() bool
+ }); ok {
+ return f.fuzzBinary()
+ }
+ return false
+}
+
// Header returns true if the module is a header-only variant. (See cc/library.go header()).
func (c *Module) Header() bool {
if h, ok := c.linker.(interface {
@@ -3396,16 +3463,56 @@
var _ snapshot.RelativeInstallPath = (*Module)(nil)
+// ConvertWithBp2build converts Module to Bazel for bp2build.
+func (c *Module) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
+ prebuilt := c.IsPrebuilt()
+ if c.Binary() {
+ if !prebuilt {
+ binaryBp2build(ctx, c, ctx.ModuleType())
+ }
+ } else if c.Object() {
+ if !prebuilt {
+ objectBp2Build(ctx, c)
+ }
+ } else if c.CcLibrary() {
+ 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 {
+ libraryHeadersBp2Build(ctx, c)
+ } else if static {
+ if prebuilt {
+ prebuiltLibraryStaticBp2Build(ctx, c)
+ } else {
+ sharedOrStaticLibraryBp2Build(ctx, c, true)
+ }
+ } else if shared {
+ if prebuilt {
+ prebuiltLibrarySharedBp2Build(ctx, c)
+ } else {
+ sharedOrStaticLibraryBp2Build(ctx, c, false)
+ }
+ }
+ }
+}
+
//
// Defaults
//
type Defaults struct {
android.ModuleBase
android.DefaultsModuleBase
- // Included to support setting bazel_module.label for multiple Soong modules to the same Bazel
- // target. This is primarily useful for modules that were architecture specific and instead are
- // handled in Bazel as a select().
- android.BazelModuleBase
android.ApexModuleBase
}
@@ -3446,6 +3553,7 @@
&SAbiProperties{},
&VndkProperties{},
<OProperties{},
+ &AfdoProperties{},
&PgoProperties{},
&android.ProtoProperties{},
// RustBindgenProperties is included here so that cc_defaults can be used for rust_bindgen modules.
@@ -3453,8 +3561,6 @@
&prebuiltLinkerProperties{},
)
- // Bazel module must be initialized _before_ Defaults to be included in cc_defaults module.
- android.InitBazelModule(module)
android.InitDefaultsModule(module)
return module
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 4c9f579..31d91b6 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -346,7 +346,7 @@
func checkVndkLibrariesOutput(t *testing.T, ctx *android.TestContext, module string, expected []string) {
t.Helper()
- got := ctx.ModuleForTests(module, "").Module().(*vndkLibrariesTxt).fileNames
+ got := ctx.ModuleForTests(module, "android_common").Module().(*vndkLibrariesTxt).fileNames
assertArrayString(t, got, expected)
}
@@ -532,11 +532,11 @@
CheckSnapshot(t, ctx, snapshotSingleton, "libllndk", "libllndk.so", llndkLib2ndPath, variant2nd)
snapshotConfigsPath := filepath.Join(snapshotVariantPath, "configs")
- CheckSnapshot(t, ctx, snapshotSingleton, "llndk.libraries.txt", "llndk.libraries.txt", snapshotConfigsPath, "")
- CheckSnapshot(t, ctx, snapshotSingleton, "vndkcore.libraries.txt", "vndkcore.libraries.txt", snapshotConfigsPath, "")
- CheckSnapshot(t, ctx, snapshotSingleton, "vndksp.libraries.txt", "vndksp.libraries.txt", snapshotConfigsPath, "")
- CheckSnapshot(t, ctx, snapshotSingleton, "vndkprivate.libraries.txt", "vndkprivate.libraries.txt", snapshotConfigsPath, "")
- CheckSnapshot(t, ctx, snapshotSingleton, "vndkproduct.libraries.txt", "vndkproduct.libraries.txt", snapshotConfigsPath, "")
+ CheckSnapshot(t, ctx, snapshotSingleton, "llndk.libraries.txt", "llndk.libraries.txt", snapshotConfigsPath, "android_common")
+ CheckSnapshot(t, ctx, snapshotSingleton, "vndkcore.libraries.txt", "vndkcore.libraries.txt", snapshotConfigsPath, "android_common")
+ CheckSnapshot(t, ctx, snapshotSingleton, "vndksp.libraries.txt", "vndksp.libraries.txt", snapshotConfigsPath, "android_common")
+ CheckSnapshot(t, ctx, snapshotSingleton, "vndkprivate.libraries.txt", "vndkprivate.libraries.txt", snapshotConfigsPath, "android_common")
+ CheckSnapshot(t, ctx, snapshotSingleton, "vndkproduct.libraries.txt", "vndkproduct.libraries.txt", snapshotConfigsPath, "android_common")
checkVndkOutput(t, ctx, "vndk/vndk.libraries.txt", []string{
"LLNDK: libc.so",
@@ -614,7 +614,7 @@
config.TestProductVariables.Platform_vndk_version = StringPtr("29")
ctx := testCcWithConfig(t, config)
- module := ctx.ModuleForTests("llndk.libraries.txt", "")
+ module := ctx.ModuleForTests("llndk.libraries.txt", "android_common")
entries := android.AndroidMkEntriesForTest(t, ctx, module.Module())[0]
assertArrayString(t, entries.EntryMap["LOCAL_MODULE_STEM"], []string{"llndk.libraries.29.txt"})
}
@@ -730,9 +730,16 @@
gtest: false,
}
+ cc_binary {
+ name: "test_bin",
+ relative_install_path: "foo/bar/baz",
+ compile_multilib: "both",
+ }
+
cc_test {
name: "main_test",
data_libs: ["test_lib"],
+ data_bins: ["test_bin"],
gtest: false,
}
`
@@ -750,10 +757,10 @@
t.Fatalf("Expected cc_test to produce output files, error: %s", err)
}
if len(outputFiles) != 1 {
- t.Errorf("expected exactly one output file. output files: [%s]", outputFiles)
+ t.Fatalf("expected exactly one output file. output files: [%s]", outputFiles)
}
- if len(testBinary.dataPaths()) != 1 {
- t.Errorf("expected exactly one test data file. test data files: [%s]", testBinary.dataPaths())
+ if len(testBinary.dataPaths()) != 2 {
+ t.Fatalf("expected exactly one test data file. test data files: [%s]", testBinary.dataPaths())
}
outputPath := outputFiles[0].String()
@@ -766,6 +773,10 @@
t.Errorf("expected LOCAL_TEST_DATA to end with `:test_lib.so:foo/bar/baz`,"+
" but was '%s'", entries.EntryMap["LOCAL_TEST_DATA"][0])
}
+ if !strings.HasSuffix(entries.EntryMap["LOCAL_TEST_DATA"][1], ":test_bin:foo/bar/baz") {
+ t.Errorf("expected LOCAL_TEST_DATA to end with `:test_bin:foo/bar/baz`,"+
+ " but was '%s'", entries.EntryMap["LOCAL_TEST_DATA"][1])
+ }
}
func TestVndkWhenVndkVersionIsNotSet(t *testing.T) {
@@ -3585,6 +3596,58 @@
}
}
+func TestAidlFlagsWithMinSdkVersion(t *testing.T) {
+ for _, tc := range []struct {
+ name string
+ sdkVersion string
+ variant string
+ expected string
+ }{
+ {
+ name: "default is current",
+ sdkVersion: "",
+ variant: "android_arm64_armv8-a_static",
+ expected: "platform_apis",
+ },
+ {
+ name: "use sdk_version",
+ sdkVersion: `sdk_version: "29"`,
+ variant: "android_arm64_armv8-a_static",
+ expected: "platform_apis",
+ },
+ {
+ name: "use sdk_version(sdk variant)",
+ sdkVersion: `sdk_version: "29"`,
+ variant: "android_arm64_armv8-a_sdk_static",
+ expected: "29",
+ },
+ {
+ name: "use min_sdk_version",
+ sdkVersion: `min_sdk_version: "29"`,
+ variant: "android_arm64_armv8-a_static",
+ expected: "29",
+ },
+ } {
+ t.Run(tc.name, func(t *testing.T) {
+ ctx := testCc(t, `
+ cc_library {
+ name: "libfoo",
+ stl: "none",
+ srcs: ["a/Foo.aidl"],
+ `+tc.sdkVersion+`
+ }
+ `)
+ libfoo := ctx.ModuleForTests("libfoo", tc.variant)
+ manifest := android.RuleBuilderSboxProtoForTests(t, libfoo.Output("aidl.sbox.textproto"))
+ aidlCommand := manifest.Commands[0].GetCommand()
+ expectedAidlFlag := "--min_sdk_version=" + tc.expected
+ if !strings.Contains(aidlCommand, expectedAidlFlag) {
+ t.Errorf("aidl command %q does not contain %q", aidlCommand, expectedAidlFlag)
+ }
+ })
+ }
+}
+
func TestMinSdkVersionInClangTriple(t *testing.T) {
ctx := testCc(t, `
cc_library_shared {
@@ -3917,9 +3980,9 @@
conly := []string{"-fPIC", "${config.CommonGlobalConlyflags}"}
cppOnly := []string{"-fPIC", "${config.CommonGlobalCppflags}", "${config.DeviceGlobalCppflags}", "${config.ArmCppflags}"}
- cflags := []string{"-Wall", "-Werror"}
- cstd := []string{"-std=gnu99"}
- cppstd := []string{"-std=gnu++17", "-fno-rtti"}
+ cflags := []string{"-Wall", "-Werror", "-std=candcpp"}
+ cstd := []string{"-std=gnu99", "-std=conly"}
+ cppstd := []string{"-std=gnu++17", "-std=cpp", "-fno-rtti"}
lastIncludes := []string{
"out/soong/ndk/sysroot/usr/include",
@@ -3942,12 +4005,12 @@
{
name: "c",
src: "foo.c",
- expected: combineSlices(baseExpectedFlags, conly, expectedIncludes, cflags, cstd, lastIncludes, []string{"${config.NoOverrideGlobalCflags}"}),
+ expected: combineSlices(baseExpectedFlags, conly, expectedIncludes, cflags, cstd, lastIncludes, []string{"${config.NoOverrideGlobalCflags}", "${config.NoOverrideExternalGlobalCflags}"}),
},
{
name: "cc",
src: "foo.cc",
- expected: combineSlices(baseExpectedFlags, cppOnly, expectedIncludes, cflags, cppstd, lastIncludes, []string{"${config.NoOverrideGlobalCflags}"}),
+ expected: combineSlices(baseExpectedFlags, cppOnly, expectedIncludes, cflags, cppstd, lastIncludes, []string{"${config.NoOverrideGlobalCflags}", "${config.NoOverrideExternalGlobalCflags}"}),
},
{
name: "assemble",
@@ -3962,6 +4025,9 @@
cc_library {
name: "libfoo",
srcs: ["%s"],
+ cflags: ["-std=candcpp"],
+ conlyflags: ["-std=conly"],
+ cppflags: ["-std=cpp"],
local_include_dirs: ["local_include_dirs"],
export_include_dirs: ["export_include_dirs"],
export_system_include_dirs: ["export_system_include_dirs"],
diff --git a/cc/ccdeps.go b/cc/ccdeps.go
index b96d8b0..75e1faf 100644
--- a/cc/ccdeps.go
+++ b/cc/ccdeps.go
@@ -44,11 +44,9 @@
var _ android.SingletonMakeVarsProvider = (*ccdepsGeneratorSingleton)(nil)
const (
- // Environment variables used to control the behavior of this singleton.
- envVariableCollectCCDeps = "SOONG_COLLECT_CC_DEPS"
- ccdepsJsonFileName = "module_bp_cc_deps.json"
- cClang = "clang"
- cppClang = "clang++"
+ ccdepsJsonFileName = "module_bp_cc_deps.json"
+ cClang = "clang"
+ cppClang = "clang++"
)
type ccIdeInfo struct {
@@ -83,10 +81,7 @@
}
func (c *ccdepsGeneratorSingleton) GenerateBuildActions(ctx android.SingletonContext) {
- if !ctx.Config().IsEnvTrue(envVariableCollectCCDeps) {
- return
- }
-
+ // (b/204397180) Generate module_bp_cc_deps.json by default.
moduleDeps := ccDeps{}
moduleInfos := map[string]ccIdeInfo{}
diff --git a/cc/compiler.go b/cc/compiler.go
index 00df669..8adc3ab 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -304,11 +304,24 @@
cppStd := String(cppStdPtr)
switch cppStd {
case "":
- cppStd = config.CppStdVersion
+ return config.CppStdVersion
case "experimental":
- cppStd = config.ExperimentalCppStdVersion
+ return config.ExperimentalCppStdVersion
+ default:
+ return cppStd
}
- return cppStd
+}
+
+func parseCStd(cStdPtr *string) string {
+ cStd := String(cStdPtr)
+ switch cStd {
+ case "":
+ return config.CStdVersion
+ case "experimental":
+ return config.ExperimentalCStdVersion
+ default:
+ return cStd
+ }
}
// Create a Flags struct that collects the compile flags from global values,
@@ -479,13 +492,7 @@
flags.Global.CommonFlags = append(flags.Global.CommonFlags, tc.ToolchainCflags())
- cStd := config.CStdVersion
- if String(compiler.Properties.C_std) == "experimental" {
- cStd = config.ExperimentalCStdVersion
- } else if String(compiler.Properties.C_std) != "" {
- cStd = String(compiler.Properties.C_std)
- }
-
+ cStd := parseCStd(compiler.Properties.C_std)
cppStd := parseCppStd(compiler.Properties.Cpp_std)
cStd, cppStd = maybeReplaceGnuToC(compiler.Properties.Gnu_extensions, cStd, cppStd)
@@ -552,6 +559,12 @@
flags.aidlFlags = append(flags.aidlFlags, "-t")
}
+ aidlMinSdkVersion := ctx.minSdkVersion()
+ if aidlMinSdkVersion == "" {
+ aidlMinSdkVersion = "platform_apis"
+ }
+ flags.aidlFlags = append(flags.aidlFlags, "--min_sdk_version="+aidlMinSdkVersion)
+
flags.Local.CommonFlags = append(flags.Local.CommonFlags,
"-I"+android.PathForModuleGen(ctx, "aidl").String())
}
@@ -624,9 +637,9 @@
func ndkPathDeps(ctx ModuleContext) android.Paths {
if ctx.Module().(*Module).IsSdkVariant() {
- // The NDK sysroot timestamp file depends on all the NDK sysroot files
- // (headers and libraries).
- return android.Paths{getNdkBaseTimestampFile(ctx)}
+ // The NDK sysroot timestamp file depends on all the NDK sysroot header files
+ // for compiling src to obj files.
+ return android.Paths{getNdkHeadersTimestampFile(ctx)}
}
return nil
}
diff --git a/cc/config/darwin_host.go b/cc/config/darwin_host.go
index 318acb4..206bec1 100644
--- a/cc/config/darwin_host.go
+++ b/cc/config/darwin_host.go
@@ -54,6 +54,7 @@
darwinSupportedSdkVersions = []string{
"11",
+ "12",
}
darwinAvailableLibraries = append(
@@ -87,6 +88,10 @@
return getMacTools(ctx).arPath
})
+ pctx.VariableFunc("MacLipoPath", func(ctx android.PackageVarContext) string {
+ return getMacTools(ctx).lipoPath
+ })
+
pctx.VariableFunc("MacStripPath", func(ctx android.PackageVarContext) string {
return getMacTools(ctx).stripPath
})
@@ -118,6 +123,7 @@
sdkRoot string
arPath string
+ lipoPath string
stripPath string
toolPath string
}
@@ -157,6 +163,7 @@
macTools.sdkRoot = xcrun("--show-sdk-path")
macTools.arPath = xcrun("--find", "ar")
+ macTools.lipoPath = xcrun("--find", "lipo")
macTools.stripPath = xcrun("--find", "strip")
macTools.toolPath = filepath.Dir(xcrun("--find", "ld"))
})
diff --git a/cc/config/global.go b/cc/config/global.go
index 7abd2fc..e46ac96 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -46,7 +46,6 @@
"-O2",
"-g",
- "-fdebug-info-for-profiling",
"-fno-strict-aliasing",
@@ -125,6 +124,9 @@
"-Werror=sequence-point",
"-Werror=format-security",
"-nostdlibinc",
+
+ // Emit additional debug info for AutoFDO
+ "-fdebug-info-for-profiling",
}
deviceGlobalCppflags = []string{
@@ -222,8 +224,6 @@
"-Wno-pessimizing-move", // http://b/154270751
// New warnings to be fixed after clang-r399163
"-Wno-non-c-typedef-for-linkage", // http://b/161304145
- // New warnings to be fixed after clang-r407598
- "-Wno-string-concatenation", // http://b/175068488
// New warnings to be fixed after clang-r428724
"-Wno-align-mismatch", // http://b/193679946
// New warnings to be fixed after clang-r433403
@@ -231,6 +231,12 @@
"-Wno-error=unused-but-set-parameter", // http://b/197240255
}
+ noOverrideExternalGlobalCflags = []string{
+ // http://b/197240255
+ "-Wno-unused-but-set-variable",
+ "-Wno-unused-but-set-parameter",
+ }
+
// Extra cflags for external third-party projects to disable warnings that
// are infeasible to fix in all the external projects and their upstream repos.
extraExternalCflags = []string{
@@ -257,6 +263,9 @@
// http://b/199369603
"-Wno-null-pointer-subtraction",
+
+ // http://b/175068488
+ "-Wno-string-concatenation",
}
IllegalFlags = []string{
@@ -270,8 +279,8 @@
// prebuilts/clang default settings.
ClangDefaultBase = "prebuilts/clang/host"
- ClangDefaultVersion = "clang-r433403b"
- ClangDefaultShortVersion = "13.0.3"
+ ClangDefaultVersion = "clang-r437112b"
+ ClangDefaultShortVersion = "14.0.1"
// Directories with warnings from Android.bp files.
WarningAllowedProjects = []string{
@@ -344,6 +353,7 @@
exportStringListStaticVariable("HostGlobalCflags", hostGlobalCflags)
exportStringListStaticVariable("NoOverrideGlobalCflags", noOverrideGlobalCflags)
+ exportStringListStaticVariable("NoOverrideExternalGlobalCflags", noOverrideExternalGlobalCflags)
exportStringListStaticVariable("CommonGlobalCppflags", commonGlobalCppflags)
exportStringListStaticVariable("ExternalCflags", extraExternalCflags)
diff --git a/cc/config/vndk.go b/cc/config/vndk.go
index 9577a8c..492cd98 100644
--- a/cc/config/vndk.go
+++ b/cc/config/vndk.go
@@ -101,6 +101,9 @@
"android.hardware.weaver-unstable-ndk_platform",
"android.system.suspend-V1-ndk",
"android.system.keystore2-V1-ndk",
+ "android.se.omapi-V1-ndk_platform",
+ "android.se.omapi-ndk_platform",
+ "android.se.omapi-unstable-ndk_platform",
"android.hardware.wifi.hostapd-V1-ndk",
"android.hardware.wifi.hostapd-V1-ndk_platform",
"android.hardware.wifi.supplicant-V1-ndk",
diff --git a/cc/fuzz.go b/cc/fuzz.go
index e987fe4..23d81d6 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -52,6 +52,10 @@
installedSharedDeps []string
}
+func (fuzz *fuzzBinary) fuzzBinary() bool {
+ return true
+}
+
func (fuzz *fuzzBinary) linkerProps() []interface{} {
props := fuzz.binaryDecorator.linkerProps()
props = append(props, &fuzz.fuzzPackagedModule.FuzzProperties)
@@ -234,7 +238,7 @@
}
func NewFuzz(hod android.HostOrDeviceSupported) *Module {
- module, binary := NewBinary(hod)
+ module, binary := newBinary(hod, false)
binary.baseInstaller = NewFuzzInstaller()
module.sanitize.SetSanitizer(Fuzzer, true)
diff --git a/cc/libbuildversion/Android.bp b/cc/libbuildversion/Android.bp
index 4debb1c..b105a30 100644
--- a/cc/libbuildversion/Android.bp
+++ b/cc/libbuildversion/Android.bp
@@ -14,8 +14,10 @@
enabled: true,
},
},
+ min_sdk_version: "26",
apex_available: [
"//apex_available:platform",
"//apex_available:anyapex",
],
+ vendor_available: true,
}
diff --git a/cc/libbuildversion/libbuildversion.cpp b/cc/libbuildversion/libbuildversion.cpp
index 5242025..1e01c11 100644
--- a/cc/libbuildversion/libbuildversion.cpp
+++ b/cc/libbuildversion/libbuildversion.cpp
@@ -36,7 +36,11 @@
return soong_build_number;
}
+#ifdef __ANDROID_VENDOR__
+ const prop_info* pi = __system_property_find("ro.vendor.build.version.incremental");
+#else
const prop_info* pi = __system_property_find("ro.build.version.incremental");
+#endif
if (pi == nullptr) return "";
std::string property_value;
diff --git a/cc/library.go b/cc/library.go
index c3f7305..b18f90d 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -207,10 +207,6 @@
func init() {
RegisterLibraryBuildComponents(android.InitRegistrationContext)
-
- android.RegisterBp2BuildMutator("cc_library_static", CcLibraryStaticBp2Build)
- android.RegisterBp2BuildMutator("cc_library_shared", CcLibrarySharedBp2Build)
- android.RegisterBp2BuildMutator("cc_library", CcLibraryBp2Build)
}
func RegisterLibraryBuildComponents(ctx android.RegistrationContext) {
@@ -236,12 +232,13 @@
Hdrs bazel.LabelListAttribute
- Deps bazel.LabelListAttribute
- Implementation_deps bazel.LabelListAttribute
- Dynamic_deps bazel.LabelListAttribute
- Implementation_dynamic_deps bazel.LabelListAttribute
- Whole_archive_deps bazel.LabelListAttribute
- System_dynamic_deps bazel.LabelListAttribute
+ Deps bazel.LabelListAttribute
+ Implementation_deps bazel.LabelListAttribute
+ Dynamic_deps bazel.LabelListAttribute
+ Implementation_dynamic_deps bazel.LabelListAttribute
+ Whole_archive_deps bazel.LabelListAttribute
+ Implementation_whole_archive_deps bazel.LabelListAttribute
+ System_dynamic_deps bazel.LabelListAttribute
Export_includes bazel.StringListAttribute
Export_system_includes bazel.StringListAttribute
@@ -253,6 +250,7 @@
Stl *string
Cpp_std *string
+ C_std *string
// This is shared only.
Link_crt bazel.BoolAttribute
@@ -275,21 +273,12 @@
None bazel.BoolAttribute
}
-func CcLibraryBp2Build(ctx android.TopDownMutatorContext) {
- m, ok := ctx.Module().(*Module)
- if !ok || !m.ConvertWithBp2build(ctx) {
- return
- }
-
- if ctx.ModuleType() != "cc_library" {
- return
- }
-
+func libraryBp2Build(ctx android.TopDownMutatorContext, m *Module) {
// For some cc_library modules, their static variants are ready to be
// converted, but not their shared variants. For these modules, delegate to
// the cc_library_static bp2build converter temporarily instead.
if android.GenerateCcLibraryStaticOnly(ctx.Module().Name()) {
- ccSharedOrStaticBp2BuildMutatorInternal(ctx, m, "cc_library_static")
+ sharedOrStaticLibraryBp2Build(ctx, m, true)
return
}
@@ -298,43 +287,89 @@
baseAttributes := bp2BuildParseBaseProps(ctx, m)
compilerAttrs := baseAttributes.compilerAttributes
linkerAttrs := baseAttributes.linkerAttributes
- exportedIncludes := bp2BuildParseExportedIncludes(ctx, m)
+ exportedIncludes := bp2BuildParseExportedIncludes(ctx, m, compilerAttrs.includes)
srcs := compilerAttrs.srcs
+ sharedAttrs.Dynamic_deps.Add(baseAttributes.protoDependency)
+ staticAttrs.Deps.Add(baseAttributes.protoDependency)
+
asFlags := compilerAttrs.asFlags
if compilerAttrs.asSrcs.IsEmpty() && sharedAttrs.Srcs_as.IsEmpty() && staticAttrs.Srcs_as.IsEmpty() {
// Skip asflags for BUILD file simplicity if there are no assembly sources.
asFlags = bazel.MakeStringListAttribute(nil)
}
- attrs := &bazelCcLibraryAttributes{
- Srcs: srcs,
- Srcs_c: compilerAttrs.cSrcs,
- Srcs_as: compilerAttrs.asSrcs,
- Hdrs: compilerAttrs.hdrs,
+ staticCommonAttrs := staticOrSharedAttributes{
+ Srcs: *srcs.Clone().Append(staticAttrs.Srcs),
+ Srcs_c: *compilerAttrs.cSrcs.Clone().Append(staticAttrs.Srcs_c),
+ Srcs_as: *compilerAttrs.asSrcs.Clone().Append(staticAttrs.Srcs_as),
+ Copts: *compilerAttrs.copts.Clone().Append(staticAttrs.Copts),
+ Hdrs: *compilerAttrs.hdrs.Clone().Append(staticAttrs.Hdrs),
- Copts: compilerAttrs.copts,
+ Deps: *linkerAttrs.deps.Clone().Append(staticAttrs.Deps),
+ Implementation_deps: *linkerAttrs.implementationDeps.Clone().Append(staticAttrs.Implementation_deps),
+ Dynamic_deps: *linkerAttrs.dynamicDeps.Clone().Append(staticAttrs.Dynamic_deps),
+ Implementation_dynamic_deps: *linkerAttrs.implementationDynamicDeps.Clone().Append(staticAttrs.Implementation_dynamic_deps),
+ Implementation_whole_archive_deps: linkerAttrs.implementationWholeArchiveDeps,
+ Whole_archive_deps: *linkerAttrs.wholeArchiveDeps.Clone().Append(staticAttrs.Whole_archive_deps),
+ System_dynamic_deps: *linkerAttrs.systemDynamicDeps.Clone().Append(staticAttrs.System_dynamic_deps),
+ }
+
+ sharedCommonAttrs := staticOrSharedAttributes{
+ Srcs: *srcs.Clone().Append(sharedAttrs.Srcs),
+ Srcs_c: *compilerAttrs.cSrcs.Clone().Append(sharedAttrs.Srcs_c),
+ Srcs_as: *compilerAttrs.asSrcs.Clone().Append(sharedAttrs.Srcs_as),
+ Copts: *compilerAttrs.copts.Clone().Append(sharedAttrs.Copts),
+ Hdrs: *compilerAttrs.hdrs.Clone().Append(sharedAttrs.Hdrs),
+
+ Deps: *linkerAttrs.deps.Clone().Append(sharedAttrs.Deps),
+ Implementation_deps: *linkerAttrs.implementationDeps.Clone().Append(sharedAttrs.Implementation_deps),
+ Dynamic_deps: *linkerAttrs.dynamicDeps.Clone().Append(sharedAttrs.Dynamic_deps),
+ Implementation_dynamic_deps: *linkerAttrs.implementationDynamicDeps.Clone().Append(sharedAttrs.Implementation_dynamic_deps),
+ Whole_archive_deps: *linkerAttrs.wholeArchiveDeps.Clone().Append(sharedAttrs.Whole_archive_deps),
+ System_dynamic_deps: *linkerAttrs.systemDynamicDeps.Clone().Append(sharedAttrs.System_dynamic_deps),
+ }
+
+ staticTargetAttrs := &bazelCcLibraryStaticAttributes{
+ staticOrSharedAttributes: staticCommonAttrs,
+
Cppflags: compilerAttrs.cppFlags,
Conlyflags: compilerAttrs.conlyFlags,
Asflags: asFlags,
- Implementation_deps: linkerAttrs.implementationDeps,
- Deps: linkerAttrs.deps,
- Implementation_dynamic_deps: linkerAttrs.implementationDynamicDeps,
- Dynamic_deps: linkerAttrs.dynamicDeps,
- Whole_archive_deps: linkerAttrs.wholeArchiveDeps,
- System_dynamic_deps: linkerAttrs.systemDynamicDeps,
- Export_includes: exportedIncludes.Includes,
- Export_system_includes: exportedIncludes.SystemIncludes,
- Local_includes: compilerAttrs.localIncludes,
- Absolute_includes: compilerAttrs.absoluteIncludes,
- Linkopts: linkerAttrs.linkopts,
- Link_crt: linkerAttrs.linkCrt,
- Use_libcrt: linkerAttrs.useLibcrt,
- Rtti: compilerAttrs.rtti,
- Stl: compilerAttrs.stl,
- Cpp_std: compilerAttrs.cppStd,
+ Export_includes: exportedIncludes.Includes,
+ Export_absolute_includes: exportedIncludes.AbsoluteIncludes,
+ Export_system_includes: exportedIncludes.SystemIncludes,
+ Local_includes: compilerAttrs.localIncludes,
+ Absolute_includes: compilerAttrs.absoluteIncludes,
+ Use_libcrt: linkerAttrs.useLibcrt,
+ Rtti: compilerAttrs.rtti,
+ Stl: compilerAttrs.stl,
+ Cpp_std: compilerAttrs.cppStd,
+ C_std: compilerAttrs.cStd,
+
+ Features: linkerAttrs.features,
+ }
+
+ sharedTargetAttrs := &bazelCcLibrarySharedAttributes{
+ staticOrSharedAttributes: sharedCommonAttrs,
+ Cppflags: compilerAttrs.cppFlags,
+ Conlyflags: compilerAttrs.conlyFlags,
+ Asflags: asFlags,
+
+ Export_includes: exportedIncludes.Includes,
+ Export_absolute_includes: exportedIncludes.AbsoluteIncludes,
+ Export_system_includes: exportedIncludes.SystemIncludes,
+ Local_includes: compilerAttrs.localIncludes,
+ Absolute_includes: compilerAttrs.absoluteIncludes,
+ Linkopts: linkerAttrs.linkopts,
+ Link_crt: linkerAttrs.linkCrt,
+ Use_libcrt: linkerAttrs.useLibcrt,
+ Rtti: compilerAttrs.rtti,
+ Stl: compilerAttrs.stl,
+ Cpp_std: compilerAttrs.cppStd,
+ C_std: compilerAttrs.cStd,
Additional_linker_inputs: linkerAttrs.additionalLinkerInputs,
@@ -345,20 +380,24 @@
All: linkerAttrs.stripAll,
None: linkerAttrs.stripNone,
},
-
- Shared: sharedAttrs,
-
- Static: staticAttrs,
-
Features: linkerAttrs.features,
}
- props := bazel.BazelTargetModuleProperties{
- Rule_class: "cc_library",
- Bzl_load_location: "//build/bazel/rules:full_cc_library.bzl",
+ staticProps := bazel.BazelTargetModuleProperties{
+ Rule_class: "cc_library_static",
+ Bzl_load_location: "//build/bazel/rules:cc_library_static.bzl",
+ }
+ sharedProps := bazel.BazelTargetModuleProperties{
+ Rule_class: "cc_library_shared",
+ Bzl_load_location: "//build/bazel/rules:cc_library_shared.bzl",
}
- ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
+ 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
@@ -373,6 +412,7 @@
staticLibrarySdkMemberType,
staticAndSharedLibrarySdkMemberType,
}
+ module.bazelable = true
module.bazelHandler = &ccLibraryBazelHandler{module: module}
return module.Init()
}
@@ -382,6 +422,7 @@
module, library := NewLibrary(android.HostAndDeviceSupported)
library.BuildOnlyStatic()
module.sdkMemberTypes = []android.SdkMemberType{staticLibrarySdkMemberType}
+ module.bazelable = true
module.bazelHandler = &ccLibraryBazelHandler{module: module}
return module.Init()
}
@@ -391,6 +432,7 @@
module, library := NewLibrary(android.HostAndDeviceSupported)
library.BuildOnlyShared()
module.sdkMemberTypes = []android.SdkMemberType{sharedLibrarySdkMemberType}
+ module.bazelable = true
module.bazelHandler = &ccLibraryBazelHandler{module: module}
return module.Init()
}
@@ -401,6 +443,8 @@
module, library := NewLibrary(android.HostSupported)
library.BuildOnlyStatic()
module.sdkMemberTypes = []android.SdkMemberType{staticLibrarySdkMemberType}
+ module.bazelable = true
+ module.bazelHandler = &ccLibraryBazelHandler{module: module}
return module.Init()
}
@@ -409,6 +453,8 @@
module, library := NewLibrary(android.HostSupported)
library.BuildOnlyShared()
module.sdkMemberTypes = []android.SdkMemberType{sharedLibrarySdkMemberType}
+ module.bazelable = true
+ module.bazelHandler = &ccLibraryBazelHandler{module: module}
return module.Init()
}
@@ -1320,11 +1366,21 @@
return outputFile
}
+func ndkSharedLibDeps(ctx ModuleContext) android.Paths {
+ if ctx.Module().(*Module).IsSdkVariant() {
+ // The NDK sysroot timestamp file depends on all the NDK
+ // sysroot header and shared library files.
+ return android.Paths{getNdkBaseTimestampFile(ctx)}
+ }
+ return nil
+}
+
func (library *libraryDecorator) linkShared(ctx ModuleContext,
flags Flags, deps PathDeps, objs Objects) android.Path {
var linkerDeps android.Paths
linkerDeps = append(linkerDeps, flags.LdFlagsDeps...)
+ linkerDeps = append(linkerDeps, ndkSharedLibDeps(ctx)...)
unexportedSymbols := ctx.ExpandOptionalSource(library.Properties.Unexported_symbols_list, "unexported_symbols_list")
forceNotWeakSymbols := ctx.ExpandOptionalSource(library.Properties.Force_symbols_not_weak_list, "force_symbols_not_weak_list")
@@ -1373,11 +1429,17 @@
builderFlags := flagsToBuilderFlags(flags)
+ if ctx.Darwin() && deps.DarwinSecondArchOutput.Valid() {
+ fatOutputFile := outputFile
+ outputFile = android.PathForModuleOut(ctx, "pre-fat", fileName)
+ transformDarwinUniversalBinary(ctx, fatOutputFile, outputFile, deps.DarwinSecondArchOutput.Path())
+ }
+
// Optimize out relinking against shared libraries whose interface hasn't changed by
// depending on a table of contents file instead of the library itself.
tocFile := outputFile.ReplaceExtension(ctx, flags.Toolchain.ShlibSuffix()[1:]+".toc")
library.tocFile = android.OptionalPathForPath(tocFile)
- transformSharedObjectToToc(ctx, outputFile, tocFile, builderFlags)
+ TransformSharedObjectToToc(ctx, outputFile, tocFile)
stripFlags := flagsToStripFlags(flags)
needsStrip := library.stripper.NeedsStrip(ctx)
@@ -2349,33 +2411,12 @@
return outputFile
}
-func ccSharedOrStaticBp2BuildMutator(ctx android.TopDownMutatorContext, modType string) {
- module, ok := ctx.Module().(*Module)
- if !ok {
- // Not a cc module
- return
- }
- if !module.ConvertWithBp2build(ctx) {
- return
- }
- if ctx.ModuleType() != modType {
- return
- }
-
- ccSharedOrStaticBp2BuildMutatorInternal(ctx, module, modType)
-}
-
-func ccSharedOrStaticBp2BuildMutatorInternal(ctx android.TopDownMutatorContext, module *Module, modType string) {
- if modType != "cc_library_static" && modType != "cc_library_shared" {
- panic("ccSharedOrStaticBp2BuildMutatorInternal only supports cc_library_{static,shared}")
- }
- isStatic := modType == "cc_library_static"
-
+func sharedOrStaticLibraryBp2Build(ctx android.TopDownMutatorContext, module *Module, isStatic bool) {
baseAttributes := bp2BuildParseBaseProps(ctx, module)
compilerAttrs := baseAttributes.compilerAttributes
linkerAttrs := baseAttributes.linkerAttributes
- exportedIncludes := bp2BuildParseExportedIncludes(ctx, module)
+ exportedIncludes := bp2BuildParseExportedIncludes(ctx, module, compilerAttrs.includes)
// Append shared/static{} stanza properties. These won't be specified on
// cc_library_* itself, but may be specified in cc_defaults that this module
@@ -2406,27 +2447,34 @@
Copts: compilerAttrs.copts,
Hdrs: compilerAttrs.hdrs,
- Deps: linkerAttrs.deps,
- Implementation_deps: linkerAttrs.implementationDeps,
- Dynamic_deps: linkerAttrs.dynamicDeps,
- Implementation_dynamic_deps: linkerAttrs.implementationDynamicDeps,
- Whole_archive_deps: linkerAttrs.wholeArchiveDeps,
- System_dynamic_deps: linkerAttrs.systemDynamicDeps,
+ Deps: linkerAttrs.deps,
+ Implementation_deps: linkerAttrs.implementationDeps,
+ Dynamic_deps: linkerAttrs.dynamicDeps,
+ Implementation_dynamic_deps: linkerAttrs.implementationDynamicDeps,
+ Whole_archive_deps: linkerAttrs.wholeArchiveDeps,
+ Implementation_whole_archive_deps: linkerAttrs.implementationWholeArchiveDeps,
+ System_dynamic_deps: linkerAttrs.systemDynamicDeps,
}
var attrs interface{}
if isStatic {
+ commonAttrs.Deps.Add(baseAttributes.protoDependency)
attrs = &bazelCcLibraryStaticAttributes{
staticOrSharedAttributes: commonAttrs,
- Use_libcrt: linkerAttrs.useLibcrt,
- Rtti: compilerAttrs.rtti,
- Stl: compilerAttrs.stl,
- Cpp_std: compilerAttrs.cppStd,
- Export_includes: exportedIncludes.Includes,
- Export_system_includes: exportedIncludes.SystemIncludes,
- Local_includes: compilerAttrs.localIncludes,
- Absolute_includes: compilerAttrs.absoluteIncludes,
+ Use_libcrt: linkerAttrs.useLibcrt,
+ Use_version_lib: linkerAttrs.useVersionLib,
+
+ Rtti: compilerAttrs.rtti,
+ Stl: compilerAttrs.stl,
+ Cpp_std: compilerAttrs.cppStd,
+ C_std: compilerAttrs.cStd,
+
+ Export_includes: exportedIncludes.Includes,
+ Export_absolute_includes: exportedIncludes.AbsoluteIncludes,
+ Export_system_includes: exportedIncludes.SystemIncludes,
+ Local_includes: compilerAttrs.localIncludes,
+ Absolute_includes: compilerAttrs.absoluteIncludes,
Cppflags: compilerAttrs.cppFlags,
Conlyflags: compilerAttrs.conlyFlags,
@@ -2435,21 +2483,27 @@
Features: linkerAttrs.features,
}
} else {
+ commonAttrs.Dynamic_deps.Add(baseAttributes.protoDependency)
+
attrs = &bazelCcLibrarySharedAttributes{
staticOrSharedAttributes: commonAttrs,
Cppflags: compilerAttrs.cppFlags,
Conlyflags: compilerAttrs.conlyFlags,
Asflags: asFlags,
- Linkopts: linkerAttrs.linkopts,
- Link_crt: linkerAttrs.linkCrt,
- Use_libcrt: linkerAttrs.useLibcrt,
- Rtti: compilerAttrs.rtti,
- Stl: compilerAttrs.stl,
- Cpp_std: compilerAttrs.cppStd,
+ Linkopts: linkerAttrs.linkopts,
+ Link_crt: linkerAttrs.linkCrt,
+ Use_libcrt: linkerAttrs.useLibcrt,
+ Use_version_lib: linkerAttrs.useVersionLib,
+
+ Rtti: compilerAttrs.rtti,
+ Stl: compilerAttrs.stl,
+ Cpp_std: compilerAttrs.cppStd,
+ C_std: compilerAttrs.cStd,
Export_includes: exportedIncludes.Includes,
+ Export_absolute_includes: exportedIncludes.AbsoluteIncludes,
Export_system_includes: exportedIncludes.SystemIncludes,
Local_includes: compilerAttrs.localIncludes,
Absolute_includes: compilerAttrs.absoluteIncludes,
@@ -2467,6 +2521,12 @@
}
}
+ var modType string
+ if isStatic {
+ modType = "cc_library_static"
+ } else {
+ modType = "cc_library_shared"
+ }
props := bazel.BazelTargetModuleProperties{
Rule_class: modType,
Bzl_load_location: fmt.Sprintf("//build/bazel/rules:%s.bzl", modType),
@@ -2479,16 +2539,20 @@
type bazelCcLibraryStaticAttributes struct {
staticOrSharedAttributes
- Use_libcrt bazel.BoolAttribute
- Rtti bazel.BoolAttribute
- Stl *string
- Cpp_std *string
+ Use_libcrt bazel.BoolAttribute
+ Use_version_lib bazel.BoolAttribute
- Export_includes bazel.StringListAttribute
- Export_system_includes bazel.StringListAttribute
- Local_includes bazel.StringListAttribute
- Absolute_includes bazel.StringListAttribute
- Hdrs bazel.LabelListAttribute
+ Rtti bazel.BoolAttribute
+ Stl *string
+ Cpp_std *string
+ C_std *string
+
+ Export_includes bazel.StringListAttribute
+ Export_absolute_includes bazel.StringListAttribute
+ Export_system_includes bazel.StringListAttribute
+ Local_includes bazel.StringListAttribute
+ Absolute_includes bazel.StringListAttribute
+ Hdrs bazel.LabelListAttribute
Cppflags bazel.StringListAttribute
Conlyflags bazel.StringListAttribute
@@ -2497,26 +2561,27 @@
Features bazel.StringListAttribute
}
-func CcLibraryStaticBp2Build(ctx android.TopDownMutatorContext) {
- ccSharedOrStaticBp2BuildMutator(ctx, "cc_library_static")
-}
-
// TODO(b/199902614): Can this be factored to share with the other Attributes?
type bazelCcLibrarySharedAttributes struct {
staticOrSharedAttributes
- Linkopts bazel.StringListAttribute
- Link_crt bazel.BoolAttribute // Only for linking shared library (and cc_binary)
- Use_libcrt bazel.BoolAttribute
- Rtti bazel.BoolAttribute
- Stl *string
- Cpp_std *string
+ Linkopts bazel.StringListAttribute
+ Link_crt bazel.BoolAttribute // Only for linking shared library (and cc_binary)
- Export_includes bazel.StringListAttribute
- Export_system_includes bazel.StringListAttribute
- Local_includes bazel.StringListAttribute
- Absolute_includes bazel.StringListAttribute
- Hdrs bazel.LabelListAttribute
+ Use_libcrt bazel.BoolAttribute
+ Use_version_lib bazel.BoolAttribute
+
+ Rtti bazel.BoolAttribute
+ Stl *string
+ Cpp_std *string
+ C_std *string
+
+ Export_includes bazel.StringListAttribute
+ Export_absolute_includes bazel.StringListAttribute
+ Export_system_includes bazel.StringListAttribute
+ Local_includes bazel.StringListAttribute
+ Absolute_includes bazel.StringListAttribute
+ Hdrs bazel.LabelListAttribute
Strip stripAttributes
Additional_linker_inputs bazel.LabelListAttribute
@@ -2527,7 +2592,3 @@
Features bazel.StringListAttribute
}
-
-func CcLibrarySharedBp2Build(ctx android.TopDownMutatorContext) {
- ccSharedOrStaticBp2BuildMutator(ctx, "cc_library_shared")
-}
diff --git a/cc/library_headers.go b/cc/library_headers.go
index ede6ab3..064e2b8 100644
--- a/cc/library_headers.go
+++ b/cc/library_headers.go
@@ -25,7 +25,6 @@
// Register sdk member types.
android.RegisterSdkMemberType(headersLibrarySdkMemberType)
- android.RegisterBp2BuildMutator("cc_library_headers", CcLibraryHeadersBp2Build)
}
var headersLibrarySdkMemberType = &librarySdkMemberType{
@@ -96,52 +95,43 @@
module, library := NewLibrary(android.HostAndDeviceSupported)
library.HeaderOnly()
module.sdkMemberTypes = []android.SdkMemberType{headersLibrarySdkMemberType}
+ module.bazelable = true
module.bazelHandler = &libraryHeaderBazelHander{module: module, library: library}
return module.Init()
}
// cc_prebuilt_library_headers is a prebuilt version of cc_library_headers
func prebuiltLibraryHeaderFactory() android.Module {
- module, library := NewPrebuiltLibrary(android.HostAndDeviceSupported)
+ module, library := NewPrebuiltLibrary(android.HostAndDeviceSupported, "")
library.HeaderOnly()
+ module.bazelable = true
+ module.bazelHandler = &ccLibraryBazelHandler{module: module}
return module.Init()
}
type bazelCcLibraryHeadersAttributes struct {
- Hdrs bazel.LabelListAttribute
- Export_includes bazel.StringListAttribute
- Export_system_includes bazel.StringListAttribute
- Deps bazel.LabelListAttribute
- Implementation_deps bazel.LabelListAttribute
- System_dynamic_deps bazel.LabelListAttribute
+ Hdrs bazel.LabelListAttribute
+ Export_includes bazel.StringListAttribute
+ Export_absolute_includes bazel.StringListAttribute
+ Export_system_includes bazel.StringListAttribute
+ Deps bazel.LabelListAttribute
+ Implementation_deps bazel.LabelListAttribute
+ System_dynamic_deps bazel.LabelListAttribute
}
-func CcLibraryHeadersBp2Build(ctx android.TopDownMutatorContext) {
- module, ok := ctx.Module().(*Module)
- if !ok {
- // Not a cc module
- return
- }
-
- if !module.ConvertWithBp2build(ctx) {
- return
- }
-
- if ctx.ModuleType() != "cc_library_headers" {
- return
- }
-
- exportedIncludes := bp2BuildParseExportedIncludes(ctx, module)
+func libraryHeadersBp2Build(ctx android.TopDownMutatorContext, module *Module) {
baseAttributes := bp2BuildParseBaseProps(ctx, module)
+ exportedIncludes := bp2BuildParseExportedIncludes(ctx, module, baseAttributes.includes)
linkerAttrs := baseAttributes.linkerAttributes
attrs := &bazelCcLibraryHeadersAttributes{
- Export_includes: exportedIncludes.Includes,
- Export_system_includes: exportedIncludes.SystemIncludes,
- Implementation_deps: linkerAttrs.implementationDeps,
- Deps: linkerAttrs.deps,
- System_dynamic_deps: linkerAttrs.systemDynamicDeps,
- Hdrs: baseAttributes.hdrs,
+ Export_includes: exportedIncludes.Includes,
+ Export_absolute_includes: exportedIncludes.AbsoluteIncludes,
+ Export_system_includes: exportedIncludes.SystemIncludes,
+ Implementation_deps: linkerAttrs.implementationDeps,
+ Deps: linkerAttrs.deps,
+ System_dynamic_deps: linkerAttrs.systemDynamicDeps,
+ Hdrs: baseAttributes.hdrs,
}
props := bazel.BazelTargetModuleProperties{
diff --git a/cc/library_headers_test.go b/cc/library_headers_test.go
index 564ef61..3e448ba 100644
--- a/cc/library_headers_test.go
+++ b/cc/library_headers_test.go
@@ -15,48 +15,85 @@
package cc
import (
- "strings"
+ "fmt"
"testing"
+
+ "android/soong/android"
+
+ "github.com/google/blueprint"
)
func TestLibraryHeaders(t *testing.T) {
- ctx := testCc(t, `
- cc_library_headers {
- name: "headers",
- export_include_dirs: ["my_include"],
- }
- cc_library_static {
- name: "lib",
- srcs: ["foo.c"],
- header_libs: ["headers"],
- }
- `)
+ bp := `
+ %s {
+ name: "headers",
+ export_include_dirs: ["my_include"],
+ }
+ cc_library_static {
+ name: "lib",
+ srcs: ["foo.c"],
+ header_libs: ["headers"],
+ }
+ `
- // test if header search paths are correctly added
- cc := ctx.ModuleForTests("lib", "android_arm64_armv8-a_static").Rule("cc")
- cflags := cc.Args["cFlags"]
- if !strings.Contains(cflags, " -Imy_include ") {
- t.Errorf("cflags for libsystem must contain -Imy_include, but was %#v.", cflags)
+ for _, headerModule := range []string{"cc_library_headers", "cc_prebuilt_library_headers"} {
+ t.Run(headerModule, func(t *testing.T) {
+ ctx := testCc(t, fmt.Sprintf(bp, headerModule))
+
+ // test if header search paths are correctly added
+ cc := ctx.ModuleForTests("lib", "android_arm64_armv8-a_static").Rule("cc")
+ android.AssertStringDoesContain(t, "cFlags for lib module", cc.Args["cFlags"], " -Imy_include ")
+
+ // Test that there's a valid AndroidMk entry.
+ headers := ctx.ModuleForTests("headers", "android_arm64_armv8-a").Module()
+ e := android.AndroidMkEntriesForTest(t, ctx, headers)[0]
+
+ // This duplicates the tests done in AndroidMkEntries.write. It would be
+ // better to test its output, but there are no test functions that capture that.
+ android.AssertBoolEquals(t, "AndroidMkEntries.Disabled", false, e.Disabled)
+ android.AssertBoolEquals(t, "AndroidMkEntries.OutputFile.Valid()", true, e.OutputFile.Valid())
+
+ android.AssertStringListContains(t, "LOCAL_EXPORT_CFLAGS for headers module", e.EntryMap["LOCAL_EXPORT_CFLAGS"], "-Imy_include")
+ })
}
}
-func TestPrebuiltLibraryHeaders(t *testing.T) {
- ctx := testCc(t, `
- cc_prebuilt_library_headers {
- name: "headers",
- export_include_dirs: ["my_include"],
- }
- cc_library_static {
- name: "lib",
- srcs: ["foo.c"],
- header_libs: ["headers"],
- }
- `)
+func TestPrebuiltLibraryHeadersPreferred(t *testing.T) {
+ bp := `
+ cc_library_headers {
+ name: "headers",
+ export_include_dirs: ["my_include"],
+ }
+ cc_prebuilt_library_headers {
+ name: "headers",
+ prefer: %t,
+ export_include_dirs: ["my_include"],
+ }
+ cc_library_static {
+ name: "lib",
+ srcs: ["foo.c"],
+ header_libs: ["headers"],
+ }
+ `
- // test if header search paths are correctly added
- cc := ctx.ModuleForTests("lib", "android_arm64_armv8-a_static").Rule("cc")
- cflags := cc.Args["cFlags"]
- if !strings.Contains(cflags, " -Imy_include ") {
- t.Errorf("cflags for libsystem must contain -Imy_include, but was %#v.", cflags)
+ for _, prebuiltPreferred := range []bool{false, true} {
+ t.Run(fmt.Sprintf("prebuilt prefer %t", prebuiltPreferred), func(t *testing.T) {
+ ctx := testCc(t, fmt.Sprintf(bp, prebuiltPreferred))
+ lib := ctx.ModuleForTests("lib", "android_arm64_armv8-a_static")
+ sourceDep := ctx.ModuleForTests("headers", "android_arm64_armv8-a")
+ prebuiltDep := ctx.ModuleForTests("prebuilt_headers", "android_arm64_armv8-a")
+ hasSourceDep := false
+ hasPrebuiltDep := false
+ ctx.VisitDirectDeps(lib.Module(), func(dep blueprint.Module) {
+ if dep == sourceDep.Module() {
+ hasSourceDep = true
+ }
+ if dep == prebuiltDep.Module() {
+ hasPrebuiltDep = true
+ }
+ })
+ android.AssertBoolEquals(t, "depends on source headers", !prebuiltPreferred, hasSourceDep)
+ android.AssertBoolEquals(t, "depends on prebuilt headers", prebuiltPreferred, hasPrebuiltDep)
+ })
}
}
diff --git a/cc/library_test.go b/cc/library_test.go
index 7ddfaa7..d220e19 100644
--- a/cc/library_test.go
+++ b/cc/library_test.go
@@ -257,9 +257,16 @@
CcObjectFiles: []string{"foo.o"},
Includes: []string{"include"},
SystemIncludes: []string{"system_include"},
- RootStaticArchives: []string{"foo.a"},
+ Headers: []string{"foo.h"},
RootDynamicLibraries: []string{"foo.so"},
},
+ "//foo/bar:bar_bp2build_cc_library_static": cquery.CcInfo{
+ CcObjectFiles: []string{"foo.o"},
+ Includes: []string{"include"},
+ SystemIncludes: []string{"system_include"},
+ Headers: []string{"foo.h"},
+ RootStaticArchives: []string{"foo.a"},
+ },
},
}
ctx := testCcWithConfig(t, config)
@@ -273,18 +280,25 @@
expectedOutputFiles := []string{"outputbase/execroot/__main__/foo.a"}
android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings())
+ flagExporter := ctx.ModuleProvider(staticFoo, FlagExporterInfoProvider).(FlagExporterInfo)
+ android.AssertPathsRelativeToTopEquals(t, "exported include dirs", []string{"outputbase/execroot/__main__/include"}, flagExporter.IncludeDirs)
+ android.AssertPathsRelativeToTopEquals(t, "exported system include dirs", []string{"outputbase/execroot/__main__/system_include"}, flagExporter.SystemIncludeDirs)
+ android.AssertPathsRelativeToTopEquals(t, "exported headers", []string{"outputbase/execroot/__main__/foo.h"}, flagExporter.GeneratedHeaders)
+ android.AssertPathsRelativeToTopEquals(t, "deps", []string{"outputbase/execroot/__main__/foo.h"}, flagExporter.Deps)
+
sharedFoo := ctx.ModuleForTests("foo", "android_arm_armv7-a-neon_shared").Module()
outputFiles, err = sharedFoo.(android.OutputFileProducer).OutputFiles("")
if err != nil {
- t.Errorf("Unexpected error getting cc_object outputfiles %s", err)
+ t.Errorf("Unexpected error getting cc_library outputfiles %s", err)
}
expectedOutputFiles = []string{"outputbase/execroot/__main__/foo.so"}
android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings())
- entries := android.AndroidMkEntriesForTest(t, ctx, sharedFoo)[0]
- expectedFlags := []string{"-Ioutputbase/execroot/__main__/include", "-isystem outputbase/execroot/__main__/system_include"}
- gotFlags := entries.EntryMap["LOCAL_EXPORT_CFLAGS"]
- android.AssertDeepEquals(t, "androidmk exported cflags", expectedFlags, gotFlags)
+ flagExporter = ctx.ModuleProvider(sharedFoo, FlagExporterInfoProvider).(FlagExporterInfo)
+ android.AssertPathsRelativeToTopEquals(t, "exported include dirs", []string{"outputbase/execroot/__main__/include"}, flagExporter.IncludeDirs)
+ android.AssertPathsRelativeToTopEquals(t, "exported system include dirs", []string{"outputbase/execroot/__main__/system_include"}, flagExporter.SystemIncludeDirs)
+ android.AssertPathsRelativeToTopEquals(t, "exported headers", []string{"outputbase/execroot/__main__/foo.h"}, flagExporter.GeneratedHeaders)
+ android.AssertPathsRelativeToTopEquals(t, "deps", []string{"outputbase/execroot/__main__/foo.h"}, flagExporter.Deps)
}
func TestLibraryVersionScript(t *testing.T) {
diff --git a/cc/linkable.go b/cc/linkable.go
index 560c9de..02d7047 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -384,9 +384,13 @@
includes := android.PathsForBazelOut(ctx, ccInfo.Includes)
systemIncludes := android.PathsForBazelOut(ctx, ccInfo.SystemIncludes)
+ headers := android.PathsForBazelOut(ctx, ccInfo.Headers)
return FlagExporterInfo{
IncludeDirs: android.FirstUniquePaths(includes),
SystemIncludeDirs: android.FirstUniquePaths(systemIncludes),
+ GeneratedHeaders: headers,
+ // necessary to ensure generated headers are considered implicit deps of dependent actions
+ Deps: headers,
}
}
diff --git a/cc/makevars.go b/cc/makevars.go
index 8d7a163..b7aaaad 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -95,6 +95,7 @@
ctx.Strict("CLANG_EXTERNAL_CFLAGS", "${config.ExternalCflags}")
ctx.Strict("GLOBAL_CLANG_CFLAGS_NO_OVERRIDE", "${config.NoOverrideGlobalCflags}")
ctx.Strict("GLOBAL_CLANG_CPPFLAGS_NO_OVERRIDE", "")
+ ctx.Strict("GLOBAL_CLANG_EXTERNAL_CFLAGS_NO_OVERRIDE", "${config.NoOverrideExternalGlobalCflags}")
ctx.Strict("BOARD_VNDK_VERSION", ctx.DeviceConfig().VndkVersion())
ctx.Strict("RECOVERY_SNAPSHOT_VERSION", ctx.DeviceConfig().RecoverySnapshotVersion())
diff --git a/cc/ndk_sysroot.go b/cc/ndk_sysroot.go
index fd458d9..6c200f5 100644
--- a/cc/ndk_sysroot.go
+++ b/cc/ndk_sysroot.go
@@ -82,6 +82,12 @@
return android.PathForOutput(ctx, "ndk_base.timestamp")
}
+// The headers timestamp file depends only on the NDK headers.
+// This is used mainly for .tidy files that do not need any stub libraries.
+func getNdkHeadersTimestampFile(ctx android.PathContext) android.WritablePath {
+ return android.PathForOutput(ctx, "ndk_headers.timestamp")
+}
+
// The full timestamp file depends on the base timestamp *and* the static
// libraries.
func getNdkFullTimestampFile(ctx android.PathContext) android.WritablePath {
@@ -96,6 +102,7 @@
func (n *ndkSingleton) GenerateBuildActions(ctx android.SingletonContext) {
var staticLibInstallPaths android.Paths
+ var headerPaths android.Paths
var installPaths android.Paths
var licensePaths android.Paths
ctx.VisitAllModules(func(module android.Module) {
@@ -104,16 +111,19 @@
}
if m, ok := module.(*headerModule); ok {
+ headerPaths = append(headerPaths, m.installPaths...)
installPaths = append(installPaths, m.installPaths...)
licensePaths = append(licensePaths, m.licensePath)
}
if m, ok := module.(*versionedHeaderModule); ok {
+ headerPaths = append(headerPaths, m.installPaths...)
installPaths = append(installPaths, m.installPaths...)
licensePaths = append(licensePaths, m.licensePath)
}
if m, ok := module.(*preprocessedHeadersModule); ok {
+ headerPaths = append(headerPaths, m.installPaths...)
installPaths = append(installPaths, m.installPaths...)
licensePaths = append(licensePaths, m.licensePath)
}
@@ -153,6 +163,12 @@
Validation: getNdkAbiDiffTimestampFile(ctx),
})
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Touch,
+ Output: getNdkHeadersTimestampFile(ctx),
+ Implicits: headerPaths,
+ })
+
fullDepPaths := append(staticLibInstallPaths, getNdkBaseTimestampFile(ctx))
// There's a phony "ndk" rule defined in core/main.mk that depends on this.
diff --git a/cc/object.go b/cc/object.go
index 0327a45..24f6ed4 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -29,7 +29,6 @@
android.RegisterModuleType("cc_object", ObjectFactory)
android.RegisterSdkMemberType(ccObjectSdkMemberType)
- android.RegisterBp2BuildMutator("cc_object", ObjectBp2Build)
}
var ccObjectSdkMemberType = &librarySdkMemberType{
@@ -117,6 +116,7 @@
module.sdkMemberTypes = []android.SdkMemberType{ccObjectSdkMemberType}
+ module.bazelable = true
return module.Init()
}
@@ -135,19 +135,9 @@
Linker_script bazel.LabelAttribute
}
-// ObjectBp2Build is the bp2build converter from cc_object modules to the
+// objectBp2Build is the bp2build converter from cc_object modules to the
// Bazel equivalent target, plus any necessary include deps for the cc_object.
-func ObjectBp2Build(ctx android.TopDownMutatorContext) {
- m, ok := ctx.Module().(*Module)
- if !ok || !m.ConvertWithBp2build(ctx) {
- return
- }
-
- // a Module can be something other than a cc_object.
- if ctx.ModuleType() != "cc_object" {
- return
- }
-
+func objectBp2Build(ctx android.TopDownMutatorContext, m *Module) {
if m.compiler == nil {
// a cc_object must have access to the compiler decorator for its props.
ctx.ModuleErrorf("compiler must not be nil for a cc_object module")
@@ -165,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/pgo.go b/cc/pgo.go
index e78549e..cd017c4 100644
--- a/cc/pgo.go
+++ b/cc/pgo.go
@@ -96,10 +96,6 @@
flags.Local.LdFlags = append(flags.Local.LdFlags, profileInstrumentFlag)
return flags
}
-func (props *PgoProperties) addSamplingProfileGatherFlags(ctx ModuleContext, flags Flags) Flags {
- flags.Local.CFlags = append(flags.Local.CFlags, props.Pgo.Cflags...)
- return flags
-}
func (props *PgoProperties) getPgoProfileFile(ctx BaseModuleContext) android.OptionalPath {
profileFile := *props.Pgo.Profile_file
@@ -313,10 +309,6 @@
if (props.ShouldProfileModule && props.isInstrumentation()) || props.PgoInstrLink {
// Instrumentation PGO use and gather flags cannot coexist.
return props.addInstrumentationProfileGatherFlags(ctx, flags)
- } else if props.ShouldProfileModule && props.isSampling() {
- flags = props.addSamplingProfileGatherFlags(ctx, flags)
- } else if ctx.DeviceConfig().SamplingPGO() {
- flags = props.addSamplingProfileGatherFlags(ctx, flags)
}
if !ctx.Config().IsEnvTrue("ANDROID_PGO_NO_PROFILE_USE") {
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index 3401e36..feae812 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -32,8 +32,6 @@
ctx.RegisterModuleType("cc_prebuilt_test_library_shared", PrebuiltSharedTestLibraryFactory)
ctx.RegisterModuleType("cc_prebuilt_object", prebuiltObjectFactory)
ctx.RegisterModuleType("cc_prebuilt_binary", prebuiltBinaryFactory)
-
- android.RegisterBp2BuildMutator("cc_prebuilt_library_shared", PrebuiltLibrarySharedBp2Build)
}
type prebuiltLinkerInterface interface {
@@ -114,8 +112,6 @@
// TODO(ccross): verify shared library dependencies
srcs := p.prebuiltSrcs(ctx)
if len(srcs) > 0 {
- builderFlags := flagsToBuilderFlags(flags)
-
if len(srcs) > 1 {
ctx.PropertyErrorf("srcs", "multiple prebuilt source files")
return nil
@@ -152,7 +148,7 @@
// depending on a table of contents file instead of the library itself.
tocFile := android.PathForModuleOut(ctx, libName+".toc")
p.tocFile = android.OptionalPathForPath(tocFile)
- transformSharedObjectToToc(ctx, outputFile, tocFile, builderFlags)
+ TransformSharedObjectToToc(ctx, outputFile, tocFile)
if ctx.Windows() && p.properties.Windows_import_lib != nil {
// Consumers of this library actually links to the import library in build
@@ -199,7 +195,13 @@
if p.header() {
ctx.SetProvider(HeaderLibraryInfoProvider, HeaderLibraryInfo{})
- return nil
+ // Need to return an output path so that the AndroidMk logic doesn't skip
+ // the prebuilt header. For compatibility, in case Android.mk files use a
+ // header lib in LOCAL_STATIC_LIBRARIES, create an empty ar file as
+ // placeholder, just like non-prebuilt header modules do in linkStatic().
+ ph := android.PathForModuleOut(ctx, ctx.ModuleName()+staticLibraryExtension)
+ transformObjToStaticLib(ctx, nil, nil, builderFlags{}, ph, nil, nil)
+ return ph
}
return nil
@@ -237,7 +239,7 @@
return android.RemoveOptionalPrebuiltPrefix(name)
}
-func NewPrebuiltLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator) {
+func NewPrebuiltLibrary(hod android.HostOrDeviceSupported, srcsProperty string) (*Module, *libraryDecorator) {
module, library := NewLibrary(hod)
module.compiler = nil
@@ -249,11 +251,15 @@
module.AddProperties(&prebuilt.properties)
- srcsSupplier := func(ctx android.BaseModuleContext, _ android.Module) []string {
- return prebuilt.prebuiltSrcs(ctx)
- }
+ if srcsProperty == "" {
+ android.InitPrebuiltModuleWithoutSrcs(module)
+ } else {
+ srcsSupplier := func(ctx android.BaseModuleContext, _ android.Module) []string {
+ return prebuilt.prebuiltSrcs(ctx)
+ }
- android.InitPrebuiltModuleWithSrcSupplier(module, srcsSupplier, "srcs")
+ android.InitPrebuiltModuleWithSrcSupplier(module, srcsSupplier, srcsProperty)
+ }
// Prebuilt libraries can be used in SDKs.
android.InitSdkAwareModule(module)
@@ -263,7 +269,7 @@
// cc_prebuilt_library installs a precompiled shared library that are
// listed in the srcs property in the device's directory.
func PrebuiltLibraryFactory() android.Module {
- module, _ := NewPrebuiltLibrary(android.HostAndDeviceSupported)
+ module, _ := NewPrebuiltLibrary(android.HostAndDeviceSupported, "srcs")
// Prebuilt shared libraries can be included in APEXes
android.InitApexModule(module)
@@ -282,15 +288,16 @@
// to be used as a data dependency of a test-related module (such as cc_test, or
// cc_test_library).
func PrebuiltSharedTestLibraryFactory() android.Module {
- module, library := NewPrebuiltLibrary(android.HostAndDeviceSupported)
+ module, library := NewPrebuiltLibrary(android.HostAndDeviceSupported, "srcs")
library.BuildOnlyShared()
library.baseInstaller = NewTestInstaller()
return module.Init()
}
func NewPrebuiltSharedLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator) {
- module, library := NewPrebuiltLibrary(hod)
+ module, library := NewPrebuiltLibrary(hod, "srcs")
library.BuildOnlyShared()
+ module.bazelable = true
// Prebuilt shared libraries can be included in APEXes
android.InitApexModule(module)
@@ -306,33 +313,43 @@
}
func NewPrebuiltStaticLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator) {
- module, library := NewPrebuiltLibrary(hod)
+ module, library := NewPrebuiltLibrary(hod, "srcs")
library.BuildOnlyStatic()
+ module.bazelable = true
module.bazelHandler = &prebuiltStaticLibraryBazelHandler{module: module, library: library}
return module, library
}
+type bazelPrebuiltLibraryStaticAttributes struct {
+ Static_library bazel.LabelAttribute
+ Export_includes bazel.StringListAttribute
+ Export_system_includes bazel.StringListAttribute
+}
+
+func prebuiltLibraryStaticBp2Build(ctx android.TopDownMutatorContext, module *Module) {
+ prebuiltAttrs := Bp2BuildParsePrebuiltLibraryProps(ctx, module)
+ exportedIncludes := Bp2BuildParseExportedIncludesForPrebuiltLibrary(ctx, module)
+
+ attrs := &bazelPrebuiltLibraryStaticAttributes{
+ Static_library: prebuiltAttrs.Src,
+ Export_includes: exportedIncludes.Includes,
+ Export_system_includes: exportedIncludes.SystemIncludes,
+ }
+
+ props := bazel.BazelTargetModuleProperties{
+ Rule_class: "prebuilt_library_static",
+ Bzl_load_location: "//build/bazel/rules:prebuilt_library_static.bzl",
+ }
+
+ name := android.RemoveOptionalPrebuiltPrefix(module.Name())
+ ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: name}, attrs)
+}
+
type bazelPrebuiltLibrarySharedAttributes struct {
Shared_library bazel.LabelAttribute
}
-func PrebuiltLibrarySharedBp2Build(ctx android.TopDownMutatorContext) {
- module, ok := ctx.Module().(*Module)
- if !ok {
- // Not a cc module
- return
- }
- if !module.ConvertWithBp2build(ctx) {
- return
- }
- if ctx.ModuleType() != "cc_prebuilt_library_shared" {
- return
- }
-
- prebuiltLibrarySharedBp2BuildInternal(ctx, module)
-}
-
-func prebuiltLibrarySharedBp2BuildInternal(ctx android.TopDownMutatorContext, module *Module) {
+func prebuiltLibrarySharedBp2Build(ctx android.TopDownMutatorContext, module *Module) {
prebuiltAttrs := Bp2BuildParsePrebuiltLibraryProps(ctx, module)
attrs := &bazelPrebuiltLibrarySharedAttributes{
@@ -535,7 +552,7 @@
}
func NewPrebuiltBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecorator) {
- module, binary := NewBinary(hod)
+ module, binary := newBinary(hod, false)
module.compiler = nil
prebuilt := &prebuiltBinaryLinker{
diff --git a/cc/proto.go b/cc/proto.go
index 4466144..f3410bc 100644
--- a/cc/proto.go
+++ b/cc/proto.go
@@ -16,8 +16,14 @@
import (
"github.com/google/blueprint/pathtools"
+ "github.com/google/blueprint/proptools"
"android/soong/android"
+ "android/soong/bazel"
+)
+
+const (
+ protoTypeDefault = "lite"
)
// genProto creates a rule to convert a .proto file to generated .pb.cc and .pb.h files and returns
@@ -63,7 +69,7 @@
var lib string
if String(p.Proto.Plugin) == "" {
- switch String(p.Proto.Type) {
+ switch proptools.StringDefault(p.Proto.Type, protoTypeDefault) {
case "full":
if ctx.useSdk() {
lib = "libprotobuf-cpp-full-ndk"
@@ -71,7 +77,7 @@
} else {
lib = "libprotobuf-cpp-full"
}
- case "lite", "":
+ case "lite":
if ctx.useSdk() {
lib = "libprotobuf-cpp-lite-ndk"
static = true
@@ -157,3 +163,69 @@
return flags
}
+
+type protoAttributes struct {
+ Deps bazel.LabelListAttribute
+}
+
+type bp2buildProtoDeps struct {
+ wholeStaticLib *bazel.LabelAttribute
+ implementationWholeStaticLib *bazel.LabelAttribute
+ protoDep *bazel.LabelAttribute
+}
+
+func bp2buildProto(ctx android.Bp2buildMutatorContext, m *Module, protoSrcs bazel.LabelListAttribute) bp2buildProtoDeps {
+ var ret bp2buildProtoDeps
+
+ protoInfo, ok := android.Bp2buildProtoProperties(ctx, m, protoSrcs)
+ if !ok {
+ return ret
+ }
+
+ var depName string
+ typ := proptools.StringDefault(protoInfo.Type, protoTypeDefault)
+ var rule_class string
+ suffix := "_cc_proto"
+ switch typ {
+ case "lite":
+ suffix += "_lite"
+ rule_class = "cc_lite_proto_library"
+ depName = "libprotobuf-cpp-lite"
+ case "full":
+ rule_class = "cc_proto_library"
+ depName = "libprotobuf-cpp-full"
+ default:
+ ctx.PropertyErrorf("proto.type", "cannot handle conversion at this time: %q", typ)
+ }
+
+ dep := android.BazelLabelForModuleDepSingle(ctx, depName)
+ ret.protoDep = &bazel.LabelAttribute{Value: &dep}
+
+ protoLabel := bazel.Label{Label: ":" + protoInfo.Name}
+ var protoAttrs protoAttributes
+ protoAttrs.Deps.SetValue(bazel.LabelList{Includes: []bazel.Label{protoLabel}})
+
+ name := m.Name() + suffix
+
+ ctx.CreateBazelTargetModule(
+ bazel.BazelTargetModuleProperties{
+ Rule_class: rule_class,
+ Bzl_load_location: "//build/bazel/rules:cc_proto.bzl",
+ },
+ android.CommonAttributes{Name: name},
+ &protoAttrs)
+
+ var privateHdrs bool
+ if lib, ok := m.linker.(*libraryDecorator); ok {
+ privateHdrs = !proptools.Bool(lib.Properties.Proto.Export_proto_headers)
+ }
+
+ labelAttr := &bazel.LabelAttribute{Value: &bazel.Label{Label: ":" + name}}
+ if privateHdrs {
+ ret.implementationWholeStaticLib = labelAttr
+ } else {
+ ret.wholeStaticLib = labelAttr
+ }
+
+ return ret
+}
diff --git a/cc/sanitize.go b/cc/sanitize.go
index f6a9d5b..6c68822 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -35,12 +35,18 @@
asanCflags = []string{
"-fno-omit-frame-pointer",
- "-fno-experimental-new-pass-manager",
}
asanLdflags = []string{"-Wl,-u,__asan_preinit"}
- hwasanCflags = []string{"-fno-omit-frame-pointer", "-Wno-frame-larger-than=",
+ hwasanCflags = []string{
+ "-fno-omit-frame-pointer",
+ "-Wno-frame-larger-than=",
"-fsanitize-hwaddress-abi=platform",
+ }
+
+ // ThinLTO performs codegen during link time, thus these flags need to
+ // passed to both CFLAGS and LDFLAGS.
+ hwasanCommonflags = []string{
// The following improves debug location information
// availability at the cost of its accuracy. It increases
// the likelihood of a stack variable's frame offset
@@ -48,11 +54,11 @@
// for the quality of hwasan reports. The downside is a
// higher number of "optimized out" stack variables.
// b/112437883.
- "-mllvm", "-instcombine-lower-dbg-declare=0",
+ "-instcombine-lower-dbg-declare=0",
// TODO(b/159343917): HWASan and GlobalISel don't play nicely, and
// GlobalISel is the default at -O0 on aarch64.
- "-mllvm", "--aarch64-enable-global-isel-at-O=-1",
- "-mllvm", "-fast-isel=false",
+ "--aarch64-enable-global-isel-at-O=-1",
+ "-fast-isel=false",
}
cfiCflags = []string{"-flto", "-fsanitize-cfi-cross-dso",
@@ -81,7 +87,7 @@
intOverflow
scs
Fuzzer
- memtag_heap
+ Memtag_heap
cfi // cfi is last to prevent it running before incompatible mutators
)
@@ -92,7 +98,7 @@
intOverflow,
scs,
Fuzzer,
- memtag_heap,
+ Memtag_heap,
cfi, // cfi is last to prevent it running before incompatible mutators
}
@@ -111,7 +117,7 @@
return "cfi"
case scs:
return "scs"
- case memtag_heap:
+ case Memtag_heap:
return "memtag_heap"
case Fuzzer:
return "fuzzer"
@@ -127,7 +133,7 @@
return "address"
case Hwasan:
return "hwaddress"
- case memtag_heap:
+ case Memtag_heap:
return "memtag_heap"
case tsan:
return "thread"
@@ -149,7 +155,7 @@
case Asan, Hwasan, Fuzzer, scs, tsan, cfi:
ctx.TopDown(t.variationName()+"_deps", sanitizerDepsMutator(t))
ctx.BottomUp(t.variationName(), sanitizerMutator(t))
- case memtag_heap, intOverflow:
+ case Memtag_heap, intOverflow:
// do nothing
default:
panic(fmt.Errorf("unknown SanitizerType %d", t))
@@ -172,6 +178,8 @@
return true
case Fuzzer:
return true
+ case Memtag_heap:
+ return true
default:
return false
}
@@ -460,7 +468,7 @@
s.Scs = nil
}
- // memtag_heap is only implemented on AArch64.
+ // Memtag_heap is only implemented on AArch64.
if ctx.Arch().ArchType != android.Arm64 {
s.Memtag_heap = nil
}
@@ -531,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
@@ -629,6 +632,14 @@
if Bool(sanitize.Properties.Sanitize.Hwaddress) {
flags.Local.CFlags = append(flags.Local.CFlags, hwasanCflags...)
+
+ for _, flag := range hwasanCommonflags {
+ flags.Local.CFlags = append(flags.Local.CFlags, "-mllvm", flag)
+ }
+ for _, flag := range hwasanCommonflags {
+ flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-mllvm,"+flag)
+ }
+
if Bool(sanitize.Properties.Sanitize.Writeonly) {
flags.Local.CFlags = append(flags.Local.CFlags, "-mllvm", "-hwasan-instrument-reads=0")
}
@@ -649,9 +660,6 @@
flags.Local.LdFlags = append(flags.Local.LdFlags, "-fno-sanitize-coverage=stack-depth")
flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize-coverage=stack-depth")
- // TODO(b/133876586): Experimental PM breaks sanitizer coverage.
- flags.Local.CFlags = append(flags.Local.CFlags, "-fno-experimental-new-pass-manager")
-
// Disable fortify for fuzzing builds. Generally, we'll be building with
// UBSan or ASan here and the fortify checks pollute the stack traces.
flags.Local.CFlags = append(flags.Local.CFlags, "-U_FORTIFY_SOURCE")
@@ -798,7 +806,7 @@
return sanitize.Properties.Sanitize.Cfi
case scs:
return sanitize.Properties.Sanitize.Scs
- case memtag_heap:
+ case Memtag_heap:
return sanitize.Properties.Sanitize.Memtag_heap
case Fuzzer:
return sanitize.Properties.Sanitize.Fuzzer
@@ -814,7 +822,7 @@
!sanitize.isSanitizerEnabled(tsan) &&
!sanitize.isSanitizerEnabled(cfi) &&
!sanitize.isSanitizerEnabled(scs) &&
- !sanitize.isSanitizerEnabled(memtag_heap) &&
+ !sanitize.isSanitizerEnabled(Memtag_heap) &&
!sanitize.isSanitizerEnabled(Fuzzer)
}
@@ -844,7 +852,7 @@
sanitize.Properties.Sanitize.Cfi = bPtr
case scs:
sanitize.Properties.Sanitize.Scs = bPtr
- case memtag_heap:
+ case Memtag_heap:
sanitize.Properties.Sanitize.Memtag_heap = bPtr
case Fuzzer:
sanitize.Properties.Sanitize.Fuzzer = bPtr
@@ -1133,7 +1141,7 @@
if lib, ok := snapshot.StaticLibs[noteDep]; ok {
noteDep = lib
}
- depTag := libraryDependencyTag{Kind: staticLibraryDependency, wholeStatic: true}
+ depTag := StaticDepTag(true)
variations := append(mctx.Target().Variations(),
blueprint.Variation{Mutator: "link", Variation: "static"})
if c.Device() {
@@ -1303,6 +1311,10 @@
func sanitizerMutator(t SanitizerType) func(android.BottomUpMutatorContext) {
return func(mctx android.BottomUpMutatorContext) {
if c, ok := mctx.Module().(PlatformSanitizeable); ok && c.SanitizePropDefined() {
+
+ // Make sure we're not setting CFI to any value if it's not supported.
+ cfiSupported := mctx.Module().(PlatformSanitizeable).SanitizerSupported(cfi)
+
if c.Binary() && c.IsSanitizerEnabled(t) {
modules := mctx.CreateVariations(t.variationName())
modules[0].(PlatformSanitizeable).SetSanitizer(t, true)
@@ -1323,7 +1335,6 @@
// is redirected to the sanitized variant of the dependent module.
defaultVariation := t.variationName()
// Not all PlatformSanitizeable modules support the CFI sanitizer
- cfiSupported := mctx.Module().(PlatformSanitizeable).SanitizerSupported(cfi)
mctx.SetDefaultDependencyVariation(&defaultVariation)
modules := mctx.CreateVariations("", t.variationName())
@@ -1370,7 +1381,7 @@
modules[0].(PlatformSanitizeable).SetInSanitizerDir()
}
- if mctx.Device() && t.incompatibleWithCfi() {
+ if mctx.Device() && t.incompatibleWithCfi() && cfiSupported {
// TODO: Make sure that cfi mutator runs "after" any of the sanitizers that
// are incompatible with cfi
modules[0].(PlatformSanitizeable).SetSanitizer(cfi, false)
diff --git a/cc/snapshot_prebuilt.go b/cc/snapshot_prebuilt.go
index 9570664..253a11b 100644
--- a/cc/snapshot_prebuilt.go
+++ b/cc/snapshot_prebuilt.go
@@ -66,7 +66,7 @@
// Override existing vendor and recovery snapshot for cc module specific extra functions
var VendorSnapshotImageSingleton vendorSnapshotImage = vendorSnapshotImage{&snapshot.VendorSnapshotImageSingleton}
-var recoverySnapshotImageSingleton recoverySnapshotImage = recoverySnapshotImage{&snapshot.RecoverySnapshotImageSingleton}
+var RecoverySnapshotImageSingleton recoverySnapshotImage = recoverySnapshotImage{&snapshot.RecoverySnapshotImageSingleton}
func RegisterVendorSnapshotModules(ctx android.RegistrationContext) {
ctx.RegisterModuleType("vendor_snapshot", vendorSnapshotFactory)
@@ -231,7 +231,7 @@
}
func recoverySnapshotFactory() android.Module {
- return snapshotFactory(recoverySnapshotImageSingleton)
+ return snapshotFactory(RecoverySnapshotImageSingleton)
}
func snapshotFactory(image SnapshotImage) android.Module {
@@ -326,7 +326,7 @@
return
}
- images := []SnapshotImage{VendorSnapshotImageSingleton, recoverySnapshotImageSingleton}
+ images := []SnapshotImage{VendorSnapshotImageSingleton, RecoverySnapshotImageSingleton}
for _, image := range images {
if p.Image == image {
@@ -476,13 +476,12 @@
if p.shared() {
libName := in.Base()
- builderFlags := flagsToBuilderFlags(flags)
// Optimize out relinking against shared libraries whose interface hasn't changed by
// depending on a table of contents file instead of the library itself.
tocFile := android.PathForModuleOut(ctx, libName+".toc")
p.tocFile = android.OptionalPathForPath(tocFile)
- transformSharedObjectToToc(ctx, in, tocFile, builderFlags)
+ TransformSharedObjectToToc(ctx, in, tocFile)
ctx.SetProvider(SharedLibraryInfoProvider, SharedLibraryInfo{
SharedLibrary: in,
@@ -584,7 +583,7 @@
// overrides the recovery variant of the cc shared library with the same name, if BOARD_VNDK_VERSION
// is set.
func RecoverySnapshotSharedFactory() android.Module {
- module, prebuilt := snapshotLibraryFactory(recoverySnapshotImageSingleton, SnapshotSharedSuffix)
+ module, prebuilt := snapshotLibraryFactory(RecoverySnapshotImageSingleton, SnapshotSharedSuffix)
prebuilt.libraryDecorator.BuildOnlyShared()
return module.Init()
}
@@ -604,7 +603,7 @@
// overrides the recovery variant of the cc static library with the same name, if BOARD_VNDK_VERSION
// is set.
func RecoverySnapshotStaticFactory() android.Module {
- module, prebuilt := snapshotLibraryFactory(recoverySnapshotImageSingleton, SnapshotStaticSuffix)
+ module, prebuilt := snapshotLibraryFactory(RecoverySnapshotImageSingleton, SnapshotStaticSuffix)
prebuilt.libraryDecorator.BuildOnlyStatic()
return module.Init()
}
@@ -624,7 +623,7 @@
// overrides the recovery variant of the cc header library with the same name, if BOARD_VNDK_VERSION
// is set.
func RecoverySnapshotHeaderFactory() android.Module {
- module, prebuilt := snapshotLibraryFactory(recoverySnapshotImageSingleton, snapshotHeaderSuffix)
+ module, prebuilt := snapshotLibraryFactory(RecoverySnapshotImageSingleton, snapshotHeaderSuffix)
prebuilt.libraryDecorator.HeaderOnly()
return module.Init()
}
@@ -699,7 +698,7 @@
// development/vendor_snapshot/update.py. As a part of recovery snapshot, recovery_snapshot_binary
// overrides the recovery variant of the cc binary with the same name, if BOARD_VNDK_VERSION is set.
func RecoverySnapshotBinaryFactory() android.Module {
- return snapshotBinaryFactory(recoverySnapshotImageSingleton, snapshotBinarySuffix)
+ return snapshotBinaryFactory(RecoverySnapshotImageSingleton, snapshotBinarySuffix)
}
func snapshotBinaryFactory(image SnapshotImage, moduleSuffix string) android.Module {
@@ -801,7 +800,7 @@
}
module.linker = prebuilt
- prebuilt.Init(module, recoverySnapshotImageSingleton, snapshotObjectSuffix)
+ prebuilt.Init(module, RecoverySnapshotImageSingleton, snapshotObjectSuffix)
module.AddProperties(&prebuilt.properties)
return module.Init()
}
diff --git a/cc/snapshot_utils.go b/cc/snapshot_utils.go
index 24abcce..de50ef5 100644
--- a/cc/snapshot_utils.go
+++ b/cc/snapshot_utils.go
@@ -113,7 +113,7 @@
return ctx.Config().VndkSnapshotBuildArtifacts()
}
- for _, image := range []SnapshotImage{VendorSnapshotImageSingleton, recoverySnapshotImageSingleton} {
+ for _, image := range []SnapshotImage{VendorSnapshotImageSingleton, RecoverySnapshotImageSingleton} {
if isSnapshotAware(ctx.DeviceConfig(), m, image.IsProprietaryPath(ctx.ModuleDir(), ctx.DeviceConfig()), apexInfo, image) {
return true
}
diff --git a/cc/test.go b/cc/test.go
index c589165..d8b7833 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -105,11 +105,6 @@
// Add RunCommandTargetPreparer to stop framework before the test and start it after the test.
Disable_framework *bool
- // Add ShippingApiLevelModuleController to auto generated test config. If the device properties
- // for the shipping api level is less than the test_min_api_level, skip this module.
- // Deprecated (b/187258404). Use test_options.min_shipping_api_level instead.
- Test_min_api_level *int64
-
// Flag to indicate whether or not to create test config automatically. If AndroidTest.xml
// doesn't exist next to the Android.bp, this attribute doesn't need to be set to true
// explicitly.
@@ -378,31 +373,26 @@
ctx.VisitDirectDepsWithTag(dataLibDepTag, func(dep android.Module) {
depName := ctx.OtherModuleName(dep)
- ccDep, ok := dep.(LinkableInterface)
-
+ linkableDep, ok := dep.(LinkableInterface)
if !ok {
- ctx.ModuleErrorf("data_lib %q is not a linkable cc module", depName)
+ ctx.ModuleErrorf("data_lib %q is not a LinkableInterface module", depName)
}
- ccModule, ok := dep.(*Module)
- if !ok {
- ctx.ModuleErrorf("data_lib %q is not a cc module", depName)
- }
- if ccDep.OutputFile().Valid() {
+ if linkableDep.OutputFile().Valid() {
test.data = append(test.data,
- android.DataPath{SrcPath: ccDep.OutputFile().Path(),
- RelativeInstallPath: ccModule.installer.relativeInstallPath()})
+ android.DataPath{SrcPath: linkableDep.OutputFile().Path(),
+ RelativeInstallPath: linkableDep.RelativeInstallPath()})
}
})
ctx.VisitDirectDepsWithTag(dataBinDepTag, func(dep android.Module) {
depName := ctx.OtherModuleName(dep)
- ccModule, ok := dep.(*Module)
+ linkableDep, ok := dep.(LinkableInterface)
if !ok {
- ctx.ModuleErrorf("data_bin %q is not a cc module", depName)
+ ctx.ModuleErrorf("data_bin %q is not a LinkableInterface module", depName)
}
- if ccModule.OutputFile().Valid() {
+ if linkableDep.OutputFile().Valid() {
test.data = append(test.data,
- android.DataPath{SrcPath: ccModule.OutputFile().Path(),
- RelativeInstallPath: ccModule.installer.relativeInstallPath()})
+ android.DataPath{SrcPath: linkableDep.OutputFile().Path(),
+ RelativeInstallPath: linkableDep.RelativeInstallPath()})
}
})
@@ -437,14 +427,6 @@
var options []tradefed.Option
options = append(options, tradefed.Option{Name: "min-api-level", Value: strconv.FormatInt(int64(*test.Properties.Test_options.Min_shipping_api_level), 10)})
configs = append(configs, tradefed.Object{"module_controller", "com.android.tradefed.testtype.suite.module.ShippingApiLevelModuleController", options})
- } else if test.Properties.Test_min_api_level != nil {
- // TODO: (b/187258404) Remove test.Properties.Test_min_api_level
- if test.Properties.Test_options.Vsr_min_shipping_api_level != nil {
- ctx.PropertyErrorf("test_min_api_level", "must not be set at the same time as 'vsr_min_shipping_api_level'.")
- }
- var options []tradefed.Option
- options = append(options, tradefed.Option{Name: "min-api-level", Value: strconv.FormatInt(int64(*test.Properties.Test_min_api_level), 10)})
- configs = append(configs, tradefed.Object{"module_controller", "com.android.tradefed.testtype.suite.module.ShippingApiLevelModuleController", options})
}
if test.Properties.Test_options.Vsr_min_shipping_api_level != nil {
var options []tradefed.Option
@@ -479,7 +461,7 @@
}
func NewTest(hod android.HostOrDeviceSupported) *Module {
- module, binary := NewBinary(hod)
+ module, binary := newBinary(hod, false)
module.multilib = android.MultilibBoth
binary.baseInstaller = NewTestInstaller()
@@ -569,6 +551,10 @@
testConfig android.Path
}
+func (benchmark *benchmarkDecorator) benchmarkBinary() bool {
+ return true
+}
+
func (benchmark *benchmarkDecorator) linkerInit(ctx BaseModuleContext) {
runpath := "../../lib"
if ctx.toolchain().Is64Bit() {
@@ -606,7 +592,7 @@
}
func NewBenchmark(hod android.HostOrDeviceSupported) *Module {
- module, binary := NewBinary(hod)
+ module, binary := newBinary(hod, false)
module.multilib = android.MultilibBoth
binary.baseInstaller = NewBaseInstaller("benchmarktest", "benchmarktest64", InstallInData)
diff --git a/cc/testing.go b/cc/testing.go
index b0a220c..3bf936d 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -763,3 +763,11 @@
}
return paths
}
+
+func AssertExcludeFromRecoverySnapshotIs(t *testing.T, ctx *android.TestContext, name string, expected bool, variant string) {
+ t.Helper()
+ m := ctx.ModuleForTests(name, variant).Module().(LinkableInterface)
+ if m.ExcludeFromRecoverySnapshot() != expected {
+ t.Errorf("expected %q ExcludeFromRecoverySnapshot to be %t", m.String(), expected)
+ }
+}
diff --git a/cc/tidy.go b/cc/tidy.go
index 53ff156..78a791f 100644
--- a/cc/tidy.go
+++ b/cc/tidy.go
@@ -15,6 +15,7 @@
package cc
import (
+ "path/filepath"
"regexp"
"strings"
@@ -183,3 +184,154 @@
}
return flags
}
+
+func init() {
+ android.RegisterSingletonType("tidy_phony_targets", TidyPhonySingleton)
+}
+
+// This TidyPhonySingleton generates both tidy-* and obj-* phony targets for C/C++ files.
+func TidyPhonySingleton() android.Singleton {
+ return &tidyPhonySingleton{}
+}
+
+type tidyPhonySingleton struct{}
+
+// Given a final module, add its tidy/obj phony targets to tidy/objModulesInDirGroup.
+func collectTidyObjModuleTargets(ctx android.SingletonContext, module android.Module,
+ tidyModulesInDirGroup, objModulesInDirGroup map[string]map[string]android.Paths) {
+ allObjFileGroups := make(map[string]android.Paths) // variant group name => obj file Paths
+ allTidyFileGroups := make(map[string]android.Paths) // variant group name => tidy file Paths
+ subsetObjFileGroups := make(map[string]android.Paths) // subset group name => obj file Paths
+ subsetTidyFileGroups := make(map[string]android.Paths) // subset group name => tidy file Paths
+
+ // (1) Collect all obj/tidy files into OS-specific groups.
+ ctx.VisitAllModuleVariants(module, func(variant android.Module) {
+ if ctx.Config().KatiEnabled() && android.ShouldSkipAndroidMkProcessing(variant) {
+ return
+ }
+ if m, ok := variant.(*Module); ok {
+ osName := variant.Target().Os.Name
+ addToOSGroup(osName, m.objFiles, allObjFileGroups, subsetObjFileGroups)
+ addToOSGroup(osName, m.tidyFiles, allTidyFileGroups, subsetTidyFileGroups)
+ }
+ })
+
+ // (2) Add an all-OS group, with "" or "subset" name, to include all os-specific phony targets.
+ addAllOSGroup(ctx, module, allObjFileGroups, "", "obj")
+ addAllOSGroup(ctx, module, allTidyFileGroups, "", "tidy")
+ addAllOSGroup(ctx, module, subsetObjFileGroups, "subset", "obj")
+ addAllOSGroup(ctx, module, subsetTidyFileGroups, "subset", "tidy")
+
+ tidyTargetGroups := make(map[string]android.Path)
+ objTargetGroups := make(map[string]android.Path)
+ genObjTidyPhonyTargets(ctx, module, "obj", allObjFileGroups, objTargetGroups)
+ genObjTidyPhonyTargets(ctx, module, "obj", subsetObjFileGroups, objTargetGroups)
+ genObjTidyPhonyTargets(ctx, module, "tidy", allTidyFileGroups, tidyTargetGroups)
+ genObjTidyPhonyTargets(ctx, module, "tidy", subsetTidyFileGroups, tidyTargetGroups)
+
+ moduleDir := ctx.ModuleDir(module)
+ appendToModulesInDirGroup(tidyTargetGroups, moduleDir, tidyModulesInDirGroup)
+ appendToModulesInDirGroup(objTargetGroups, moduleDir, objModulesInDirGroup)
+}
+
+func (m *tidyPhonySingleton) GenerateBuildActions(ctx android.SingletonContext) {
+ // For tidy-* directory phony targets, there are different variant groups.
+ // tidyModulesInDirGroup[G][D] is for group G, directory D, with Paths
+ // of all phony targets to be included into direct dependents of tidy-D_G.
+ tidyModulesInDirGroup := make(map[string]map[string]android.Paths)
+ // Also for obj-* directory phony targets.
+ objModulesInDirGroup := make(map[string]map[string]android.Paths)
+
+ // Collect tidy/obj targets from the 'final' modules.
+ ctx.VisitAllModules(func(module android.Module) {
+ if module == ctx.FinalModule(module) {
+ collectTidyObjModuleTargets(ctx, module, tidyModulesInDirGroup, objModulesInDirGroup)
+ }
+ })
+
+ suffix := ""
+ if ctx.Config().KatiEnabled() {
+ suffix = "-soong"
+ }
+ generateObjTidyPhonyTargets(ctx, suffix, "obj", objModulesInDirGroup)
+ generateObjTidyPhonyTargets(ctx, suffix, "tidy", tidyModulesInDirGroup)
+}
+
+// The name for an obj/tidy module variant group phony target is Name_group-obj/tidy,
+func objTidyModuleGroupName(module android.Module, group string, suffix string) string {
+ if group == "" {
+ return module.Name() + "-" + suffix
+ }
+ return module.Name() + "_" + group + "-" + suffix
+}
+
+// Generate obj-* or tidy-* phony targets.
+func generateObjTidyPhonyTargets(ctx android.SingletonContext, suffix string, prefix string, objTidyModulesInDirGroup map[string]map[string]android.Paths) {
+ // For each variant group, create a <prefix>-<directory>_group target that
+ // depends on all subdirectories and modules in the directory.
+ for group, modulesInDir := range objTidyModulesInDirGroup {
+ groupSuffix := ""
+ if group != "" {
+ groupSuffix = "_" + group
+ }
+ mmTarget := func(dir string) string {
+ return prefix + "-" + strings.Replace(filepath.Clean(dir), "/", "-", -1) + groupSuffix
+ }
+ dirs, topDirs := android.AddAncestors(ctx, modulesInDir, mmTarget)
+ // Create a <prefix>-soong_group target that depends on all <prefix>-dir_group of top level dirs.
+ var topDirPaths android.Paths
+ for _, dir := range topDirs {
+ topDirPaths = append(topDirPaths, android.PathForPhony(ctx, mmTarget(dir)))
+ }
+ ctx.Phony(prefix+suffix+groupSuffix, topDirPaths...)
+ // Create a <prefix>-dir_group target that depends on all targets in modulesInDir[dir]
+ for _, dir := range dirs {
+ if dir != "." && dir != "" {
+ ctx.Phony(mmTarget(dir), modulesInDir[dir]...)
+ }
+ }
+ }
+}
+
+// Append (obj|tidy)TargetGroups[group] into (obj|tidy)ModulesInDirGroups[group][moduleDir].
+func appendToModulesInDirGroup(targetGroups map[string]android.Path, moduleDir string, modulesInDirGroup map[string]map[string]android.Paths) {
+ for group, phonyPath := range targetGroups {
+ if _, found := modulesInDirGroup[group]; !found {
+ modulesInDirGroup[group] = make(map[string]android.Paths)
+ }
+ modulesInDirGroup[group][moduleDir] = append(modulesInDirGroup[group][moduleDir], phonyPath)
+ }
+}
+
+// Add given files to the OS group and subset group.
+func addToOSGroup(osName string, files android.Paths, allGroups, subsetGroups map[string]android.Paths) {
+ if len(files) > 0 {
+ subsetName := osName + "_subset"
+ allGroups[osName] = append(allGroups[osName], files...)
+ // Now include only the first variant in the subsetGroups.
+ // If clang and clang-tidy get faster, we might include more variants.
+ if _, found := subsetGroups[subsetName]; !found {
+ subsetGroups[subsetName] = files
+ }
+ }
+}
+
+// Add an all-OS group, with groupName, to include all os-specific phony targets.
+func addAllOSGroup(ctx android.SingletonContext, module android.Module, phonyTargetGroups map[string]android.Paths, groupName string, objTidyName string) {
+ if len(phonyTargetGroups) > 0 {
+ var targets android.Paths
+ for group, _ := range phonyTargetGroups {
+ targets = append(targets, android.PathForPhony(ctx, objTidyModuleGroupName(module, group, objTidyName)))
+ }
+ phonyTargetGroups[groupName] = targets
+ }
+}
+
+// Create one phony targets for each group and add them to the targetGroups.
+func genObjTidyPhonyTargets(ctx android.SingletonContext, module android.Module, objTidyName string, fileGroups map[string]android.Paths, targetGroups map[string]android.Path) {
+ for group, files := range fileGroups {
+ groupName := objTidyModuleGroupName(module, group, objTidyName)
+ ctx.Phony(groupName, files...)
+ targetGroups[group] = android.PathForPhony(ctx, groupName)
+ }
+}
diff --git a/cc/vendor_snapshot_test.go b/cc/vendor_snapshot_test.go
index ca2f569..b5022c8 100644
--- a/cc/vendor_snapshot_test.go
+++ b/cc/vendor_snapshot_test.go
@@ -1020,14 +1020,6 @@
assertString(t, staticCfiModule.outputFile.Path().Base(), "libsnapshot.cfi.a")
}
-func assertExcludeFromRecoverySnapshotIs(t *testing.T, ctx *android.TestContext, name string, expected bool) {
- t.Helper()
- m := ctx.ModuleForTests(name, recoveryVariant).Module().(*Module)
- if m.ExcludeFromRecoverySnapshot() != expected {
- t.Errorf("expected %q ExcludeFromRecoverySnapshot to be %t", m.String(), expected)
- }
-}
-
func TestVendorSnapshotExclude(t *testing.T) {
// This test verifies that the exclude_from_vendor_snapshot property
@@ -1371,13 +1363,13 @@
android.FailIfErrored(t, errs)
// Test an include and exclude framework module.
- assertExcludeFromRecoverySnapshotIs(t, ctx, "libinclude", false)
- assertExcludeFromRecoverySnapshotIs(t, ctx, "libexclude", true)
- assertExcludeFromRecoverySnapshotIs(t, ctx, "libavailable_exclude", true)
+ AssertExcludeFromRecoverySnapshotIs(t, ctx, "libinclude", false, recoveryVariant)
+ AssertExcludeFromRecoverySnapshotIs(t, ctx, "libexclude", true, recoveryVariant)
+ AssertExcludeFromRecoverySnapshotIs(t, ctx, "libavailable_exclude", true, recoveryVariant)
// A recovery module is excluded, but by its path, not the
// exclude_from_recovery_snapshot property.
- assertExcludeFromRecoverySnapshotIs(t, ctx, "librecovery", false)
+ AssertExcludeFromRecoverySnapshotIs(t, ctx, "librecovery", false, recoveryVariant)
// Verify the content of the recovery snapshot.
diff --git a/cc/vndk.go b/cc/vndk.go
index 1ae79de..c9c9f2c 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -495,7 +495,7 @@
filterOutFromMakeVar: filter,
}
m.AddProperties(&m.properties)
- android.InitAndroidModule(m)
+ android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon)
return m
}
diff --git a/cc/vndk_prebuilt.go b/cc/vndk_prebuilt.go
index da34f36..31b6d10 100644
--- a/cc/vndk_prebuilt.go
+++ b/cc/vndk_prebuilt.go
@@ -144,7 +144,6 @@
// current VNDK prebuilts are only shared libs.
in := p.singleSourcePath(ctx)
- builderFlags := flagsToBuilderFlags(flags)
p.unstrippedOutputFile = in
libName := in.Base()
if p.stripper.NeedsStrip(ctx) {
@@ -158,7 +157,7 @@
// depending on a table of contents file instead of the library itself.
tocFile := android.PathForModuleOut(ctx, libName+".toc")
p.tocFile = android.OptionalPathForPath(tocFile)
- transformSharedObjectToToc(ctx, in, tocFile, builderFlags)
+ TransformSharedObjectToToc(ctx, in, tocFile)
p.androidMkSuffix = p.NameSuffix()
diff --git a/cmd/extract_apks/main.go b/cmd/extract_apks/main.go
index 6e51a28..1cf64de 100644
--- a/cmd/extract_apks/main.go
+++ b/cmd/extract_apks/main.go
@@ -356,7 +356,7 @@
// Writes out selected entries, renaming them as needed
func (apkSet *ApkSet) writeApks(selected SelectionResult, config TargetConfig,
- writer Zip2ZipWriter, partition string) ([]string, error) {
+ outFile io.Writer, zipWriter Zip2ZipWriter, partition string) ([]string, error) {
// Renaming rules:
// splits/MODULE-master.apk to STEM.apk
// else
@@ -406,8 +406,14 @@
origin, inName, outName)
}
entryOrigin[outName] = inName
- if err := writer.CopyFrom(apkFile, outName); err != nil {
- return nil, err
+ if outName == config.stem+".apk" {
+ if err := writeZipEntryToFile(outFile, apkFile); err != nil {
+ return nil, err
+ }
+ } else {
+ if err := zipWriter.CopyFrom(apkFile, outName); err != nil {
+ return nil, err
+ }
}
if partition != "" {
apkcerts = append(apkcerts, fmt.Sprintf(
@@ -426,14 +432,13 @@
if !ok {
return fmt.Errorf("Couldn't find apk path %s", selected.entries[0])
}
- inputReader, _ := apk.Open()
- _, err := io.Copy(outFile, inputReader)
- return err
+ return writeZipEntryToFile(outFile, apk)
}
// Arguments parsing
var (
- outputFile = flag.String("o", "", "output file containing extracted entries")
+ outputFile = flag.String("o", "", "output file for primary entry")
+ zipFile = flag.String("zip", "", "output file containing additional extracted entries")
targetConfig = TargetConfig{
screenDpi: map[android_bundle_proto.ScreenDensity_DensityAlias]bool{},
abis: map[android_bundle_proto.Abi_AbiAlias]int{},
@@ -494,7 +499,8 @@
func processArgs() {
flag.Usage = func() {
- fmt.Fprintln(os.Stderr, `usage: extract_apks -o <output-file> -sdk-version value -abis value `+
+ fmt.Fprintln(os.Stderr, `usage: extract_apks -o <output-file> [-zip <output-zip-file>] `+
+ `-sdk-version value -abis value `+
`-screen-densities value {-stem value | -extract-single} [-allow-prereleased] `+
`[-apkcerts <apkcerts output file> -partition <partition>] <APK set>`)
flag.PrintDefaults()
@@ -510,7 +516,8 @@
flag.StringVar(&targetConfig.stem, "stem", "", "output entries base name in the output zip file")
flag.Parse()
if (*outputFile == "") || len(flag.Args()) != 1 || *version == 0 ||
- (targetConfig.stem == "" && !*extractSingle) || (*apkcertsOutput != "" && *partition == "") {
+ ((targetConfig.stem == "" || *zipFile == "") && !*extractSingle) ||
+ (*apkcertsOutput != "" && *partition == "") {
flag.Usage()
}
targetConfig.sdkVersion = int32(*version)
@@ -542,13 +549,20 @@
if *extractSingle {
err = apkSet.extractAndCopySingle(sel, outFile)
} else {
- writer := zip.NewWriter(outFile)
+ zipOutputFile, err := os.Create(*zipFile)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer zipOutputFile.Close()
+
+ zipWriter := zip.NewWriter(zipOutputFile)
defer func() {
- if err := writer.Close(); err != nil {
+ if err := zipWriter.Close(); err != nil {
log.Fatal(err)
}
}()
- apkcerts, err := apkSet.writeApks(sel, targetConfig, writer, *partition)
+
+ apkcerts, err := apkSet.writeApks(sel, targetConfig, outFile, zipWriter, *partition)
if err == nil && *apkcertsOutput != "" {
apkcertsFile, err := os.Create(*apkcertsOutput)
if err != nil {
@@ -567,3 +581,13 @@
log.Fatal(err)
}
}
+
+func writeZipEntryToFile(outFile io.Writer, zipEntry *zip.File) error {
+ reader, err := zipEntry.Open()
+ if err != nil {
+ return err
+ }
+ defer reader.Close()
+ _, err = io.Copy(outFile, reader)
+ return err
+}
diff --git a/cmd/extract_apks/main_test.go b/cmd/extract_apks/main_test.go
index 9fcf324..f5e4046 100644
--- a/cmd/extract_apks/main_test.go
+++ b/cmd/extract_apks/main_test.go
@@ -15,6 +15,7 @@
package main
import (
+ "bytes"
"fmt"
"reflect"
"testing"
@@ -437,8 +438,8 @@
stem string
partition string
// what we write from what
- expectedZipEntries map[string]string
- expectedApkcerts []string
+ zipEntries map[string]string
+ expectedApkcerts []string
}
func TestWriteApks(t *testing.T) {
@@ -448,7 +449,7 @@
moduleName: "mybase",
stem: "Foo",
partition: "system",
- expectedZipEntries: map[string]string{
+ zipEntries: map[string]string{
"Foo.apk": "splits/mybase-master.apk",
"Foo-xhdpi.apk": "splits/mybase-xhdpi.apk",
},
@@ -462,7 +463,7 @@
moduleName: "base",
stem: "Bar",
partition: "product",
- expectedZipEntries: map[string]string{
+ zipEntries: map[string]string{
"Bar.apk": "universal.apk",
},
expectedApkcerts: []string{
@@ -471,23 +472,46 @@
},
}
for _, testCase := range testCases {
- apkSet := ApkSet{entries: make(map[string]*zip.File)}
- sel := SelectionResult{moduleName: testCase.moduleName}
- for _, in := range testCase.expectedZipEntries {
- apkSet.entries[in] = &zip.File{FileHeader: zip.FileHeader{Name: in}}
- sel.entries = append(sel.entries, in)
- }
- writer := testZip2ZipWriter{make(map[string]string)}
- config := TargetConfig{stem: testCase.stem}
- apkcerts, err := apkSet.writeApks(sel, config, writer, testCase.partition)
- if err != nil {
- t.Error(err)
- }
- if !reflect.DeepEqual(testCase.expectedZipEntries, writer.entries) {
- t.Errorf("expected zip entries %v, got %v", testCase.expectedZipEntries, writer.entries)
- }
- if !reflect.DeepEqual(testCase.expectedApkcerts, apkcerts) {
- t.Errorf("expected apkcerts %v, got %v", testCase.expectedApkcerts, apkcerts)
- }
+ t.Run(testCase.name, func(t *testing.T) {
+ testZipBuf := &bytes.Buffer{}
+ testZip := zip.NewWriter(testZipBuf)
+ for _, in := range testCase.zipEntries {
+ f, _ := testZip.Create(in)
+ f.Write([]byte(in))
+ }
+ testZip.Close()
+
+ zipReader, _ := zip.NewReader(bytes.NewReader(testZipBuf.Bytes()), int64(testZipBuf.Len()))
+
+ apkSet := ApkSet{entries: make(map[string]*zip.File)}
+ sel := SelectionResult{moduleName: testCase.moduleName}
+ for _, f := range zipReader.File {
+ apkSet.entries[f.Name] = f
+ sel.entries = append(sel.entries, f.Name)
+ }
+
+ zipWriter := testZip2ZipWriter{make(map[string]string)}
+ outWriter := &bytes.Buffer{}
+ config := TargetConfig{stem: testCase.stem}
+ apkcerts, err := apkSet.writeApks(sel, config, outWriter, zipWriter, testCase.partition)
+ if err != nil {
+ t.Error(err)
+ }
+ expectedZipEntries := make(map[string]string)
+ for k, v := range testCase.zipEntries {
+ if k != testCase.stem+".apk" {
+ expectedZipEntries[k] = v
+ }
+ }
+ if !reflect.DeepEqual(expectedZipEntries, zipWriter.entries) {
+ t.Errorf("expected zip entries %v, got %v", testCase.zipEntries, zipWriter.entries)
+ }
+ if !reflect.DeepEqual(testCase.expectedApkcerts, apkcerts) {
+ t.Errorf("expected apkcerts %v, got %v", testCase.expectedApkcerts, apkcerts)
+ }
+ if g, w := outWriter.String(), testCase.zipEntries[testCase.stem+".apk"]; !reflect.DeepEqual(g, w) {
+ t.Errorf("expected output file contents %q, got %q", testCase.stem+".apk", outWriter.String())
+ }
+ })
}
}
diff --git a/cmd/sbox/sbox.go b/cmd/sbox/sbox.go
index c7f3f6a..4fa7486 100644
--- a/cmd/sbox/sbox.go
+++ b/cmd/sbox/sbox.go
@@ -164,7 +164,7 @@
if useSubDir {
localTempDir = filepath.Join(localTempDir, strconv.Itoa(i))
}
- depFile, err := runCommand(command, localTempDir)
+ depFile, err := runCommand(command, localTempDir, i)
if err != nil {
// Running the command failed, keep the temporary output directory around in
// case a user wants to inspect it for debugging purposes. Soong will delete
@@ -194,6 +194,28 @@
return nil
}
+// createCommandScript will create and return an exec.Cmd that runs rawCommand.
+//
+// rawCommand is executed via a script in the sandbox.
+// tempDir is the temporary where the script is created.
+// toDirInSandBox is the path containing the script in the sbox environment.
+// toDirInSandBox is the path containing the script in the sbox environment.
+// seed is a unique integer used to distinguish different scripts that might be at location.
+//
+// returns an exec.Cmd that can be ran from within sbox context if no error, or nil if error.
+// caller must ensure script is cleaned up if function succeeds.
+//
+func createCommandScript(rawCommand string, tempDir, toDirInSandbox string, seed int) (*exec.Cmd, error) {
+ scriptName := fmt.Sprintf("sbox_command.%d.bash", seed)
+ scriptPathAndName := joinPath(tempDir, scriptName)
+ err := os.WriteFile(scriptPathAndName, []byte(rawCommand), 0644)
+ if err != nil {
+ return nil, fmt.Errorf("failed to write command %s... to %s",
+ rawCommand[0:40], scriptPathAndName)
+ }
+ return exec.Command("bash", joinPath(toDirInSandbox, filepath.Base(scriptName))), nil
+}
+
// readManifest reads an sbox manifest from a textproto file.
func readManifest(file string) (*sbox_proto.Manifest, error) {
manifestData, err := ioutil.ReadFile(file)
@@ -213,7 +235,7 @@
// runCommand runs a single command from a manifest. If the command references the
// __SBOX_DEPFILE__ placeholder it returns the name of the depfile that was used.
-func runCommand(command *sbox_proto.Command, tempDir string) (depFile string, err error) {
+func runCommand(command *sbox_proto.Command, tempDir string, commandIndex int) (depFile string, err error) {
rawCommand := command.GetCommand()
if rawCommand == "" {
return "", fmt.Errorf("command is required")
@@ -255,7 +277,11 @@
return "", err
}
- cmd := exec.Command("bash", "-c", rawCommand)
+ cmd, err := createCommandScript(rawCommand, tempDir, pathToTempDirInSbox, commandIndex)
+ if err != nil {
+ return "", err
+ }
+
buf := &bytes.Buffer{}
cmd.Stdin = os.Stdin
cmd.Stdout = buf
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index e9eabd3..f07eafa 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -386,7 +386,7 @@
// - won't be overwritten by corresponding bp2build generated files
//
// And return their paths so they can be left out of the Bazel workspace dir (i.e. ignored)
-func getPathsToIgnoredBuildFiles(topDir string, generatedRoot string, srcDirBazelFiles []string) []string {
+func getPathsToIgnoredBuildFiles(topDir string, generatedRoot string, srcDirBazelFiles []string, verbose bool) []string {
paths := make([]string, 0)
for _, srcDirBazelFileRelativePath := range srcDirBazelFiles {
@@ -416,7 +416,9 @@
// BUILD file clash resolution happens later in the symlink forest creation
continue
}
- fmt.Fprintf(os.Stderr, "Ignoring existing BUILD file: %s\n", srcDirBazelFileRelativePath)
+ if verbose {
+ fmt.Fprintf(os.Stderr, "Ignoring existing BUILD file: %s\n", srcDirBazelFileRelativePath)
+ }
paths = append(paths, srcDirBazelFileRelativePath)
}
@@ -464,6 +466,11 @@
// conversion for Bazel conversion.
bp2buildCtx := android.NewContext(configuration)
+ // Soong internals like LoadHooks behave differently when running as
+ // bp2build. This is the bit to differentiate between Soong-as-Soong and
+ // Soong-as-bp2build.
+ bp2buildCtx.SetRunningAsBp2build()
+
// Propagate "allow misssing dependencies" bit. This is normally set in
// newContext(), but we create bp2buildCtx without calling that method.
bp2buildCtx.SetAllowMissingDependencies(configuration.AllowMissingDependencies())
@@ -518,7 +525,7 @@
os.Exit(1)
}
- pathsToIgnoredBuildFiles := getPathsToIgnoredBuildFiles(topDir, generatedRoot, existingBazelRelatedFiles)
+ pathsToIgnoredBuildFiles := getPathsToIgnoredBuildFiles(topDir, generatedRoot, existingBazelRelatedFiles, configuration.IsEnvTrue("BP2BUILD_VERBOSE"))
excludes = append(excludes, pathsToIgnoredBuildFiles...)
excludes = append(excludes, getTemporaryExcludes()...)
@@ -530,6 +537,7 @@
// for queryview, since that's a total repo-wide conversion and there's a
// 1:1 mapping for each module.
metrics.Print()
+ writeBp2BuildMetrics(&metrics, configuration)
ninjaDeps = append(ninjaDeps, codegenContext.AdditionalNinjaDeps()...)
ninjaDeps = append(ninjaDeps, symlinkForestDeps...)
@@ -539,3 +547,13 @@
// Create an empty bp2build marker file.
touch(shared.JoinPath(topDir, bp2buildMarker))
}
+
+// Write Bp2Build metrics into $LOG_DIR
+func writeBp2BuildMetrics(metrics *bp2build.CodegenMetrics, configuration android.Config) {
+ metricsDir := configuration.Getenv("LOG_DIR")
+ if len(metricsDir) < 1 {
+ fmt.Fprintf(os.Stderr, "\nMissing required env var for generating bp2build metrics: LOG_DIR\n")
+ os.Exit(1)
+ }
+ metrics.Write(metricsDir)
+}
diff --git a/compliance/build_license_metadata/Android.bp b/compliance/build_license_metadata/Android.bp
index 5000346..4826526 100644
--- a/compliance/build_license_metadata/Android.bp
+++ b/compliance/build_license_metadata/Android.bp
@@ -25,5 +25,6 @@
"license_metadata_proto",
"golang-protobuf-proto",
"golang-protobuf-encoding-prototext",
+ "soong-response",
],
}
diff --git a/compliance/build_license_metadata/build_license_metadata.go b/compliance/build_license_metadata/build_license_metadata.go
index ba3cc3e..53d2407 100644
--- a/compliance/build_license_metadata/build_license_metadata.go
+++ b/compliance/build_license_metadata/build_license_metadata.go
@@ -26,28 +26,12 @@
"google.golang.org/protobuf/proto"
"android/soong/compliance/license_metadata_proto"
+ "android/soong/response"
)
-var (
- packageName = flag.String("p", "", "license package name")
- moduleType = newMultiString("mt", "module type")
- moduleClass = newMultiString("mc", "module class")
- kinds = newMultiString("k", "license kinds")
- conditions = newMultiString("c", "license conditions")
- notices = newMultiString("n", "license notice file")
- deps = newMultiString("d", "license metadata file dependency")
- sources = newMultiString("s", "source (input) dependency")
- built = newMultiString("t", "built targets")
- installed = newMultiString("i", "installed targets")
- roots = newMultiString("r", "root directory of project")
- installedMap = newMultiString("m", "map dependent targets to their installed names")
- isContainer = flag.Bool("is_container", false, "preserved dependent target name when given")
- outFile = flag.String("o", "", "output file")
-)
-
-func newMultiString(name, usage string) *multiString {
+func newMultiString(flags *flag.FlagSet, name, usage string) *multiString {
var f multiString
- flag.Var(&f, name, usage)
+ flags.Var(&f, name, usage)
return &f
}
@@ -57,7 +41,45 @@
func (ms *multiString) Set(s string) error { *ms = append(*ms, s); return nil }
func main() {
- flag.Parse()
+ var expandedArgs []string
+ for _, arg := range os.Args[1:] {
+ if strings.HasPrefix(arg, "@") {
+ f, err := os.Open(strings.TrimPrefix(arg, "@"))
+ if err != nil {
+ fmt.Fprintln(os.Stderr, err.Error())
+ os.Exit(1)
+ }
+
+ respArgs, err := response.ReadRspFile(f)
+ f.Close()
+ if err != nil {
+ fmt.Fprintln(os.Stderr, err.Error())
+ os.Exit(1)
+ }
+ expandedArgs = append(expandedArgs, respArgs...)
+ } else {
+ expandedArgs = append(expandedArgs, arg)
+ }
+ }
+
+ flags := flag.NewFlagSet("flags", flag.ExitOnError)
+
+ packageName := flags.String("p", "", "license package name")
+ moduleType := newMultiString(flags, "mt", "module type")
+ kinds := newMultiString(flags, "k", "license kinds")
+ moduleClass := newMultiString(flags, "mc", "module class")
+ conditions := newMultiString(flags, "c", "license conditions")
+ notices := newMultiString(flags, "n", "license notice file")
+ deps := newMultiString(flags, "d", "license metadata file dependency")
+ sources := newMultiString(flags, "s", "source (input) dependency")
+ built := newMultiString(flags, "t", "built targets")
+ installed := newMultiString(flags, "i", "installed targets")
+ roots := newMultiString(flags, "r", "root directory of project")
+ installedMap := newMultiString(flags, "m", "map dependent targets to their installed names")
+ isContainer := flags.Bool("is_container", false, "preserved dependent target name when given")
+ outFile := flags.String("o", "", "output file")
+
+ flags.Parse(expandedArgs)
metadata := license_metadata_proto.LicenseMetadata{}
metadata.PackageName = proto.String(*packageName)
@@ -119,7 +141,7 @@
for _, installMap := range installMaps {
components := strings.Split(installMap, ":")
if len(components) != 2 {
- panic(fmt.Errorf("install map entry %q contains %d colons, expected 1", len(components)-1))
+ panic(fmt.Errorf("install map entry %q contains %d colons, expected 1", installMap, len(components)-1))
}
ret = append(ret, &license_metadata_proto.InstallMap{
FromPath: proto.String(components[0]),
@@ -140,7 +162,7 @@
dep := components[0]
components = components[1:]
ad := &license_metadata_proto.AnnotatedDependency{
- File: proto.String(dep),
+ File: proto.String(dep),
Annotations: make([]string, 0, len(components)),
}
for _, ann := range components {
diff --git a/cuj/run_cuj_tests.sh b/cuj/run_cuj_tests.sh
index b4f9f88..a746bd5 100755
--- a/cuj/run_cuj_tests.sh
+++ b/cuj/run_cuj_tests.sh
@@ -18,11 +18,10 @@
cd "$ANDROID_TOP"
export OUT_DIR="${OUT_DIR:-out}"
-readonly SOONG_OUT="${OUT_DIR}/soong"
-build/soong/soong_ui.bash --make-mode "${SOONG_OUT}/host/${OS}-x86/bin/cuj_tests"
+build/soong/soong_ui.bash --make-mode "${OUT_DIR}/host/${OS}-x86/bin/cuj_tests"
-"${SOONG_OUT}/host/${OS}-x86/bin/cuj_tests" || true
+"${OUT_DIR}/host/${OS}-x86/bin/cuj_tests" || true
if [ -n "${DIST_DIR}" ]; then
cp -r "${OUT_DIR}/cuj_tests/logs" "${DIST_DIR}"
diff --git a/dexpreopt/class_loader_context_test.go b/dexpreopt/class_loader_context_test.go
index d81ac2c..4a3d390 100644
--- a/dexpreopt/class_loader_context_test.go
+++ b/dexpreopt/class_loader_context_test.go
@@ -115,16 +115,16 @@
// Test that class loader context structure is correct.
t.Run("string", func(t *testing.T) {
wantStr := " --host-context-for-sdk 29 " +
- "PCL[out/" + AndroidHidlManager + ".jar]#" +
- "PCL[out/" + AndroidHidlBase + ".jar]" +
+ "PCL[out/soong/" + AndroidHidlManager + ".jar]#" +
+ "PCL[out/soong/" + AndroidHidlBase + ".jar]" +
" --target-context-for-sdk 29 " +
"PCL[/system/framework/" + AndroidHidlManager + ".jar]#" +
"PCL[/system/framework/" + AndroidHidlBase + ".jar]" +
" --host-context-for-sdk any " +
- "PCL[out/a.jar]#PCL[out/b.jar]#PCL[out/c.jar]#PCL[out/d.jar]" +
- "{PCL[out/a2.jar]#PCL[out/b2.jar]#PCL[out/c2.jar]" +
- "{PCL[out/a1.jar]#PCL[out/b1.jar]}}#" +
- "PCL[out/f.jar]#PCL[out/a3.jar]#PCL[out/b3.jar]" +
+ "PCL[out/soong/a.jar]#PCL[out/soong/b.jar]#PCL[out/soong/c.jar]#PCL[out/soong/d.jar]" +
+ "{PCL[out/soong/a2.jar]#PCL[out/soong/b2.jar]#PCL[out/soong/c2.jar]" +
+ "{PCL[out/soong/a1.jar]#PCL[out/soong/b1.jar]}}#" +
+ "PCL[out/soong/f.jar]#PCL[out/soong/a3.jar]#PCL[out/soong/b3.jar]" +
" --target-context-for-sdk any " +
"PCL[/system/a.jar]#PCL[/system/b.jar]#PCL[/system/c.jar]#PCL[/system/d.jar]" +
"{PCL[/system/a2.jar]#PCL[/system/b2.jar]#PCL[/system/c2.jar]" +
@@ -138,11 +138,11 @@
// Test that all expected build paths are gathered.
t.Run("paths", func(t *testing.T) {
wantPaths := []string{
- "out/android.hidl.manager-V1.0-java.jar", "out/android.hidl.base-V1.0-java.jar",
- "out/a.jar", "out/b.jar", "out/c.jar", "out/d.jar",
- "out/a2.jar", "out/b2.jar", "out/c2.jar",
- "out/a1.jar", "out/b1.jar",
- "out/f.jar", "out/a3.jar", "out/b3.jar",
+ "out/soong/android.hidl.manager-V1.0-java.jar", "out/soong/android.hidl.base-V1.0-java.jar",
+ "out/soong/a.jar", "out/soong/b.jar", "out/soong/c.jar", "out/soong/d.jar",
+ "out/soong/a2.jar", "out/soong/b2.jar", "out/soong/c2.jar",
+ "out/soong/a1.jar", "out/soong/b1.jar",
+ "out/soong/f.jar", "out/soong/a3.jar", "out/soong/b3.jar",
}
if !reflect.DeepEqual(wantPaths, havePaths.Strings()) {
t.Errorf("\nwant paths: %s\nhave paths: %s", wantPaths, havePaths)
@@ -270,13 +270,13 @@
// Test that class loader context structure is correct.
t.Run("string", func(t *testing.T) {
- wantStr := " --host-context-for-sdk 30 PCL[out/c.jar]" +
+ wantStr := " --host-context-for-sdk 30 PCL[out/soong/c.jar]" +
" --target-context-for-sdk 30 PCL[/system/c.jar]" +
- " --host-context-for-sdk 29 PCL[out/b.jar]" +
+ " --host-context-for-sdk 29 PCL[out/soong/b.jar]" +
" --target-context-for-sdk 29 PCL[/system/b.jar]" +
- " --host-context-for-sdk 28 PCL[out/a.jar]" +
+ " --host-context-for-sdk 28 PCL[out/soong/a.jar]" +
" --target-context-for-sdk 28 PCL[/system/a.jar]" +
- " --host-context-for-sdk any PCL[out/d.jar]" +
+ " --host-context-for-sdk any PCL[out/soong/d.jar]" +
" --target-context-for-sdk any PCL[/system/d.jar]"
if wantStr != haveStr {
t.Errorf("\nwant class loader context: %s\nhave class loader context: %s", wantStr, haveStr)
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index de3666a..1f99a96 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -49,10 +49,12 @@
ArtApexJars android.ConfiguredJarList // modules for jars that are in the ART APEX
- SystemServerJars android.ConfiguredJarList // jars that form the system server
- SystemServerApps []string // apps that are loaded into system server
- ApexSystemServerJars android.ConfiguredJarList // jars within apex that are loaded into system server
- SpeedApps []string // apps that should be speed optimized
+ SystemServerJars android.ConfiguredJarList // system_server classpath jars on the platform
+ SystemServerApps []string // apps that are loaded into system server
+ ApexSystemServerJars android.ConfiguredJarList // system_server classpath jars delivered via apex
+ StandaloneSystemServerJars android.ConfiguredJarList // jars on the platform that system_server loads dynamically using separate classloaders
+ ApexStandaloneSystemServerJars android.ConfiguredJarList // jars delivered via apex that system_server loads dynamically using separate classloaders
+ SpeedApps []string // apps that should be speed optimized
BrokenSuboptimalOrderOfSystemServerJars bool // if true, sub-optimal order does not cause a build error
@@ -98,6 +100,48 @@
RelaxUsesLibraryCheck bool
}
+var allPlatformSystemServerJarsKey = android.NewOnceKey("allPlatformSystemServerJars")
+
+// Returns all jars on the platform that system_server loads, including those on classpath and those
+// loaded dynamically.
+func (g *GlobalConfig) AllPlatformSystemServerJars(ctx android.PathContext) *android.ConfiguredJarList {
+ return ctx.Config().Once(allPlatformSystemServerJarsKey, func() interface{} {
+ res := g.SystemServerJars.AppendList(&g.StandaloneSystemServerJars)
+ return &res
+ }).(*android.ConfiguredJarList)
+}
+
+var allApexSystemServerJarsKey = android.NewOnceKey("allApexSystemServerJars")
+
+// Returns all jars delivered via apex that system_server loads, including those on classpath and
+// those loaded dynamically.
+func (g *GlobalConfig) AllApexSystemServerJars(ctx android.PathContext) *android.ConfiguredJarList {
+ return ctx.Config().Once(allApexSystemServerJarsKey, func() interface{} {
+ res := g.ApexSystemServerJars.AppendList(&g.ApexStandaloneSystemServerJars)
+ return &res
+ }).(*android.ConfiguredJarList)
+}
+
+var allSystemServerClasspathJarsKey = android.NewOnceKey("allSystemServerClasspathJars")
+
+// Returns all system_server classpath jars.
+func (g *GlobalConfig) AllSystemServerClasspathJars(ctx android.PathContext) *android.ConfiguredJarList {
+ return ctx.Config().Once(allSystemServerClasspathJarsKey, func() interface{} {
+ res := g.SystemServerJars.AppendList(&g.ApexSystemServerJars)
+ return &res
+ }).(*android.ConfiguredJarList)
+}
+
+var allSystemServerJarsKey = android.NewOnceKey("allSystemServerJars")
+
+// Returns all jars that system_server loads.
+func (g *GlobalConfig) AllSystemServerJars(ctx android.PathContext) *android.ConfiguredJarList {
+ return ctx.Config().Once(allSystemServerJarsKey, func() interface{} {
+ res := g.AllPlatformSystemServerJars(ctx).AppendList(g.AllApexSystemServerJars(ctx))
+ return &res
+ }).(*android.ConfiguredJarList)
+}
+
// GlobalSoongConfig contains the global config that is generated from Soong,
// stored in dexpreopt_soong.config.
type GlobalSoongConfig struct {
@@ -619,6 +663,8 @@
SystemServerJars: android.EmptyConfiguredJarList(),
SystemServerApps: nil,
ApexSystemServerJars: android.EmptyConfiguredJarList(),
+ StandaloneSystemServerJars: android.EmptyConfiguredJarList(),
+ ApexStandaloneSystemServerJars: android.EmptyConfiguredJarList(),
SpeedApps: nil,
PreoptFlags: nil,
DefaultCompilerFilter: "",
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index 3145315..de139c4 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -115,7 +115,7 @@
// /data. If we don't do this they will need to be extracted which is not favorable for RAM usage
// or performance. If PreoptExtractedApk is true, we ignore the only preopt boot image options.
if global.OnlyPreoptBootImageAndSystemServer && !global.BootJars.ContainsJar(module.Name) &&
- !AllSystemServerJars(ctx, global).ContainsJar(module.Name) && !module.PreoptExtractedApk {
+ !global.AllSystemServerJars(ctx).ContainsJar(module.Name) && !module.PreoptExtractedApk {
return true
}
@@ -197,8 +197,8 @@
}
// Returns the dex location of a system server java library.
-func GetSystemServerDexLocation(global *GlobalConfig, lib string) string {
- if apex := global.ApexSystemServerJars.ApexOfJar(lib); apex != "" {
+func GetSystemServerDexLocation(ctx android.PathContext, global *GlobalConfig, lib string) string {
+ if apex := global.AllApexSystemServerJars(ctx).ApexOfJar(lib); apex != "" {
return fmt.Sprintf("/apex/%s/javalib/%s.jar", apex, lib)
}
return fmt.Sprintf("/system/framework/%s.jar", lib)
@@ -240,7 +240,8 @@
invocationPath := odexPath.ReplaceExtension(ctx, "invocation")
- systemServerJars := AllSystemServerJars(ctx, global)
+ systemServerJars := global.AllSystemServerJars(ctx)
+ systemServerClasspathJars := global.AllSystemServerClasspathJars(ctx)
rule.Command().FlagWithArg("mkdir -p ", filepath.Dir(odexPath.String()))
rule.Command().FlagWithOutput("rm -f ", odexPath)
@@ -251,10 +252,15 @@
var clcHost android.Paths
var clcTarget []string
- for i := 0; i < jarIndex; i++ {
- lib := systemServerJars.Jar(i)
+ endIndex := systemServerClasspathJars.IndexOfJar(module.Name)
+ if endIndex < 0 {
+ // The jar is a standalone one. Use the full classpath as the class loader context.
+ endIndex = systemServerClasspathJars.Len()
+ }
+ for i := 0; i < endIndex; i++ {
+ lib := systemServerClasspathJars.Jar(i)
clcHost = append(clcHost, SystemServerDexJarHostPath(ctx, lib))
- clcTarget = append(clcTarget, GetSystemServerDexLocation(global, lib))
+ clcTarget = append(clcTarget, GetSystemServerDexLocation(ctx, global, lib))
}
if DexpreoptRunningInSoong {
@@ -270,12 +276,22 @@
// cannot see the rule in the generated dexpreopt.sh script).
}
- checkSystemServerOrder(ctx, jarIndex)
+ clcHostString := "PCL[" + strings.Join(clcHost.Strings(), ":") + "]"
+ clcTargetString := "PCL[" + strings.Join(clcTarget, ":") + "]"
+
+ if systemServerClasspathJars.ContainsJar(module.Name) {
+ checkSystemServerOrder(ctx, jarIndex)
+ } else {
+ // Standalone jars are loaded by separate class loaders with SYSTEMSERVERCLASSPATH as the
+ // parent.
+ clcHostString = "PCL[];" + clcHostString
+ clcTargetString = "PCL[];" + clcTargetString
+ }
rule.Command().
- Text("class_loader_context_arg=--class-loader-context=PCL[" + strings.Join(clcHost.Strings(), ":") + "]").
+ Text(`class_loader_context_arg=--class-loader-context="` + clcHostString + `"`).
Implicits(clcHost).
- Text("stored_class_loader_context_arg=--stored-class-loader-context=PCL[" + strings.Join(clcTarget, ":") + "]")
+ Text(`stored_class_loader_context_arg=--stored-class-loader-context="` + clcTargetString + `"`)
} else {
// There are three categories of Java modules handled here:
@@ -533,17 +549,6 @@
}
}
-var allSystemServerJarsKey = android.NewOnceKey("allSystemServerJars")
-
-// TODO: eliminate the superficial global config parameter by moving global config definition
-// from java subpackage to dexpreopt.
-func AllSystemServerJars(ctx android.PathContext, global *GlobalConfig) *android.ConfiguredJarList {
- return ctx.Config().Once(allSystemServerJarsKey, func() interface{} {
- allSystemServerJars := global.SystemServerJars.AppendList(global.ApexSystemServerJars)
- return &allSystemServerJars
- }).(*android.ConfiguredJarList)
-}
-
// A predefined location for the system server dex jars. This is needed in order to generate
// class loader context for dex2oat, as the path to the jar in the Soong module may be unknown
// at that time (Soong processes the jars in dependency order, which may be different from the
@@ -567,7 +572,7 @@
mctx, isModule := ctx.(android.ModuleContext)
if isModule {
config := GetGlobalConfig(ctx)
- jars := AllSystemServerJars(ctx, config)
+ jars := config.AllSystemServerClasspathJars(ctx)
mctx.WalkDeps(func(dep android.Module, parent android.Module) bool {
depIndex := jars.IndexOfJar(dep.Name())
if jarIndex < depIndex && !config.BrokenSuboptimalOrderOfSystemServerJars {
diff --git a/dexpreopt/dexpreopt_test.go b/dexpreopt/dexpreopt_test.go
index 798d776..07e4fad 100644
--- a/dexpreopt/dexpreopt_test.go
+++ b/dexpreopt/dexpreopt_test.go
@@ -50,6 +50,15 @@
android.PathForOutput(ctx, fmt.Sprintf("%s/enforce_uses_libraries.status", name)))
}
+func testPlatformSystemServerModuleConfig(ctx android.PathContext, name string) *ModuleConfig {
+ return createTestModuleConfig(
+ name,
+ fmt.Sprintf("/system/framework/%s.jar", name),
+ android.PathForOutput(ctx, fmt.Sprintf("%s/dexpreopt/%s.jar", name, name)),
+ android.PathForOutput(ctx, fmt.Sprintf("%s/aligned/%s.jar", name, name)),
+ android.PathForOutput(ctx, fmt.Sprintf("%s/enforce_uses_libraries.status", name)))
+}
+
func createTestModuleConfig(name, dexLocation string, buildPath, dexPath, enforceUsesLibrariesStatusFile android.OutputPath) *ModuleConfig {
return &ModuleConfig{
Name: name,
@@ -181,6 +190,52 @@
android.AssertStringEquals(t, "installs", wantInstalls.String(), rule.Installs().String())
}
+func TestDexPreoptStandaloneSystemServerJars(t *testing.T) {
+ config := android.TestConfig("out", nil, "", nil)
+ ctx := android.BuilderContextForTesting(config)
+ globalSoong := globalSoongConfigForTests()
+ global := GlobalConfigForTests(ctx)
+ module := testPlatformSystemServerModuleConfig(ctx, "service-A")
+
+ global.StandaloneSystemServerJars = android.CreateTestConfiguredJarList(
+ []string{"platform:service-A"})
+
+ rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ wantInstalls := android.RuleBuilderInstalls{
+ {android.PathForOutput(ctx, "service-A/dexpreopt/oat/arm/javalib.odex"), "/system/framework/oat/arm/service-A.odex"},
+ {android.PathForOutput(ctx, "service-A/dexpreopt/oat/arm/javalib.vdex"), "/system/framework/oat/arm/service-A.vdex"},
+ }
+
+ android.AssertStringEquals(t, "installs", wantInstalls.String(), rule.Installs().String())
+}
+
+func TestDexPreoptApexStandaloneSystemServerJars(t *testing.T) {
+ config := android.TestConfig("out", nil, "", nil)
+ ctx := android.BuilderContextForTesting(config)
+ globalSoong := globalSoongConfigForTests()
+ global := GlobalConfigForTests(ctx)
+ module := testApexModuleConfig(ctx, "service-A", "com.android.apex1")
+
+ global.ApexStandaloneSystemServerJars = android.CreateTestConfiguredJarList(
+ []string{"com.android.apex1:service-A"})
+
+ rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ wantInstalls := android.RuleBuilderInstalls{
+ {android.PathForOutput(ctx, "service-A/dexpreopt/oat/arm/javalib.odex"), "/system/framework/oat/arm/apex@com.android.apex1@javalib@service-A.jar@classes.odex"},
+ {android.PathForOutput(ctx, "service-A/dexpreopt/oat/arm/javalib.vdex"), "/system/framework/oat/arm/apex@com.android.apex1@javalib@service-A.jar@classes.vdex"},
+ }
+
+ android.AssertStringEquals(t, "installs", wantInstalls.String(), rule.Installs().String())
+}
+
func TestDexPreoptProfile(t *testing.T) {
config := android.TestConfig("out", nil, "", nil)
ctx := android.BuilderContextForTesting(config)
diff --git a/dexpreopt/testing.go b/dexpreopt/testing.go
index 8f5c315..47ae494 100644
--- a/dexpreopt/testing.go
+++ b/dexpreopt/testing.go
@@ -85,12 +85,12 @@
// Prepares a test fixture by enabling dexpreopt, registering the fake_tool_binary module type and
// using that to define the `dex2oatd` module.
var PrepareForTestByEnablingDexpreopt = android.GroupFixturePreparers(
- FixtureModifyGlobalConfig(func(*GlobalConfig) {}),
+ FixtureModifyGlobalConfig(func(android.PathContext, *GlobalConfig) {}),
)
// FixtureModifyGlobalConfig enables dexpreopt (unless modified by the mutator) and modifies the
// configuration.
-func FixtureModifyGlobalConfig(configModifier func(dexpreoptConfig *GlobalConfig)) android.FixturePreparer {
+func FixtureModifyGlobalConfig(configModifier func(ctx android.PathContext, dexpreoptConfig *GlobalConfig)) android.FixturePreparer {
return android.FixtureModifyConfig(func(config android.Config) {
// Initialize the dexpreopt GlobalConfig to an empty structure. This has no effect if it has
// already been set.
@@ -100,48 +100,77 @@
// Retrieve the existing configuration and modify it.
dexpreoptConfig = GetGlobalConfig(pathCtx)
- configModifier(dexpreoptConfig)
+ configModifier(pathCtx, dexpreoptConfig)
})
}
// FixtureSetArtBootJars enables dexpreopt and sets the ArtApexJars property.
func FixtureSetArtBootJars(bootJars ...string) android.FixturePreparer {
- return FixtureModifyGlobalConfig(func(dexpreoptConfig *GlobalConfig) {
+ return FixtureModifyGlobalConfig(func(_ android.PathContext, dexpreoptConfig *GlobalConfig) {
dexpreoptConfig.ArtApexJars = android.CreateTestConfiguredJarList(bootJars)
})
}
// FixtureSetBootJars enables dexpreopt and sets the BootJars property.
func FixtureSetBootJars(bootJars ...string) android.FixturePreparer {
- return FixtureModifyGlobalConfig(func(dexpreoptConfig *GlobalConfig) {
+ return FixtureModifyGlobalConfig(func(_ android.PathContext, dexpreoptConfig *GlobalConfig) {
dexpreoptConfig.BootJars = android.CreateTestConfiguredJarList(bootJars)
})
}
// FixtureSetApexBootJars sets the ApexBootJars property in the global config.
func FixtureSetApexBootJars(bootJars ...string) android.FixturePreparer {
- return FixtureModifyGlobalConfig(func(dexpreoptConfig *GlobalConfig) {
+ return FixtureModifyGlobalConfig(func(_ android.PathContext, dexpreoptConfig *GlobalConfig) {
dexpreoptConfig.ApexBootJars = android.CreateTestConfiguredJarList(bootJars)
})
}
+// FixtureSetStandaloneSystemServerJars sets the StandaloneSystemServerJars property.
+func FixtureSetStandaloneSystemServerJars(jars ...string) android.FixturePreparer {
+ return FixtureModifyGlobalConfig(func(_ android.PathContext, dexpreoptConfig *GlobalConfig) {
+ dexpreoptConfig.StandaloneSystemServerJars = android.CreateTestConfiguredJarList(jars)
+ })
+}
+
// FixtureSetSystemServerJars sets the SystemServerJars property.
func FixtureSetSystemServerJars(jars ...string) android.FixturePreparer {
- return FixtureModifyGlobalConfig(func(dexpreoptConfig *GlobalConfig) {
+ return FixtureModifyGlobalConfig(func(_ android.PathContext, dexpreoptConfig *GlobalConfig) {
dexpreoptConfig.SystemServerJars = android.CreateTestConfiguredJarList(jars)
})
}
// FixtureSetApexSystemServerJars sets the ApexSystemServerJars property in the global config.
func FixtureSetApexSystemServerJars(jars ...string) android.FixturePreparer {
- return FixtureModifyGlobalConfig(func(dexpreoptConfig *GlobalConfig) {
+ return FixtureModifyGlobalConfig(func(_ android.PathContext, dexpreoptConfig *GlobalConfig) {
dexpreoptConfig.ApexSystemServerJars = android.CreateTestConfiguredJarList(jars)
})
}
+// FixtureSetApexStandaloneSystemServerJars sets the ApexStandaloneSystemServerJars property in the
+// global config.
+func FixtureSetApexStandaloneSystemServerJars(jars ...string) android.FixturePreparer {
+ return FixtureModifyGlobalConfig(func(_ android.PathContext, dexpreoptConfig *GlobalConfig) {
+ dexpreoptConfig.ApexStandaloneSystemServerJars = android.CreateTestConfiguredJarList(jars)
+ })
+}
+
// FixtureSetPreoptWithUpdatableBcp sets the PreoptWithUpdatableBcp property in the global config.
func FixtureSetPreoptWithUpdatableBcp(value bool) android.FixturePreparer {
- return FixtureModifyGlobalConfig(func(dexpreoptConfig *GlobalConfig) {
+ return FixtureModifyGlobalConfig(func(_ android.PathContext, dexpreoptConfig *GlobalConfig) {
dexpreoptConfig.PreoptWithUpdatableBcp = value
})
}
+
+// FixtureSetBootImageProfiles sets the BootImageProfiles property in the global config.
+func FixtureSetBootImageProfiles(profiles ...string) android.FixturePreparer {
+ return FixtureModifyGlobalConfig(func(ctx android.PathContext, dexpreoptConfig *GlobalConfig) {
+ dexpreoptConfig.BootImageProfiles = android.PathsForSource(ctx, profiles)
+ })
+}
+
+// FixtureDisableGenerateProfile sets the DisableGenerateProfile property in the global config.
+func FixtureDisableGenerateProfile(disable bool) android.FixturePreparer {
+ return FixtureModifyGlobalConfig(func(_ android.PathContext, dexpreoptConfig *GlobalConfig) {
+ dexpreoptConfig.DisableGenerateProfile = disable
+ })
+}
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index 2865ffa..377a566 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -63,7 +63,6 @@
ctx.RegisterModuleType("prebuilt_defaults", defaultsFactory)
- android.RegisterBp2BuildMutator("prebuilt_etc", PrebuiltEtcBp2Build)
}
var PrepareForTestWithPrebuiltEtc = android.FixtureRegisterWithContext(RegisterPrebuiltEtcBuildComponents)
@@ -377,7 +376,7 @@
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
entries.SetString("LOCAL_MODULE_TAGS", "optional")
- entries.SetString("LOCAL_MODULE_PATH", p.installDirPath.ToMakePath().String())
+ entries.SetString("LOCAL_MODULE_PATH", p.installDirPath.String())
entries.SetString("LOCAL_INSTALLED_MODULE_STEM", p.outputFilePath.Base())
if len(p.properties.Symlinks) > 0 {
entries.AddStrings("LOCAL_MODULE_SYMLINKS", p.properties.Symlinks...)
@@ -440,6 +439,7 @@
// This module is host-only
android.InitAndroidArchModule(module, android.HostSupported, android.MultilibCommon)
android.InitDefaultableModule(module)
+ android.InitBazelModule(module)
return module
}
@@ -663,20 +663,14 @@
Installable bazel.BoolAttribute
}
-func PrebuiltEtcBp2Build(ctx android.TopDownMutatorContext) {
- module, ok := ctx.Module().(*PrebuiltEtc)
- if !ok {
- // Not an prebuilt_etc
- return
- }
- if !module.ConvertWithBp2build(ctx) {
- return
- }
- if ctx.ModuleType() != "prebuilt_etc" {
+// 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 p.installDirBase != "etc" {
return
}
- prebuiltEtcBp2BuildInternal(ctx, module)
+ prebuiltEtcBp2BuildInternal(ctx, p)
}
func prebuiltEtcBp2BuildInternal(ctx android.TopDownMutatorContext, module *PrebuiltEtc) {
@@ -688,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/etc/snapshot_etc.go b/etc/snapshot_etc.go
index 9a25d5a..b54a8a6 100644
--- a/etc/snapshot_etc.go
+++ b/etc/snapshot_etc.go
@@ -128,7 +128,7 @@
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
entries.SetString("LOCAL_MODULE_TAGS", "optional")
- entries.SetString("LOCAL_MODULE_PATH", p.installDirPath.ToMakePath().String())
+ entries.SetString("LOCAL_MODULE_PATH", p.installDirPath.String())
entries.SetString("LOCAL_INSTALLED_MODULE_STEM", p.outputFilePath.Base())
},
},
diff --git a/filesystem/bootimg.go b/filesystem/bootimg.go
index 73d807d..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)
@@ -267,7 +263,7 @@
OutputFile: android.OptionalPathForPath(b.output),
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- entries.SetString("LOCAL_MODULE_PATH", b.installDir.ToMakePath().String())
+ entries.SetString("LOCAL_MODULE_PATH", b.installDir.String())
entries.SetString("LOCAL_INSTALLED_MODULE_STEM", b.installFileName())
},
},
diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go
index b2caa51..0796258 100644
--- a/filesystem/filesystem.go
+++ b/filesystem/filesystem.go
@@ -394,7 +394,7 @@
OutputFile: android.OptionalPathForPath(f.output),
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- entries.SetString("LOCAL_MODULE_PATH", f.installDir.ToMakePath().String())
+ entries.SetString("LOCAL_MODULE_PATH", f.installDir.String())
entries.SetString("LOCAL_INSTALLED_MODULE_STEM", f.installFileName())
},
},
diff --git a/filesystem/logical_partition.go b/filesystem/logical_partition.go
index 739e609..e2f7d7b 100644
--- a/filesystem/logical_partition.go
+++ b/filesystem/logical_partition.go
@@ -215,7 +215,7 @@
OutputFile: android.OptionalPathForPath(l.output),
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- entries.SetString("LOCAL_MODULE_PATH", l.installDir.ToMakePath().String())
+ entries.SetString("LOCAL_MODULE_PATH", l.installDir.String())
entries.SetString("LOCAL_INSTALLED_MODULE_STEM", l.installFileName())
},
},
diff --git a/filesystem/vbmeta.go b/filesystem/vbmeta.go
index 3f16c0d..63e0aba 100644
--- a/filesystem/vbmeta.go
+++ b/filesystem/vbmeta.go
@@ -247,7 +247,7 @@
OutputFile: android.OptionalPathForPath(v.output),
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- entries.SetString("LOCAL_MODULE_PATH", v.installDir.ToMakePath().String())
+ entries.SetString("LOCAL_MODULE_PATH", v.installDir.String())
entries.SetString("LOCAL_INSTALLED_MODULE_STEM", v.installFileName())
},
},
diff --git a/genrule/genrule.go b/genrule/genrule.go
index c9bf958..6a91e01 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -67,13 +67,6 @@
ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) {
ctx.BottomUp("genrule_tool_deps", toolDepsMutator).Parallel()
})
-
- android.RegisterBp2BuildMutator("genrule", GenruleBp2Build)
- android.RegisterBp2BuildMutator("cc_genrule", CcGenruleBp2Build)
-}
-
-func RegisterGenruleBp2BuildDeps(ctx android.RegisterMutatorsContext) {
- ctx.BottomUp("genrule_tool_deps", toolDepsMutator)
}
var (
@@ -110,6 +103,7 @@
type hostToolDependencyTag struct {
blueprint.BaseDependencyTag
+ android.LicenseAnnotationToolchainDependencyTag
label string
}
type generatorProperties struct {
@@ -832,38 +826,8 @@
Cmd string
}
-// CcGenruleBp2Build is for cc_genrule.
-func CcGenruleBp2Build(ctx android.TopDownMutatorContext) {
- m, ok := ctx.Module().(*Module)
- if !ok || !m.ConvertWithBp2build(ctx) {
- return
- }
-
- if ctx.ModuleType() != "cc_genrule" {
- // Not a cc_genrule.
- return
- }
-
- genruleBp2Build(ctx)
-}
-
-// GenruleBp2Build is used for genrule.
-func GenruleBp2Build(ctx android.TopDownMutatorContext) {
- m, ok := ctx.Module().(*Module)
- if !ok || !m.ConvertWithBp2build(ctx) {
- return
- }
-
- if ctx.ModuleType() != "genrule" {
- // Not a regular genrule.
- return
- }
-
- genruleBp2Build(ctx)
-}
-
-func genruleBp2Build(ctx android.TopDownMutatorContext) {
- m, _ := ctx.Module().(*Module)
+// ConvertWithBp2build converts a Soong module -> Bazel target.
+func (m *Module) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
// Bazel only has the "tools" attribute.
tools_prop := android.BazelLabelForModuleDeps(ctx, m.properties.Tools)
tool_files_prop := android.BazelLabelForModuleSrc(ctx, m.properties.Tool_files)
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/android_manifest.go b/java/android_manifest.go
index 38065f1..f29d8ad 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -16,6 +16,7 @@
import (
"fmt"
+ "strconv"
"strings"
"github.com/google/blueprint"
@@ -42,6 +43,21 @@
},
"args", "libs")
+// targetSdkVersion for manifest_fixer
+// When TARGET_BUILD_APPS is not empty, this method returns 10000 for modules targeting an unreleased SDK
+// This enables release builds (that run with TARGET_BUILD_APPS=[val...]) to target APIs that have not yet been finalized as part of an SDK
+func targetSdkVersionForManifestFixer(ctx android.ModuleContext, sdkContext android.SdkContext) string {
+ targetSdkVersionSpec := sdkContext.TargetSdkVersion(ctx)
+ if ctx.Config().UnbundledBuildApps() && targetSdkVersionSpec.ApiLevel.IsPreview() {
+ return strconv.Itoa(android.FutureApiLevel.FinalOrFutureInt())
+ }
+ targetSdkVersion, err := targetSdkVersionSpec.EffectiveVersionString(ctx)
+ if err != nil {
+ ctx.ModuleErrorf("invalid targetSdkVersion: %s", err)
+ }
+ return targetSdkVersion
+}
+
// Uses manifest_fixer.py to inject minSdkVersion, etc. into an AndroidManifest.xml
func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext android.SdkContext,
classLoaderContexts dexpreopt.ClassLoaderContextMap, isLibrary, useEmbeddedNativeLibs, usesNonSdkApis,
@@ -89,10 +105,8 @@
args = append(args, "--logging-parent", loggingParent)
}
var deps android.Paths
- targetSdkVersion, err := sdkContext.TargetSdkVersion(ctx).EffectiveVersionString(ctx)
- if err != nil {
- ctx.ModuleErrorf("invalid targetSdkVersion: %s", err)
- }
+ targetSdkVersion := targetSdkVersionForManifestFixer(ctx, sdkContext)
+
if UseApiFingerprint(ctx) && ctx.ModuleName() != "framework-res" {
targetSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", ApiFingerprintPath(ctx).String())
deps = append(deps, ApiFingerprintPath(ctx))
diff --git a/java/android_resources.go b/java/android_resources.go
index 6864ebb..8c5908f 100644
--- a/java/android_resources.go
+++ b/java/android_resources.go
@@ -43,7 +43,7 @@
// androidResourceGlob returns the list of files in the given directory, using the standard
// exclusion patterns for Android resources.
-func androidResourceGlob(ctx android.ModuleContext, dir android.Path) android.Paths {
+func androidResourceGlob(ctx android.EarlyModuleContext, dir android.Path) android.Paths {
return ctx.GlobFiles(filepath.Join(dir.String(), "**/*"), androidResourceIgnoreFilenames)
}
diff --git a/java/androidmk.go b/java/androidmk.go
index eca5caa..19fe7e2 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -47,6 +47,7 @@
if library.dexJarFile.IsSet() {
entries.SetPath("LOCAL_SOONG_DEX_JAR", library.dexJarFile.Path())
}
+ entries.SetPath("LOCAL_SOONG_INSTALLED_MODULE", library.hostdexInstallFile)
entries.SetPath("LOCAL_SOONG_HEADER_JAR", library.headerJarFile)
entries.SetPath("LOCAL_SOONG_CLASSES_JAR", library.implementationAndResourcesJar)
entries.SetString("LOCAL_MODULE_STEM", library.Stem()+"-hostdex")
@@ -181,7 +182,14 @@
}
func (prebuilt *Import) AndroidMkEntries() []android.AndroidMkEntries {
- if prebuilt.hideApexVariantFromMake || !prebuilt.ContainingSdk().Unversioned() {
+ if prebuilt.hideApexVariantFromMake {
+ // For a library imported from a prebuilt APEX, we don't need a Make module for itself, as we
+ // don't need to install it. However, we need to add its dexpreopt outputs as sub-modules, if it
+ // is preopted.
+ dexpreoptEntries := prebuilt.dexpreopter.AndroidMkEntriesForApex()
+ return append(dexpreoptEntries, android.AndroidMkEntries{Disabled: true})
+ }
+ if !prebuilt.ContainingSdk().Unversioned() {
return []android.AndroidMkEntries{android.AndroidMkEntries{
Disabled: true,
}}
@@ -285,11 +293,6 @@
}}
} else {
outputFile := binary.wrapperFile
- // Have Make installation trigger Soong installation by using Soong's install path as
- // the output file.
- if binary.Host() {
- outputFile = binary.binaryFile
- }
return []android.AndroidMkEntries{android.AndroidMkEntries{
Class: "EXECUTABLES",
@@ -689,7 +692,7 @@
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
entries.SetString("LOCAL_CERTIFICATE", r.certificate.AndroidMkString())
- entries.SetPath("LOCAL_MODULE_PATH", r.installDir.ToMakePath())
+ entries.SetPath("LOCAL_MODULE_PATH", r.installDir)
entries.AddStrings("LOCAL_OVERRIDES_PACKAGES", r.properties.Overrides...)
},
},
@@ -700,12 +703,12 @@
return []android.AndroidMkEntries{
android.AndroidMkEntries{
Class: "APPS",
- OutputFile: android.OptionalPathForPath(apkSet.packedOutput),
+ OutputFile: android.OptionalPathForPath(apkSet.primaryOutput),
Include: "$(BUILD_SYSTEM)/soong_android_app_set.mk",
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
entries.SetBoolIfTrue("LOCAL_PRIVILEGED_MODULE", apkSet.Privileged())
- entries.SetString("LOCAL_APK_SET_INSTALL_FILE", apkSet.InstallFile())
+ entries.SetPath("LOCAL_APK_SET_INSTALL_FILE", apkSet.PackedAdditionalOutputs())
entries.SetPath("LOCAL_APKCERTS_FILE", apkSet.apkcertsFile)
entries.AddStrings("LOCAL_OVERRIDES_PACKAGES", apkSet.properties.Overrides...)
},
diff --git a/java/app.go b/java/app.go
index 6554d66..1c69aeb 100755
--- a/java/app.go
+++ b/java/app.go
@@ -43,8 +43,6 @@
ctx.RegisterModuleType("android_app_certificate", AndroidAppCertificateFactory)
ctx.RegisterModuleType("override_android_app", OverrideAndroidAppModuleFactory)
ctx.RegisterModuleType("override_android_test", OverrideAndroidTestModuleFactory)
-
- android.RegisterBp2BuildMutator("android_app_certificate", AndroidAppCertificateBp2Build)
}
// AndroidManifest.xml merging
@@ -139,6 +137,7 @@
}
type AndroidApp struct {
+ android.BazelModuleBase
Library
aapt
android.OverridableModuleBase
@@ -291,7 +290,7 @@
if minSdkVersion, err := a.MinSdkVersion(ctx).EffectiveVersion(ctx); err == nil {
a.checkJniLibsSdkVersion(ctx, minSdkVersion)
- android.CheckMinSdkVersion(a, ctx, minSdkVersion)
+ android.CheckMinSdkVersion(ctx, minSdkVersion, a.WalkPayloadDeps)
} else {
ctx.PropertyErrorf("min_sdk_version", "%s", err.Error())
}
@@ -471,6 +470,7 @@
a.dexpreopter.enforceUsesLibs = a.usesLibrary.enforceUsesLibraries()
a.dexpreopter.classLoaderContexts = a.classLoaderContexts
a.dexpreopter.manifestFile = a.mergedManifestFile
+ a.dexpreopter.preventInstall = a.appProperties.PreventInstall
if ctx.ModuleName() != "framework-res" {
a.Module.compile(ctx, a.aaptSrcJar)
@@ -485,7 +485,7 @@
a.jniLibs = jniLibs
if a.shouldEmbedJnis(ctx) {
jniJarFile = android.PathForModuleOut(ctx, "jnilibs.zip")
- a.installPathForJNISymbols = a.installPath(ctx).ToMakePath()
+ a.installPathForJNISymbols = a.installPath(ctx)
TransformJniLibsToJar(ctx, jniJarFile, jniLibs, a.useEmbeddedNativeLibs(ctx))
for _, jni := range jniLibs {
if jni.coverageFile.Valid() {
@@ -720,11 +720,15 @@
apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
// Install the app package.
- if (Bool(a.Module.properties.Installable) || ctx.Host()) && apexInfo.IsForPlatform() {
- ctx.InstallFile(a.installDir, a.outputFile.Base(), a.outputFile)
+ if (Bool(a.Module.properties.Installable) || ctx.Host()) && apexInfo.IsForPlatform() &&
+ !a.appProperties.PreventInstall {
+
+ var extraInstalledPaths android.Paths
for _, extra := range a.extraOutputFiles {
- ctx.InstallFile(a.installDir, extra.Base(), extra)
+ installed := ctx.InstallFile(a.installDir, extra.Base(), extra)
+ extraInstalledPaths = append(extraInstalledPaths, installed)
}
+ ctx.InstallFile(a.installDir, a.outputFile.Base(), a.outputFile, extraInstalledPaths...)
}
a.buildAppDependencyInfo(ctx)
@@ -938,6 +942,7 @@
android.InitDefaultableModule(module)
android.InitOverridableModule(module, &module.appProperties.Overrides)
android.InitApexModule(module)
+ android.InitBazelModule(module)
return module
}
@@ -1400,23 +1405,11 @@
Certificate string
}
-func AndroidAppCertificateBp2Build(ctx android.TopDownMutatorContext) {
- module, ok := ctx.Module().(*AndroidAppCertificate)
- if !ok {
- // Not an Android app certificate
- return
- }
- if !module.ConvertWithBp2build(ctx) {
- return
- }
- if ctx.ModuleType() != "android_app_certificate" {
- return
- }
-
- androidAppCertificateBp2BuildInternal(ctx, module)
+func (m *AndroidAppCertificate) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
+ androidAppCertificateBp2Build(ctx, m)
}
-func androidAppCertificateBp2BuildInternal(ctx android.TopDownMutatorContext, module *AndroidAppCertificate) {
+func androidAppCertificateBp2Build(ctx android.TopDownMutatorContext, module *AndroidAppCertificate) {
var certificate string
if module.properties.Certificate != nil {
certificate = *module.properties.Certificate
@@ -1433,3 +1426,39 @@
ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name()}, attrs)
}
+
+type bazelAndroidAppAttributes struct {
+ Srcs bazel.LabelListAttribute
+ Manifest bazel.Label
+ Custom_package *string
+ Resource_files bazel.LabelListAttribute
+}
+
+// ConvertWithBp2build is used to convert android_app to Bazel.
+func (a *AndroidApp) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
+ //TODO(b/209577426): Support multiple arch variants
+ srcs := bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrcExcludes(ctx, a.properties.Srcs, a.properties.Exclude_srcs))
+
+ manifest := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml")
+
+ resourceFiles := bazel.LabelList{
+ Includes: []bazel.Label{},
+ }
+ for _, dir := range android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Resource_dirs, "res") {
+ files := android.RootToModuleRelativePaths(ctx, androidResourceGlob(ctx, dir))
+ resourceFiles.Includes = append(resourceFiles.Includes, files...)
+ }
+
+ attrs := &bazelAndroidAppAttributes{
+ Srcs: srcs,
+ Manifest: android.BazelLabelForModuleSrcSingle(ctx, manifest),
+ // TODO(b/209576404): handle package name override by product variable PRODUCT_MANIFEST_PACKAGE_NAME_OVERRIDES
+ Custom_package: a.overridableAppProperties.Package_name,
+ Resource_files: bazel.MakeLabelListAttribute(resourceFiles),
+ }
+ props := bazel.BazelTargetModuleProperties{Rule_class: "android_binary",
+ Bzl_load_location: "@rules_android//rules:rules.bzl"}
+
+ ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: a.Name()}, attrs)
+
+}
diff --git a/java/app_set.go b/java/app_set.go
index 6b25638..694b167 100644
--- a/java/app_set.go
+++ b/java/app_set.go
@@ -55,10 +55,10 @@
android.DefaultableModuleBase
prebuilt android.Prebuilt
- properties AndroidAppSetProperties
- packedOutput android.WritablePath
- installFile string
- apkcertsFile android.ModuleOutPath
+ properties AndroidAppSetProperties
+ packedOutput android.WritablePath
+ primaryOutput android.WritablePath
+ apkcertsFile android.ModuleOutPath
}
func (as *AndroidAppSet) Name() string {
@@ -78,11 +78,11 @@
}
func (as *AndroidAppSet) OutputFile() android.Path {
- return as.packedOutput
+ return as.primaryOutput
}
-func (as *AndroidAppSet) InstallFile() string {
- return as.installFile
+func (as *AndroidAppSet) PackedAdditionalOutputs() android.Path {
+ return as.packedOutput
}
func (as *AndroidAppSet) APKCertsFile() android.Path {
@@ -114,11 +114,11 @@
func (as *AndroidAppSet) GenerateAndroidBuildActions(ctx android.ModuleContext) {
as.packedOutput = android.PathForModuleOut(ctx, ctx.ModuleName()+".zip")
+ as.primaryOutput = android.PathForModuleOut(ctx, as.BaseModuleName()+".apk")
as.apkcertsFile = android.PathForModuleOut(ctx, "apkcerts.txt")
// We are assuming here that the install file in the APK
// set has `.apk` suffix. If it doesn't the build will fail.
// APK sets containing APEX files are handled elsewhere.
- as.installFile = as.BaseModuleName() + ".apk"
screenDensities := "all"
if dpis := ctx.Config().ProductAAPTPrebuiltDPI(); len(dpis) > 0 {
screenDensities = strings.ToUpper(strings.Join(dpis, ","))
@@ -127,11 +127,11 @@
// TODO(asmundak): do we support device features
ctx.Build(pctx,
android.BuildParams{
- Rule: extractMatchingApks,
- Description: "Extract APKs from APK set",
- Output: as.packedOutput,
- ImplicitOutput: as.apkcertsFile,
- Inputs: android.Paths{as.prebuilt.SingleSourcePath(ctx)},
+ Rule: extractMatchingApks,
+ Description: "Extract APKs from APK set",
+ Output: as.primaryOutput,
+ ImplicitOutputs: android.WritablePaths{as.packedOutput, as.apkcertsFile},
+ Inputs: android.Paths{as.prebuilt.SingleSourcePath(ctx)},
Args: map[string]string{
"abis": strings.Join(SupportedAbis(ctx), ","),
"allow-prereleased": strconv.FormatBool(proptools.Bool(as.properties.Prerelease)),
@@ -140,10 +140,21 @@
"stem": as.BaseModuleName(),
"apkcerts": as.apkcertsFile.String(),
"partition": as.PartitionTag(ctx.DeviceConfig()),
+ "zip": as.packedOutput.String(),
},
})
+
+ var installDir android.InstallPath
+ if as.Privileged() {
+ installDir = android.PathForModuleInstall(ctx, "priv-app", as.BaseModuleName())
+ } else {
+ installDir = android.PathForModuleInstall(ctx, "app", as.BaseModuleName())
+ }
+ ctx.InstallFileWithExtraFilesZip(installDir, as.BaseModuleName()+".apk", as.primaryOutput, as.packedOutput)
}
+func (as *AndroidAppSet) InstallBypassMake() bool { return true }
+
// android_app_set extracts a set of APKs based on the target device
// configuration and installs this set as "split APKs".
// The extracted set always contains an APK whose name is
diff --git a/java/app_set_test.go b/java/app_set_test.go
index adaf71b..03eb667 100644
--- a/java/app_set_test.go
+++ b/java/app_set_test.go
@@ -17,19 +17,20 @@
import (
"fmt"
"reflect"
+ "strings"
"testing"
"android/soong/android"
)
func TestAndroidAppSet(t *testing.T) {
- ctx, _ := testJava(t, `
+ result := PrepareForTestWithJavaDefaultModules.RunTestWithBp(t, `
android_app_set {
name: "foo",
set: "prebuilts/apks/app.apks",
prerelease: true,
}`)
- module := ctx.ModuleForTests("foo", "android_common")
+ module := result.ModuleForTests("foo", "android_common")
const packedSplitApks = "foo.zip"
params := module.Output(packedSplitApks)
if params.Rule == nil {
@@ -41,9 +42,22 @@
if s := params.Args["partition"]; s != "system" {
t.Errorf("wrong partition value: '%s', expected 'system'", s)
}
- mkEntries := android.AndroidMkEntriesForTest(t, ctx, module.Module())[0]
+
+ android.AssertPathRelativeToTopEquals(t, "incorrect output path",
+ "out/soong/.intermediates/foo/android_common/foo.apk", params.Output)
+
+ android.AssertPathsRelativeToTopEquals(t, "incorrect implicit output paths",
+ []string{
+ "out/soong/.intermediates/foo/android_common/foo.zip",
+ "out/soong/.intermediates/foo/android_common/apkcerts.txt",
+ },
+ params.ImplicitOutputs.Paths())
+
+ mkEntries := android.AndroidMkEntriesForTest(t, result.TestContext, module.Module())[0]
actualInstallFile := mkEntries.EntryMap["LOCAL_APK_SET_INSTALL_FILE"]
- expectedInstallFile := []string{"foo.apk"}
+ expectedInstallFile := []string{
+ strings.Replace(params.ImplicitOutputs[0].String(), android.OutSoongDir, result.Config.SoongOutDir(), 1),
+ }
if !reflect.DeepEqual(actualInstallFile, expectedInstallFile) {
t.Errorf("Unexpected LOCAL_APK_SET_INSTALL_FILE value: '%s', expected: '%s',",
actualInstallFile, expectedInstallFile)
diff --git a/java/app_test.go b/java/app_test.go
index 07439fc..4da7c3d 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -144,14 +144,14 @@
}
`)
- testJavaError(t, "platform_apis must be true when sdk_version is empty.", `
+ testJavaError(t, "This module has conflicting settings. sdk_version is empty, which means that this module is build against platform APIs. However platform_apis is not set to true", `
android_app {
name: "bar",
srcs: ["b.java"],
}
`)
- testJavaError(t, "platform_apis must be false when sdk_version is not empty.", `
+ testJavaError(t, "This module has conflicting settings. sdk_version is not empty, which means this module cannot use platform APIs. However platform_apis is set to true.", `
android_app {
name: "bar",
srcs: ["b.java"],
@@ -2873,3 +2873,76 @@
t.Errorf("App does not use library proguard config")
}
}
+
+func TestTargetSdkVersionManifestFixer(t *testing.T) {
+ platform_sdk_codename := "Tiramisu"
+ testCases := []struct {
+ name string
+ targetSdkVersionInBp string
+ targetSdkVersionExpected string
+ unbundledBuild bool
+ }{
+ {
+ name: "Non-Unbundled build: Android.bp has targetSdkVersion",
+ targetSdkVersionInBp: "30",
+ targetSdkVersionExpected: "30",
+ unbundledBuild: false,
+ },
+ {
+ name: "Unbundled build: Android.bp has targetSdkVersion",
+ targetSdkVersionInBp: "30",
+ targetSdkVersionExpected: "30",
+ unbundledBuild: true,
+ },
+ {
+ name: "Non-Unbundled build: Android.bp has targetSdkVersion equal to platform_sdk_codename",
+ targetSdkVersionInBp: platform_sdk_codename,
+ targetSdkVersionExpected: platform_sdk_codename,
+ unbundledBuild: false,
+ },
+ {
+ name: "Unbundled build: Android.bp has targetSdkVersion equal to platform_sdk_codename",
+ targetSdkVersionInBp: platform_sdk_codename,
+ targetSdkVersionExpected: "10000",
+ unbundledBuild: true,
+ },
+
+ {
+ name: "Non-Unbundled build: Android.bp has no targetSdkVersion",
+ targetSdkVersionExpected: platform_sdk_codename,
+ unbundledBuild: false,
+ },
+ {
+ name: "Unbundled build: Android.bp has no targetSdkVersion",
+ targetSdkVersionExpected: "10000",
+ unbundledBuild: true,
+ },
+ }
+ for _, testCase := range testCases {
+ bp := fmt.Sprintf(`
+ android_app {
+ name: "foo",
+ sdk_version: "current",
+ target_sdk_version: "%v",
+ }
+ `, testCase.targetSdkVersionInBp)
+ fixture := android.GroupFixturePreparers(
+ prepareForJavaTest,
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ // explicitly set platform_sdk_codename to make the test deterministic
+ variables.Platform_sdk_codename = &platform_sdk_codename
+ variables.Platform_version_active_codenames = []string{platform_sdk_codename}
+ // create a non-empty list if unbundledBuild==true
+ if testCase.unbundledBuild {
+ variables.Unbundled_build_apps = []string{"apex_a", "apex_b"}
+ }
+ }),
+ )
+
+ result := fixture.RunTestWithBp(t, bp)
+ foo := result.ModuleForTests("foo", "android_common")
+
+ manifestFixerArgs := foo.Output("manifest_fixer/AndroidManifest.xml").Args
+ android.AssertStringEquals(t, testCase.name, testCase.targetSdkVersionExpected, manifestFixerArgs["targetSdkVersion"])
+ }
+}
diff --git a/java/base.go b/java/base.go
index ca34f2e..7cd71a2 100644
--- a/java/base.go
+++ b/java/base.go
@@ -122,6 +122,14 @@
Javacflags []string
}
+ Openjdk11 struct {
+ // List of source files that should only be used when passing -source 1.9 or higher
+ Srcs []string `android:"path"`
+
+ // List of javac flags that should only be used when passing -source 1.9 or higher
+ Javacflags []string
+ }
+
// When compiling language level 9+ .java code in packages that are part of
// a system module, patch_module names the module that your sources and
// dependencies should be patched into. The Android runtime currently
@@ -184,16 +192,25 @@
// Properties that are specific to device modules. Host module factories should not add these when
// constructing a new module.
type DeviceProperties struct {
- // if not blank, set to the version of the sdk to compile against.
+ // If not blank, set to the version of the sdk to compile against.
// Defaults to compiling against the current platform.
+ // Values are of one of the following forms:
+ // 1) numerical API level or "current"
+ // 2) An SDK kind with an API level: "<sdk kind>_<API level>". See
+ // build/soong/android/sdk_version.go for the complete and up to date list of
+ // SDK kinds. If the SDK kind value is empty, it will be set to public.
Sdk_version *string
// if not blank, set the minimum version of the sdk that the compiled artifacts will run against.
- // Defaults to sdk_version if not set.
+ // Defaults to sdk_version if not set. See sdk_version for possible values.
Min_sdk_version *string
+ // if not blank, set the maximum version of the sdk that the compiled artifacts will run against.
+ // Defaults to empty string "". See sdk_version for possible values.
+ Max_sdk_version *string
+
// if not blank, set the targetSdkVersion in the AndroidManifest.xml.
- // Defaults to sdk_version if not set.
+ // Defaults to sdk_version if not set. See sdk_version for possible values.
Target_sdk_version *string
// Whether to compile against the platform APIs instead of an SDK.
@@ -363,6 +380,7 @@
android.DefaultableModuleBase
android.ApexModuleBase
android.SdkBase
+ android.BazelModuleBase
// Functionality common to Module and Import.
embeddableInModuleAndImport
@@ -407,6 +425,9 @@
// installed file for binary dependency
installFile android.Path
+ // installed file for hostdex copy
+ hostdexInstallFile android.InstallPath
+
// list of .java files and srcjars that was passed to javac
compiledJavaSrcs android.Paths
compiledSrcJars android.Paths
@@ -452,6 +473,7 @@
sdkVersion android.SdkSpec
minSdkVersion android.SdkSpec
+ maxSdkVersion android.SdkSpec
}
func (j *Module) CheckStableSdkVersion(ctx android.BaseModuleContext) error {
@@ -502,9 +524,9 @@
usePlatformAPI := proptools.Bool(j.deviceProperties.Platform_apis)
sdkVersionSpecified := sc.SdkVersion(ctx).Specified()
if usePlatformAPI && sdkVersionSpecified {
- ctx.PropertyErrorf("platform_apis", "platform_apis must be false when sdk_version is not empty.")
+ ctx.PropertyErrorf("platform_apis", "This module has conflicting settings. sdk_version is not empty, which means this module cannot use platform APIs. However platform_apis is set to true.")
} else if !usePlatformAPI && !sdkVersionSpecified {
- ctx.PropertyErrorf("platform_apis", "platform_apis must be true when sdk_version is empty.")
+ ctx.PropertyErrorf("platform_apis", "This module has conflicting settings. sdk_version is empty, which means that this module is build against platform APIs. However platform_apis is not set to true")
}
}
@@ -609,6 +631,13 @@
return j.SdkVersion(ctx)
}
+func (j *Module) MaxSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
+ maxSdkVersion := proptools.StringDefault(j.deviceProperties.Max_sdk_version, "")
+ // SdkSpecFrom returns SdkSpecPrivate for this, which may be confusing.
+ // TODO(b/208456999): ideally MaxSdkVersion should be an ApiLevel and not SdkSpec.
+ return android.SdkSpecFrom(ctx, maxSdkVersion)
+}
+
func (j *Module) MinSdkVersionString() string {
return j.minSdkVersion.Raw
}
@@ -784,6 +813,9 @@
flags = append(flags, "--transaction_names")
}
+ aidlMinSdkVersion := j.MinSdkVersion(ctx).ApiLevel.String()
+ flags = append(flags, "--min_sdk_version="+aidlMinSdkVersion)
+
return strings.Join(flags, " "), deps
}
@@ -935,6 +967,10 @@
if flags.javaVersion.usesJavaModules() {
j.properties.Srcs = append(j.properties.Srcs, j.properties.Openjdk9.Srcs...)
}
+ if ctx.Config().TargetsJava11() {
+ j.properties.Srcs = append(j.properties.Srcs, j.properties.Openjdk11.Srcs...)
+ }
+
srcFiles := android.PathsForModuleSrcExcludes(ctx, j.properties.Srcs, j.properties.Exclude_srcs)
if hasSrcExt(srcFiles.Strings(), ".proto") {
flags = protoFlags(ctx, &j.properties, &j.protoProperties, flags)
@@ -1055,7 +1091,7 @@
j.compiledSrcJars = srcJars
enableSharding := false
- var headerJarFileWithoutJarjar android.Path
+ var headerJarFileWithoutDepsOrJarjar android.Path
if ctx.Device() && !ctx.Config().IsEnvFalse("TURBINE_ENABLED") && !deps.disableTurbine {
if j.properties.Javac_shard_size != nil && *(j.properties.Javac_shard_size) > 0 {
enableSharding = true
@@ -1065,7 +1101,7 @@
// allow for the use of annotation processors that do function correctly
// with sharding enabled. See: b/77284273.
}
- headerJarFileWithoutJarjar, j.headerJarFile =
+ headerJarFileWithoutDepsOrJarjar, j.headerJarFile =
j.compileJavaHeader(ctx, uniqueSrcFiles, srcJars, deps, flags, jarName, kotlinJars)
if ctx.Failed() {
return
@@ -1094,7 +1130,9 @@
}
if enableSharding {
- flags.classpath = append(flags.classpath, headerJarFileWithoutJarjar)
+ if headerJarFileWithoutDepsOrJarjar != nil {
+ flags.classpath = append(classpath{headerJarFileWithoutDepsOrJarjar}, flags.classpath...)
+ }
shardSize := int(*(j.properties.Javac_shard_size))
var shardSrcs []android.Paths
if len(uniqueSrcFiles) > 0 {
@@ -1497,7 +1535,7 @@
func (j *Module) compileJavaHeader(ctx android.ModuleContext, srcFiles, srcJars android.Paths,
deps deps, flags javaBuilderFlags, jarName string,
- extraJars android.Paths) (headerJar, jarjarHeaderJar android.Path) {
+ extraJars android.Paths) (headerJar, jarjarAndDepsHeaderJar android.Path) {
var jars android.Paths
if len(srcFiles) > 0 || len(srcJars) > 0 {
@@ -1508,6 +1546,7 @@
return nil, nil
}
jars = append(jars, turbineJar)
+ headerJar = turbineJar
}
jars = append(jars, extraJars...)
@@ -1521,20 +1560,19 @@
combinedJar := android.PathForModuleOut(ctx, "turbine-combined", jarName)
TransformJarsToJar(ctx, combinedJar, "for turbine", jars, android.OptionalPath{},
false, nil, []string{"META-INF/TRANSITIVE"})
- headerJar = combinedJar
- jarjarHeaderJar = combinedJar
+ jarjarAndDepsHeaderJar = combinedJar
if j.expandJarjarRules != nil {
// Transform classes.jar into classes-jarjar.jar
jarjarFile := android.PathForModuleOut(ctx, "turbine-jarjar", jarName)
- TransformJarJar(ctx, jarjarFile, headerJar, j.expandJarjarRules)
- jarjarHeaderJar = jarjarFile
+ TransformJarJar(ctx, jarjarFile, jarjarAndDepsHeaderJar, j.expandJarjarRules)
+ jarjarAndDepsHeaderJar = jarjarFile
if ctx.Failed() {
return nil, nil
}
}
- return headerJar, jarjarHeaderJar
+ return headerJar, jarjarAndDepsHeaderJar
}
func (j *Module) instrument(ctx android.ModuleContext, flags javaBuilderFlags,
@@ -1618,8 +1656,7 @@
}
// Implements android.ApexModule
-func (j *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext,
- sdkVersion android.ApiLevel) error {
+func (j *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion android.ApiLevel) error {
sdkSpec := j.MinSdkVersion(ctx)
if !sdkSpec.Specified() {
return fmt.Errorf("min_sdk_version is not specified")
@@ -1928,3 +1965,17 @@
}
var _ ModuleWithStem = (*Module)(nil)
+
+func (j *Module) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
+ switch ctx.ModuleType() {
+ case "java_library", "java_library_host":
+ if lib, ok := ctx.Module().(*Library); ok {
+ javaLibraryBp2Build(ctx, lib)
+ }
+ case "java_binary_host":
+ if binary, ok := ctx.Module().(*Binary); ok {
+ javaBinaryHostBp2Build(ctx, binary)
+ }
+ }
+
+}
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index bfa6838..bfe895c 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -390,6 +390,13 @@
// 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
+
+ // Path to the image profile file on host (or empty, if profile is not generated).
+ profilePathOnHost android.Path
+
+ // Install path of the boot image profile if it needs to be installed in the APEX, or empty if not
+ // needed.
+ profileInstallPathInApex string
}
func (i BootclasspathFragmentApexContentInfo) Modules() android.ConfiguredJarList {
@@ -418,6 +425,14 @@
}
}
+func (i BootclasspathFragmentApexContentInfo) ProfilePathOnHost() android.Path {
+ return i.profilePathOnHost
+}
+
+func (i BootclasspathFragmentApexContentInfo) ProfileInstallPathInApex() string {
+ return i.profileInstallPathInApex
+}
+
func (b *BootclasspathFragmentModule) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
tag := ctx.OtherModuleDependencyTag(dep)
if IsBootclasspathFragmentContentDepTag(tag) {
@@ -579,6 +594,11 @@
if imageConfig != nil {
info.modules = imageConfig.modules
+ global := dexpreopt.GetGlobalConfig(ctx)
+ if !global.DisableGenerateProfile {
+ info.profilePathOnHost = imageConfig.profilePathOnHost
+ info.profileInstallPathInApex = imageConfig.profileInstallPathInApex
+ }
}
info.bootImageFilesByArch = bootImageFilesByArch
diff --git a/java/builder.go b/java/builder.go
index ae124a3..e64a61f 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -120,14 +120,14 @@
"extractMatchingApks",
blueprint.RuleParams{
Command: `rm -rf "$out" && ` +
- `${config.ExtractApksCmd} -o "${out}" -allow-prereleased=${allow-prereleased} ` +
+ `${config.ExtractApksCmd} -o "${out}" -zip "${zip}" -allow-prereleased=${allow-prereleased} ` +
`-sdk-version=${sdk-version} -abis=${abis} ` +
`--screen-densities=${screen-densities} --stem=${stem} ` +
`-apkcerts=${apkcerts} -partition=${partition} ` +
`${in}`,
CommandDeps: []string{"${config.ExtractApksCmd}"},
},
- "abis", "allow-prereleased", "screen-densities", "sdk-version", "stem", "apkcerts", "partition")
+ "abis", "allow-prereleased", "screen-densities", "sdk-version", "stem", "apkcerts", "partition", "zip")
turbine, turbineRE = pctx.RemoteStaticRules("turbine",
blueprint.RuleParams{
diff --git a/java/classpath_fragment.go b/java/classpath_fragment.go
index f63d81d..ca27528 100644
--- a/java/classpath_fragment.go
+++ b/java/classpath_fragment.go
@@ -25,7 +25,7 @@
"android/soong/android"
)
-// Build rules and utilities to generate individual packages/modules/SdkExtensions/proto/classpaths.proto
+// Build rules and utilities to generate individual packages/modules/common/proto/classpaths.proto
// config files based on build configuration to embed into /system and /apex on a device.
//
// See `derive_classpath` service that reads the configs at runtime and defines *CLASSPATH variables
@@ -34,14 +34,15 @@
type classpathType int
const (
- // Matches definition in packages/modules/SdkExtensions/proto/classpaths.proto
+ // Matches definition in packages/modules/common/proto/classpaths.proto
BOOTCLASSPATH classpathType = iota
DEX2OATBOOTCLASSPATH
SYSTEMSERVERCLASSPATH
+ STANDALONE_SYSTEMSERVER_JARS
)
func (c classpathType) String() string {
- return [...]string{"BOOTCLASSPATH", "DEX2OATBOOTCLASSPATH", "SYSTEMSERVERCLASSPATH"}[c]
+ return [...]string{"BOOTCLASSPATH", "DEX2OATBOOTCLASSPATH", "SYSTEMSERVERCLASSPATH", "STANDALONE_SYSTEMSERVER_JARS"}[c]
}
type classpathFragmentProperties struct {
@@ -84,11 +85,10 @@
// Matches definition of Jar in packages/modules/SdkExtensions/proto/classpaths.proto
type classpathJar struct {
- path string
- classpath classpathType
- // TODO(satayev): propagate min/max sdk versions for the jars
- minSdkVersion int32
- maxSdkVersion int32
+ path string
+ classpath classpathType
+ minSdkVersion string
+ maxSdkVersion string
}
// gatherPossibleApexModuleNamesAndStems returns a set of module and stem names from the
@@ -120,10 +120,32 @@
jars := make([]classpathJar, 0, len(paths)*len(classpaths))
for i := 0; i < len(paths); i++ {
for _, classpathType := range classpaths {
- jars = append(jars, classpathJar{
+ jar := classpathJar{
classpath: classpathType,
path: paths[i],
+ }
+ ctx.VisitDirectDepsIf(func(m android.Module) bool {
+ return m.Name() == configuredJars.Jar(i)
+ }, func(m android.Module) {
+ if s, ok := m.(*SdkLibrary); ok {
+ // TODO(208456999): instead of mapping "current" to latest, min_sdk_version should never be set to "current"
+ if s.minSdkVersion.Specified() {
+ if s.minSdkVersion.ApiLevel.IsCurrent() {
+ jar.minSdkVersion = ctx.Config().LatestPreviewApiLevel().String()
+ } else {
+ jar.minSdkVersion = s.minSdkVersion.ApiLevel.String()
+ }
+ }
+ if s.maxSdkVersion.Specified() {
+ if s.maxSdkVersion.ApiLevel.IsCurrent() {
+ jar.maxSdkVersion = ctx.Config().LatestPreviewApiLevel().String()
+ } else {
+ jar.maxSdkVersion = s.maxSdkVersion.ApiLevel.String()
+ }
+ }
+ }
})
+ jars = append(jars, jar)
}
}
return jars
@@ -136,15 +158,15 @@
c.outputFilepath = android.PathForModuleOut(ctx, outputFilename).OutputPath
c.installDirPath = android.PathForModuleInstall(ctx, "etc", "classpaths")
- generatedJson := android.PathForModuleOut(ctx, outputFilename+".json")
- writeClasspathsJson(ctx, generatedJson, jars)
+ generatedTextproto := android.PathForModuleOut(ctx, outputFilename+".textproto")
+ writeClasspathsTextproto(ctx, generatedTextproto, jars)
rule := android.NewRuleBuilder(pctx, ctx)
rule.Command().
BuiltTool("conv_classpaths_proto").
Flag("encode").
- Flag("--format=json").
- FlagWithInput("--input=", generatedJson).
+ Flag("--format=textproto").
+ FlagWithInput("--input=", generatedTextproto).
FlagWithOutput("--output=", c.outputFilepath)
rule.Build("classpath_fragment", "Compiling "+c.outputFilepath.String())
@@ -159,24 +181,18 @@
ctx.SetProvider(ClasspathFragmentProtoContentInfoProvider, classpathProtoInfo)
}
-func writeClasspathsJson(ctx android.ModuleContext, output android.WritablePath, jars []classpathJar) {
+func writeClasspathsTextproto(ctx android.ModuleContext, output android.WritablePath, jars []classpathJar) {
var content strings.Builder
- fmt.Fprintf(&content, "{\n")
- fmt.Fprintf(&content, "\"jars\": [\n")
- for idx, jar := range jars {
- fmt.Fprintf(&content, "{\n")
- fmt.Fprintf(&content, "\"path\": \"%s\",\n", jar.path)
- fmt.Fprintf(&content, "\"classpath\": \"%s\"\n", jar.classpath)
-
- if idx < len(jars)-1 {
- fmt.Fprintf(&content, "},\n")
- } else {
- fmt.Fprintf(&content, "}\n")
- }
+ for _, jar := range jars {
+ fmt.Fprintf(&content, "jars {\n")
+ fmt.Fprintf(&content, "path: \"%s\"\n", jar.path)
+ fmt.Fprintf(&content, "classpath: %s\n", jar.classpath)
+ fmt.Fprintf(&content, "min_sdk_version: \"%s\"\n", jar.minSdkVersion)
+ fmt.Fprintf(&content, "max_sdk_version: \"%s\"\n", jar.maxSdkVersion)
+ fmt.Fprintf(&content, "}\n")
}
- fmt.Fprintf(&content, "]\n")
- fmt.Fprintf(&content, "}\n")
+
android.WriteFileRule(ctx, output, content.String())
}
@@ -188,7 +204,7 @@
OutputFile: android.OptionalPathForPath(c.outputFilepath),
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- entries.SetString("LOCAL_MODULE_PATH", c.installDirPath.ToMakePath().String())
+ entries.SetString("LOCAL_MODULE_PATH", c.installDirPath.String())
entries.SetString("LOCAL_INSTALLED_MODULE_STEM", c.outputFilepath.Base())
},
},
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index e9dc982..e9bc518 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -66,6 +66,7 @@
isApp bool
isTest bool
isPresignedPrebuilt bool
+ preventInstall bool
manifestFile android.Path
statusFile android.WritablePath
@@ -114,6 +115,11 @@
return !apexInfo.IsForPlatform()
}
+func forPrebuiltApex(ctx android.BaseModuleContext) bool {
+ apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+ return apexInfo.ForPrebuiltApex
+}
+
func moduleName(ctx android.BaseModuleContext) string {
// Remove the "prebuilt_" prefix if the module is from a prebuilt because the prefix is not
// expected by dexpreopter.
@@ -121,13 +127,7 @@
}
func (d *dexpreopter) dexpreoptDisabled(ctx android.BaseModuleContext) bool {
- global := dexpreopt.GetGlobalConfig(ctx)
-
- if global.DisablePreopt {
- return true
- }
-
- if inList(moduleName(ctx), global.DisablePreoptModules) {
+ if !ctx.Device() {
return true
}
@@ -139,31 +139,40 @@
return true
}
- if !ctx.Module().(DexpreopterInterface).IsInstallable() {
+ // If the module is from a prebuilt APEX, it shouldn't be installable, but it can still be
+ // dexpreopted.
+ if !ctx.Module().(DexpreopterInterface).IsInstallable() && !forPrebuiltApex(ctx) {
return true
}
- if ctx.Host() {
- return true
- }
-
- if isApexVariant(ctx) {
- // Don't preopt APEX variant module unless the module is an APEX system server jar and we are
- // building the entire system image.
- if !global.ApexSystemServerJars.ContainsJar(moduleName(ctx)) || ctx.Config().UnbundledBuild() {
- return true
- }
- } else {
- // Don't preopt the platform variant of an APEX system server jar to avoid conflicts.
- if global.ApexSystemServerJars.ContainsJar(moduleName(ctx)) {
- return true
- }
- }
-
if !android.IsModulePreferred(ctx.Module()) {
return true
}
+ global := dexpreopt.GetGlobalConfig(ctx)
+
+ if global.DisablePreopt {
+ return true
+ }
+
+ if inList(moduleName(ctx), global.DisablePreoptModules) {
+ return true
+ }
+
+ isApexSystemServerJar := global.AllApexSystemServerJars(ctx).ContainsJar(moduleName(ctx))
+ if isApexVariant(ctx) {
+ // Don't preopt APEX variant module unless the module is an APEX system server jar and we are
+ // building the entire system image.
+ if !isApexSystemServerJar || ctx.Config().UnbundledBuild() {
+ return true
+ }
+ } else {
+ // Don't preopt the platform variant of an APEX system server jar to avoid conflicts.
+ if isApexSystemServerJar {
+ return true
+ }
+ }
+
// TODO: contains no java code
return false
@@ -190,8 +199,8 @@
func (d *dexpreopter) getInstallPath(
ctx android.ModuleContext, defaultInstallPath android.InstallPath) android.InstallPath {
global := dexpreopt.GetGlobalConfig(ctx)
- if global.ApexSystemServerJars.ContainsJar(moduleName(ctx)) {
- dexLocation := dexpreopt.GetSystemServerDexLocation(global, moduleName(ctx))
+ if global.AllApexSystemServerJars(ctx).ContainsJar(moduleName(ctx)) {
+ dexLocation := dexpreopt.GetSystemServerDexLocation(ctx, global, moduleName(ctx))
return android.PathForModuleInPartitionInstall(ctx, "", strings.TrimPrefix(dexLocation, "/"))
}
if !d.dexpreoptDisabled(ctx) && isApexVariant(ctx) &&
@@ -228,8 +237,7 @@
return
}
- isSystemServerJar := global.SystemServerJars.ContainsJar(moduleName(ctx)) ||
- global.ApexSystemServerJars.ContainsJar(moduleName(ctx))
+ isSystemServerJar := global.AllSystemServerJars(ctx).ContainsJar(moduleName(ctx))
bootImage := defaultBootImageConfig(ctx)
if global.UseArtImage {
@@ -335,17 +343,21 @@
dexpreoptRule.Build("dexpreopt", "dexpreopt")
- if global.ApexSystemServerJars.ContainsJar(moduleName(ctx)) {
- // APEX variants of java libraries are hidden from Make, so their dexpreopt outputs need special
- // handling. Currently, for APEX variants of java libraries, only those in the system server
- // classpath are handled here. Preopting of boot classpath jars in the ART APEX are handled in
- // java/dexpreopt_bootjars.go, and other APEX jars are not preopted.
- for _, install := range dexpreoptRule.Installs() {
- // 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)
- arch := filepath.Base(installDir)
- installPath := android.PathForModuleInPartitionInstall(ctx, "", installDir)
+ isApexSystemServerJar := global.AllApexSystemServerJars(ctx).ContainsJar(moduleName(ctx))
+
+ for _, install := range dexpreoptRule.Installs() {
+ // 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)
+ arch := filepath.Base(installDir)
+ installPath := android.PathForModuleInPartitionInstall(ctx, "", installDir)
+
+ if isApexSystemServerJar {
+ // APEX variants of java libraries are hidden from Make, so their dexpreopt
+ // outputs need special handling. Currently, for APEX variants of java
+ // libraries, only those in the system server classpath are handled here.
+ // Preopting of boot classpath jars in the ART APEX are handled in
+ // java/dexpreopt_bootjars.go, and other APEX jars are not preopted.
// The installs will be handled by Make as sub-modules of the java library.
d.builtInstalledForApex = append(d.builtInstalledForApex, dexpreopterInstall{
name: arch + "-" + installBase,
@@ -354,10 +366,12 @@
installDirOnDevice: installPath,
installFileOnDevice: installBase,
})
+ } else if !d.preventInstall {
+ ctx.InstallFile(installPath, installBase, install.From)
}
- } else {
- // The installs will be handled by Make as LOCAL_SOONG_BUILT_INSTALLED of the java library
- // module.
+ }
+
+ if !isApexSystemServerJar {
d.builtInstalled = dexpreoptRule.Installs().String()
}
}
@@ -376,7 +390,7 @@
OutputFile: android.OptionalPathForPath(install.outputPathOnHost),
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- entries.SetString("LOCAL_MODULE_PATH", install.installDirOnDevice.ToMakePath().String())
+ entries.SetString("LOCAL_MODULE_PATH", install.installDirOnDevice.String())
entries.SetString("LOCAL_INSTALLED_MODULE_STEM", install.installFileOnDevice)
entries.SetString("LOCAL_NOT_AVAILABLE_FOR_PLATFORM", "false")
},
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 284a19a..c599c4d 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -256,6 +256,10 @@
// Subdirectory where the image files on device are installed.
installDirOnDevice string
+ // Install path of the boot image profile if it needs to be installed in the APEX, or empty if not
+ // needed.
+ profileInstallPathInApex string
+
// A list of (location, jar) pairs for the Java modules in this image.
modules android.ConfiguredJarList
@@ -272,6 +276,9 @@
// Rules which should be used in make to install the outputs.
profileInstalls android.RuleBuilderInstalls
+ // Path to the image profile file on host (or empty, if profile is not generated).
+ profilePathOnHost android.Path
+
// Target-dependent fields.
variants []*bootImageVariant
}
@@ -499,8 +506,18 @@
dst := dstBootJarsByModule[name]
if src == nil {
+ // A dex boot jar should be provided by the source java module. It needs to be installable or
+ // have compile_dex=true - cf. assignments to java.Module.dexJarFile.
+ //
+ // However, the source java module may be either replaced or overridden (using prefer:true) by
+ // a prebuilt java module with the same name. In that case the dex boot jar needs to be
+ // provided by the corresponding prebuilt APEX module. That APEX is the one that refers
+ // through a exported_(boot|systemserver)classpath_fragments property to a
+ // prebuilt_(boot|systemserver)classpath_fragment module, which in turn lists the prebuilt
+ // java module in the contents property. If that chain is broken then this dependency will
+ // fail.
if !ctx.Config().AllowMissingDependencies() {
- ctx.ModuleErrorf("module %s does not provide a dex boot jar", name)
+ ctx.ModuleErrorf("module %s does not provide a dex boot jar (see comment next to this message in Soong for details)", name)
} else {
ctx.AddMissingDependencies([]string{name})
}
@@ -625,7 +642,6 @@
Flag("--runtime-arg").FlagWithArg("-Xmx", global.Dex2oatImageXmx)
if profile != nil {
- cmd.FlagWithArg("--compiler-filter=", "speed-profile")
cmd.FlagWithInput("--profile-file=", profile)
}
@@ -770,11 +786,14 @@
FlagForEachArg("--dex-location=", image.getAnyAndroidVariant().dexLocationsDeps).
FlagWithOutput("--reference-profile-file=", profile)
- rule.Install(profile, "/system/etc/boot-image.prof")
+ if image == defaultBootImageConfig(ctx) {
+ rule.Install(profile, "/system/etc/boot-image.prof")
+ image.profileInstalls = append(image.profileInstalls, rule.Installs()...)
+ }
rule.Build("bootJarsProfile", "profile boot jars")
- image.profileInstalls = append(image.profileInstalls, rule.Installs()...)
+ image.profilePathOnHost = profile
return profile
}
diff --git a/java/dexpreopt_check.go b/java/dexpreopt_check.go
index 565901d..83c088c 100644
--- a/java/dexpreopt_check.go
+++ b/java/dexpreopt_check.go
@@ -59,7 +59,7 @@
func getInstallPath(ctx android.ModuleContext, location string) android.InstallPath {
return android.PathForModuleInPartitionInstall(
- ctx, "", strings.TrimPrefix(location, "/")).ToMakePath()
+ ctx, "", strings.TrimPrefix(location, "/"))
}
func (m *dexpreoptSystemserverCheck) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -72,9 +72,9 @@
return
}
- systemServerJars := dexpreopt.AllSystemServerJars(ctx, global)
+ systemServerJars := global.AllSystemServerJars(ctx)
for _, jar := range systemServerJars.CopyOfJars() {
- dexLocation := dexpreopt.GetSystemServerDexLocation(global, jar)
+ dexLocation := dexpreopt.GetSystemServerDexLocation(ctx, global, jar)
odexLocation := dexpreopt.ToOdexPath(dexLocation, targets[0].Arch.ArchType)
odexPath := getInstallPath(ctx, odexLocation)
vdexPath := getInstallPath(ctx, pathtools.ReplaceExtension(odexLocation, "vdex"))
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index 415a1d4..26c1105 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -56,22 +56,20 @@
artModules := global.ArtApexJars
frameworkModules := global.BootJars.RemoveList(artModules)
- artDirOnHost := "apex/art_boot_images/javalib"
- artDirOnDevice := "apex/com.android.art/javalib"
- frameworkSubdir := "system/framework"
-
// ART config for the primary boot image in the ART apex.
// It includes the Core Libraries.
artCfg := bootImageConfig{
- name: artBootImageName,
- stem: "boot",
- installDirOnHost: artDirOnHost,
- installDirOnDevice: artDirOnDevice,
- modules: artModules,
+ name: artBootImageName,
+ stem: "boot",
+ installDirOnHost: "apex/art_boot_images/javalib",
+ installDirOnDevice: "apex/com.android.art/javalib",
+ profileInstallPathInApex: "etc/boot-image.prof",
+ modules: artModules,
}
// Framework config for the boot image extension.
// It includes framework libraries and depends on the ART config.
+ frameworkSubdir := "system/framework"
frameworkCfg := bootImageConfig{
extends: &artCfg,
name: frameworkBootImageName,
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 869a598..c84a15c 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -769,8 +769,8 @@
d.Javadoc.docZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"docs.zip")
- jsilver := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", "jsilver.jar")
- doclava := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", "doclava.jar")
+ jsilver := ctx.Config().HostJavaToolPath(ctx, "jsilver.jar")
+ doclava := ctx.Config().HostJavaToolPath(ctx, "doclava.jar")
outDir := android.PathForModuleOut(ctx, "out")
srcJarDir := android.PathForModuleOut(ctx, "srcjars")
diff --git a/java/droidstubs.go b/java/droidstubs.go
index 0c66ccf..7ad316f 100644
--- a/java/droidstubs.go
+++ b/java/droidstubs.go
@@ -16,6 +16,7 @@
import (
"fmt"
+ "path/filepath"
"strings"
"github.com/google/blueprint/proptools"
@@ -805,7 +806,7 @@
properties PrebuiltStubsSourcesProperties
- stubsSrcJar android.ModuleOutPath
+ stubsSrcJar android.Path
}
func (p *PrebuiltStubsSources) OutputFiles(tag string) (android.Paths, error) {
@@ -822,35 +823,39 @@
}
func (p *PrebuiltStubsSources) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- p.stubsSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar")
-
if len(p.properties.Srcs) != 1 {
- ctx.PropertyErrorf("srcs", "must only specify one directory path, contains %d paths", len(p.properties.Srcs))
+ ctx.PropertyErrorf("srcs", "must only specify one directory path or srcjar, contains %d paths", len(p.properties.Srcs))
return
}
- localSrcDir := p.properties.Srcs[0]
- // Although PathForModuleSrc can return nil if either the path doesn't exist or
- // the path components are invalid it won't in this case because no components
- // are specified and the module directory must exist in order to get this far.
- srcDir := android.PathForModuleSrc(ctx).(android.SourcePath).Join(ctx, localSrcDir)
+ src := p.properties.Srcs[0]
+ if filepath.Ext(src) == ".srcjar" {
+ // This is a srcjar. We can use it directly.
+ p.stubsSrcJar = android.PathForModuleSrc(ctx, src)
+ } else {
+ outPath := android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar")
- // Glob the contents of the directory just in case the directory does not exist.
- srcGlob := localSrcDir + "/**/*"
- srcPaths := android.PathsForModuleSrc(ctx, []string{srcGlob})
+ // This is a directory. Glob the contents just in case the directory does not exist.
+ srcGlob := src + "/**/*"
+ srcPaths := android.PathsForModuleSrc(ctx, []string{srcGlob})
- rule := android.NewRuleBuilder(pctx, ctx)
- rule.Command().
- BuiltTool("soong_zip").
- Flag("-write_if_changed").
- Flag("-jar").
- FlagWithOutput("-o ", p.stubsSrcJar).
- FlagWithArg("-C ", srcDir.String()).
- FlagWithRspFileInputList("-r ", p.stubsSrcJar.ReplaceExtension(ctx, "rsp"), srcPaths)
+ // Although PathForModuleSrc can return nil if either the path doesn't exist or
+ // the path components are invalid it won't in this case because no components
+ // are specified and the module directory must exist in order to get this far.
+ srcDir := android.PathForModuleSrc(ctx).(android.SourcePath).Join(ctx, src)
- rule.Restat()
-
- rule.Build("zip src", "Create srcjar from prebuilt source")
+ rule := android.NewRuleBuilder(pctx, ctx)
+ rule.Command().
+ BuiltTool("soong_zip").
+ Flag("-write_if_changed").
+ Flag("-jar").
+ FlagWithOutput("-o ", outPath).
+ FlagWithArg("-C ", srcDir.String()).
+ FlagWithRspFileInputList("-r ", outPath.ReplaceExtension(ctx, "rsp"), srcPaths)
+ rule.Restat()
+ rule.Build("zip src", "Create srcjar from prebuilt source")
+ p.stubsSrcJar = outPath
+ }
}
func (p *PrebuiltStubsSources) Prebuilt() *android.Prebuilt {
diff --git a/java/fuzz.go b/java/fuzz.go
new file mode 100644
index 0000000..f72bfff
--- /dev/null
+++ b/java/fuzz.go
@@ -0,0 +1,72 @@
+// 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"
+
+ "android/soong/android"
+ "android/soong/fuzz"
+)
+
+func init() {
+ RegisterJavaFuzzBuildComponents(android.InitRegistrationContext)
+}
+
+func RegisterJavaFuzzBuildComponents(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("java_fuzz_host", FuzzFactory)
+}
+
+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)
+
+ module.initModuleAndImport(module)
+ android.InitSdkAwareModule(module)
+ InitJavaModule(module, android.HostSupported)
+ return module
+}
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 854097b..9b4a005 100644
--- a/java/java.go
+++ b/java/java.go
@@ -21,7 +21,9 @@
import (
"fmt"
"path/filepath"
+ "strings"
+ "android/soong/bazel"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
@@ -268,6 +270,9 @@
type dependencyTag struct {
blueprint.BaseDependencyTag
name string
+
+ // True if the dependency is relinked at runtime.
+ runtimeLinked bool
}
// installDependencyTag is a dependency tag that is annotated to cause the installed files of the
@@ -278,6 +283,15 @@
name string
}
+func (d dependencyTag) LicenseAnnotations() []android.LicenseAnnotation {
+ if d.runtimeLinked {
+ return []android.LicenseAnnotation{android.LicenseAnnotationSharedDependency}
+ }
+ return nil
+}
+
+var _ android.LicenseAnnotationsDependencyTag = dependencyTag{}
+
type usesLibraryDependencyTag struct {
dependencyTag
@@ -294,10 +308,13 @@
func makeUsesLibraryDependencyTag(sdkVersion int, optional bool, implicit bool) usesLibraryDependencyTag {
return usesLibraryDependencyTag{
- dependencyTag: dependencyTag{name: fmt.Sprintf("uses-library-%d", sdkVersion)},
- sdkVersion: sdkVersion,
- optional: optional,
- implicit: implicit,
+ dependencyTag: dependencyTag{
+ name: fmt.Sprintf("uses-library-%d", sdkVersion),
+ runtimeLinked: true,
+ },
+ sdkVersion: sdkVersion,
+ optional: optional,
+ implicit: implicit,
}
}
@@ -308,22 +325,22 @@
var (
dataNativeBinsTag = dependencyTag{name: "dataNativeBins"}
staticLibTag = dependencyTag{name: "staticlib"}
- libTag = dependencyTag{name: "javalib"}
- java9LibTag = dependencyTag{name: "java9lib"}
+ libTag = dependencyTag{name: "javalib", runtimeLinked: true}
+ java9LibTag = dependencyTag{name: "java9lib", runtimeLinked: true}
pluginTag = dependencyTag{name: "plugin"}
errorpronePluginTag = dependencyTag{name: "errorprone-plugin"}
exportedPluginTag = dependencyTag{name: "exported-plugin"}
- bootClasspathTag = dependencyTag{name: "bootclasspath"}
- systemModulesTag = dependencyTag{name: "system modules"}
+ bootClasspathTag = dependencyTag{name: "bootclasspath", runtimeLinked: true}
+ systemModulesTag = dependencyTag{name: "system modules", runtimeLinked: true}
frameworkResTag = dependencyTag{name: "framework-res"}
- kotlinStdlibTag = dependencyTag{name: "kotlin-stdlib"}
- kotlinAnnotationsTag = dependencyTag{name: "kotlin-annotations"}
+ kotlinStdlibTag = dependencyTag{name: "kotlin-stdlib", runtimeLinked: true}
+ kotlinAnnotationsTag = dependencyTag{name: "kotlin-annotations", runtimeLinked: true}
kotlinPluginTag = dependencyTag{name: "kotlin-plugin"}
proguardRaiseTag = dependencyTag{name: "proguard-raise"}
certificateTag = dependencyTag{name: "certificate"}
instrumentationForTag = dependencyTag{name: "instrumentation_for"}
extraLintCheckTag = dependencyTag{name: "extra-lint-check"}
- jniLibTag = dependencyTag{name: "jnilib"}
+ jniLibTag = dependencyTag{name: "jnilib", runtimeLinked: true}
syspropPublicStubDepTag = dependencyTag{name: "sysprop public stub"}
jniInstallTag = installDependencyTag{name: "jni install"}
binaryInstallTag = installDependencyTag{name: "binary install"}
@@ -432,6 +449,12 @@
return normalizeJavaVersion(ctx, javaVersion)
} else if ctx.Device() {
return defaultJavaLanguageVersion(ctx, sdkContext.SdkVersion(ctx))
+ } else if ctx.Config().TargetsJava11() {
+ // Temporary experimental flag to be able to try and build with
+ // java version 11 options. The flag, if used, just sets Java
+ // 11 as the default version, leaving any components that
+ // target an older version intact.
+ return JAVA_VERSION_11
} else {
return JAVA_VERSION_9
}
@@ -445,6 +468,7 @@
JAVA_VERSION_7 = 7
JAVA_VERSION_8 = 8
JAVA_VERSION_9 = 9
+ JAVA_VERSION_11 = 11
)
func (v javaVersion) String() string {
@@ -457,6 +481,8 @@
return "1.8"
case JAVA_VERSION_9:
return "1.9"
+ case JAVA_VERSION_11:
+ return "11"
default:
return "unsupported"
}
@@ -477,8 +503,10 @@
return JAVA_VERSION_8
case "1.9", "9":
return JAVA_VERSION_9
- case "10", "11":
- ctx.PropertyErrorf("java_version", "Java language levels above 9 are not supported")
+ case "11":
+ return JAVA_VERSION_11
+ case "10":
+ ctx.PropertyErrorf("java_version", "Java language levels 10 is not supported")
return JAVA_VERSION_UNSUPPORTED
default:
ctx.PropertyErrorf("java_version", "Unrecognized Java language level")
@@ -543,6 +571,7 @@
func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) {
j.sdkVersion = j.SdkVersion(ctx)
j.minSdkVersion = j.MinSdkVersion(ctx)
+ j.maxSdkVersion = j.MaxSdkVersion(ctx)
apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
if !apexInfo.IsForPlatform() {
@@ -567,8 +596,23 @@
if j.InstallMixin != nil {
extraInstallDeps = j.InstallMixin(ctx, j.outputFile)
}
- j.installFile = ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"),
- j.Stem()+".jar", j.outputFile, extraInstallDeps...)
+ hostDexNeeded := Bool(j.deviceProperties.Hostdex) && !ctx.Host()
+ if hostDexNeeded {
+ j.hostdexInstallFile = ctx.InstallFile(
+ android.PathForHostDexInstall(ctx, "framework"),
+ j.Stem()+"-hostdex.jar", j.outputFile)
+ }
+ var installDir android.InstallPath
+ if ctx.InstallInTestcases() {
+ var archDir string
+ if !ctx.Host() {
+ archDir = ctx.DeviceConfig().DeviceArch()
+ }
+ installDir = android.PathForModuleInstall(ctx, ctx.ModuleName(), archDir)
+ } else {
+ installDir = android.PathForModuleInstall(ctx, "framework")
+ }
+ j.installFile = ctx.InstallFile(installDir, j.Stem()+".jar", j.outputFile, extraInstallDeps...)
}
}
@@ -712,6 +756,7 @@
android.InitApexModule(module)
android.InitSdkAwareModule(module)
+ android.InitBazelModule(module)
InitJavaModule(module, android.HostAndDeviceSupported)
return module
}
@@ -734,6 +779,7 @@
android.InitApexModule(module)
android.InitSdkAwareModule(module)
+ android.InitBazelModule(module)
InitJavaModule(module, android.HostSupported)
return module
}
@@ -842,6 +888,20 @@
dexJarFile android.Path
}
+func (j *Test) InstallInTestcases() bool {
+ // Host java tests install into $(HOST_OUT_JAVA_LIBRARIES), and then are copied into
+ // testcases by base_rules.mk.
+ return !j.Host()
+}
+
+func (j *TestHelperLibrary) InstallInTestcases() bool {
+ return true
+}
+
+func (j *JavaTestImport) InstallInTestcases() bool {
+ return true
+}
+
func (j *TestHost) DepsMutator(ctx android.BottomUpMutatorContext) {
if len(j.testHostProperties.Data_native_bins) > 0 {
for _, target := range ctx.MultiTargets() {
@@ -1170,6 +1230,8 @@
android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommonFirst)
android.InitDefaultableModule(module)
+ android.InitBazelModule(module)
+
return module
}
@@ -1187,6 +1249,7 @@
android.InitAndroidArchModule(module, android.HostSupported, android.MultilibCommonFirst)
android.InitDefaultableModule(module)
+ android.InitBazelModule(module)
return module
}
@@ -1376,8 +1439,17 @@
})
if Bool(j.properties.Installable) {
- ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"),
- jarName, outputFile)
+ var installDir android.InstallPath
+ if ctx.InstallInTestcases() {
+ var archDir string
+ if !ctx.Host() {
+ archDir = ctx.DeviceConfig().DeviceArch()
+ }
+ installDir = android.PathForModuleInstall(ctx, ctx.ModuleName(), archDir)
+ } else {
+ installDir = android.PathForModuleInstall(ctx, "framework")
+ }
+ ctx.InstallFile(installDir, jarName, outputFile)
}
j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.properties.Aidl.Export_include_dirs)
@@ -1894,3 +1966,103 @@
clcMap.AddContextMap(dep.ClassLoaderContexts(), depName)
}
}
+
+type javaLibraryAttributes struct {
+ Srcs bazel.LabelListAttribute
+ Deps bazel.LabelListAttribute
+ Javacopts bazel.StringListAttribute
+}
+
+func javaLibraryBp2Build(ctx android.TopDownMutatorContext, m *Library) {
+ srcs := bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs))
+ attrs := &javaLibraryAttributes{
+ Srcs: srcs,
+ }
+
+ if m.properties.Javacflags != nil {
+ attrs.Javacopts = bazel.MakeStringListAttribute(m.properties.Javacflags)
+ }
+
+ if m.properties.Libs != nil {
+ attrs.Deps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, m.properties.Libs))
+ }
+
+ props := bazel.BazelTargetModuleProperties{
+ Rule_class: "java_library",
+ Bzl_load_location: "//build/bazel/rules/java:library.bzl",
+ }
+
+ ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
+}
+
+type javaBinaryHostAttributes struct {
+ Srcs bazel.LabelListAttribute
+ Deps bazel.LabelListAttribute
+ Main_class string
+ Jvm_flags bazel.StringListAttribute
+}
+
+// JavaBinaryHostBp2Build is for java_binary_host bp2build.
+func javaBinaryHostBp2Build(ctx android.TopDownMutatorContext, m *Binary) {
+ mainClass := ""
+ if m.binaryProperties.Main_class != nil {
+ mainClass = *m.binaryProperties.Main_class
+ }
+ if m.properties.Manifest != nil {
+ mainClassInManifest, err := android.GetMainClassInManifest(ctx.Config(), android.PathForModuleSrc(ctx, *m.properties.Manifest).String())
+ if err != nil {
+ return
+ }
+ mainClass = mainClassInManifest
+ }
+ srcs := bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs))
+ attrs := &javaBinaryHostAttributes{
+ Srcs: srcs,
+ Main_class: mainClass,
+ }
+
+ // Attribute deps
+ deps := []string{}
+ if m.properties.Static_libs != nil {
+ deps = append(deps, m.properties.Static_libs...)
+ }
+ if m.binaryProperties.Jni_libs != nil {
+ deps = append(deps, m.binaryProperties.Jni_libs...)
+ }
+ if len(deps) > 0 {
+ attrs.Deps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, deps))
+ }
+
+ // Attribute jvm_flags
+ if m.binaryProperties.Jni_libs != nil {
+ jniLibPackages := map[string]bool{}
+ for _, jniLibLabel := range android.BazelLabelForModuleDeps(ctx, m.binaryProperties.Jni_libs).Includes {
+ jniLibPackage := jniLibLabel.Label
+ indexOfColon := strings.Index(jniLibLabel.Label, ":")
+ if indexOfColon > 0 {
+ // JNI lib from other package
+ jniLibPackage = jniLibLabel.Label[2:indexOfColon]
+ } else if indexOfColon == 0 {
+ // JNI lib in the same package of java_binary
+ packageOfCurrentModule := m.GetBazelLabel(ctx, m)
+ jniLibPackage = packageOfCurrentModule[2:strings.Index(packageOfCurrentModule, ":")]
+ }
+ if _, inMap := jniLibPackages[jniLibPackage]; !inMap {
+ jniLibPackages[jniLibPackage] = true
+ }
+ }
+ jniLibPaths := []string{}
+ for jniLibPackage, _ := range jniLibPackages {
+ // See cs/f:.*/third_party/bazel/.*java_stub_template.txt for the use of RUNPATH
+ jniLibPaths = append(jniLibPaths, "$${RUNPATH}"+jniLibPackage)
+ }
+ attrs.Jvm_flags = bazel.MakeStringListAttribute([]string{"-Djava.library.path=" + strings.Join(jniLibPaths, ":")})
+ }
+
+ props := bazel.BazelTargetModuleProperties{
+ Rule_class: "java_binary",
+ }
+
+ // Create the BazelTargetModule.
+ ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
+}
diff --git a/java/java_test.go b/java/java_test.go
index bc9b409..6e4e673 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -988,11 +988,11 @@
}
`)
- barHeaderJar := filepath.Join("out", "soong", ".intermediates", "bar", "android_common", "turbine-combined", "bar.jar")
+ barHeaderJar := filepath.Join("out", "soong", ".intermediates", "bar", "android_common", "turbine", "bar.jar")
for i := 0; i < 3; i++ {
barJavac := ctx.ModuleForTests("bar", "android_common").Description("javac" + strconv.Itoa(i))
- if !strings.Contains(barJavac.Args["classpath"], barHeaderJar) {
- t.Errorf("bar javac classpath %v does not contain %q", barJavac.Args["classpath"], barHeaderJar)
+ if !strings.HasPrefix(barJavac.Args["classpath"], "-classpath "+barHeaderJar+":") {
+ t.Errorf("bar javac classpath %v does start with %q", barJavac.Args["classpath"], barHeaderJar)
}
}
}
@@ -1357,6 +1357,36 @@
}
}
+func TestAidlFlagsWithMinSdkVersion(t *testing.T) {
+ fixture := android.GroupFixturePreparers(
+ prepareForJavaTest, FixtureWithPrebuiltApis(map[string][]string{"14": {"foo"}}))
+
+ for _, tc := range []struct {
+ name string
+ sdkVersion string
+ expected string
+ }{
+ {"default is current", "", "current"},
+ {"use sdk_version", `sdk_version: "14"`, "14"},
+ {"system_current", `sdk_version: "system_current"`, "current"},
+ } {
+ t.Run(tc.name, func(t *testing.T) {
+ ctx := fixture.RunTestWithBp(t, `
+ java_library {
+ name: "foo",
+ srcs: ["aidl/foo/IFoo.aidl"],
+ `+tc.sdkVersion+`
+ }
+ `)
+ aidlCommand := ctx.ModuleForTests("foo", "android_common").Rule("aidl").RuleParams.Command
+ expectedAidlFlag := "--min_sdk_version=" + tc.expected
+ if !strings.Contains(aidlCommand, expectedAidlFlag) {
+ t.Errorf("aidl command %q does not contain %q", aidlCommand, expectedAidlFlag)
+ }
+ })
+ }
+}
+
func TestDataNativeBinaries(t *testing.T) {
ctx, _ := testJava(t, `
java_test_host {
diff --git a/java/jdeps.go b/java/jdeps.go
index 0ab2e42..eff9a31 100644
--- a/java/jdeps.go
+++ b/java/jdeps.go
@@ -40,16 +40,11 @@
var _ android.SingletonMakeVarsProvider = (*jdepsGeneratorSingleton)(nil)
const (
- // Environment variables used to modify behavior of this singleton.
- envVariableCollectJavaDeps = "SOONG_COLLECT_JAVA_DEPS"
- jdepsJsonFileName = "module_bp_java_deps.json"
+ jdepsJsonFileName = "module_bp_java_deps.json"
)
func (j *jdepsGeneratorSingleton) GenerateBuildActions(ctx android.SingletonContext) {
- if !ctx.Config().IsEnvTrue(envVariableCollectJavaDeps) {
- return
- }
-
+ // (b/204397180) Generate module_bp_java_deps.json by default.
moduleInfos := make(map[string]android.IdeInfo)
ctx.VisitAllModules(func(module android.Module) {
diff --git a/java/lint.go b/java/lint.go
index fe3218e..7845c33 100644
--- a/java/lint.go
+++ b/java/lint.go
@@ -377,6 +377,7 @@
html := android.PathForModuleOut(ctx, "lint", "lint-report.html")
text := android.PathForModuleOut(ctx, "lint", "lint-report.txt")
xml := android.PathForModuleOut(ctx, "lint", "lint-report.xml")
+ baseline := android.PathForModuleOut(ctx, "lint", "lint-baseline.xml")
depSetsBuilder := NewLintDepSetBuilder().Direct(html, text, xml)
@@ -447,6 +448,8 @@
cmd.FlagWithInput("--baseline ", lintBaseline.Path())
}
+ cmd.FlagWithOutput("--write-reference-baseline ", baseline)
+
cmd.Text("|| (").Text("if [ -e").Input(text).Text("]; then cat").Input(text).Text("; fi; exit 7)")
rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go
index 9fec08a..1e27238 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -68,7 +68,6 @@
func platformBootclasspathFactory() android.SingletonModule {
m := &platformBootclasspathModule{}
m.AddProperties(&m.properties)
- // TODO(satayev): split apex jars into separate configs.
initClasspathFragment(m, BOOTCLASSPATH)
android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon)
return m
diff --git a/java/platform_compat_config.go b/java/platform_compat_config.go
index 0d8ebac..f442ddf 100644
--- a/java/platform_compat_config.go
+++ b/java/platform_compat_config.go
@@ -115,7 +115,7 @@
Include: "$(BUILD_PREBUILT)",
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- entries.SetString("LOCAL_MODULE_PATH", p.installDirPath.ToMakePath().String())
+ entries.SetString("LOCAL_MODULE_PATH", p.installDirPath.String())
entries.SetString("LOCAL_INSTALLED_MODULE_STEM", p.configFile.Base())
},
},
diff --git a/java/robolectric.go b/java/robolectric.go
index 16af546..f719521 100644
--- a/java/robolectric.go
+++ b/java/robolectric.go
@@ -352,7 +352,6 @@
return module
}
-func (r *robolectricTest) InstallBypassMake() bool { return true }
func (r *robolectricTest) InstallInTestcases() bool { return true }
func (r *robolectricTest) InstallForceOS() (*android.OsType, *android.ArchType) {
return &r.forceOSType, &r.forceArchType
@@ -430,7 +429,6 @@
}
}
-func (r *robolectricRuntimes) InstallBypassMake() bool { return true }
func (r *robolectricRuntimes) InstallInTestcases() bool { return true }
func (r *robolectricRuntimes) InstallForceOS() (*android.OsType, *android.ArchType) {
return &r.forceOSType, &r.forceArchType
diff --git a/java/rro_test.go b/java/rro_test.go
index 27abbe4..be0d7ba 100644
--- a/java/rro_test.go
+++ b/java/rro_test.go
@@ -62,6 +62,7 @@
result := android.GroupFixturePreparers(
PrepareForTestWithJavaDefaultModules,
PrepareForTestWithOverlayBuildComponents,
+ android.FixtureModifyConfig(android.SetKatiEnabledForTests),
fs.AddToFixture(),
).RunTestWithBp(t, bp)
@@ -127,7 +128,10 @@
}
func TestRuntimeResourceOverlay_JavaDefaults(t *testing.T) {
- ctx, config := testJava(t, `
+ result := android.GroupFixturePreparers(
+ PrepareForTestWithJavaDefaultModules,
+ android.FixtureModifyConfig(android.SetKatiEnabledForTests),
+ ).RunTestWithBp(t, `
java_defaults {
name: "rro_defaults",
theme: "default_theme",
@@ -148,7 +152,7 @@
//
// RRO module with defaults
//
- m := ctx.ModuleForTests("foo_with_defaults", "android_common")
+ m := result.ModuleForTests("foo_with_defaults", "android_common")
// Check AAPT2 link flags.
aapt2Flags := strings.Split(m.Output("package-res.apk").Args["flags"], " ")
@@ -159,14 +163,14 @@
}
// Check device location.
- path := android.AndroidMkEntriesForTest(t, ctx, m.Module())[0].EntryMap["LOCAL_MODULE_PATH"]
+ path := android.AndroidMkEntriesForTest(t, result.TestContext, m.Module())[0].EntryMap["LOCAL_MODULE_PATH"]
expectedPath := []string{shared.JoinPath("out/target/product/test_device/product/overlay/default_theme")}
- android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_MODULE_PATH", config, expectedPath, path)
+ android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_MODULE_PATH", result.Config, expectedPath, path)
//
// RRO module without defaults
//
- m = ctx.ModuleForTests("foo_barebones", "android_common")
+ m = result.ModuleForTests("foo_barebones", "android_common")
// Check AAPT2 link flags.
aapt2Flags = strings.Split(m.Output("package-res.apk").Args["flags"], " ")
@@ -176,9 +180,9 @@
}
// Check device location.
- path = android.AndroidMkEntriesForTest(t, ctx, m.Module())[0].EntryMap["LOCAL_MODULE_PATH"]
+ path = android.AndroidMkEntriesForTest(t, result.TestContext, m.Module())[0].EntryMap["LOCAL_MODULE_PATH"]
expectedPath = []string{shared.JoinPath("out/target/product/test_device/product/overlay")}
- android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_MODULE_PATH", config, expectedPath, path)
+ android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_MODULE_PATH", result.Config, expectedPath, path)
}
func TestOverrideRuntimeResourceOverlay(t *testing.T) {
diff --git a/java/sdk.go b/java/sdk.go
index 697deb1..756a24d 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -55,6 +55,12 @@
return JAVA_VERSION_7
} else if sdk.FinalOrFutureInt() <= 29 {
return JAVA_VERSION_8
+ } else if ctx.Config().TargetsJava11() {
+ // Temporary experimental flag to be able to try and build with
+ // java version 11 options. The flag, if used, just sets Java
+ // 11 as the default version, leaving any components that
+ // target an older version intact.
+ return JAVA_VERSION_11
} else {
return JAVA_VERSION_9
}
@@ -141,11 +147,13 @@
}
}
- toModule := func(systemModules string, module string, aidl android.Path) sdkDep {
+ toModule := func(module string, aidl android.Path) sdkDep {
+ // Select the kind of system modules needed for the sdk version.
+ systemModulesKind := systemModuleKind(sdkVersion.Kind, android.FutureApiLevel)
return sdkDep{
useModule: true,
bootclasspath: []string{module, config.DefaultLambdaStubsLibrary},
- systemModules: systemModules,
+ systemModules: fmt.Sprintf("core-%s-stubs-system-modules", systemModulesKind),
java9Classpath: []string{module},
frameworkResModule: "framework-res",
aidl: android.OptionalPathForPath(aidl),
@@ -186,11 +194,11 @@
noFrameworksLibs: true,
}
case android.SdkPublic:
- return toModule("core-public-stubs-system-modules", "android_stubs_current", sdkFrameworkAidlPath(ctx))
+ return toModule("android_stubs_current", sdkFrameworkAidlPath(ctx))
case android.SdkSystem:
- return toModule("core-public-stubs-system-modules", "android_system_stubs_current", sdkFrameworkAidlPath(ctx))
+ return toModule("android_system_stubs_current", sdkFrameworkAidlPath(ctx))
case android.SdkTest:
- return toModule("core-public-stubs-system-modules", "android_test_stubs_current", sdkFrameworkAidlPath(ctx))
+ return toModule("android_test_stubs_current", sdkFrameworkAidlPath(ctx))
case android.SdkCore:
return sdkDep{
useModule: true,
@@ -200,10 +208,10 @@
}
case android.SdkModule:
// TODO(146757305): provide .apk and .aidl that have more APIs for modules
- return toModule("core-module-lib-stubs-system-modules", "android_module_lib_stubs_current", nonUpdatableFrameworkAidlPath(ctx))
+ return toModule("android_module_lib_stubs_current", nonUpdatableFrameworkAidlPath(ctx))
case android.SdkSystemServer:
// TODO(146757305): provide .apk and .aidl that have more APIs for modules
- return toModule("core-module-lib-stubs-system-modules", "android_system_server_stubs_current", sdkFrameworkAidlPath(ctx))
+ return toModule("android_system_server_stubs_current", sdkFrameworkAidlPath(ctx))
default:
panic(fmt.Errorf("invalid sdk %q", sdkVersion.Raw))
}
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 273efec..7849f96 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -21,6 +21,7 @@
"reflect"
"regexp"
"sort"
+ "strconv"
"strings"
"sync"
@@ -32,25 +33,7 @@
)
const (
- sdkXmlFileSuffix = ".xml"
- permissionsTemplate = `<?xml version=\"1.0\" encoding=\"utf-8\"?>\n` +
- `<!-- Copyright (C) 2018 The Android Open Source Project\n` +
- `\n` +
- ` Licensed under the Apache License, Version 2.0 (the \"License\");\n` +
- ` you may not use this file except in compliance with the License.\n` +
- ` You may obtain a copy of the License at\n` +
- `\n` +
- ` http://www.apache.org/licenses/LICENSE-2.0\n` +
- `\n` +
- ` Unless required by applicable law or agreed to in writing, software\n` +
- ` distributed under the License is distributed on an \"AS IS\" BASIS,\n` +
- ` WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n` +
- ` See the License for the specific language governing permissions and\n` +
- ` limitations under the License.\n` +
- `-->\n` +
- `<permissions>\n` +
- ` <library name=\"%s\" file=\"%s\"/>\n` +
- `</permissions>\n`
+ sdkXmlFileSuffix = ".xml"
)
// A tag to associated a dependency with a specific api scope.
@@ -361,13 +344,14 @@
// The sdk_version to use for building the stubs.
//
// If not specified then it will use an sdk_version determined as follows:
+ //
// 1) If the sdk_version specified on the java_sdk_library is none then this
- // will be none. This is used for java_sdk_library instances that are used
- // to create stubs that contribute to the core_current sdk version.
- // 2) Otherwise, it is assumed that this library extends but does not contribute
- // directly to a specific sdk_version and so this uses the sdk_version appropriate
- // for the api scope. e.g. public will use sdk_version: current, system will use
- // sdk_version: system_current, etc.
+ // will be none. This is used for java_sdk_library instances that are used
+ // to create stubs that contribute to the core_current sdk version.
+ // 2) Otherwise, it is assumed that this library extends but does not
+ // contribute directly to a specific sdk_version and so this uses the
+ // sdk_version appropriate for the api scope. e.g. public will use
+ // sdk_version: current, system will use sdk_version: system_current, etc.
//
// This does not affect the sdk_version used for either generating the stubs source
// or the API file. They both have to use the same sdk_version as is used for
@@ -636,6 +620,33 @@
// Files containing information about supported java doc tags.
Doctag_files []string `android:"path"`
+
+ // Signals that this shared library is part of the bootclasspath starting
+ // on the version indicated in this attribute.
+ //
+ // This will make platforms at this level and above to ignore
+ // <uses-library> tags with this library name because the library is already
+ // available
+ On_bootclasspath_since *string
+
+ // Signals that this shared library was part of the bootclasspath before
+ // (but not including) the version indicated in this attribute.
+ //
+ // The system will automatically add a <uses-library> tag with this library to
+ // apps that target any SDK less than the version indicated in this attribute.
+ On_bootclasspath_before *string
+
+ // Indicates that PackageManager should ignore this shared library if the
+ // platform is below the version indicated in this attribute.
+ //
+ // This means that the device won't recognise this library as installed.
+ Min_device_sdk *string
+
+ // Indicates that PackageManager should ignore this shared library if the
+ // platform is above the version indicated in this attribute.
+ //
+ // This means that the device won't recognise this library as installed.
+ Max_device_sdk *string
}
// commonSdkLibraryAndImportModule defines the interface that must be provided by a module that
@@ -1118,6 +1129,22 @@
return generatedScopes
}
+var _ android.ModuleWithMinSdkVersionCheck = (*SdkLibrary)(nil)
+
+func (module *SdkLibrary) CheckMinSdkVersion(ctx android.ModuleContext) {
+ android.CheckMinSdkVersion(ctx, module.MinSdkVersion(ctx).ApiLevel, func(c android.ModuleContext, do android.PayloadDepsCallback) {
+ ctx.WalkDeps(func(child android.Module, parent android.Module) bool {
+ isExternal := !module.depIsInSameApex(ctx, child)
+ if am, ok := child.(android.ApexModule); ok {
+ if !do(ctx, parent, am, isExternal) {
+ return false
+ }
+ }
+ return !isExternal
+ })
+ })
+}
+
type sdkLibraryComponentTag struct {
blueprint.BaseDependencyTag
name string
@@ -1195,14 +1222,23 @@
func (module *SdkLibrary) OutputFiles(tag string) (android.Paths, error) {
paths, err := module.commonOutputFiles(tag)
- if paths == nil && err == nil {
- return module.Library.OutputFiles(tag)
- } else {
+ if paths != nil || err != nil {
return paths, err
}
+ if module.requiresRuntimeImplementationLibrary() {
+ return module.Library.OutputFiles(tag)
+ }
+ if tag == "" {
+ return nil, nil
+ }
+ return nil, fmt.Errorf("unsupported module reference tag %q", tag)
}
func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ if proptools.String(module.deviceProperties.Min_sdk_version) != "" {
+ module.CheckMinSdkVersion(ctx)
+ }
+
module.generateCommonBuildActions(ctx)
// Only build an implementation library if required.
@@ -1356,6 +1392,10 @@
Srcs []string
Javacflags []string
}
+ Openjdk11 struct {
+ Srcs []string
+ Javacflags []string
+ }
Dist struct {
Targets []string
Dest *string
@@ -1382,6 +1422,8 @@
}
props.Openjdk9.Srcs = module.properties.Openjdk9.Srcs
props.Openjdk9.Javacflags = module.properties.Openjdk9.Javacflags
+ props.Openjdk11.Srcs = module.properties.Openjdk11.Srcs
+ props.Openjdk11.Javacflags = module.properties.Openjdk11.Javacflags
// We compile the stubs for 1.8 in line with the main android.jar stubs, and potential
// interop with older developer tools that don't support 1.9.
props.Java_version = proptools.StringPtr("1.8")
@@ -1579,14 +1621,29 @@
// Creates the xml file that publicizes the runtime library
func (module *SdkLibrary) createXmlFile(mctx android.DefaultableHookContext) {
+ moduleMinApiLevel := module.Library.MinSdkVersion(mctx).ApiLevel
+ var moduleMinApiLevelStr = moduleMinApiLevel.String()
+ if moduleMinApiLevel == android.NoneApiLevel {
+ moduleMinApiLevelStr = "current"
+ }
props := struct {
- Name *string
- Lib_name *string
- Apex_available []string
+ Name *string
+ Lib_name *string
+ Apex_available []string
+ On_bootclasspath_since *string
+ On_bootclasspath_before *string
+ Min_device_sdk *string
+ Max_device_sdk *string
+ Sdk_library_min_api_level *string
}{
- Name: proptools.StringPtr(module.xmlPermissionsModuleName()),
- Lib_name: proptools.StringPtr(module.BaseModuleName()),
- Apex_available: module.ApexProperties.Apex_available,
+ Name: proptools.StringPtr(module.xmlPermissionsModuleName()),
+ Lib_name: proptools.StringPtr(module.BaseModuleName()),
+ Apex_available: module.ApexProperties.Apex_available,
+ On_bootclasspath_since: module.commonSdkLibraryProperties.On_bootclasspath_since,
+ On_bootclasspath_before: module.commonSdkLibraryProperties.On_bootclasspath_before,
+ Min_device_sdk: module.commonSdkLibraryProperties.Min_device_sdk,
+ Max_device_sdk: module.commonSdkLibraryProperties.Max_device_sdk,
+ Sdk_library_min_api_level: &moduleMinApiLevelStr,
}
mctx.CreateModule(sdkLibraryXmlFactory, &props)
@@ -2382,6 +2439,38 @@
type sdkLibraryXmlProperties struct {
// canonical name of the lib
Lib_name *string
+
+ // Signals that this shared library is part of the bootclasspath starting
+ // on the version indicated in this attribute.
+ //
+ // This will make platforms at this level and above to ignore
+ // <uses-library> tags with this library name because the library is already
+ // available
+ On_bootclasspath_since *string
+
+ // Signals that this shared library was part of the bootclasspath before
+ // (but not including) the version indicated in this attribute.
+ //
+ // The system will automatically add a <uses-library> tag with this library to
+ // apps that target any SDK less than the version indicated in this attribute.
+ On_bootclasspath_before *string
+
+ // Indicates that PackageManager should ignore this shared library if the
+ // platform is below the version indicated in this attribute.
+ //
+ // This means that the device won't recognise this library as installed.
+ Min_device_sdk *string
+
+ // Indicates that PackageManager should ignore this shared library if the
+ // platform is above the version indicated in this attribute.
+ //
+ // This means that the device won't recognise this library as installed.
+ Max_device_sdk *string
+
+ // The SdkLibrary's min api level as a string
+ //
+ // This value comes from the ApiLevel of the MinSdkVersion property.
+ Sdk_library_min_api_level *string
}
// java_sdk_library_xml builds the permission xml file for a java_sdk_library.
@@ -2458,11 +2547,81 @@
return "/" + partition + "/framework/" + implName + ".jar"
}
+func formattedOptionalSdkLevelAttribute(ctx android.ModuleContext, attrName string, value *string) string {
+ if value == nil {
+ return ""
+ }
+ apiLevel, err := android.ApiLevelFromUser(ctx, *value)
+ if err != nil {
+ // attributes in bp files have underscores but in the xml have dashes.
+ ctx.PropertyErrorf(strings.ReplaceAll(attrName, "-", "_"), err.Error())
+ return ""
+ }
+ intStr := strconv.Itoa(apiLevel.FinalOrPreviewInt())
+ return formattedOptionalAttribute(attrName, &intStr)
+}
+
+// formats an attribute for the xml permissions file if the value is not null
+// returns empty string otherwise
+func formattedOptionalAttribute(attrName string, value *string) string {
+ if value == nil {
+ return ""
+ }
+ return fmt.Sprintf(` %s=\"%s\"\n`, attrName, *value)
+}
+
+func (module *sdkLibraryXml) permissionsContents(ctx android.ModuleContext) string {
+ libName := proptools.String(module.properties.Lib_name)
+ libNameAttr := formattedOptionalAttribute("name", &libName)
+ filePath := module.implPath(ctx)
+ filePathAttr := formattedOptionalAttribute("file", &filePath)
+ implicitFromAttr := formattedOptionalSdkLevelAttribute(ctx, "on-bootclasspath-since", module.properties.On_bootclasspath_since)
+ 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 <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 = ` <apex-library\n`
+ } else {
+ libraryTag = ` <library\n`
+ }
+
+ return strings.Join([]string{
+ `<?xml version=\"1.0\" encoding=\"utf-8\"?>\n`,
+ `<!-- Copyright (C) 2018 The Android Open Source Project\n`,
+ `\n`,
+ ` Licensed under the Apache License, Version 2.0 (the \"License\");\n`,
+ ` you may not use this file except in compliance with the License.\n`,
+ ` You may obtain a copy of the License at\n`,
+ `\n`,
+ ` http://www.apache.org/licenses/LICENSE-2.0\n`,
+ `\n`,
+ ` Unless required by applicable law or agreed to in writing, software\n`,
+ ` distributed under the License is distributed on an \"AS IS\" BASIS,\n`,
+ ` WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n`,
+ ` See the License for the specific language governing permissions and\n`,
+ ` limitations under the License.\n`,
+ `-->\n`,
+ `<permissions>\n`,
+ libraryTag,
+ libNameAttr,
+ filePathAttr,
+ implicitFromAttr,
+ implicitUntilAttr,
+ minSdkAttr,
+ maxSdkAttr,
+ ` />\n`,
+ `</permissions>\n`}, "")
+}
+
func (module *sdkLibraryXml) GenerateAndroidBuildActions(ctx android.ModuleContext) {
module.hideApexVariantFromMake = !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform()
libName := proptools.String(module.properties.Lib_name)
- xmlContent := fmt.Sprintf(permissionsTemplate, libName, module.implPath(ctx))
+ module.selfValidate(ctx)
+ xmlContent := module.permissionsContents(ctx)
module.outputFilePath = android.PathForModuleOut(ctx, libName+".xml").OutputPath
rule := android.NewRuleBuilder(pctx, ctx)
@@ -2477,24 +2636,99 @@
func (module *sdkLibraryXml) AndroidMkEntries() []android.AndroidMkEntries {
if module.hideApexVariantFromMake {
- return []android.AndroidMkEntries{android.AndroidMkEntries{
+ return []android.AndroidMkEntries{{
Disabled: true,
}}
}
- return []android.AndroidMkEntries{android.AndroidMkEntries{
+ return []android.AndroidMkEntries{{
Class: "ETC",
OutputFile: android.OptionalPathForPath(module.outputFilePath),
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
entries.SetString("LOCAL_MODULE_TAGS", "optional")
- entries.SetString("LOCAL_MODULE_PATH", module.installDirPath.ToMakePath().String())
+ entries.SetString("LOCAL_MODULE_PATH", module.installDirPath.String())
entries.SetString("LOCAL_INSTALLED_MODULE_STEM", module.outputFilePath.Base())
},
},
}}
}
+func (module *sdkLibraryXml) selfValidate(ctx android.ModuleContext) {
+ module.validateAtLeastTAttributes(ctx)
+ module.validateMinAndMaxDeviceSdk(ctx)
+ module.validateMinMaxDeviceSdkAndModuleMinSdk(ctx)
+ module.validateOnBootclasspathBeforeRequirements(ctx)
+}
+
+func (module *sdkLibraryXml) validateAtLeastTAttributes(ctx android.ModuleContext) {
+ t := android.ApiLevelOrPanic(ctx, "Tiramisu")
+ module.attrAtLeastT(ctx, t, module.properties.Min_device_sdk, "min_device_sdk")
+ module.attrAtLeastT(ctx, t, module.properties.Max_device_sdk, "max_device_sdk")
+ module.attrAtLeastT(ctx, t, module.properties.On_bootclasspath_before, "on_bootclasspath_before")
+ module.attrAtLeastT(ctx, t, module.properties.On_bootclasspath_since, "on_bootclasspath_since")
+}
+
+func (module *sdkLibraryXml) attrAtLeastT(ctx android.ModuleContext, t android.ApiLevel, attr *string, attrName string) {
+ if attr != nil {
+ if level, err := android.ApiLevelFromUser(ctx, *attr); err == nil {
+ // we will inform the user of invalid inputs when we try to write the
+ // permissions xml file so we don't need to do it here
+ if t.GreaterThan(level) {
+ ctx.PropertyErrorf(attrName, "Attribute value needs to be at least T")
+ }
+ }
+ }
+}
+
+func (module *sdkLibraryXml) validateMinAndMaxDeviceSdk(ctx android.ModuleContext) {
+ if module.properties.Min_device_sdk != nil && module.properties.Max_device_sdk != nil {
+ min, minErr := android.ApiLevelFromUser(ctx, *module.properties.Min_device_sdk)
+ max, maxErr := android.ApiLevelFromUser(ctx, *module.properties.Max_device_sdk)
+ if minErr == nil && maxErr == nil {
+ // we will inform the user of invalid inputs when we try to write the
+ // permissions xml file so we don't need to do it here
+ if min.GreaterThan(max) {
+ ctx.ModuleErrorf("min_device_sdk can't be greater than max_device_sdk")
+ }
+ }
+ }
+}
+
+func (module *sdkLibraryXml) validateMinMaxDeviceSdkAndModuleMinSdk(ctx android.ModuleContext) {
+ moduleMinApi := android.ApiLevelOrPanic(ctx, *module.properties.Sdk_library_min_api_level)
+ if module.properties.Min_device_sdk != nil {
+ api, err := android.ApiLevelFromUser(ctx, *module.properties.Min_device_sdk)
+ if err == nil {
+ if moduleMinApi.GreaterThan(api) {
+ ctx.PropertyErrorf("min_device_sdk", "Can't be less than module's min sdk (%s)", moduleMinApi)
+ }
+ }
+ }
+ if module.properties.Max_device_sdk != nil {
+ api, err := android.ApiLevelFromUser(ctx, *module.properties.Max_device_sdk)
+ if err == nil {
+ if moduleMinApi.GreaterThan(api) {
+ ctx.PropertyErrorf("max_device_sdk", "Can't be less than module's min sdk (%s)", moduleMinApi)
+ }
+ }
+ }
+}
+
+func (module *sdkLibraryXml) validateOnBootclasspathBeforeRequirements(ctx android.ModuleContext) {
+ moduleMinApi := android.ApiLevelOrPanic(ctx, *module.properties.Sdk_library_min_api_level)
+ if module.properties.On_bootclasspath_before != nil {
+ t := android.ApiLevelOrPanic(ctx, "Tiramisu")
+ // if we use the attribute, then we need to do this validation
+ if moduleMinApi.LessThan(t) {
+ // if minAPi is < T, then we need to have min_device_sdk (which only accepts T+)
+ if module.properties.Min_device_sdk == nil {
+ ctx.PropertyErrorf("on_bootclasspath_before", "Using this property requires that the module's min_sdk_version or the shared library's min_device_sdk is at least T")
+ }
+ }
+ }
+}
+
type sdkLibrarySdkMemberType struct {
android.SdkMemberTypeBase
}
@@ -2546,6 +2780,33 @@
Doctag_paths android.Paths
Permitted_packages []string
+
+ // Signals that this shared library is part of the bootclasspath starting
+ // on the version indicated in this attribute.
+ //
+ // This will make platforms at this level and above to ignore
+ // <uses-library> tags with this library name because the library is already
+ // available
+ On_bootclasspath_since *string
+
+ // Signals that this shared library was part of the bootclasspath before
+ // (but not including) the version indicated in this attribute.
+ //
+ // The system will automatically add a <uses-library> tag with this library to
+ // apps that target any SDK less than the version indicated in this attribute.
+ On_bootclasspath_before *string
+
+ // Indicates that PackageManager should ignore this shared library if the
+ // platform is below the version indicated in this attribute.
+ //
+ // This means that the device won't recognise this library as installed.
+ Min_device_sdk *string
+
+ // Indicates that PackageManager should ignore this shared library if the
+ // platform is above the version indicated in this attribute.
+ //
+ // This means that the device won't recognise this library as installed.
+ Max_device_sdk *string
}
type scopeProperties struct {
@@ -2592,6 +2853,10 @@
s.Compile_dex = sdk.dexProperties.Compile_dex
s.Doctag_paths = sdk.doctagPaths
s.Permitted_packages = sdk.PermittedPackagesForUpdatableBootJars()
+ s.On_bootclasspath_since = sdk.commonSdkLibraryProperties.On_bootclasspath_since
+ s.On_bootclasspath_before = sdk.commonSdkLibraryProperties.On_bootclasspath_before
+ s.Min_device_sdk = sdk.commonSdkLibraryProperties.Min_device_sdk
+ s.Max_device_sdk = sdk.commonSdkLibraryProperties.Max_device_sdk
}
func (s *sdkLibrarySdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go
index be23536..e60ca00 100644
--- a/java/sdk_library_test.go
+++ b/java/sdk_library_test.go
@@ -15,12 +15,13 @@
package java
import (
- "android/soong/android"
"fmt"
"path/filepath"
"regexp"
"testing"
+ "android/soong/android"
+
"github.com/google/blueprint/proptools"
)
@@ -107,7 +108,7 @@
libs: ["foo"],
sdk_version: "module_30",
}
- `)
+ `)
// check the existence of the internal modules
foo := result.ModuleForTests("foo", "android_common")
@@ -162,6 +163,185 @@
}
}
+func TestJavaSdkLibrary_UpdatableLibrary(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForJavaTest,
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithPrebuiltApis(map[string][]string{
+ "28": {"foo"},
+ "29": {"foo"},
+ "30": {"foo", "fooUpdatable", "fooUpdatableErr"},
+ }),
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.Platform_version_active_codenames = []string{"Tiramisu", "U", "V", "W"}
+ }),
+ ).RunTestWithBp(t,
+ `
+ java_sdk_library {
+ name: "fooUpdatable",
+ srcs: ["a.java", "b.java"],
+ api_packages: ["foo"],
+ on_bootclasspath_since: "U",
+ on_bootclasspath_before: "V",
+ min_device_sdk: "W",
+ max_device_sdk: "current",
+ min_sdk_version: "S",
+ }
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java", "b.java"],
+ api_packages: ["foo"],
+ }
+`)
+ // test that updatability attributes are passed on correctly
+ fooUpdatable := result.ModuleForTests("fooUpdatable.xml", "android_common").Rule("java_sdk_xml")
+ android.AssertStringDoesContain(t, "fooUpdatable.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `on-bootclasspath-since=\"9001\"`)
+ android.AssertStringDoesContain(t, "fooUpdatable.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `on-bootclasspath-before=\"9002\"`)
+ android.AssertStringDoesContain(t, "fooUpdatable.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `min-device-sdk=\"9003\"`)
+ android.AssertStringDoesContain(t, "fooUpdatable.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `max-device-sdk=\"10000\"`)
+
+ // double check that updatability attributes are not written if they don't exist in the bp file
+ // the permissions file for the foo library defined above
+ fooPermissions := result.ModuleForTests("foo.xml", "android_common").Rule("java_sdk_xml")
+ android.AssertStringDoesNotContain(t, "foo.xml java_sdk_xml command", fooPermissions.RuleParams.Command, `on-bootclasspath-since`)
+ android.AssertStringDoesNotContain(t, "foo.xml java_sdk_xml command", fooPermissions.RuleParams.Command, `on-bootclasspath-before`)
+ android.AssertStringDoesNotContain(t, "foo.xml java_sdk_xml command", fooPermissions.RuleParams.Command, `min-device-sdk`)
+ android.AssertStringDoesNotContain(t, "foo.xml java_sdk_xml command", fooPermissions.RuleParams.Command, `max-device-sdk`)
+}
+
+func TestJavaSdkLibrary_UpdatableLibrary_Validation_ValidVersion(t *testing.T) {
+ android.GroupFixturePreparers(
+ prepareForJavaTest,
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithPrebuiltApis(map[string][]string{
+ "30": {"fooUpdatable", "fooUpdatableErr"},
+ }),
+ ).ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern(
+ []string{
+ `on_bootclasspath_since: "aaa" could not be parsed as an integer and is not a recognized codename`,
+ `on_bootclasspath_before: "bbc" could not be parsed as an integer and is not a recognized codename`,
+ `min_device_sdk: "ccc" could not be parsed as an integer and is not a recognized codename`,
+ `max_device_sdk: "ddd" could not be parsed as an integer and is not a recognized codename`,
+ })).RunTestWithBp(t,
+ `
+ java_sdk_library {
+ name: "fooUpdatableErr",
+ srcs: ["a.java", "b.java"],
+ api_packages: ["foo"],
+ on_bootclasspath_since: "aaa",
+ on_bootclasspath_before: "bbc",
+ min_device_sdk: "ccc",
+ max_device_sdk: "ddd",
+ }
+`)
+}
+
+func TestJavaSdkLibrary_UpdatableLibrary_Validation_AtLeastTAttributes(t *testing.T) {
+ android.GroupFixturePreparers(
+ prepareForJavaTest,
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithPrebuiltApis(map[string][]string{
+ "28": {"foo"},
+ }),
+ ).ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern(
+ []string{
+ "on_bootclasspath_since: Attribute value needs to be at least T",
+ "on_bootclasspath_before: Attribute value needs to be at least T",
+ "min_device_sdk: Attribute value needs to be at least T",
+ "max_device_sdk: Attribute value needs to be at least T",
+ },
+ )).RunTestWithBp(t,
+ `
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java", "b.java"],
+ api_packages: ["foo"],
+ on_bootclasspath_since: "S",
+ on_bootclasspath_before: "S",
+ min_device_sdk: "S",
+ max_device_sdk: "S",
+ min_sdk_version: "S",
+ }
+`)
+}
+
+func TestJavaSdkLibrary_UpdatableLibrary_Validation_MinAndMaxDeviceSdk(t *testing.T) {
+ android.GroupFixturePreparers(
+ prepareForJavaTest,
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithPrebuiltApis(map[string][]string{
+ "28": {"foo"},
+ }),
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.Platform_version_active_codenames = []string{"Tiramisu", "U", "V"}
+ }),
+ ).ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern(
+ []string{
+ "min_device_sdk can't be greater than max_device_sdk",
+ },
+ )).RunTestWithBp(t,
+ `
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java", "b.java"],
+ api_packages: ["foo"],
+ min_device_sdk: "V",
+ max_device_sdk: "U",
+ min_sdk_version: "S",
+ }
+`)
+}
+
+func TestJavaSdkLibrary_UpdatableLibrary_Validation_MinAndMaxDeviceSdkAndModuleMinSdk(t *testing.T) {
+ android.GroupFixturePreparers(
+ prepareForJavaTest,
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithPrebuiltApis(map[string][]string{
+ "28": {"foo"},
+ }),
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.Platform_version_active_codenames = []string{"Tiramisu", "U", "V"}
+ }),
+ ).ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern(
+ []string{
+ regexp.QuoteMeta("min_device_sdk: Can't be less than module's min sdk (V)"),
+ regexp.QuoteMeta("max_device_sdk: Can't be less than module's min sdk (V)"),
+ },
+ )).RunTestWithBp(t,
+ `
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java", "b.java"],
+ api_packages: ["foo"],
+ min_device_sdk: "U",
+ max_device_sdk: "U",
+ min_sdk_version: "V",
+ }
+`)
+}
+
+func TestJavaSdkLibrary_UpdatableLibrary_usesNewTag(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForJavaTest,
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithPrebuiltApis(map[string][]string{
+ "30": {"foo"},
+ }),
+ ).RunTestWithBp(t,
+ `
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java", "b.java"],
+ min_device_sdk: "Tiramisu",
+ min_sdk_version: "S",
+ }
+`)
+ // 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, `<apex-library`)
+ android.AssertStringDoesNotContain(t, "foo.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `<library`)
+}
+
func TestJavaSdkLibrary_StubOrImplOnlyLibs(t *testing.T) {
result := android.GroupFixturePreparers(
prepareForJavaTest,
@@ -960,3 +1140,87 @@
})
}
}
+
+func TestSdkLibrary_CheckMinSdkVersion(t *testing.T) {
+ preparer := android.GroupFixturePreparers(
+ PrepareForTestWithJavaBuildComponents,
+ PrepareForTestWithJavaDefaultModules,
+ PrepareForTestWithJavaSdkLibraryFiles,
+ )
+
+ preparer.RunTestWithBp(t, `
+ java_sdk_library {
+ name: "sdklib",
+ srcs: ["a.java"],
+ static_libs: ["util"],
+ min_sdk_version: "30",
+ unsafe_ignore_missing_latest_api: true,
+ }
+
+ java_library {
+ name: "util",
+ srcs: ["a.java"],
+ min_sdk_version: "30",
+ }
+ `)
+
+ preparer.
+ RunTestWithBp(t, `
+ java_sdk_library {
+ name: "sdklib",
+ srcs: ["a.java"],
+ libs: ["util"],
+ impl_only_libs: ["util"],
+ stub_only_libs: ["util"],
+ stub_only_static_libs: ["util"],
+ min_sdk_version: "30",
+ unsafe_ignore_missing_latest_api: true,
+ }
+
+ java_library {
+ name: "util",
+ srcs: ["a.java"],
+ }
+ `)
+
+ preparer.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "util".*should support min_sdk_version\(30\)`)).
+ RunTestWithBp(t, `
+ java_sdk_library {
+ name: "sdklib",
+ srcs: ["a.java"],
+ static_libs: ["util"],
+ min_sdk_version: "30",
+ unsafe_ignore_missing_latest_api: true,
+ }
+
+ java_library {
+ name: "util",
+ srcs: ["a.java"],
+ min_sdk_version: "31",
+ }
+ `)
+
+ preparer.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "another_util".*should support min_sdk_version\(30\)`)).
+ RunTestWithBp(t, `
+ java_sdk_library {
+ name: "sdklib",
+ srcs: ["a.java"],
+ static_libs: ["util"],
+ min_sdk_version: "30",
+ unsafe_ignore_missing_latest_api: true,
+ }
+
+ java_library {
+ name: "util",
+ srcs: ["a.java"],
+ static_libs: ["another_util"],
+ min_sdk_version: "30",
+ }
+
+ java_library {
+ name: "another_util",
+ srcs: ["a.java"],
+ min_sdk_version: "31",
+ }
+ `)
+}
diff --git a/java/systemserver_classpath_fragment.go b/java/systemserver_classpath_fragment.go
index d75635c..fa61ea6 100644
--- a/java/systemserver_classpath_fragment.go
+++ b/java/systemserver_classpath_fragment.go
@@ -58,6 +58,10 @@
func (p *platformSystemServerClasspathModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
configuredJars := p.configuredJars(ctx)
classpathJars := configuredJarListToClasspathJars(ctx, configuredJars, p.classpathType)
+ standaloneConfiguredJars := p.standaloneConfiguredJars(ctx)
+ standaloneClasspathJars := configuredJarListToClasspathJars(ctx, standaloneConfiguredJars, STANDALONE_SYSTEMSERVER_JARS)
+ configuredJars = configuredJars.AppendList(&standaloneConfiguredJars)
+ classpathJars = append(classpathJars, standaloneClasspathJars...)
p.classpathFragmentBase().generateClasspathProtoBuildActions(ctx, configuredJars, classpathJars)
}
@@ -66,6 +70,10 @@
return dexpreopt.GetGlobalConfig(ctx).SystemServerJars
}
+func (p *platformSystemServerClasspathModule) standaloneConfiguredJars(ctx android.ModuleContext) android.ConfiguredJarList {
+ return dexpreopt.GetGlobalConfig(ctx).StandaloneSystemServerJars
+}
+
type SystemServerClasspathModule struct {
android.ModuleBase
android.ApexModuleBase
@@ -84,10 +92,15 @@
}
type systemServerClasspathFragmentProperties struct {
- // The contents of this systemserverclasspath_fragment, could be either java_library, or java_sdk_library.
+ // List of system_server classpath jars, could be either java_library, or java_sdk_library.
//
// The order of this list matters as it is the order that is used in the SYSTEMSERVERCLASSPATH.
Contents []string
+
+ // List of jars that system_server loads dynamically using separate classloaders.
+ //
+ // The order does not matter.
+ Standalone_contents []string
}
func systemServerClasspathFactory() android.Module {
@@ -101,12 +114,16 @@
}
func (s *SystemServerClasspathModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- if len(s.properties.Contents) == 0 {
- ctx.PropertyErrorf("contents", "empty contents are not allowed")
+ if len(s.properties.Contents) == 0 && len(s.properties.Standalone_contents) == 0 {
+ ctx.PropertyErrorf("contents", "Either contents or standalone_contents needs to be non-empty")
}
configuredJars := s.configuredJars(ctx)
classpathJars := configuredJarListToClasspathJars(ctx, configuredJars, s.classpathType)
+ standaloneConfiguredJars := s.standaloneConfiguredJars(ctx)
+ standaloneClasspathJars := configuredJarListToClasspathJars(ctx, standaloneConfiguredJars, STANDALONE_SYSTEMSERVER_JARS)
+ configuredJars = configuredJars.AppendList(&standaloneConfiguredJars)
+ classpathJars = append(classpathJars, standaloneClasspathJars...)
s.classpathFragmentBase().generateClasspathProtoBuildActions(ctx, configuredJars, classpathJars)
// Collect the module directory for IDE info in java/jdeps.go.
@@ -125,6 +142,12 @@
// TODO(b/203233647): Add better mechanism to make it optional.
_, unknown = android.RemoveFromList("car-frameworks-service-module", unknown)
+ // This module is optional, so it is not present in all products.
+ // (See PRODUCT_ISOLATED_COMPILATION_ENABLED.)
+ // So ignore it even if it is not in PRODUCT_APEX_SYSTEM_SERVER_JARS.
+ // TODO(b/203233647): Add better mechanism to make it optional.
+ _, unknown = android.RemoveFromList("service-compos", unknown)
+
// TODO(satayev): for apex_test we want to include all contents unconditionally to classpaths
// config. However, any test specific jars would not be present in ApexSystemServerJars. Instead,
// we should check if we are creating a config for apex_test via ApexInfo and amend the values.
@@ -139,6 +162,17 @@
return jars
}
+func (s *SystemServerClasspathModule) standaloneConfiguredJars(ctx android.ModuleContext) android.ConfiguredJarList {
+ global := dexpreopt.GetGlobalConfig(ctx)
+
+ possibleUpdatableModules := gatherPossibleApexModuleNamesAndStems(ctx, s.properties.Standalone_contents, systemServerClasspathFragmentContentDepTag)
+ jars, _ := global.ApexStandaloneSystemServerJars.Filter(possibleUpdatableModules)
+
+ // TODO(jiakaiz): add a check to ensure that the contents are declared in make.
+
+ return jars
+}
+
type systemServerClasspathFragmentContentDependencyTag struct {
blueprint.BaseDependencyTag
}
@@ -186,8 +220,11 @@
func (s *SystemServerClasspathModule) ComponentDepsMutator(ctx android.BottomUpMutatorContext) {
module := ctx.Module()
_, isSourceModule := module.(*SystemServerClasspathModule)
+ var deps []string
+ deps = append(deps, s.properties.Contents...)
+ deps = append(deps, s.properties.Standalone_contents...)
- for _, name := range s.properties.Contents {
+ for _, name := range deps {
// A systemserverclasspath_fragment must depend only on other source modules, while the
// prebuilt_systemserverclasspath_fragment_fragment must only depend on other prebuilt modules.
if !isSourceModule {
@@ -200,6 +237,7 @@
// Collect information for opening IDE project files in java/jdeps.go.
func (s *SystemServerClasspathModule) IDEInfo(dpInfo *android.IdeInfo) {
dpInfo.Deps = append(dpInfo.Deps, s.properties.Contents...)
+ dpInfo.Deps = append(dpInfo.Deps, s.properties.Standalone_contents...)
dpInfo.Paths = append(dpInfo.Paths, s.modulePaths...)
}
@@ -227,14 +265,22 @@
type systemServerClasspathFragmentSdkMemberProperties struct {
android.SdkMemberPropertiesBase
- // Contents of the systemserverclasspath fragment
+ // List of system_server classpath jars, could be either java_library, or java_sdk_library.
+ //
+ // The order of this list matters as it is the order that is used in the SYSTEMSERVERCLASSPATH.
Contents []string
+
+ // List of jars that system_server loads dynamically using separate classloaders.
+ //
+ // The order does not matter.
+ Standalone_contents []string
}
func (s *systemServerClasspathFragmentSdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
module := variant.(*SystemServerClasspathModule)
s.Contents = module.properties.Contents
+ s.Standalone_contents = module.properties.Standalone_contents
}
func (s *systemServerClasspathFragmentSdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
@@ -244,6 +290,10 @@
if len(s.Contents) > 0 {
propertySet.AddPropertyWithTag("contents", s.Contents, requiredMemberDependency)
}
+
+ if len(s.Standalone_contents) > 0 {
+ propertySet.AddPropertyWithTag("standalone_contents", s.Standalone_contents, requiredMemberDependency)
+ }
}
var _ android.SdkMemberType = (*systemServerClasspathFragmentMemberType)(nil)
diff --git a/java/systemserver_classpath_fragment_test.go b/java/systemserver_classpath_fragment_test.go
index 9ad50dd..ba328e7 100644
--- a/java/systemserver_classpath_fragment_test.go
+++ b/java/systemserver_classpath_fragment_test.go
@@ -99,7 +99,7 @@
func TestSystemServerClasspathFragmentWithoutContents(t *testing.T) {
prepareForTestWithSystemServerClasspath.
ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
- `\Qempty contents are not allowed\E`)).
+ `\QEither contents or standalone_contents needs to be non-empty\E`)).
RunTestWithBp(t, `
systemserverclasspath_fragment {
name: "systemserverclasspath-fragment",
diff --git a/licenses/Android.bp b/licenses/Android.bp
index a983b5b..5b764dc 100644
--- a/licenses/Android.bp
+++ b/licenses/Android.bp
@@ -492,36 +492,36 @@
license_kind {
name: "SPDX-license-identifier-CC-BY-ND",
- conditions: ["restricted"],
+ conditions: ["by_exception_only"],
}
license_kind {
name: "SPDX-license-identifier-CC-BY-ND-1.0",
- conditions: ["restricted"],
+ conditions: ["by_exception_only"],
url: "https://spdx.org/licenses/CC-BY-ND-1.0.html",
}
license_kind {
name: "SPDX-license-identifier-CC-BY-ND-2.0",
- conditions: ["restricted"],
+ conditions: ["by_exception_only"],
url: "https://spdx.org/licenses/CC-BY-ND-2.0.html",
}
license_kind {
name: "SPDX-license-identifier-CC-BY-ND-2.5",
- conditions: ["restricted"],
+ conditions: ["by_exception_only"],
url: "https://spdx.org/licenses/CC-BY-ND-2.5.html",
}
license_kind {
name: "SPDX-license-identifier-CC-BY-ND-3.0",
- conditions: ["restricted"],
+ conditions: ["by_exception_only"],
url: "https://spdx.org/licenses/CC-BY-ND-3.0.html",
}
license_kind {
name: "SPDX-license-identifier-CC-BY-ND-4.0",
- conditions: ["restricted"],
+ conditions: ["by_exception_only"],
url: "https://spdx.org/licenses/CC-BY-ND-4.0.html",
}
@@ -562,7 +562,10 @@
license_kind {
name: "SPDX-license-identifier-CC-BY-SA-ND",
- conditions: ["restricted"],
+ conditions: [
+ "restricted",
+ "by_exception_only",
+ ],
}
license_kind {
diff --git a/linkerconfig/linkerconfig.go b/linkerconfig/linkerconfig.go
index 8d0ad7c..dbc112e 100644
--- a/linkerconfig/linkerconfig.go
+++ b/linkerconfig/linkerconfig.go
@@ -155,7 +155,7 @@
OutputFile: android.OptionalPathForPath(l.outputFilePath),
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- entries.SetString("LOCAL_MODULE_PATH", l.installDirPath.ToMakePath().String())
+ entries.SetString("LOCAL_MODULE_PATH", l.installDirPath.String())
entries.SetString("LOCAL_INSTALLED_MODULE_STEM", l.outputFilePath.Base())
entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", !installable)
entries.SetString("LINKER_CONFIG_PATH_"+l.Name(), l.OutputFile().String())
diff --git a/mk2rbc/Android.bp b/mk2rbc/Android.bp
index b18bfc7..4fa3eb6 100644
--- a/mk2rbc/Android.bp
+++ b/mk2rbc/Android.bp
@@ -38,7 +38,6 @@
"soong_variables.go",
"types.go",
"variable.go",
- "version_defaults.go",
],
deps: ["androidmk-parser"],
}
diff --git a/mk2rbc/cmd/mk2rbc.go b/mk2rbc/cmd/mk2rbc.go
index b089f91..d9b4e86 100644
--- a/mk2rbc/cmd/mk2rbc.go
+++ b/mk2rbc/cmd/mk2rbc.go
@@ -46,17 +46,17 @@
dryRun = flag.Bool("dry_run", false, "dry run")
recurse = flag.Bool("convert_dependents", false, "convert all dependent files")
mode = flag.String("mode", "", `"backup" to back up existing files, "write" to overwrite them`)
- warn = flag.Bool("warnings", false, "warn about partially failed conversions")
- verbose = flag.Bool("v", false, "print summary")
errstat = flag.Bool("error_stat", false, "print error statistics")
traceVar = flag.String("trace", "", "comma-separated list of variables to trace")
// TODO(asmundak): this option is for debugging
allInSource = flag.Bool("all", false, "convert all product config makefiles in the tree under //")
outputTop = flag.String("outdir", "", "write output files into this directory hierarchy")
- launcher = flag.String("launcher", "", "generated launcher path. If set, the non-flag argument is _product_name_")
+ launcher = flag.String("launcher", "", "generated launcher path.")
+ boardlauncher = flag.String("boardlauncher", "", "generated board configuration launcher path.")
printProductConfigMap = flag.Bool("print_product_config_map", false, "print product config map and exit")
cpuProfile = flag.String("cpu_profile", "", "write cpu profile to file")
traceCalls = flag.Bool("trace_calls", false, "trace function calls")
+ inputVariables = flag.String("input_variables", "", "starlark file containing product config and global variables")
)
func init() {
@@ -73,22 +73,19 @@
flagAlias("root", "d")
flagAlias("dry_run", "n")
flagAlias("convert_dependents", "r")
- flagAlias("warnings", "w")
flagAlias("error_stat", "e")
}
var backupSuffix string
var tracedVariables []string
-var errorLogger = errorsByType{data: make(map[string]datum)}
+var errorLogger = errorSink{data: make(map[string]datum)}
var makefileFinder = &LinuxMakefileFinder{}
-var versionDefaultsMk = filepath.Join("build", "make", "core", "version_defaults.mk")
func main() {
flag.Usage = func() {
cmd := filepath.Base(os.Args[0])
fmt.Fprintf(flag.CommandLine.Output(),
- "Usage: %[1]s flags file...\n"+
- "or: %[1]s flags --launcher=PATH PRODUCT\n", cmd)
+ "Usage: %[1]s flags file...\n", cmd)
flag.PrintDefaults()
}
flag.Parse()
@@ -170,43 +167,47 @@
if len(files) != 1 {
quit(fmt.Errorf("a launcher can be generated only for a single product"))
}
- versionDefaults, err := generateVersionDefaults()
- if err != nil {
- quit(err)
+ if *inputVariables == "" {
+ quit(fmt.Errorf("the product launcher requires an input variables file"))
}
- versionDefaultsPath := outputFilePath(versionDefaultsMk)
- err = writeGenerated(versionDefaultsPath, versionDefaults)
- if err != nil {
- fmt.Fprintf(os.Stderr, "%s:%s", files[0], err)
- ok = false
+ if !convertOne(*inputVariables) {
+ quit(fmt.Errorf("the product launcher input variables file failed to convert"))
}
- err = writeGenerated(*launcher, mk2rbc.Launcher(outputFilePath(files[0]), versionDefaultsPath,
+ err := writeGenerated(*launcher, mk2rbc.Launcher(outputFilePath(files[0]), outputFilePath(*inputVariables),
mk2rbc.MakePath2ModuleName(files[0])))
if err != nil {
- fmt.Fprintf(os.Stderr, "%s:%s", files[0], err)
+ fmt.Fprintf(os.Stderr, "%s: %s", files[0], err)
+ ok = false
+ }
+ }
+ if *boardlauncher != "" {
+ if len(files) != 1 {
+ quit(fmt.Errorf("a launcher can be generated only for a single product"))
+ }
+ if *inputVariables == "" {
+ quit(fmt.Errorf("the board launcher requires an input variables file"))
+ }
+ if !convertOne(*inputVariables) {
+ quit(fmt.Errorf("the board launcher input variables file failed to convert"))
+ }
+ err := writeGenerated(*boardlauncher, mk2rbc.BoardLauncher(
+ outputFilePath(files[0]), outputFilePath(*inputVariables)))
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "%s: %s", files[0], err)
ok = false
}
}
- printStats()
if *errstat {
errorLogger.printStatistics()
+ printStats()
}
if !ok {
os.Exit(1)
}
}
-func generateVersionDefaults() (string, error) {
- versionSettings, err := mk2rbc.ParseVersionDefaults(filepath.Join(*rootDir, versionDefaultsMk))
- if err != nil {
- return "", err
- }
- return mk2rbc.VersionDefaults(versionSettings), nil
-
-}
-
func quit(s interface{}) {
fmt.Fprintln(os.Stderr, s)
os.Exit(2)
@@ -311,19 +312,16 @@
}()
mk2starRequest := mk2rbc.Request{
- MkFile: mkFile,
- Reader: nil,
- RootDir: *rootDir,
- OutputDir: *outputTop,
- OutputSuffix: *suffix,
- TracedVariables: tracedVariables,
- TraceCalls: *traceCalls,
- WarnPartialSuccess: *warn,
- SourceFS: os.DirFS(*rootDir),
- MakefileFinder: makefileFinder,
- }
- if *errstat {
- mk2starRequest.ErrorLogger = errorLogger
+ MkFile: mkFile,
+ Reader: nil,
+ RootDir: *rootDir,
+ OutputDir: *outputTop,
+ OutputSuffix: *suffix,
+ TracedVariables: tracedVariables,
+ TraceCalls: *traceCalls,
+ SourceFS: os.DirFS(*rootDir),
+ MakefileFinder: makefileFinder,
+ ErrorLogger: errorLogger,
}
ss, err := mk2rbc.Convert(mk2starRequest)
if err != nil {
@@ -401,9 +399,6 @@
func printStats() {
var sortedFiles []string
- if !*warn && !*verbose {
- return
- }
for p := range converted {
sortedFiles = append(sortedFiles, p)
}
@@ -419,29 +414,22 @@
nOk++
}
}
- if *warn {
- if nPartial > 0 {
- fmt.Fprintf(os.Stderr, "Conversion was partially successful for:\n")
- for _, f := range sortedFiles {
- if ss := converted[f]; ss != nil && ss.HasErrors() {
- fmt.Fprintln(os.Stderr, " ", f)
- }
- }
- }
-
- if nFailed > 0 {
- fmt.Fprintf(os.Stderr, "Conversion failed for files:\n")
- for _, f := range sortedFiles {
- if converted[f] == nil {
- fmt.Fprintln(os.Stderr, " ", f)
- }
+ if nPartial > 0 {
+ fmt.Fprintf(os.Stderr, "Conversion was partially successful for:\n")
+ for _, f := range sortedFiles {
+ if ss := converted[f]; ss != nil && ss.HasErrors() {
+ fmt.Fprintln(os.Stderr, " ", f)
}
}
}
- if *verbose {
- fmt.Fprintf(os.Stderr, "%-16s%5d\n", "Succeeded:", nOk)
- fmt.Fprintf(os.Stderr, "%-16s%5d\n", "Partial:", nPartial)
- fmt.Fprintf(os.Stderr, "%-16s%5d\n", "Failed:", nFailed)
+
+ if nFailed > 0 {
+ fmt.Fprintf(os.Stderr, "Conversion failed for files:\n")
+ for _, f := range sortedFiles {
+ if converted[f] == nil {
+ fmt.Fprintln(os.Stderr, " ", f)
+ }
+ }
}
}
@@ -450,11 +438,18 @@
formattingArgs []string
}
-type errorsByType struct {
+type errorSink struct {
data map[string]datum
}
-func (ebt errorsByType) NewError(message string, node parser.Node, args ...interface{}) {
+func (ebt errorSink) NewError(el mk2rbc.ErrorLocation, node parser.Node, message string, args ...interface{}) {
+ fmt.Fprint(os.Stderr, el, ": ")
+ fmt.Fprintf(os.Stderr, message, args...)
+ fmt.Fprintln(os.Stderr)
+ if !*errstat {
+ return
+ }
+
v, exists := ebt.data[message]
if exists {
v.count++
@@ -479,7 +474,7 @@
ebt.data[message] = v
}
-func (ebt errorsByType) printStatistics() {
+func (ebt errorSink) printStatistics() {
if len(ebt.data) > 0 {
fmt.Fprintln(os.Stderr, "Error counts:")
}
diff --git a/mk2rbc/expr.go b/mk2rbc/expr.go
index 0bb8b95..e78f492 100644
--- a/mk2rbc/expr.go
+++ b/mk2rbc/expr.go
@@ -16,23 +16,22 @@
import (
"fmt"
- "strconv"
"strings"
-
- mkparser "android/soong/androidmk/parser"
)
-// Represents an expression in the Starlark code. An expression has
-// a type, and it can be evaluated.
+// Represents an expression in the Starlark code. An expression has a type.
type starlarkExpr interface {
starlarkNode
typ() starlarkType
- // Try to substitute variable values. Return substitution result
- // and whether it is the same as the original expression.
- eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool)
// Emit the code to copy the expression, otherwise we will end up
// with source and target pointing to the same list.
emitListVarCopy(gctx *generationContext)
+ // Return the expression, calling the transformer func for
+ // every expression in the tree. If the transformer func returns non-nil,
+ // its result is used in place of the expression it was called with in the
+ // resulting expression. The resulting starlarkExpr will contain as many
+ // of the same objects from the original expression as possible.
+ transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr
}
func maybeString(expr starlarkExpr) (string, bool) {
@@ -46,12 +45,6 @@
literal string
}
-func (s *stringLiteralExpr) eval(_ map[string]starlarkExpr) (res starlarkExpr, same bool) {
- res = s
- same = true
- return
-}
-
func (s *stringLiteralExpr) emit(gctx *generationContext) {
gctx.writef("%q", s.literal)
}
@@ -64,17 +57,19 @@
s.emit(gctx)
}
+func (s *stringLiteralExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
+ if replacement := transformer(s); replacement != nil {
+ return replacement
+ } else {
+ return s
+ }
+}
+
// Integer literal
type intLiteralExpr struct {
literal int
}
-func (s *intLiteralExpr) eval(_ map[string]starlarkExpr) (res starlarkExpr, same bool) {
- res = s
- same = true
- return
-}
-
func (s *intLiteralExpr) emit(gctx *generationContext) {
gctx.writef("%d", s.literal)
}
@@ -87,6 +82,66 @@
s.emit(gctx)
}
+func (s *intLiteralExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
+ if replacement := transformer(s); replacement != nil {
+ return replacement
+ } else {
+ return s
+ }
+}
+
+// Boolean literal
+type boolLiteralExpr struct {
+ literal bool
+}
+
+func (b *boolLiteralExpr) emit(gctx *generationContext) {
+ if b.literal {
+ gctx.write("True")
+ } else {
+ gctx.write("False")
+ }
+}
+
+func (_ *boolLiteralExpr) typ() starlarkType {
+ return starlarkTypeBool
+}
+
+func (b *boolLiteralExpr) emitListVarCopy(gctx *generationContext) {
+ b.emit(gctx)
+}
+
+func (b *boolLiteralExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
+ if replacement := transformer(b); replacement != nil {
+ return replacement
+ } else {
+ return b
+ }
+}
+
+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]
@@ -95,6 +150,35 @@
args []starlarkExpr
}
+func NewInterpolateExpr(parts []starlarkExpr) starlarkExpr {
+ result := &interpolateExpr{}
+ needString := true
+ for _, part := range parts {
+ if needString {
+ if strLit, ok := part.(*stringLiteralExpr); ok {
+ result.chunks = append(result.chunks, strLit.literal)
+ } else {
+ result.chunks = append(result.chunks, "")
+ }
+ needString = false
+ } else {
+ if strLit, ok := part.(*stringLiteralExpr); ok {
+ result.chunks[len(result.chunks)-1] += strLit.literal
+ } else {
+ result.args = append(result.args, part)
+ needString = true
+ }
+ }
+ }
+ if len(result.chunks) == len(result.args) {
+ result.chunks = append(result.chunks, "")
+ }
+ if len(result.args) == 0 {
+ return &stringLiteralExpr{literal: strings.Join(result.chunks, "")}
+ }
+ return result
+}
+
func (xi *interpolateExpr) emit(gctx *generationContext) {
if len(xi.chunks) != len(xi.args)+1 {
panic(fmt.Errorf("malformed interpolateExpr: #chunks(%d) != #args(%d)+1",
@@ -106,7 +190,7 @@
format += "%s" + strings.ReplaceAll(chunk, "%", "%%")
}
gctx.writef("%q %% ", format)
- emitarg := func(arg starlarkExpr) {
+ emitArg := func(arg starlarkExpr) {
if arg.typ() == starlarkTypeList {
gctx.write(`" ".join(`)
arg.emit(gctx)
@@ -116,49 +200,18 @@
}
}
if len(xi.args) == 1 {
- emitarg(xi.args[0])
+ emitArg(xi.args[0])
} else {
sep := "("
for _, arg := range xi.args {
gctx.write(sep)
- emitarg(arg)
+ emitArg(arg)
sep = ", "
}
gctx.write(")")
}
}
-func (xi *interpolateExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) {
- same = true
- newChunks := []string{xi.chunks[0]}
- var newArgs []starlarkExpr
- for i, arg := range xi.args {
- newArg, sameArg := arg.eval(valueMap)
- same = same && sameArg
- switch x := newArg.(type) {
- case *stringLiteralExpr:
- newChunks[len(newChunks)-1] += x.literal + xi.chunks[i+1]
- same = false
- continue
- case *intLiteralExpr:
- newChunks[len(newChunks)-1] += strconv.Itoa(x.literal) + xi.chunks[i+1]
- same = false
- continue
- default:
- newChunks = append(newChunks, xi.chunks[i+1])
- newArgs = append(newArgs, newArg)
- }
- }
- if same {
- res = xi
- } else if len(newChunks) == 1 {
- res = &stringLiteralExpr{newChunks[0]}
- } else {
- res = &interpolateExpr{chunks: newChunks, args: newArgs}
- }
- return
-}
-
func (_ *interpolateExpr) typ() starlarkType {
return starlarkTypeString
}
@@ -167,19 +220,29 @@
xi.emit(gctx)
}
+func (xi *interpolateExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
+ argsCopy := make([]starlarkExpr, len(xi.args))
+ for i, arg := range xi.args {
+ argsCopy[i] = arg.transform(transformer)
+ }
+ xi.args = argsCopy
+ if replacement := transformer(xi); replacement != nil {
+ return replacement
+ } else {
+ return xi
+ }
+}
+
type variableRefExpr struct {
ref variable
isDefined bool
}
-func (v *variableRefExpr) eval(map[string]starlarkExpr) (res starlarkExpr, same bool) {
- predefined, ok := v.ref.(*predefinedVariable)
- if same = !ok; same {
- res = v
- } else {
- res = predefined.value
+func NewVariableRefExpr(ref variable, isDefined bool) starlarkExpr {
+ if predefined, ok := ref.(*predefinedVariable); ok {
+ return predefined.value
}
- return
+ return &variableRefExpr{ref, isDefined}
}
func (v *variableRefExpr) emit(gctx *generationContext) {
@@ -197,17 +260,61 @@
}
}
-type notExpr struct {
+func (v *variableRefExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
+ if replacement := transformer(v); replacement != nil {
+ return replacement
+ } else {
+ return v
+ }
+}
+
+type toStringExpr struct {
expr starlarkExpr
}
-func (n *notExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) {
- if x, same := n.expr.eval(valueMap); same {
- res = n
- } else {
- res = ¬Expr{expr: x}
+func (s *toStringExpr) emit(ctx *generationContext) {
+ switch s.expr.typ() {
+ case starlarkTypeString, starlarkTypeUnknown:
+ // Assume unknown types are strings already.
+ s.expr.emit(ctx)
+ case starlarkTypeList:
+ ctx.write(`" ".join(`)
+ s.expr.emit(ctx)
+ ctx.write(")")
+ case starlarkTypeInt:
+ ctx.write(`("%d" % (`)
+ s.expr.emit(ctx)
+ ctx.write("))")
+ case starlarkTypeBool:
+ ctx.write(`("true" if (`)
+ s.expr.emit(ctx)
+ ctx.write(`) else "")`)
+ case starlarkTypeVoid:
+ ctx.write(`""`)
+ default:
+ panic("Unknown starlark type!")
}
- return
+}
+
+func (s *toStringExpr) typ() starlarkType {
+ return starlarkTypeString
+}
+
+func (s *toStringExpr) emitListVarCopy(gctx *generationContext) {
+ s.emit(gctx)
+}
+
+func (s *toStringExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
+ s.expr = s.expr.transform(transformer)
+ if replacement := transformer(s); replacement != nil {
+ return replacement
+ } else {
+ return s
+ }
+}
+
+type notExpr struct {
+ expr starlarkExpr
}
func (n *notExpr) emit(ctx *generationContext) {
@@ -223,38 +330,26 @@
n.emit(gctx)
}
+func (n *notExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
+ n.expr = n.expr.transform(transformer)
+ if replacement := transformer(n); replacement != nil {
+ return replacement
+ } else {
+ return n
+ }
+}
+
type eqExpr struct {
left, right starlarkExpr
isEq bool // if false, it's !=
}
-func (eq *eqExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) {
- xLeft, sameLeft := eq.left.eval(valueMap)
- xRight, sameRight := eq.right.eval(valueMap)
- if same = sameLeft && sameRight; same {
- res = eq
- } else {
- res = &eqExpr{left: xLeft, right: xRight, isEq: eq.isEq}
- }
- return
-}
-
func (eq *eqExpr) emit(gctx *generationContext) {
- emitSimple := func(expr starlarkExpr) {
- if eq.isEq {
- gctx.write("not ")
- }
- expr.emit(gctx)
+ if eq.left.typ() != eq.right.typ() {
+ eq.left = &toStringExpr{expr: eq.left}
+ eq.right = &toStringExpr{expr: eq.right}
}
- // Are we checking that a variable is empty?
- if isEmptyString(eq.left) {
- emitSimple(eq.right)
- return
- } else if isEmptyString(eq.right) {
- emitSimple(eq.left)
- return
- }
// General case
eq.left.emit(gctx)
if eq.isEq {
@@ -273,18 +368,21 @@
eq.emit(gctx)
}
+func (eq *eqExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
+ eq.left = eq.left.transform(transformer)
+ eq.right = eq.right.transform(transformer)
+ if replacement := transformer(eq); replacement != nil {
+ return replacement
+ } else {
+ return eq
+ }
+}
+
// variableDefinedExpr corresponds to Make's ifdef VAR
type variableDefinedExpr struct {
v variable
}
-func (v *variableDefinedExpr) eval(_ map[string]starlarkExpr) (res starlarkExpr, same bool) {
- res = v
- same = true
- return
-
-}
-
func (v *variableDefinedExpr) emit(gctx *generationContext) {
if v.v != nil {
v.v.emitDefined(gctx)
@@ -301,24 +399,13 @@
v.emit(gctx)
}
-type listExpr struct {
- items []starlarkExpr
+func (v *variableDefinedExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
+ // TODO: VariableDefinedExpr isn't really an expression?
+ return v
}
-func (l *listExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) {
- newItems := make([]starlarkExpr, len(l.items))
- same = true
- for i, item := range l.items {
- var sameItem bool
- newItems[i], sameItem = item.eval(valueMap)
- same = same && sameItem
- }
- if same {
- res = l
- } else {
- res = &listExpr{newItems}
- }
- return
+type listExpr struct {
+ items []starlarkExpr
}
func (l *listExpr) emit(gctx *generationContext) {
@@ -355,6 +442,19 @@
l.emit(gctx)
}
+func (l *listExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
+ itemsCopy := make([]starlarkExpr, len(l.items))
+ for i, item := range l.items {
+ itemsCopy[i] = item.transform(transformer)
+ }
+ l.items = itemsCopy
+ if replacement := transformer(l); replacement != nil {
+ return replacement
+ } else {
+ return l
+ }
+}
+
func newStringListExpr(items []string) *listExpr {
v := listExpr{}
for _, item := range items {
@@ -363,7 +463,7 @@
return &v
}
-// concatExpr generates epxr1 + expr2 + ... + exprN in Starlark.
+// concatExpr generates expr1 + expr2 + ... + exprN in Starlark.
type concatExpr struct {
items []starlarkExpr
}
@@ -394,22 +494,6 @@
gctx.indentLevel -= 2
}
-func (c *concatExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) {
- same = true
- xConcat := &concatExpr{items: make([]starlarkExpr, len(c.items))}
- for i, item := range c.items {
- var sameItem bool
- xConcat.items[i], sameItem = item.eval(valueMap)
- same = same && sameItem
- }
- if same {
- res = c
- } else {
- res = xConcat
- }
- return
-}
-
func (_ *concatExpr) typ() starlarkType {
return starlarkTypeList
}
@@ -418,6 +502,19 @@
c.emit(gctx)
}
+func (c *concatExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
+ itemsCopy := make([]starlarkExpr, len(c.items))
+ for i, item := range c.items {
+ itemsCopy[i] = item.transform(transformer)
+ }
+ c.items = itemsCopy
+ if replacement := transformer(c); replacement != nil {
+ return replacement
+ } else {
+ return c
+ }
+}
+
// inExpr generates <expr> [not] in <list>
type inExpr struct {
expr starlarkExpr
@@ -425,19 +522,6 @@
isNot bool
}
-func (i *inExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) {
- x := &inExpr{isNot: i.isNot}
- var sameExpr, sameList bool
- x.expr, sameExpr = i.expr.eval(valueMap)
- x.list, sameList = i.list.eval(valueMap)
- if same = sameExpr && sameList; same {
- res = i
- } else {
- res = x
- }
- return
-}
-
func (i *inExpr) emit(gctx *generationContext) {
i.expr.emit(gctx)
if i.isNot {
@@ -456,35 +540,44 @@
i.emit(gctx)
}
+func (i *inExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
+ i.expr = i.expr.transform(transformer)
+ i.list = i.list.transform(transformer)
+ if replacement := transformer(i); replacement != nil {
+ return replacement
+ } else {
+ return i
+ }
+}
+
type indexExpr struct {
array starlarkExpr
index starlarkExpr
}
-func (ix indexExpr) emit(gctx *generationContext) {
+func (ix *indexExpr) emit(gctx *generationContext) {
ix.array.emit(gctx)
gctx.write("[")
ix.index.emit(gctx)
gctx.write("]")
}
-func (ix indexExpr) typ() starlarkType {
+func (ix *indexExpr) typ() starlarkType {
return starlarkTypeString
}
-func (ix indexExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) {
- newArray, isSameArray := ix.array.eval(valueMap)
- newIndex, isSameIndex := ix.index.eval(valueMap)
- if same = isSameArray && isSameIndex; same {
- res = ix
- } else {
- res = &indexExpr{newArray, newIndex}
- }
- return
+func (ix *indexExpr) emitListVarCopy(gctx *generationContext) {
+ ix.emit(gctx)
}
-func (ix indexExpr) emitListVarCopy(gctx *generationContext) {
- ix.emit(gctx)
+func (ix *indexExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
+ ix.array = ix.array.transform(transformer)
+ ix.index = ix.index.transform(transformer)
+ if replacement := transformer(ix); replacement != nil {
+ return replacement
+ } else {
+ return ix
+ }
}
type callExpr struct {
@@ -494,51 +587,16 @@
returnType starlarkType
}
-func (cx *callExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) {
- newCallExpr := &callExpr{name: cx.name, args: make([]starlarkExpr, len(cx.args)),
- returnType: cx.returnType}
- if cx.object != nil {
- newCallExpr.object, same = cx.object.eval(valueMap)
- } else {
- same = true
- }
- for i, args := range cx.args {
- var s bool
- newCallExpr.args[i], s = args.eval(valueMap)
- same = same && s
- }
- if same {
- res = cx
- } else {
- res = newCallExpr
- }
- return
-}
-
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)
@@ -555,29 +613,146 @@
cx.emit(gctx)
}
+func (cx *callExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
+ if cx.object != nil {
+ cx.object = cx.object.transform(transformer)
+ }
+ argsCopy := make([]starlarkExpr, len(cx.args))
+ for i, arg := range cx.args {
+ argsCopy[i] = arg.transform(transformer)
+ }
+ if replacement := transformer(cx); replacement != nil {
+ return replacement
+ } else {
+ return cx
+ }
+}
+
+type ifExpr struct {
+ condition starlarkExpr
+ ifTrue starlarkExpr
+ ifFalse starlarkExpr
+}
+
+func (i *ifExpr) emit(gctx *generationContext) {
+ gctx.write("(")
+ i.ifTrue.emit(gctx)
+ gctx.write(" if ")
+ i.condition.emit(gctx)
+ gctx.write(" else ")
+ i.ifFalse.emit(gctx)
+ gctx.write(")")
+}
+
+func (i *ifExpr) typ() starlarkType {
+ tType := i.ifTrue.typ()
+ fType := i.ifFalse.typ()
+ if tType != fType && tType != starlarkTypeUnknown && fType != starlarkTypeUnknown {
+ panic("Conflicting types in if expression")
+ }
+ if tType != starlarkTypeUnknown {
+ return tType
+ } else {
+ return fType
+ }
+}
+
+func (i *ifExpr) emitListVarCopy(gctx *generationContext) {
+ i.emit(gctx)
+}
+
+func (i *ifExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
+ i.condition = i.condition.transform(transformer)
+ i.ifTrue = i.ifTrue.transform(transformer)
+ i.ifFalse = i.ifFalse.transform(transformer)
+ if replacement := transformer(i); replacement != nil {
+ return replacement
+ } else {
+ return i
+ }
+}
+
+type identifierExpr struct {
+ name string
+}
+
+func (i *identifierExpr) emit(gctx *generationContext) {
+ gctx.write(i.name)
+}
+
+func (i *identifierExpr) typ() starlarkType {
+ return starlarkTypeUnknown
+}
+
+func (i *identifierExpr) emitListVarCopy(gctx *generationContext) {
+ i.emit(gctx)
+}
+
+func (i *identifierExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
+ if replacement := transformer(i); replacement != nil {
+ return replacement
+ } else {
+ return i
+ }
+}
+
+type foreachExpr struct {
+ varName string
+ list starlarkExpr
+ action starlarkExpr
+}
+
+func (f *foreachExpr) emit(gctx *generationContext) {
+ gctx.write("[")
+ f.action.emit(gctx)
+ gctx.write(" for " + f.varName + " in ")
+ f.list.emit(gctx)
+ gctx.write("]")
+}
+
+func (f *foreachExpr) typ() starlarkType {
+ return starlarkTypeList
+}
+
+func (f *foreachExpr) emitListVarCopy(gctx *generationContext) {
+ f.emit(gctx)
+}
+
+func (f *foreachExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
+ f.list = f.list.transform(transformer)
+ f.action = f.action.transform(transformer)
+ if replacement := transformer(f); replacement != nil {
+ return replacement
+ } else {
+ return f
+ }
+}
+
type badExpr struct {
- node mkparser.Node
- message string
+ errorLocation ErrorLocation
+ message string
}
-func (b *badExpr) eval(_ map[string]starlarkExpr) (res starlarkExpr, same bool) {
- res = b
- same = true
- return
-}
-
-func (b *badExpr) emit(_ *generationContext) {
- panic("implement me")
+func (b *badExpr) emit(gctx *generationContext) {
+ gctx.emitConversionError(b.errorLocation, b.message)
}
func (_ *badExpr) typ() starlarkType {
return starlarkTypeUnknown
}
-func (b *badExpr) emitListVarCopy(gctx *generationContext) {
+func (_ *badExpr) emitListVarCopy(_ *generationContext) {
panic("implement me")
}
+func (b *badExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
+ if replacement := transformer(b); replacement != nil {
+ return replacement
+ } else {
+ return b
+ }
+}
+
func maybeConvertToStringList(expr starlarkExpr) starlarkExpr {
if xString, ok := expr.(*stringLiteralExpr); ok {
return newStringListExpr(strings.Fields(xString.literal))
diff --git a/mk2rbc/mk2rbc.go b/mk2rbc/mk2rbc.go
index 6227164..04038e4 100644
--- a/mk2rbc/mk2rbc.go
+++ b/mk2rbc/mk2rbc.go
@@ -52,6 +52,7 @@
// And here are the functions and variables:
cfnGetCfg = baseName + ".cfg"
cfnMain = baseName + ".product_configuration"
+ cfnBoardMain = baseName + ".board_configuration"
cfnPrintVars = baseName + ".printvars"
cfnWarning = baseName + ".warning"
cfnLocalAppend = baseName + ".local_append"
@@ -61,114 +62,104 @@
)
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"
- 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},
- "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},
- "enforce-product-packages-exist": {baseName + ".enforce_product_packages_exist", starlarkTypeVoid, hiddenArgNone},
- "error": {baseName + ".mkerror", starlarkTypeVoid, hiddenArgNone},
- "findstring": {"!findstring", starlarkTypeInt, 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},
- "get-vendor-board-platforms": {"!get-vendor-board-platforms", starlarkTypeList, hiddenArgNone}, // internal macro, used by is-board-platform, etc.
- "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": &isBoardPlatformCallParser{},
+ "is-board-platform2": &simpleCallParser{name: baseName + ".board_platform_is", returnType: starlarkTypeBool, addGlobals: true},
+ "is-board-platform-in-list": &isBoardPlatformInListCallParser{},
+ "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},
+ "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},
+ "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},
}
-var builtinFuncRex = regexp.MustCompile(
- "^(addprefix|addsuffix|abspath|and|basename|call|dir|error|eval" +
- "|flavor|foreach|file|filter|filter-out|findstring|firstword|guile" +
- "|if|info|join|lastword|notdir|or|origin|patsubst|realpath" +
- "|shell|sort|strip|subst|suffix|value|warning|word|wordlist|words" +
- "|wildcard)")
+// 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_]*$")
// Conversion request parameters
type Request struct {
- MkFile string // file to convert
- Reader io.Reader // if set, read input from this stream instead
- RootDir string // root directory path used to resolve included files
- OutputSuffix string // generated Starlark files suffix
- OutputDir string // if set, root of the output hierarchy
- ErrorLogger ErrorMonitorCB
- TracedVariables []string // trace assignment to these variables
- TraceCalls bool
- WarnPartialSuccess bool
- SourceFS fs.FS
- MakefileFinder MakefileFinder
+ MkFile string // file to convert
+ Reader io.Reader // if set, read input from this stream instead
+ RootDir string // root directory path used to resolve included files
+ OutputSuffix string // generated Starlark files suffix
+ OutputDir string // if set, root of the output hierarchy
+ ErrorLogger ErrorLogger
+ TracedVariables []string // trace assignment to these variables
+ TraceCalls bool
+ SourceFS fs.FS
+ MakefileFinder MakefileFinder
}
-// An error sink allowing to gather error statistics.
-// NewError is called on every error encountered during processing.
-type ErrorMonitorCB interface {
- NewError(s string, node mkparser.Node, args ...interface{})
+// ErrorLogger prints errors and gathers error statistics.
+// Its NewError function is called on every error encountered during the conversion.
+type ErrorLogger interface {
+ NewError(el ErrorLocation, node mkparser.Node, text string, args ...interface{})
+}
+
+type ErrorLocation struct {
+ MkFile string
+ MkLine int
+}
+
+func (el ErrorLocation) String() string {
+ return fmt.Sprintf("%s:%d", el.MkFile, el.MkLine)
}
// Derives module name for a given file. It is base name
@@ -244,10 +235,6 @@
node.emit(gctx)
}
- if ss.hasErrors && ss.warnPartialSuccess {
- gctx.newLine()
- gctx.writef("%s(%q, %q)", cfnWarning, filepath.Base(ss.mkFile), "partially successful conversion")
- }
if gctx.starScript.traceCalls {
gctx.newLine()
gctx.writef(`print("<%s")`, gctx.starScript.mkFile)
@@ -302,6 +289,10 @@
gctx.writef("%*s", 2*gctx.indentLevel, "")
}
+func (gctx *generationContext) emitConversionError(el ErrorLocation, message string) {
+ gctx.writef(`rblf.mk2rbc_error("%s", %q)`, el, message)
+}
+
type knownVariable struct {
name string
class varClass
@@ -366,17 +357,17 @@
// Information about the generated Starlark script.
type StarlarkScript struct {
- mkFile string
- moduleName string
- mkPos scanner.Position
- nodes []starlarkNode
- inherited []*moduleInfo
- hasErrors bool
- topDir string
- traceCalls bool // print enter/exit each init function
- warnPartialSuccess bool
- sourceFS fs.FS
- makefileFinder MakefileFinder
+ mkFile string
+ moduleName string
+ mkPos scanner.Position
+ nodes []starlarkNode
+ inherited []*moduleInfo
+ hasErrors bool
+ topDir string
+ traceCalls bool // print enter/exit each init function
+ sourceFS fs.FS
+ makefileFinder MakefileFinder
+ nodeLocator func(pos mkparser.Pos) int
}
func (ss *StarlarkScript) newNode(node starlarkNode) {
@@ -400,9 +391,8 @@
ifNestLevel int
moduleNameCount map[string]int // count of imported modules with given basename
fatalError error
- builtinMakeVars map[string]starlarkExpr
outputSuffix string
- errorLogger ErrorMonitorCB
+ errorLogger ErrorLogger
tracedVariables map[string]bool // variables to be traced in the generated script
variables map[string]variable
varAssignments *varAssignmentScope
@@ -453,7 +443,6 @@
currentNodeIndex: 0,
ifNestLevel: 0,
moduleNameCount: make(map[string]int),
- builtinMakeVars: map[string]starlarkExpr{},
variables: make(map[string]variable),
dependentModules: make(map[string]*moduleInfo),
soongNamespaces: make(map[string]map[string]bool),
@@ -536,7 +525,15 @@
return
}
name := a.Name.Strings[0]
- // Soong confuguration
+ // The `override` directive
+ // override FOO :=
+ // is parsed as an assignment to a variable named `override FOO`.
+ // There are very few places where `override` is used, just flag it.
+ if strings.HasPrefix(name, "override ") {
+ ctx.errorf(a, "cannot handle override directive")
+ }
+
+ // Soong configuration
if strings.HasPrefix(name, soongNsPrefix) {
ctx.handleSoongNsAssignment(strings.TrimPrefix(name, soongNsPrefix), a)
return
@@ -547,7 +544,7 @@
return
}
_, isTraced := ctx.tracedVariables[name]
- asgn := &assignmentNode{lhs: lhs, mkValue: a.Value, isTraced: isTraced}
+ asgn := &assignmentNode{lhs: lhs, mkValue: a.Value, isTraced: isTraced, location: ctx.errorLocation(a)}
if lhs.valueType() == starlarkTypeUnknown {
// Try to divine variable type from the RHS
asgn.value = ctx.parseMakeString(a, a.Value)
@@ -581,9 +578,6 @@
}
}
- // TODO(asmundak): move evaluation to a separate pass
- asgn.value, _ = asgn.value.eval(ctx.builtinMakeVars)
-
asgn.previous = ctx.lastAssignment(name)
ctx.setLastAssignment(name, asgn)
switch a.Type {
@@ -610,7 +604,6 @@
ctx.wrapBadExpr(xBad)
return
}
- val, _ = val.eval(ctx.builtinMakeVars)
// Unfortunately, Soong namespaces can be set up by directly setting corresponding Make
// variables instead of via add_soong_config_namespace + add_soong_config_var_value.
@@ -628,8 +621,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,
}})
}
@@ -637,7 +630,7 @@
// Upon seeing
// SOONG_CONFIG_x_y = v
// find a namespace called `x` and act as if we encountered
- // $(call add_config_var_value(x,y,v)
+ // $(call soong_config_set,x,y,v)
// or check that `x_y` is a namespace, and then add the RHS of this assignment as variables in
// it.
// Emit an error in the ambiguous situation (namespaces `foo_bar` with a variable `baz`
@@ -678,13 +671,13 @@
ctx.errorf(asgn, "no %s variable in %s namespace, please use add_soong_config_var_value instead", varName, namespaceName)
return
}
- fname := soongConfigVarSetOld
+ 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,7 +759,6 @@
func (ctx *parseContext) handleSubConfig(
v mkparser.Node, pathExpr starlarkExpr, loadAlways bool, processModule func(inheritedModule)) {
- pathExpr, _ = pathExpr.eval(ctx.builtinMakeVars)
// In a simple case, the name of a module to inherit/include is known statically.
if path, ok := maybeString(pathExpr); ok {
@@ -866,7 +858,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})
})
@@ -885,36 +883,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)
}
}
@@ -961,25 +963,16 @@
ctx.pushReceiver(&block)
for ctx.hasNodes() {
node := ctx.getNode()
- if ctx.handleSimpleStatement(node) {
- continue
- }
- switch d := node.(type) {
- case *mkparser.Directive:
+ if d, ok := node.(*mkparser.Directive); ok {
switch d.Name {
case "else", "elifdef", "elifndef", "elifeq", "elifneq", "endif":
ctx.popReceiver()
ctx.receiver.newNode(&block)
ctx.backNode()
return
- case "ifdef", "ifndef", "ifeq", "ifneq":
- ctx.handleIfBlock(d)
- default:
- ctx.errorf(d, "unexpected directive %s", d.Name)
}
- default:
- ctx.errorf(node, "unexpected statement")
}
+ ctx.handleSimpleStatement(node)
}
ctx.fatalError = fmt.Errorf("no matching endif for %s", check.Dump())
ctx.popReceiver()
@@ -1019,10 +1012,10 @@
func (ctx *parseContext) newBadExpr(node mkparser.Node, text string, args ...interface{}) starlarkExpr {
message := fmt.Sprintf(text, args...)
if ctx.errorLogger != nil {
- ctx.errorLogger.NewError(text, node, args)
+ ctx.errorLogger.NewError(ctx.errorLocation(node), node, text, args...)
}
ctx.script.hasErrors = true
- return &badExpr{node, message}
+ return &badExpr{errorLocation: ctx.errorLocation(node), message: message}
}
func (ctx *parseContext) parseCompare(cond *mkparser.Directive) starlarkExpr {
@@ -1040,146 +1033,105 @@
args[1].TrimLeftSpaces()
isEq := !strings.HasSuffix(cond.Name, "neq")
- switch xLeft := ctx.parseMakeString(cond, args[0]).(type) {
- case *stringLiteralExpr, *variableRefExpr:
- switch xRight := ctx.parseMakeString(cond, args[1]).(type) {
- case *stringLiteralExpr, *variableRefExpr:
- return &eqExpr{left: xLeft, right: xRight, isEq: isEq}
- case *badExpr:
- return xRight
+ xLeft := ctx.parseMakeString(cond, args[0])
+ xRight := ctx.parseMakeString(cond, args[1])
+ if bad, ok := xLeft.(*badExpr); ok {
+ return bad
+ }
+ if bad, ok := xRight.(*badExpr); ok {
+ return bad
+ }
+
+ if expr, ok := ctx.parseCompareSpecialCases(cond, xLeft, xRight); ok {
+ 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
default:
- expr, ok := ctx.parseCheckFunctionCallResult(cond, xLeft, args[1])
- if ok {
- return expr
- }
- return ctx.newBadExpr(cond, "right operand is too complex: %s", args[1].Dump())
- }
- case *badExpr:
- return xLeft
- default:
- switch xRight := ctx.parseMakeString(cond, args[1]).(type) {
- case *stringLiteralExpr, *variableRefExpr:
- expr, ok := ctx.parseCheckFunctionCallResult(cond, xRight, args[0])
- if ok {
- return expr
- }
- return ctx.newBadExpr(cond, "left operand is too complex: %s", args[0].Dump())
- case *badExpr:
- return xRight
- default:
- return ctx.newBadExpr(cond, "operands are too complex: (%s,%s)", args[0].Dump(), args[1].Dump())
+ 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
+ }
+ }
+ }
+
+ return &eqExpr{left: xLeft, right: xRight, isEq: isEq}
}
-func (ctx *parseContext) parseCheckFunctionCallResult(directive *mkparser.Directive, xValue starlarkExpr,
- varArg *mkparser.MakeString) (starlarkExpr, bool) {
- mkSingleVar, ok := varArg.SingleVariable()
- if !ok {
- return nil, false
- }
- expr := ctx.parseReference(directive, mkSingleVar)
- negate := strings.HasSuffix(directive.Name, "neq")
- checkIsSomethingFunction := func(xCall *callExpr) starlarkExpr {
- s, ok := maybeString(xValue)
- 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 x := expr.(type) {
- case *callExpr:
- switch x.name {
- case "filter":
- return ctx.parseCompareFilterFuncResult(directive, x, xValue, !negate), true
- case "filter-out":
- return ctx.parseCompareFilterFuncResult(directive, x, xValue, negate), true
- case "wildcard":
- return ctx.parseCompareWildcardFuncResult(directive, x, xValue, negate), true
- case "findstring":
- return ctx.parseCheckFindstringFuncResult(directive, x, xValue, negate), true
- case "strip":
- return ctx.parseCompareStripFuncResult(directive, x, xValue, negate), true
- case "is-board-platform":
- if xBad := checkIsSomethingFunction(x); xBad != nil {
- return xBad, true
- }
- return &eqExpr{
- left: &variableRefExpr{ctx.addVariable("TARGET_BOARD_PLATFORM"), false},
- right: x.args[0],
- isEq: !negate,
- }, true
- case "is-board-platform-in-list":
- if xBad := checkIsSomethingFunction(x); xBad != nil {
- return xBad, true
- }
- return &inExpr{
- expr: &variableRefExpr{ctx.addVariable("TARGET_BOARD_PLATFORM"), false},
- list: maybeConvertToStringList(x.args[0]),
- isNot: negate,
- }, true
- case "is-product-in-list":
- if xBad := checkIsSomethingFunction(x); xBad != nil {
- return xBad, true
- }
- return &inExpr{
- expr: &variableRefExpr{ctx.addVariable("TARGET_PRODUCT"), true},
- list: maybeConvertToStringList(x.args[0]),
- isNot: negate,
- }, true
- case "is-vendor-board-platform":
- if xBad := checkIsSomethingFunction(x); xBad != nil {
- return xBad, true
- }
- s, ok := maybeString(x.args[0])
- if !ok {
- return ctx.newBadExpr(directive, "cannot handle non-constant argument to is-vendor-board-platform"), true
- }
- return &inExpr{
- expr: &variableRefExpr{ctx.addVariable("TARGET_BOARD_PLATFORM"), false},
- list: &variableRefExpr{ctx.addVariable(s + "_BOARD_PLATFORMS"), true},
- isNot: negate,
- }, true
+// Given an if statement's directive and the left/right starlarkExprs,
+// check if the starlarkExprs are one of a few hardcoded special cases
+// that can be converted to a simpler equalify expression than simply comparing
+// the two.
+func (ctx *parseContext) parseCompareSpecialCases(directive *mkparser.Directive, left starlarkExpr,
+ right starlarkExpr) (starlarkExpr, bool) {
+ isEq := !strings.HasSuffix(directive.Name, "neq")
- case "is-board-platform2", "is-board-platform-in-list2":
- if s, ok := maybeString(xValue); !ok || s != "" {
- return ctx.newBadExpr(directive,
- fmt.Sprintf("the result of %s can be compared only to empty", x.name)), true
- }
- if len(x.args) != 1 {
- return ctx.newBadExpr(directive, "%s requires an argument", x.name), true
- }
- cc := &callExpr{
- name: x.name,
- args: []starlarkExpr{x.args[0]},
- returnType: starlarkTypeBool,
- }
- if !negate {
- return ¬Expr{cc}, true
- }
- return cc, true
- case "is-vendor-board-qcom":
- if s, ok := maybeString(xValue); !ok || s != "" {
- return ctx.newBadExpr(directive,
- fmt.Sprintf("the result of %s can be compared only to empty", x.name)), true
- }
- return &inExpr{
- expr: &variableRefExpr{ctx.addVariable("TARGET_BOARD_PLATFORM"), false},
- list: &variableRefExpr{ctx.addVariable("QCOM_BOARD_PLATFORMS"), true},
- isNot: negate,
- }, true
- default:
- return ctx.newBadExpr(directive, "Unknown function in ifeq: %s", x.name), true
+ // All the special cases require a call on one side and a
+ // string literal/variable on the other. Turn the left/right variables into
+ // call/value variables, and return false if that's not possible.
+ var value starlarkExpr = nil
+ call, ok := left.(*callExpr)
+ if ok {
+ switch right.(type) {
+ case *stringLiteralExpr, *variableRefExpr:
+ value = right
}
- case *badExpr:
- return x, true
- default:
+ } else {
+ call, _ = right.(*callExpr)
+ switch left.(type) {
+ case *stringLiteralExpr, *variableRefExpr:
+ value = left
+ }
+ }
+
+ if call == nil || value == nil {
return nil, false
}
+
+ switch call.name {
+ case baseName + ".filter", baseName + ".filter-out":
+ return ctx.parseCompareFilterFuncResult(directive, call, value, isEq), true
+ case baseName + ".expand_wildcard":
+ return ctx.parseCompareWildcardFuncResult(directive, call, value, !isEq), true
+ case baseName + ".findstring":
+ return ctx.parseCheckFindstringFuncResult(directive, call, value, !isEq), true
+ case baseName + ".strip":
+ return ctx.parseCompareStripFuncResult(directive, call, value, !isEq), true
+ }
+ return nil, false
}
func (ctx *parseContext) parseCompareFilterFuncResult(cond *mkparser.Directive,
@@ -1252,9 +1204,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 {
@@ -1276,8 +1228,21 @@
right: &intLiteralExpr{-1},
isEq: !negate,
}
+ } else if s, ok := maybeString(xValue); ok {
+ if s2, ok := maybeString(xCall.args[0]); ok && s == s2 {
+ return &eqExpr{
+ left: &callExpr{
+ object: xCall.args[1],
+ name: "find",
+ args: []starlarkExpr{xCall.args[0]},
+ returnType: starlarkTypeInt,
+ },
+ right: &intLiteralExpr{-1},
+ isEq: negate,
+ }
+ }
}
- return ctx.newBadExpr(directive, "findstring result can be compared only to empty: %s", xValue)
+ return ctx.newBadExpr(directive, "$(findstring) can only be compared to nothing or its first argument")
}
func (ctx *parseContext) parseCompareStripFuncResult(directive *mkparser.Directive,
@@ -1308,37 +1273,51 @@
// 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: %s", refDump)
+ return ctx.newBadExpr(node, "SOONG_CONFIG_ variables cannot be referenced, use soong_config_get instead: %s", refDump)
+ }
+ // Handle substitution references: https://www.gnu.org/software/make/manual/html_node/Substitution-Refs.html
+ if strings.Contains(refDump, ":") {
+ parts := strings.SplitN(refDump, ":", 2)
+ substParts := strings.SplitN(parts[1], "=", 2)
+ if len(substParts) < 2 || strings.Count(substParts[0], "%") > 1 {
+ return ctx.newBadExpr(node, "Invalid substitution reference")
+ }
+ if !strings.Contains(substParts[0], "%") {
+ if strings.Contains(substParts[1], "%") {
+ return ctx.newBadExpr(node, "A substitution reference must have a %% in the \"before\" part of the substitution if it has one in the \"after\" part.")
+ }
+ substParts[0] = "%" + substParts[0]
+ substParts[1] = "%" + substParts[1]
+ }
+ v := ctx.addVariable(parts[0])
+ if v == nil {
+ return ctx.newBadExpr(node, "unknown variable %s", refDump)
+ }
+ return &callExpr{
+ name: baseName + ".mkpatsubst",
+ returnType: starlarkTypeString,
+ args: []starlarkExpr{
+ &stringLiteralExpr{literal: substParts[0]},
+ &stringLiteralExpr{literal: substParts[1]},
+ NewVariableRefExpr(v, ctx.lastAssignment(v.name()) != nil),
+ },
+ }
}
if v := ctx.addVariable(refDump); v != nil {
- return &variableRefExpr{v, ctx.lastAssignment(v.name()) != nil}
+ return NewVariableRefExpr(v, ctx.lastAssignment(v.name()) != nil)
}
return ctx.newBadExpr(node, "unknown variable %s", refDump)
}
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() {
@@ -1352,64 +1331,251 @@
}
}
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 "word":
- return ctx.parseWordFunc(node, args)
- case "firstword", "lastword":
- return ctx.parseFirstOrLastwordFunc(node, expr.name, args)
- case "my-dir":
- return &variableRefExpr{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 isBoardPlatformCallParser struct{}
+
+func (p *isBoardPlatformCallParser) parse(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString) starlarkExpr {
+ if args.Empty() {
+ return ctx.newBadExpr(node, "is-board-platform requires an argument")
+ }
+ return &eqExpr{
+ left: &variableRefExpr{ctx.addVariable("TARGET_BOARD_PLATFORM"), false},
+ right: ctx.parseMakeString(node, args),
+ isEq: true,
+ }
+}
+
+type isBoardPlatformInListCallParser struct{}
+
+func (p *isBoardPlatformInListCallParser) parse(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString) starlarkExpr {
+ if args.Empty() {
+ return ctx.newBadExpr(node, "is-board-platform-in-list requires an argument")
+ }
+ return &inExpr{
+ expr: &variableRefExpr{ctx.addVariable("TARGET_BOARD_PLATFORM"), false},
+ list: maybeConvertToStringList(ctx.parseMakeString(node, args)),
+ isNot: false,
+ }
+}
+
+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)
}
- if !words[0].Const() || !words[1].Const() {
- return ctx.newBadExpr(node, "%s function's from and to arguments should be constant", fname)
+ from := ctx.parseMakeString(node, words[0])
+ if xBad, ok := from.(*badExpr); ok {
+ return xBad
}
- from := words[0].Strings[0]
- to := words[1].Strings[0]
+ to := ctx.parseMakeString(node, words[1])
+ if xBad, ok := to.(*badExpr); ok {
+ return xBad
+ }
words[2].TrimLeftSpaces()
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,
name: "replace",
- args: []starlarkExpr{&stringLiteralExpr{from}, &stringLiteralExpr{to}},
+ args: []starlarkExpr{from, to},
returnType: typ,
}
}
return &callExpr{
- name: fname,
- args: []starlarkExpr{&stringLiteralExpr{from}, &stringLiteralExpr{to}, obj},
+ name: baseName + ".mk" + p.fname,
+ args: []starlarkExpr{from, to, obj},
returnType: obj.typ(),
}
}
-func (ctx *parseContext) parseWordFunc(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)))
+ }
+ condition := ctx.parseMakeString(node, words[0])
+ ifTrue := ctx.parseMakeString(node, words[1])
+ var ifFalse starlarkExpr
+ if len(words) == 3 {
+ ifFalse = ctx.parseMakeString(node, words[2])
+ } else {
+ switch ifTrue.typ() {
+ case starlarkTypeList:
+ ifFalse = &listExpr{items: []starlarkExpr{}}
+ case starlarkTypeInt:
+ ifFalse = &intLiteralExpr{literal: 0}
+ case starlarkTypeBool:
+ ifFalse = &boolLiteralExpr{literal: false}
+ default:
+ ifFalse = &stringLiteralExpr{literal: ""}
+ }
+ }
+ return &ifExpr{
+ condition,
+ ifTrue,
+ ifFalse,
+ }
+}
+
+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)))
+ }
+ if !words[0].Const() || words[0].Empty() || !identifierFullMatchRegex.MatchString(words[0].Strings[0]) {
+ return ctx.newBadExpr(node, "first argument to foreach function must be a simple string identifier")
+ }
+ loopVarName := words[0].Strings[0]
+ list := ctx.parseMakeString(node, words[1])
+ action := ctx.parseMakeString(node, words[2]).transform(func(expr starlarkExpr) starlarkExpr {
+ if varRefExpr, ok := expr.(*variableRefExpr); ok && varRefExpr.ref.name() == loopVarName {
+ return &identifierExpr{loopVarName}
+ }
+ return nil
+ })
+
+ if list.typ() != starlarkTypeList {
+ list = &callExpr{
+ name: baseName + ".words",
+ returnType: starlarkTypeList,
+ args: []starlarkExpr{list},
+ }
+ }
+
+ return &foreachExpr{
+ varName: loopVarName,
+ list: list,
+ action: action,
+ }
+}
+
+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")
@@ -1430,16 +1596,20 @@
if array.typ() != starlarkTypeList {
array = &callExpr{object: array, name: "split", returnType: starlarkTypeList}
}
- return indexExpr{array, &intLiteralExpr{int(index - 1)}}
+ 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}
}
@@ -1461,24 +1631,24 @@
// If we reached here, it's neither string literal nor a simple variable,
// we need a full-blown interpolation node that will generate
// "a%b%c" % (X, Y) for a$(X)b$(Y)c
- xInterp := &interpolateExpr{args: make([]starlarkExpr, len(mk.Variables))}
- for i, ref := range mk.Variables {
- arg := ctx.parseReference(node, ref.Name)
- if x, ok := arg.(*badExpr); ok {
- return x
+ parts := make([]starlarkExpr, len(mk.Variables)+len(mk.Strings))
+ for i := 0; i < len(parts); i++ {
+ if i%2 == 0 {
+ parts[i] = &stringLiteralExpr{literal: mk.Strings[i/2]}
+ } else {
+ parts[i] = ctx.parseReference(node, mk.Variables[i/2].Name)
+ if x, ok := parts[i].(*badExpr); ok {
+ return x
+ }
}
- xInterp.args[i] = arg
}
- xInterp.chunks = append(xInterp.chunks, mk.Strings...)
- return xInterp
+ return NewInterpolateExpr(parts)
}
// Handles the statements whose treatment is the same in all contexts: comment,
// assignment, variable (which is a macro call in reality) and all constructs that
// do not handle in any context ('define directive and any unrecognized stuff).
-// Return true if we handled it.
-func (ctx *parseContext) handleSimpleStatement(node mkparser.Node) bool {
- handled := true
+func (ctx *parseContext) handleSimpleStatement(node mkparser.Node) {
switch x := node.(type) {
case *mkparser.Comment:
ctx.maybeHandleAnnotation(x)
@@ -1493,13 +1663,14 @@
ctx.handleDefine(x)
case "include", "-include":
ctx.handleInclude(node, ctx.parseMakeString(node, x.Args), x.Name[0] != '-')
+ case "ifeq", "ifneq", "ifdef", "ifndef":
+ ctx.handleIfBlock(x)
default:
- handled = false
+ ctx.errorf(x, "unexpected directive %s", x.Name)
}
default:
ctx.errorf(x, "unsupported line %s", strings.ReplaceAll(x.Dump(), "\n", "\n#"))
}
- return handled
}
// Processes annotation. An annotation is a comment that starts with #RBC# and provides
@@ -1517,6 +1688,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
}
@@ -1537,17 +1715,14 @@
// records that the given node failed to be converted and includes an explanatory message
func (ctx *parseContext) errorf(failedNode mkparser.Node, message string, args ...interface{}) {
if ctx.errorLogger != nil {
- ctx.errorLogger.NewError(message, failedNode, args...)
+ ctx.errorLogger.NewError(ctx.errorLocation(failedNode), failedNode, message, args...)
}
- message = fmt.Sprintf(message, args...)
- ctx.insertComment(fmt.Sprintf("# MK2RBC TRANSLATION ERROR: %s", message))
- ctx.carryAsComment(failedNode)
+ ctx.receiver.newNode(&exprNode{ctx.newBadExpr(failedNode, message, args...)})
ctx.script.hasErrors = true
}
func (ctx *parseContext) wrapBadExpr(xBad *badExpr) {
- ctx.insertComment(fmt.Sprintf("# MK2RBC TRANSLATION ERROR: %s", xBad.message))
- ctx.carryAsComment(xBad.node)
+ ctx.receiver.newNode(&exprNode{xBad})
}
func (ctx *parseContext) loadedModulePath(path string) string {
@@ -1613,6 +1788,10 @@
return ok
}
+func (ctx *parseContext) errorLocation(node mkparser.Node) ErrorLocation {
+ return ErrorLocation{ctx.script.mkFile, ctx.script.nodeLocator(node.Pos())}
+}
+
func (ss *StarlarkScript) String() string {
return NewGenerateContext(ss).emit()
}
@@ -1651,13 +1830,13 @@
return nil, fmt.Errorf("bad makefile %s", req.MkFile)
}
starScript := &StarlarkScript{
- moduleName: moduleNameForFile(req.MkFile),
- mkFile: req.MkFile,
- topDir: req.RootDir,
- traceCalls: req.TraceCalls,
- warnPartialSuccess: req.WarnPartialSuccess,
- sourceFS: req.SourceFS,
- makefileFinder: req.MakefileFinder,
+ moduleName: moduleNameForFile(req.MkFile),
+ mkFile: req.MkFile,
+ topDir: req.RootDir,
+ traceCalls: req.TraceCalls,
+ sourceFS: req.SourceFS,
+ makefileFinder: req.MakefileFinder,
+ nodeLocator: func(pos mkparser.Pos) int { return parser.Unpack(pos).Line },
}
ctx := newParseContext(starScript, nodes)
ctx.outputSuffix = req.OutputSuffix
@@ -1671,21 +1850,7 @@
}
ctx.pushReceiver(starScript)
for ctx.hasNodes() && ctx.fatalError == nil {
- node := ctx.getNode()
- if ctx.handleSimpleStatement(node) {
- continue
- }
- switch x := node.(type) {
- case *mkparser.Directive:
- switch x.Name {
- case "ifeq", "ifneq", "ifdef", "ifndef":
- ctx.handleIfBlock(x)
- default:
- ctx.errorf(x, "unexpected directive %s", x.Name)
- }
- default:
- ctx.errorf(x, "unsupported line")
- }
+ ctx.handleSimpleStatement(ctx.getNode())
}
if ctx.fatalError != nil {
return nil, ctx.fatalError
@@ -1693,12 +1858,23 @@
return starScript, nil
}
-func Launcher(mainModuleUri, versionDefaultsUri, mainModuleName string) string {
+func Launcher(mainModuleUri, inputVariablesUri, mainModuleName string) string {
var buf bytes.Buffer
fmt.Fprintf(&buf, "load(%q, %q)\n", baseUri, baseName)
- fmt.Fprintf(&buf, "load(%q, \"version_defaults\")\n", versionDefaultsUri)
+ fmt.Fprintf(&buf, "load(%q, input_variables_init = \"init\")\n", inputVariablesUri)
fmt.Fprintf(&buf, "load(%q, \"init\")\n", mainModuleUri)
- fmt.Fprintf(&buf, "%s(%s(%q, init, version_defaults))\n", cfnPrintVars, cfnMain, mainModuleName)
+ fmt.Fprintf(&buf, "%s(%s(%q, init, input_variables_init))\n", cfnPrintVars, cfnMain, mainModuleName)
+ return buf.String()
+}
+
+func BoardLauncher(mainModuleUri string, inputVariablesUri string) string {
+ var buf bytes.Buffer
+ fmt.Fprintf(&buf, "load(%q, %q)\n", baseUri, baseName)
+ fmt.Fprintf(&buf, "load(%q, \"init\")\n", mainModuleUri)
+ fmt.Fprintf(&buf, "load(%q, input_variables_init = \"init\")\n", inputVariablesUri)
+ fmt.Fprintf(&buf, "globals, cfg, globals_base = %s(init, input_variables_init)\n", cfnBoardMain)
+ fmt.Fprintf(&buf, "# TODO: Some product config variables need to be printed, but most are readonly so we can't just print cfg here.\n")
+ fmt.Fprintf(&buf, "%s((globals, cfg, globals_base))\n", cfnPrintVars)
return buf.String()
}
diff --git a/mk2rbc/mk2rbc_test.go b/mk2rbc/mk2rbc_test.go
index 511bb0f..1ba273b 100644
--- a/mk2rbc/mk2rbc_test.go
+++ b/mk2rbc/mk2rbc_test.go
@@ -105,15 +105,12 @@
PRODUCT_NAME := $(call foo1, bar)
PRODUCT_NAME := $(call foo0)
`,
- expected: `# MK2RBC TRANSLATION ERROR: cannot handle invoking foo1
-# PRODUCT_NAME := $(call foo1, bar)
-# MK2RBC TRANSLATION ERROR: cannot handle invoking foo0
-# PRODUCT_NAME := $(call foo0)
-load("//build/make/core:product_config.rbc", "rblf")
+ expected: `load("//build/make/core:product_config.rbc", "rblf")
def init(g, handle):
cfg = rblf.cfg(handle)
- rblf.warning("product.mk", "partially successful conversion")
+ rblf.mk2rbc_error("product.mk:2", "cannot handle invoking foo1")
+ rblf.mk2rbc_error("product.mk:3", "cannot handle invoking foo0")
`,
},
{
@@ -207,15 +204,11 @@
$(info foo)
endef
`,
- expected: `# MK2RBC TRANSLATION ERROR: define is not supported: some-macro
-# define some-macro
-# $(info foo)
-# endef
-load("//build/make/core:product_config.rbc", "rblf")
+ expected: `load("//build/make/core:product_config.rbc", "rblf")
def init(g, handle):
cfg = rblf.cfg(handle)
- rblf.warning("product.mk", "partially successful conversion")
+ rblf.mk2rbc_error("product.mk:2", "define is not supported: some-macro")
`,
},
{
@@ -226,6 +219,9 @@
PRODUCT_NAME = gizmo
else
endif
+local_var :=
+ifdef local_var
+endif
`,
expected: `load("//build/make/core:product_config.rbc", "rblf")
@@ -235,6 +231,9 @@
cfg["PRODUCT_NAME"] = "gizmo"
else:
pass
+ _local_var = ""
+ if _local_var:
+ pass
`,
},
{
@@ -276,9 +275,7 @@
# Comment
pass
else:
- # MK2RBC TRANSLATION ERROR: cannot set predefined variable TARGET_COPY_OUT_RECOVERY to "foo", its value should be "recovery"
- pass
- rblf.warning("product.mk", "partially successful conversion")
+ rblf.mk2rbc_error("product.mk:5", "cannot set predefined variable TARGET_COPY_OUT_RECOVERY to \"foo\", its value should be \"recovery\"")
`,
},
{
@@ -347,6 +344,36 @@
`,
},
{
+ desc: "ifeq with soong_config_get",
+ mkname: "product.mk",
+ in: `
+ifeq (true,$(call soong_config_get,art_module,source_build))
+endif
+`,
+ expected: `load("//build/make/core:product_config.rbc", "rblf")
+
+def init(g, handle):
+ cfg = rblf.cfg(handle)
+ if "true" == rblf.soong_config_get(g, "art_module", "source_build"):
+ pass
+`,
+ },
+ {
+ desc: "ifeq with $(NATIVE_COVERAGE)",
+ mkname: "product.mk",
+ in: `
+ifeq ($(NATIVE_COVERAGE),true)
+endif
+`,
+ expected: `load("//build/make/core:product_config.rbc", "rblf")
+
+def init(g, handle):
+ cfg = rblf.cfg(handle)
+ if g.get("NATIVE_COVERAGE", False):
+ pass
+`,
+ },
+ {
desc: "Check filter result",
mkname: "product.mk",
in: `
@@ -363,6 +390,8 @@
ifeq (,$(filter barbet coral%,$(TARGET_PRODUCT)))
else ifneq (,$(filter barbet%,$(TARGET_PRODUCT)))
endif
+ifeq (,$(filter-out sunfish_kasan, $(TARGET_PRODUCT)))
+endif
`,
expected: `load("//build/make/core:product_config.rbc", "rblf")
@@ -382,6 +411,8 @@
pass
elif rblf.filter("barbet%", g["TARGET_PRODUCT"]):
pass
+ if not rblf.filter_out("sunfish_kasan", g["TARGET_PRODUCT"]):
+ pass
`,
},
{
@@ -509,6 +540,21 @@
`,
},
{
+ desc: "if with interpolation",
+ mkname: "product.mk",
+ in: `
+ifeq ($(VARIABLE1)text$(VARIABLE2),true)
+endif
+`,
+ expected: `load("//build/make/core:product_config.rbc", "rblf")
+
+def init(g, handle):
+ cfg = rblf.cfg(handle)
+ if "%stext%s" % (g.get("VARIABLE1", ""), g.get("VARIABLE2", "")) == "true":
+ pass
+`,
+ },
+ {
desc: "ifneq $(X),true",
mkname: "product.mk",
in: `
@@ -579,7 +625,7 @@
pass
elif not rblf.board_platform_is(g, "copper"):
pass
- elif g.get("TARGET_BOARD_PLATFORM", "") not in g["QCOM_BOARD_PLATFORMS"]:
+ elif g.get("TARGET_BOARD_PLATFORM", "") in g["QCOM_BOARD_PLATFORMS"]:
pass
`,
},
@@ -587,15 +633,42 @@
desc: "findstring call",
mkname: "product.mk",
in: `
+result := $(findstring a,a b c)
+result := $(findstring b,x y z)
+`,
+ expected: `load("//build/make/core:product_config.rbc", "rblf")
+
+def init(g, handle):
+ cfg = rblf.cfg(handle)
+ _result = rblf.findstring("a", "a b c")
+ _result = rblf.findstring("b", "x y z")
+`,
+ },
+ {
+ desc: "findstring in if statement",
+ mkname: "product.mk",
+ in: `
+ifeq ($(findstring foo,$(PRODUCT_PACKAGES)),)
+endif
ifneq ($(findstring foo,$(PRODUCT_PACKAGES)),)
endif
+ifeq ($(findstring foo,$(PRODUCT_PACKAGES)),foo)
+endif
+ifneq ($(findstring foo,$(PRODUCT_PACKAGES)),foo)
+endif
`,
expected: `load("//build/make/core:product_config.rbc", "rblf")
def init(g, handle):
cfg = rblf.cfg(handle)
+ if (cfg.get("PRODUCT_PACKAGES", [])).find("foo") == -1:
+ pass
if (cfg.get("PRODUCT_PACKAGES", [])).find("foo") != -1:
pass
+ if (cfg.get("PRODUCT_PACKAGES", [])).find("foo") != -1:
+ pass
+ if (cfg.get("PRODUCT_PACKAGES", [])).find("foo") == -1:
+ pass
`,
},
{
@@ -653,6 +726,7 @@
$(call enforce-product-packages-exist, foo)
$(call require-artifacts-in-path, foo, bar)
$(call require-artifacts-in-path-relaxed, foo, bar)
+$(call dist-for-goals, goal, from:to)
`,
expected: `load("//build/make/core:product_config.rbc", "rblf")
@@ -662,6 +736,7 @@
rblf.enforce_product_packages_exist("foo")
rblf.require_artifacts_in_path("foo", "bar")
rblf.require_artifacts_in_path_relaxed("foo", "bar")
+ rblf.mkdist_for_goals(g, "goal", "from:to")
`,
},
{
@@ -691,7 +766,7 @@
PRODUCT_COPY_FILES := $(addprefix pfx-,a b c)
PRODUCT_COPY_FILES := $(addsuffix .sff, a b c)
PRODUCT_NAME := $(word 1, $(subst ., ,$(TARGET_BOARD_PLATFORM)))
-$(info $(patsubst %.pub,%,$(PRODUCT_ADB_KEYS)))
+$(info $(patsubst %.pub,$(PRODUCT_NAME)%,$(PRODUCT_ADB_KEYS)))
$(info $(dir foo/bar))
$(info $(firstword $(PRODUCT_COPY_FILES)))
$(info $(lastword $(PRODUCT_COPY_FILES)))
@@ -714,7 +789,7 @@
cfg["PRODUCT_COPY_FILES"] = rblf.addprefix("pfx-", "a b c")
cfg["PRODUCT_COPY_FILES"] = rblf.addsuffix(".sff", "a b c")
cfg["PRODUCT_NAME"] = ((g.get("TARGET_BOARD_PLATFORM", "")).replace(".", " ")).split()[0]
- rblf.mkinfo("product.mk", rblf.mkpatsubst("%.pub", "%", g.get("PRODUCT_ADB_KEYS", "")))
+ rblf.mkinfo("product.mk", rblf.mkpatsubst("%.pub", "%s%%" % cfg["PRODUCT_NAME"], g.get("PRODUCT_ADB_KEYS", "")))
rblf.mkinfo("product.mk", rblf.dir("foo/bar"))
rblf.mkinfo("product.mk", cfg["PRODUCT_COPY_FILES"][0])
rblf.mkinfo("product.mk", cfg["PRODUCT_COPY_FILES"][-1])
@@ -821,9 +896,27 @@
rblf.soong_config_namespace(g, "cvd")
rblf.soong_config_set(g, "cvd", "launch_configs", "cvd_config_auto.json")
rblf.soong_config_append(g, "cvd", "grub_config", "grub.cfg")
- # MK2RBC TRANSLATION ERROR: SOONG_CONFIG_ variables cannot be referenced: SOONG_CONFIG_cvd_grub_config
- # x := $(SOONG_CONFIG_cvd_grub_config)
- rblf.warning("product.mk", "partially successful conversion")
+ rblf.mk2rbc_error("product.mk:7", "SOONG_CONFIG_ variables cannot be referenced, use soong_config_get instead: SOONG_CONFIG_cvd_grub_config")
+`,
+ }, {
+ desc: "soong namespace accesses",
+ mkname: "product.mk",
+ in: `
+SOONG_CONFIG_NAMESPACES += cvd
+SOONG_CONFIG_cvd += launch_configs
+SOONG_CONFIG_cvd_launch_configs = cvd_config_auto.json
+SOONG_CONFIG_cvd += grub_config
+SOONG_CONFIG_cvd_grub_config += grub.cfg
+x := $(call soong_config_get,cvd,grub_config)
+`,
+ expected: `load("//build/make/core:product_config.rbc", "rblf")
+
+def init(g, handle):
+ cfg = rblf.cfg(handle)
+ rblf.soong_config_namespace(g, "cvd")
+ rblf.soong_config_set(g, "cvd", "launch_configs", "cvd_config_auto.json")
+ rblf.soong_config_append(g, "cvd", "grub_config", "grub.cfg")
+ _x = rblf.soong_config_get(g, "cvd", "grub_config")
`,
},
{
@@ -956,7 +1049,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)
`,
},
@@ -980,7 +1073,41 @@
}.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)
`,
},
@@ -990,15 +1117,128 @@
in: `
foo: foo.c
gcc -o $@ $*`,
- expected: `# MK2RBC TRANSLATION ERROR: unsupported line rule: foo: foo.c
-#gcc -o $@ $*
-# rule: foo: foo.c
-# gcc -o $@ $*
-load("//build/make/core:product_config.rbc", "rblf")
+ expected: `load("//build/make/core:product_config.rbc", "rblf")
def init(g, handle):
cfg = rblf.cfg(handle)
- rblf.warning("product.mk", "partially successful conversion")
+ rblf.mk2rbc_error("product.mk:2", "unsupported line rule: foo: foo.c\n#gcc -o $@ $*")
+`,
+ },
+ {
+ desc: "Flag override",
+ mkname: "product.mk",
+ in: `
+override FOO:=`,
+ expected: `load("//build/make/core:product_config.rbc", "rblf")
+
+def init(g, handle):
+ cfg = rblf.cfg(handle)
+ rblf.mk2rbc_error("product.mk:2", "cannot handle override directive")
+ g["override FOO"] = ""
+`,
+ },
+ {
+ desc: "Bad expression",
+ mkname: "build/product.mk",
+ in: `
+ifeq (,$(call foobar))
+endif
+`,
+ expected: `load("//build/make/core:product_config.rbc", "rblf")
+
+def init(g, handle):
+ cfg = rblf.cfg(handle)
+ if rblf.mk2rbc_error("build/product.mk:2", "cannot handle invoking foobar"):
+ pass
+`,
+ },
+ {
+ desc: "if expression",
+ mkname: "product.mk",
+ in: `
+TEST_VAR := foo
+TEST_VAR_LIST := foo
+TEST_VAR_LIST += bar
+TEST_VAR_2 := $(if $(TEST_VAR),bar)
+TEST_VAR_3 := $(if $(TEST_VAR),bar,baz)
+TEST_VAR_3 := $(if $(TEST_VAR),$(TEST_VAR_LIST))
+`,
+ expected: `load("//build/make/core:product_config.rbc", "rblf")
+
+def init(g, handle):
+ cfg = rblf.cfg(handle)
+ g["TEST_VAR"] = "foo"
+ g["TEST_VAR_LIST"] = ["foo"]
+ g["TEST_VAR_LIST"] += ["bar"]
+ g["TEST_VAR_2"] = ("bar" if g["TEST_VAR"] else "")
+ g["TEST_VAR_3"] = ("bar" if g["TEST_VAR"] else "baz")
+ g["TEST_VAR_3"] = (g["TEST_VAR_LIST"] if g["TEST_VAR"] else [])
+`,
+ },
+ {
+ desc: "substitution references",
+ mkname: "product.mk",
+ in: `
+SOURCES := foo.c bar.c
+OBJECTS := $(SOURCES:.c=.o)
+OBJECTS2 := $(SOURCES:%.c=%.o)
+`,
+ expected: `load("//build/make/core:product_config.rbc", "rblf")
+
+def init(g, handle):
+ cfg = rblf.cfg(handle)
+ g["SOURCES"] = "foo.c bar.c"
+ g["OBJECTS"] = rblf.mkpatsubst("%.c", "%.o", g["SOURCES"])
+ g["OBJECTS2"] = rblf.mkpatsubst("%.c", "%.o", g["SOURCES"])
+`,
+ },
+ {
+ desc: "foreach expressions",
+ mkname: "product.mk",
+ in: `
+BOOT_KERNEL_MODULES := foo.ko bar.ko
+BOOT_KERNEL_MODULES_FILTER := $(foreach m,$(BOOT_KERNEL_MODULES),%/$(m))
+BOOT_KERNEL_MODULES_LIST := foo.ko
+BOOT_KERNEL_MODULES_LIST += bar.ko
+BOOT_KERNEL_MODULES_FILTER_2 := $(foreach m,$(BOOT_KERNEL_MODULES_LIST),%/$(m))
+
+`,
+ expected: `load("//build/make/core:product_config.rbc", "rblf")
+
+def init(g, handle):
+ cfg = rblf.cfg(handle)
+ g["BOOT_KERNEL_MODULES"] = "foo.ko bar.ko"
+ g["BOOT_KERNEL_MODULES_FILTER"] = ["%%/%s" % m for m in rblf.words(g["BOOT_KERNEL_MODULES"])]
+ g["BOOT_KERNEL_MODULES_LIST"] = ["foo.ko"]
+ g["BOOT_KERNEL_MODULES_LIST"] += ["bar.ko"]
+ 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", "")))
`,
},
}
@@ -1008,6 +1248,7 @@
class varClass
starlarkType
}{
+ {"NATIVE_COVERAGE", VarClassSoong, starlarkTypeBool},
{"PRODUCT_NAME", VarClassConfig, starlarkTypeString},
{"PRODUCT_MODEL", VarClassConfig, starlarkTypeString},
{"PRODUCT_PACKAGES", VarClassConfig, starlarkTypeList},
@@ -1069,13 +1310,12 @@
t.Run(test.desc,
func(t *testing.T) {
ss, err := Convert(Request{
- MkFile: test.mkname,
- Reader: bytes.NewBufferString(test.in),
- RootDir: ".",
- OutputSuffix: ".star",
- WarnPartialSuccess: true,
- SourceFS: fs,
- MakefileFinder: &testMakefileFinder{fs: fs},
+ MkFile: test.mkname,
+ Reader: bytes.NewBufferString(test.in),
+ RootDir: ".",
+ OutputSuffix: ".star",
+ SourceFS: fs,
+ MakefileFinder: &testMakefileFinder{fs: fs},
})
if err != nil {
t.Error(err)
diff --git a/mk2rbc/node.go b/mk2rbc/node.go
index 3fe1a17..ebc57b2 100644
--- a/mk2rbc/node.go
+++ b/mk2rbc/node.go
@@ -110,7 +110,9 @@
gctx.writef("if not %s:", i.entryName())
gctx.indentLevel++
gctx.newLine()
- gctx.write(`rblf.mkerror("cannot")`)
+ gctx.write(`rblf.mkerror("`, gctx.starScript.mkFile, `", "Cannot find %s" % (`)
+ i.path.emit(gctx)
+ gctx.write("))")
gctx.indentLevel--
}
}
@@ -183,6 +185,7 @@
value starlarkExpr
mkValue *mkparser.MakeString
flavor assignmentFlavor
+ location ErrorLocation
isTraced bool
previous *assignmentNode
}
@@ -223,18 +226,6 @@
}
gctx.newLine()
- if bad, ok := in.expr.(*badExpr); ok {
- gctx.write("# MK2STAR ERROR converting:")
- gctx.newLine()
- gctx.writef("# %s", bad.node.Dump())
- gctx.newLine()
- gctx.writef("# %s", bad.message)
- gctx.newLine()
- // The init function emits a warning if the conversion was not
- // fullly successful, so here we (arbitrarily) take the false path.
- gctx.writef("%sFalse:", ifElif)
- return
- }
gctx.write(ifElif)
in.expr.emit(gctx)
gctx.write(":")
diff --git a/mk2rbc/variable.go b/mk2rbc/variable.go
index 4bb9ed5..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 {
@@ -177,8 +181,8 @@
baseVariable
}
-func (lv localVariable) emitDefined(_ *generationContext) {
- panic("implement me")
+func (lv localVariable) emitDefined(gctx *generationContext) {
+ gctx.writef(lv.String())
}
func (lv localVariable) String() string {
@@ -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)
@@ -228,10 +234,9 @@
if actualValue == expectedValue {
return
}
- gctx.writef("# MK2RBC TRANSLATION ERROR: cannot set predefined variable %s to %q, its value should be %q",
- pv.name(), actualValue, expectedValue)
- gctx.newLine()
- gctx.write("pass")
+ gctx.emitConversionError(asgn.location,
+ fmt.Sprintf("cannot set predefined variable %s to %q, its value should be %q",
+ pv.name(), actualValue, expectedValue))
gctx.starScript.hasErrors = true
return
}
diff --git a/mk2rbc/version_defaults.go b/mk2rbc/version_defaults.go
deleted file mode 100644
index 64645d7..0000000
--- a/mk2rbc/version_defaults.go
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// 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 mk2rbc
-
-import (
- "bytes"
- "fmt"
- "io/ioutil"
- "os"
- "sort"
- "strconv"
- "strings"
-
- mkparser "android/soong/androidmk/parser"
-)
-
-const codenamePrefix = "PLATFORM_VERSION_CODENAME."
-
-// ParseVersionDefaults extracts version settings from the given file
-// and returns the map.
-func ParseVersionDefaults(path string) (map[string]string, error) {
- contents, err := ioutil.ReadFile(path)
- if err != nil {
- return nil, err
- }
- parser := mkparser.NewParser(path, bytes.NewBuffer(contents))
- nodes, errs := parser.Parse()
- if len(errs) > 0 {
- for _, e := range errs {
- fmt.Fprintln(os.Stderr, "ERROR:", e)
- }
- return nil, fmt.Errorf("cannot parse %s", path)
- }
-
- result := map[string]string{
- "DEFAULT_PLATFORM_VERSION": "",
- "MAX_PLATFORM_VERSION": "",
- "MIN_PLATFORM_VERSION": "A",
- "PLATFORM_BASE_SDK_EXTENSION_VERSION": "",
- "PLATFORM_SDK_EXTENSION_VERSION": "",
- "PLATFORM_SDK_VERSION": "",
- "PLATFORM_SECURITY_PATCH": "",
- "PLATFORM_VERSION_LAST_STABLE": "",
- }
- for _, node := range nodes {
- asgn, ok := node.(*mkparser.Assignment)
- if !(ok && asgn.Name.Const()) {
- continue
- }
- s := asgn.Name.Strings[0]
- _, ok = result[s]
- if !ok {
- ok = strings.HasPrefix(s, codenamePrefix)
- }
- if !ok {
- continue
- }
- v := asgn.Value
- if !v.Const() {
- return nil, fmt.Errorf("the value of %s should be constant", s)
- }
- result[s] = strings.TrimSpace(v.Strings[0])
- }
- return result, nil
-}
-
-func genericValue(s string) interface{} {
- if ival, err := strconv.ParseInt(s, 0, 0); err == nil {
- return ival
- }
- return s
-}
-
-// VersionDefaults generates the contents of the version_defaults.rbc file
-func VersionDefaults(values map[string]string) string {
- var sink bytes.Buffer
- var lines []string
- var codenames []string
- for name, value := range values {
- if strings.HasPrefix(name, codenamePrefix) {
- codenames = append(codenames,
- fmt.Sprintf("%q: %q", strings.TrimPrefix(name, codenamePrefix), value))
- } else {
- // Print numbers as such
- lines = append(lines, fmt.Sprintf(" %s = %#v,\n",
- strings.ToLower(name), genericValue(value)))
- }
- }
-
- sort.Strings(lines)
- sort.Strings(codenames)
-
- sink.WriteString("version_defaults = struct(\n")
- for _, l := range lines {
- sink.WriteString(l)
- }
- sink.WriteString(" codenames = { ")
- sink.WriteString(strings.Join(codenames, ", "))
- sink.WriteString(" }\n)\n")
- return sink.String()
-}
diff --git a/mk2rbc/version_defaults_test.go b/mk2rbc/version_defaults_test.go
deleted file mode 100644
index c78fa32..0000000
--- a/mk2rbc/version_defaults_test.go
+++ /dev/null
@@ -1,60 +0,0 @@
-package mk2rbc
-
-import (
- "path/filepath"
- "reflect"
- "strings"
- "testing"
-)
-
-func TestParseVersionDefaults(t *testing.T) {
- testDir := getTestDirectory()
- abspath := func(relPath string) string { return filepath.Join(testDir, relPath) }
- actualProducts, err := ParseVersionDefaults(abspath("version_defaults.mk.test"))
- if err != nil {
- t.Fatal(err)
- }
- expectedProducts := map[string]string{
- "DEFAULT_PLATFORM_VERSION": "TP1A",
- "MAX_PLATFORM_VERSION": "TP1A",
- "MIN_PLATFORM_VERSION": "TP1A",
- "PLATFORM_BASE_SDK_EXTENSION_VERSION": "0",
- "PLATFORM_SDK_EXTENSION_VERSION": "1",
- "PLATFORM_SDK_VERSION": "31",
- "PLATFORM_SECURITY_PATCH": "2021-10-05",
- "PLATFORM_VERSION_LAST_STABLE": "12",
- "PLATFORM_VERSION_CODENAME.SP2A": "Sv2",
- "PLATFORM_VERSION_CODENAME.TP1A": "Tiramisu",
- }
- if !reflect.DeepEqual(actualProducts, expectedProducts) {
- t.Errorf("\nExpected: %v\n Actual: %v", expectedProducts, actualProducts)
- }
-}
-
-func TestVersionDefaults(t *testing.T) {
- testDir := getTestDirectory()
- abspath := func(relPath string) string { return filepath.Join(testDir, relPath) }
- actualProducts, err := ParseVersionDefaults(abspath("version_defaults.mk.test"))
- if err != nil {
- t.Fatal(err)
- }
- expectedString := `version_defaults = struct(
- default_platform_version = "TP1A",
- max_platform_version = "TP1A",
- min_platform_version = "TP1A",
- platform_base_sdk_extension_version = 0,
- platform_sdk_extension_version = 1,
- platform_sdk_version = 31,
- platform_security_patch = "2021-10-05",
- platform_version_last_stable = 12,
- codenames = { "SP2A": "Sv2", "TP1A": "Tiramisu" }
-)
-`
- actualString := VersionDefaults(actualProducts)
- if !reflect.DeepEqual(actualString, expectedString) {
- t.Errorf("\nExpected: %v\nActual:\n%v",
- strings.ReplaceAll(expectedString, "\n", "\n"),
- strings.ReplaceAll(actualString, "\n", "\n"))
- }
-
-}
diff --git a/python/androidmk.go b/python/androidmk.go
index 13b4172..233d867 100644
--- a/python/androidmk.go
+++ b/python/androidmk.go
@@ -75,16 +75,10 @@
}
func (installer *pythonInstaller) AndroidMk(base *Module, entries *android.AndroidMkEntries) {
- // Soong installation is only supported for host modules. Have Make
- // installation trigger Soong installation.
- if base.Target().Os.Class == android.Host {
- entries.OutputFile = android.OptionalPathForPath(installer.path)
- }
-
entries.Required = append(entries.Required, "libc++")
entries.ExtraEntries = append(entries.ExtraEntries,
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- path, file := filepath.Split(installer.path.ToMakePath().String())
+ path, file := filepath.Split(installer.path.String())
stem := strings.TrimSuffix(file, filepath.Ext(file))
entries.SetString("LOCAL_MODULE_SUFFIX", filepath.Ext(file))
diff --git a/python/binary.go b/python/binary.go
index bf6167c..99c6259 100644
--- a/python/binary.go
+++ b/python/binary.go
@@ -27,7 +27,6 @@
func init() {
registerPythonBinaryComponents(android.InitRegistrationContext)
- android.RegisterBp2BuildMutator("python_binary_host", PythonBinaryBp2Build)
}
func registerPythonBinaryComponents(ctx android.RegistrationContext) {
@@ -35,29 +34,19 @@
}
type bazelPythonBinaryAttributes struct {
- Main string
+ Main *string
Srcs bazel.LabelListAttribute
Deps bazel.LabelListAttribute
- Python_version string
+ Python_version *string
}
-func PythonBinaryBp2Build(ctx android.TopDownMutatorContext) {
- m, ok := ctx.Module().(*Module)
- if !ok || !m.ConvertWithBp2build(ctx) {
- return
- }
-
- // a Module can be something other than a python_binary_host
- if ctx.ModuleType() != "python_binary_host" {
- return
- }
-
- var main string
+func pythonBinaryBp2Build(ctx android.TopDownMutatorContext, m *Module) {
+ var main *string
for _, propIntf := range m.GetProperties() {
if props, ok := propIntf.(*BinaryProperties); ok {
// main is optional.
if props.Main != nil {
- main = *props.Main
+ main = props.Main
break
}
}
@@ -69,13 +58,13 @@
// under Bionic.
py3Enabled := proptools.BoolDefault(m.properties.Version.Py3.Enabled, false)
py2Enabled := proptools.BoolDefault(m.properties.Version.Py2.Enabled, false)
- var python_version string
+ var python_version *string
if py3Enabled && py2Enabled {
panic(fmt.Errorf(
"error for '%s' module: bp2build's python_binary_host converter does not support "+
"converting a module that is enabled for both Python 2 and 3 at the same time.", m.Name()))
} else if py2Enabled {
- python_version = "PY2"
+ python_version = &pyVersion2
} else {
// do nothing, since python_version defaults to PY3.
}
diff --git a/python/library.go b/python/library.go
index d136a4e..d026c13 100644
--- a/python/library.go
+++ b/python/library.go
@@ -17,17 +17,14 @@
// This file contains the module types for building Python library.
import (
- "fmt"
-
"android/soong/android"
"android/soong/bazel"
+
"github.com/google/blueprint/proptools"
)
func init() {
registerPythonLibraryComponents(android.InitRegistrationContext)
- android.RegisterBp2BuildMutator("python_library_host", PythonLibraryHostBp2Build)
- android.RegisterBp2BuildMutator("python_library", PythonLibraryBp2Build)
}
func registerPythonLibraryComponents(ctx android.RegistrationContext) {
@@ -46,43 +43,23 @@
type bazelPythonLibraryAttributes struct {
Srcs bazel.LabelListAttribute
Deps bazel.LabelListAttribute
- Srcs_version string
+ Srcs_version *string
}
-func PythonLibraryHostBp2Build(ctx android.TopDownMutatorContext) {
- pythonLibBp2Build(ctx, "python_library_host")
-}
-
-func PythonLibraryBp2Build(ctx android.TopDownMutatorContext) {
- pythonLibBp2Build(ctx, "python_library")
-}
-
-func pythonLibBp2Build(ctx android.TopDownMutatorContext, modType string) {
- m, ok := ctx.Module().(*Module)
- if !ok || !m.ConvertWithBp2build(ctx) {
- return
- }
-
- // a Module can be something other than a `modType`
- if ctx.ModuleType() != modType {
- return
- }
-
+func pythonLibBp2Build(ctx android.TopDownMutatorContext, m *Module) {
// TODO(b/182306917): this doesn't fully handle all nested props versioned
// by the python version, which would have been handled by the version split
// mutator. This is sufficient for very simple python_library modules under
// Bionic.
py3Enabled := proptools.BoolDefault(m.properties.Version.Py3.Enabled, true)
py2Enabled := proptools.BoolDefault(m.properties.Version.Py2.Enabled, false)
- var python_version string
+ var python_version *string
if py2Enabled && !py3Enabled {
- python_version = "PY2"
+ python_version = &pyVersion2
} else if !py2Enabled && py3Enabled {
- python_version = "PY3"
+ python_version = &pyVersion3
} else if !py2Enabled && !py3Enabled {
- panic(fmt.Errorf(
- "error for '%s' module: bp2build's %s converter doesn't understand having "+
- "neither py2 nor py3 enabled", m.Name(), modType))
+ ctx.ModuleErrorf("bp2build converter doesn't understand having neither py2 nor py3 enabled")
} else {
// do nothing, since python_version defaults to PY2ANDPY3
}
@@ -95,8 +72,8 @@
}
props := bazel.BazelTargetModuleProperties{
- // Use the native py_library rule.
- Rule_class: "py_library",
+ Rule_class: "py_library",
+ Bzl_load_location: "//build/bazel/rules/python:library.bzl",
}
ctx.CreateBazelTargetModule(props, android.CommonAttributes{
diff --git a/python/python.go b/python/python.go
index 401d91f..734ac57 100644
--- a/python/python.go
+++ b/python/python.go
@@ -23,6 +23,7 @@
"strings"
"android/soong/bazel"
+
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
@@ -667,18 +668,25 @@
}
// isPythonLibModule returns whether the given module is a Python library Module or not
-// This is distinguished by the fact that Python libraries are not installable, while other Python
-// modules are.
func isPythonLibModule(module blueprint.Module) bool {
if m, ok := module.(*Module); ok {
- // Python library has no bootstrapper or installer
- if m.bootstrapper == nil && m.installer == nil {
- return true
- }
+ return m.isLibrary()
}
return false
}
+// This is distinguished by the fact that Python libraries are not installable, while other Python
+// modules are.
+func (p *Module) isLibrary() bool {
+ // Python library has no bootstrapper or installer
+ return p.bootstrapper == nil && p.installer == nil
+}
+
+func (p *Module) isBinary() bool {
+ _, ok := p.bootstrapper.(*binaryDecorator)
+ return ok
+}
+
// collectPathsFromTransitiveDeps checks for source/data files for duplicate paths
// for module and its transitive dependencies and collects list of data/source file
// zips for transitive dependencies.
@@ -752,6 +760,14 @@
return true
}
+func (p *Module) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
+ if p.isLibrary() {
+ pythonLibBp2Build(ctx, p)
+ } else if p.isBinary() {
+ pythonBinaryBp2Build(ctx, p)
+ }
+}
+
var Bool = proptools.Bool
var BoolDefault = proptools.BoolDefault
var String = proptools.String
diff --git a/rust/Android.bp b/rust/Android.bp
index 0ee673d..5e14da8 100644
--- a/rust/Android.bp
+++ b/rust/Android.bp
@@ -38,6 +38,7 @@
"strip.go",
"test.go",
"testing.go",
+ "toolchain_library.go",
],
testSrcs: [
"benchmark_test.go",
@@ -54,6 +55,7 @@
"project_json_test.go",
"protobuf_test.go",
"rust_test.go",
+ "sanitize_test.go",
"source_provider_test.go",
"test_test.go",
"vendor_snapshot_test.go",
diff --git a/rust/androidmk.go b/rust/androidmk.go
index 630805a..4e58632 100644
--- a/rust/androidmk.go
+++ b/rust/androidmk.go
@@ -50,8 +50,8 @@
}
ret := android.AndroidMkEntries{
- OutputFile: mod.unstrippedOutputFile,
- Include: "$(BUILD_SYSTEM)/soong_rust_prebuilt.mk",
+ OutputFile: android.OptionalPathForPath(mod.UnstrippedOutputFile()),
+ Include: "$(BUILD_SYSTEM)/soong_cc_rust_prebuilt.mk",
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
entries.AddStrings("LOCAL_RLIB_LIBRARIES", mod.Properties.AndroidMkRlibs...)
@@ -137,10 +137,15 @@
} else if library.shared() {
ret.Class = "SHARED_LIBRARIES"
}
-
if library.distFile.Valid() {
ret.DistFiles = android.MakeDefaultDistFiles(library.distFile.Path())
}
+ ret.ExtraEntries = append(ret.ExtraEntries,
+ func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+ if library.tocFile.Valid() {
+ entries.SetString("LOCAL_SOONG_TOC", library.tocFile.String())
+ }
+ })
}
func (procMacro *procMacroDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkEntries) {
@@ -181,19 +186,14 @@
return
}
- var unstrippedOutputFile android.OptionalPath
- // Soong installation is only supported for host modules. Have Make
- // installation trigger Soong installation.
- if ctx.Target().Os.Class == android.Host {
- ret.OutputFile = android.OptionalPathForPath(compiler.path)
- } else if compiler.strippedOutputFile.Valid() {
- unstrippedOutputFile = ret.OutputFile
+ if compiler.strippedOutputFile.Valid() {
ret.OutputFile = compiler.strippedOutputFile
}
+
ret.ExtraEntries = append(ret.ExtraEntries,
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- entries.SetOptionalPath("LOCAL_SOONG_UNSTRIPPED_BINARY", unstrippedOutputFile)
- path, file := filepath.Split(compiler.path.ToMakePath().String())
+ entries.SetPath("LOCAL_SOONG_UNSTRIPPED_BINARY", compiler.unstrippedOutputFile)
+ path, file := filepath.Split(compiler.path.String())
stem, suffix, _ := android.SplitFileExt(file)
entries.SetString("LOCAL_MODULE_SUFFIX", suffix)
entries.SetString("LOCAL_MODULE_PATH", path)
diff --git a/rust/binary.go b/rust/binary.go
index 7c18730..db91ccb 100644
--- a/rust/binary.go
+++ b/rust/binary.go
@@ -34,6 +34,7 @@
type binaryInterface interface {
binary() bool
staticallyLinked() bool
+ testBinary() bool
}
type binaryDecorator struct {
@@ -122,20 +123,24 @@
fileName := binary.getStem(ctx) + ctx.toolchain().ExecutableSuffix()
srcPath, _ := srcPathFromModuleSrcs(ctx, binary.baseCompiler.Properties.Srcs)
outputFile := android.PathForModuleOut(ctx, fileName)
+ ret := outputFile
flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
flags.LinkFlags = append(flags.LinkFlags, deps.depLinkFlags...)
flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects...)
+ if binary.stripper.NeedsStrip(ctx) {
+ strippedOutputFile := outputFile
+ outputFile = android.PathForModuleOut(ctx, "unstripped", fileName)
+ binary.stripper.StripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile)
+
+ binary.baseCompiler.strippedOutputFile = android.OptionalPathForPath(strippedOutputFile)
+ }
+ binary.baseCompiler.unstrippedOutputFile = outputFile
+
TransformSrcToBinary(ctx, srcPath, deps, flags, outputFile)
- if binary.stripper.NeedsStrip(ctx) {
- strippedOutputFile := android.PathForModuleOut(ctx, "stripped", fileName)
- binary.stripper.StripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile)
- binary.strippedOutputFile = android.OptionalPathForPath(strippedOutputFile)
- }
-
- return outputFile
+ return ret
}
func (binary *binaryDecorator) autoDep(ctx android.BottomUpMutatorContext) autoDep {
@@ -168,3 +173,7 @@
func (binary *binaryDecorator) staticallyLinked() bool {
return Bool(binary.Properties.Static_executable)
}
+
+func (binary *binaryDecorator) testBinary() bool {
+ return false
+}
diff --git a/rust/binary_test.go b/rust/binary_test.go
index 968c0c1..7dac249 100644
--- a/rust/binary_test.go
+++ b/rust/binary_test.go
@@ -106,7 +106,7 @@
srcs: ["foo.rs"],
}`)
- fizzBuzz := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Output("fizz-buzz")
+ fizzBuzz := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Rule("rustc")
flags := fizzBuzz.Args["rustcFlags"]
if strings.Contains(flags, "--test") {
@@ -139,7 +139,7 @@
static_executable: true,
}`)
- fizzOut := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Output("fizz")
+ fizzOut := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Rule("rustc")
fizzMod := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Module().(*Module)
flags := fizzOut.Args["rustcFlags"]
@@ -173,7 +173,7 @@
name: "libfoo",
}`)
- fizzBuzz := ctx.ModuleForTests("fizz-buzz", "android_arm64_armv8-a").Output("fizz-buzz")
+ fizzBuzz := ctx.ModuleForTests("fizz-buzz", "android_arm64_armv8-a").Rule("rustc")
linkFlags := fizzBuzz.Args["linkFlags"]
if !strings.Contains(linkFlags, "/libfoo.so") {
t.Errorf("missing shared dependency 'libfoo.so' in linkFlags: %#v", linkFlags)
@@ -197,15 +197,17 @@
`)
foo := ctx.ModuleForTests("foo", "android_arm64_armv8-a")
- foo.Output("stripped/foo")
+ foo.Output("unstripped/foo")
+ foo.Output("foo")
+
// Check that the `cp` rules is using the stripped version as input.
cp := foo.Rule("android.Cp")
- if !strings.HasSuffix(cp.Input.String(), "stripped/foo") {
+ if strings.HasSuffix(cp.Input.String(), "unstripped/foo") {
t.Errorf("installed binary not based on stripped version: %v", cp.Input)
}
- fizzBar := ctx.ModuleForTests("bar", "android_arm64_armv8-a").MaybeOutput("stripped/bar")
+ fizzBar := ctx.ModuleForTests("bar", "android_arm64_armv8-a").MaybeOutput("unstripped/bar")
if fizzBar.Rule != nil {
- t.Errorf("stripped version of bar has been generated")
+ t.Errorf("unstripped binary exists, so stripped binary has incorrectly been generated")
}
}
diff --git a/rust/bindgen.go b/rust/bindgen.go
index 845f258..ef5702b 100644
--- a/rust/bindgen.go
+++ b/rust/bindgen.go
@@ -15,6 +15,7 @@
package rust
import (
+ "fmt"
"strings"
"github.com/google/blueprint"
@@ -29,7 +30,7 @@
defaultBindgenFlags = []string{""}
// bindgen should specify its own Clang revision so updating Clang isn't potentially blocked on bindgen failures.
- bindgenClangVersion = "clang-r433403"
+ bindgenClangVersion = "clang-r437112b"
_ = pctx.VariableFunc("bindgenClangVersion", func(ctx android.PackageVarContext) string {
if override := ctx.Config().Getenv("LLVM_BINDGEN_PREBUILTS_VERSION"); override != "" {
@@ -147,6 +148,31 @@
cflags = append(cflags, strings.ReplaceAll(ccToolchain.Cflags(), "${config.", "${cc_config."))
cflags = append(cflags, strings.ReplaceAll(ccToolchain.ToolchainCflags(), "${config.", "${cc_config."))
+ if ctx.RustModule().UseVndk() {
+ cflags = append(cflags, "-D__ANDROID_VNDK__")
+ if ctx.RustModule().InVendor() {
+ cflags = append(cflags, "-D__ANDROID_VENDOR__")
+ } else if ctx.RustModule().InProduct() {
+ cflags = append(cflags, "-D__ANDROID_PRODUCT__")
+ }
+ }
+
+ if ctx.RustModule().InRecovery() {
+ cflags = append(cflags, "-D__ANDROID_RECOVERY__")
+ }
+
+ if mctx, ok := ctx.(*moduleContext); ok && mctx.apexVariationName() != "" {
+ cflags = append(cflags, "-D__ANDROID_APEX__")
+ if ctx.Device() {
+ cflags = append(cflags, fmt.Sprintf("-D__ANDROID_APEX_MIN_SDK_VERSION__=%d",
+ ctx.RustModule().apexSdkVersion.FinalOrFutureInt()))
+ }
+ }
+
+ if ctx.Target().NativeBridge == android.NativeBridgeEnabled {
+ cflags = append(cflags, "-D__ANDROID_NATIVE_BRIDGE__")
+ }
+
// Dependency clang flags and include paths
cflags = append(cflags, deps.depClangFlags...)
for _, include := range deps.depIncludePaths {
diff --git a/rust/builder.go b/rust/builder.go
index f79cf9b..a7efc28 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -185,7 +185,7 @@
}
func transformSrctoCrate(ctx ModuleContext, main android.Path, deps PathDeps, flags Flags,
- outputFile android.WritablePath, crate_type string) buildOutput {
+ outputFile android.WritablePath, crateType string) buildOutput {
var inputs android.Paths
var implicits android.Paths
@@ -204,7 +204,7 @@
// Collect rustc flags
rustcFlags = append(rustcFlags, flags.GlobalRustFlags...)
rustcFlags = append(rustcFlags, flags.RustFlags...)
- rustcFlags = append(rustcFlags, "--crate-type="+crate_type)
+ rustcFlags = append(rustcFlags, "--crate-type="+crateType)
if crateName != "" {
rustcFlags = append(rustcFlags, "--crate-name="+crateName)
}
@@ -216,6 +216,13 @@
// Suppress an implicit sysroot
rustcFlags = append(rustcFlags, "--sysroot=/dev/null")
+ // Enable incremental compilation if requested by user
+ if ctx.Config().IsEnvTrue("SOONG_RUSTC_INCREMENTAL") {
+ incrementalPath := android.PathForOutput(ctx, "rustc").String()
+
+ rustcFlags = append(rustcFlags, "-C incremental="+incrementalPath)
+ }
+
// Collect linker flags
linkFlags = append(linkFlags, flags.GlobalLinkFlags...)
linkFlags = append(linkFlags, flags.LinkFlags...)
@@ -361,7 +368,7 @@
Description: "rustdoc " + main.Rel(),
Output: docTimestampFile,
Input: main,
- Implicit: ctx.RustModule().unstrippedOutputFile.Path(),
+ Implicit: ctx.RustModule().UnstrippedOutputFile(),
Args: map[string]string{
"rustdocFlags": strings.Join(rustdocFlags, " "),
"outDir": docDir.String(),
diff --git a/rust/compiler.go b/rust/compiler.go
index cada985..3040e5d 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -181,7 +181,11 @@
sanitize *sanitize
distFile android.OptionalPath
- // Stripped output file. If Valid(), this file will be installed instead of outputFile.
+
+ // unstripped output file.
+ unstrippedOutputFile android.Path
+
+ // stripped output file.
strippedOutputFile android.OptionalPath
// If a crate has a source-generated dependency, a copy of the source file
@@ -340,6 +344,10 @@
return String(compiler.Properties.Cargo_pkg_version)
}
+func (compiler *baseCompiler) unstrippedOutputFilePath() android.Path {
+ return compiler.unstrippedOutputFile
+}
+
func (compiler *baseCompiler) strippedOutputFilePath() android.OptionalPath {
return compiler.strippedOutputFile
}
@@ -355,9 +363,9 @@
if !Bool(compiler.Properties.No_stdlibs) {
for _, stdlib := range config.Stdlibs {
- // If we're building for the primary arch of the build host, use the compiler's stdlibs
+ // If we're building for the build host, use the prebuilt stdlibs
if ctx.Target().Os == ctx.Config().BuildOS {
- stdlib = stdlib + "_" + ctx.toolchain().RustTriple()
+ stdlib = "prebuilt_" + stdlib
}
deps.Stdlibs = append(deps.Stdlibs, stdlib)
}
diff --git a/rust/config/allowed_list.go b/rust/config/allowed_list.go
index 8182c32..0d0b712 100644
--- a/rust/config/allowed_list.go
+++ b/rust/config/allowed_list.go
@@ -11,17 +11,19 @@
"external/crosvm",
"external/libchromeos-rs",
"external/minijail",
+ "external/open-dice",
"external/rust",
"external/selinux/libselinux",
"external/uwb",
"external/vm_tools/p9",
"frameworks/native/libs/binder/rust",
"frameworks/proto_logging/stats",
+ "hardware/interfaces/security",
+ "packages/modules/Bluetooth",
"packages/modules/DnsResolver",
"packages/modules/Uwb",
"packages/modules/Virtualization",
"prebuilts/rust",
- "system/bt",
"system/core/libstats/pull_rust",
"system/extras/profcollectd",
"system/extras/simpleperf",
diff --git a/rust/config/global.go b/rust/config/global.go
index b163bb6..bfb2d1f 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -24,9 +24,9 @@
var pctx = android.NewPackageContext("android/soong/rust/config")
var (
- RustDefaultVersion = "1.55.0"
+ RustDefaultVersion = "1.57.0"
RustDefaultBase = "prebuilts/rust/"
- DefaultEdition = "2018"
+ DefaultEdition = "2021"
Stdlibs = []string{
"libstd",
}
@@ -41,12 +41,13 @@
}
GlobalRustFlags = []string{
- "--remap-path-prefix $$(pwd)=",
+ "-Z remap-cwd-prefix=.",
"-C codegen-units=1",
"-C debuginfo=2",
"-C opt-level=3",
"-C relocation-model=pic",
"-C overflow-checks=on",
+ "-C force-unwind-tables=yes",
// Use v0 mangling to distinguish from C++ symbols
"-Z symbol-mangling-version=v0",
}
@@ -54,6 +55,8 @@
deviceGlobalRustFlags = []string{
"-C panic=abort",
"-Z link-native-libraries=no",
+ // Generate additional debug info for AutoFDO
+ "-Z debug-info-for-profiling",
}
deviceGlobalLinkFlags = []string{
diff --git a/rust/fuzz.go b/rust/fuzz.go
index a628b61..55921ba 100644
--- a/rust/fuzz.go
+++ b/rust/fuzz.go
@@ -36,7 +36,7 @@
fuzzPackagedModule fuzz.FuzzPackagedModule
}
-var _ compiler = (*binaryDecorator)(nil)
+var _ compiler = (*fuzzDecorator)(nil)
// rust_binary produces a binary that is runnable on a device.
func RustFuzzFactory() android.Module {
@@ -147,7 +147,7 @@
files = s.PackageArtifacts(ctx, module, fuzzModule.fuzzPackagedModule, archDir, builder)
// The executable.
- files = append(files, fuzz.FileToZip{rustModule.unstrippedOutputFile.Path(), ""})
+ files = append(files, fuzz.FileToZip{rustModule.UnstrippedOutputFile(), ""})
// Grab the list of required shared libraries.
sharedLibraries := fuzz.CollectAllSharedDependencies(ctx, module, cc.UnstrippedOutputFile, cc.IsValidSharedDependency)
diff --git a/rust/fuzz_test.go b/rust/fuzz_test.go
index 2524f91..98be7c2 100644
--- a/rust/fuzz_test.go
+++ b/rust/fuzz_test.go
@@ -45,7 +45,7 @@
}
// Check that compiler flags are set appropriately .
- fuzz_libtest := ctx.ModuleForTests("fuzz_libtest", "android_arm64_armv8-a_fuzzer").Output("fuzz_libtest")
+ fuzz_libtest := ctx.ModuleForTests("fuzz_libtest", "android_arm64_armv8-a_fuzzer").Rule("rustc")
if !strings.Contains(fuzz_libtest.Args["rustcFlags"], "-Z sanitizer=hwaddress") ||
!strings.Contains(fuzz_libtest.Args["rustcFlags"], "-C passes='sancov'") ||
!strings.Contains(fuzz_libtest.Args["rustcFlags"], "--cfg fuzzing") {
diff --git a/rust/library.go b/rust/library.go
index 38dae4d..bb2e83f 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -102,6 +102,9 @@
sourceProvider SourceProvider
collectedSnapshotHeaders android.Paths
+
+ // table-of-contents file for cdylib crates to optimize out relinking when possible
+ tocFile android.OptionalPath
}
type libraryInterface interface {
@@ -137,12 +140,18 @@
BuildOnlyDylib()
BuildOnlyStatic()
BuildOnlyShared()
+
+ toc() android.OptionalPath
}
func (library *libraryDecorator) nativeCoverage() bool {
return true
}
+func (library *libraryDecorator) toc() android.OptionalPath {
+ return library.tocFile
+}
+
func (library *libraryDecorator) rlib() bool {
return library.MutatedProperties.VariantIsRlib
}
@@ -460,7 +469,7 @@
}
func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path {
- var outputFile android.ModuleOutPath
+ var outputFile, ret android.ModuleOutPath
var fileName string
srcPath := library.srcPath(ctx, deps)
@@ -468,6 +477,34 @@
deps.srcProviderFiles = append(deps.srcProviderFiles, library.sourceProvider.Srcs()...)
}
+ // Calculate output filename
+ if library.rlib() {
+ fileName = library.getStem(ctx) + ctx.toolchain().RlibSuffix()
+ outputFile = android.PathForModuleOut(ctx, fileName)
+ ret = outputFile
+ } else if library.dylib() {
+ fileName = library.getStem(ctx) + ctx.toolchain().DylibSuffix()
+ outputFile = android.PathForModuleOut(ctx, fileName)
+ ret = outputFile
+ } else if library.static() {
+ fileName = library.getStem(ctx) + ctx.toolchain().StaticLibSuffix()
+ outputFile = android.PathForModuleOut(ctx, fileName)
+ ret = outputFile
+ } else if library.shared() {
+ fileName = library.sharedLibFilename(ctx)
+ outputFile = android.PathForModuleOut(ctx, fileName)
+ ret = outputFile
+ }
+
+ if !library.rlib() && !library.static() && library.stripper.NeedsStrip(ctx) {
+ strippedOutputFile := outputFile
+ outputFile = android.PathForModuleOut(ctx, "unstripped", fileName)
+ library.stripper.StripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile)
+
+ library.baseCompiler.strippedOutputFile = android.OptionalPathForPath(strippedOutputFile)
+ }
+ library.baseCompiler.unstrippedOutputFile = outputFile
+
flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
flags.LinkFlags = append(flags.LinkFlags, deps.depLinkFlags...)
flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects...)
@@ -479,34 +516,17 @@
flags.RustFlags = append(flags.RustFlags, "-C prefer-dynamic")
}
+ // Call the appropriate builder for this library type
if library.rlib() {
- fileName = library.getStem(ctx) + ctx.toolchain().RlibSuffix()
- outputFile = android.PathForModuleOut(ctx, fileName)
-
TransformSrctoRlib(ctx, srcPath, deps, flags, outputFile)
} else if library.dylib() {
- fileName = library.getStem(ctx) + ctx.toolchain().DylibSuffix()
- outputFile = android.PathForModuleOut(ctx, fileName)
-
TransformSrctoDylib(ctx, srcPath, deps, flags, outputFile)
} else if library.static() {
- fileName = library.getStem(ctx) + ctx.toolchain().StaticLibSuffix()
- outputFile = android.PathForModuleOut(ctx, fileName)
-
TransformSrctoStatic(ctx, srcPath, deps, flags, outputFile)
} else if library.shared() {
- fileName = library.sharedLibFilename(ctx)
- outputFile = android.PathForModuleOut(ctx, fileName)
-
TransformSrctoShared(ctx, srcPath, deps, flags, outputFile)
}
- if !library.rlib() && !library.static() && library.stripper.NeedsStrip(ctx) {
- strippedOutputFile := android.PathForModuleOut(ctx, "stripped", fileName)
- library.stripper.StripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile)
- library.strippedOutputFile = android.OptionalPathForPath(strippedOutputFile)
- }
-
if library.rlib() || library.dylib() {
library.flagExporter.exportLinkDirs(deps.linkDirs...)
library.flagExporter.exportLinkObjects(deps.linkObjects...)
@@ -519,9 +539,16 @@
}
if library.shared() {
+ // Optimize out relinking against shared libraries whose interface hasn't changed by
+ // depending on a table of contents file instead of the library itself.
+ tocFile := outputFile.ReplaceExtension(ctx, flags.Toolchain.SharedLibSuffix()[1:]+".toc")
+ library.tocFile = android.OptionalPathForPath(tocFile)
+ cc.TransformSharedObjectToToc(ctx, outputFile, tocFile)
+
ctx.SetProvider(cc.SharedLibraryInfoProvider, cc.SharedLibraryInfo{
- SharedLibrary: outputFile,
- Target: ctx.Target(),
+ TableOfContents: android.OptionalPathForPath(tocFile),
+ SharedLibrary: outputFile,
+ Target: ctx.Target(),
})
}
@@ -536,7 +563,7 @@
library.flagExporter.setProvider(ctx)
- return outputFile
+ return ret
}
func (library *libraryDecorator) srcPath(ctx ModuleContext, deps PathDeps) android.Path {
@@ -654,6 +681,12 @@
}
variation := v.(*Module).ModuleBase.ImageVariation().Variation
+ if strings.HasPrefix(variation, cc.VendorVariationPrefix) {
+ // TODO(b/204303985)
+ // Disable vendor dylibs until they are supported
+ v.(*Module).Disable()
+ }
+
if strings.HasPrefix(variation, cc.VendorVariationPrefix) &&
m.HasVendorVariant() &&
!snapshot.IsVendorProprietaryModule(mctx) &&
diff --git a/rust/library_test.go b/rust/library_test.go
index cb4ef7e..d78dcdd 100644
--- a/rust/library_test.go
+++ b/rust/library_test.go
@@ -37,10 +37,10 @@
}`)
// Test all variants are being built.
- libfooRlib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_rlib_rlib-std").Output("libfoo.rlib")
- libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Output("libfoo.dylib.so")
- libfooStatic := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_static").Output("libfoo.ffi.a")
- libfooShared := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_shared").Output("libfoo.ffi.so")
+ libfooRlib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_rlib_rlib-std").Rule("rustc")
+ libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc")
+ libfooStatic := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_static").Rule("rustc")
+ libfooShared := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_shared").Rule("rustc")
rlibCrateType := "rlib"
dylibCrateType := "dylib"
@@ -78,7 +78,7 @@
crate_name: "foo",
}`)
- libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Output("libfoo.dylib.so")
+ libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc")
if !strings.Contains(libfooDylib.Args["rustcFlags"], "prefer-dynamic") {
t.Errorf("missing prefer-dynamic flag for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"])
@@ -94,7 +94,7 @@
crate_name: "foo",
}`)
- libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Output("libfoo.dylib.so")
+ libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc")
if !strings.Contains(libfooDylib.Args["rustcFlags"], "--cfg 'android_dylib'") {
t.Errorf("missing android_dylib cfg flag for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"])
@@ -148,7 +148,7 @@
libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared")
- libfooOutput := libfoo.Output("libfoo.so")
+ libfooOutput := libfoo.Rule("rustc")
if !strings.Contains(libfooOutput.Args["linkFlags"], "-Wl,-soname=libfoo.so") {
t.Errorf("missing expected -Wl,-soname linker flag for libfoo shared lib, linkFlags: %#v",
libfooOutput.Args["linkFlags"])
@@ -160,6 +160,26 @@
}
}
+func TestSharedLibraryToc(t *testing.T) {
+ ctx := testRust(t, `
+ rust_ffi_shared {
+ name: "libfoo",
+ srcs: ["foo.rs"],
+ crate_name: "foo",
+ }
+ cc_binary {
+ name: "fizzbuzz",
+ shared_libs: ["libfoo"],
+ }`)
+
+ fizzbuzz := ctx.ModuleForTests("fizzbuzz", "android_arm64_armv8-a").Rule("ld")
+
+ if !android.SuffixInList(fizzbuzz.Implicits.Strings(), "libfoo.so.toc") {
+ t.Errorf("missing expected libfoo.so.toc implicit dependency, instead found: %#v",
+ fizzbuzz.Implicits.Strings())
+ }
+}
+
func TestStaticLibraryLinkage(t *testing.T) {
ctx := testRust(t, `
rust_ffi_static {
@@ -242,16 +262,17 @@
`)
foo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib")
- foo.Output("stripped/libfoo.dylib.so")
+ foo.Output("libfoo.dylib.so")
+ foo.Output("unstripped/libfoo.dylib.so")
// Check that the `cp` rule is using the stripped version as input.
cp := foo.Rule("android.Cp")
- if !strings.HasSuffix(cp.Input.String(), "stripped/libfoo.dylib.so") {
- t.Errorf("installed binary not based on stripped version: %v", cp.Input)
+ if strings.HasSuffix(cp.Input.String(), "unstripped/libfoo.dylib.so") {
+ t.Errorf("installed library not based on stripped version: %v", cp.Input)
}
- fizzBar := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_dylib").MaybeOutput("stripped/libbar.dylib.so")
+ fizzBar := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_dylib").MaybeOutput("unstripped/libbar.dylib.so")
if fizzBar.Rule != nil {
- t.Errorf("stripped version of bar has been generated")
+ t.Errorf("unstripped library exists, so stripped library has incorrectly been generated")
}
}
diff --git a/rust/prebuilt.go b/rust/prebuilt.go
index 49f3c0f..6f17272 100644
--- a/rust/prebuilt.go
+++ b/rust/prebuilt.go
@@ -32,6 +32,8 @@
}
type prebuiltLibraryDecorator struct {
+ android.Prebuilt
+
*libraryDecorator
Properties PrebuiltProperties
}
@@ -54,6 +56,13 @@
return module.Init()
}
+func addSrcSupplier(module android.PrebuiltInterface, prebuilt *prebuiltLibraryDecorator) {
+ srcsSupplier := func(_ android.BaseModuleContext, _ android.Module) []string {
+ return prebuilt.prebuiltSrcs()
+ }
+ android.InitPrebuiltModuleWithSrcSupplier(module, srcsSupplier, "srcs")
+}
+
func NewPrebuiltLibrary(hod android.HostOrDeviceSupported) (*Module, *prebuiltLibraryDecorator) {
module, library := NewRustLibrary(hod)
library.BuildOnlyRust()
@@ -62,6 +71,9 @@
libraryDecorator: library,
}
module.compiler = prebuilt
+
+ addSrcSupplier(module, prebuilt)
+
return module, prebuilt
}
@@ -73,6 +85,9 @@
libraryDecorator: library,
}
module.compiler = prebuilt
+
+ addSrcSupplier(module, prebuilt)
+
return module, prebuilt
}
@@ -84,6 +99,9 @@
libraryDecorator: library,
}
module.compiler = prebuilt
+
+ addSrcSupplier(module, prebuilt)
+
return module, prebuilt
}
@@ -100,6 +118,7 @@
if len(paths) > 0 {
ctx.PropertyErrorf("srcs", "prebuilt libraries can only have one entry in srcs (the prebuilt path)")
}
+ prebuilt.baseCompiler.unstrippedOutputFile = srcPath
return srcPath
}
@@ -129,3 +148,7 @@
return srcs
}
+
+func (prebuilt *prebuiltLibraryDecorator) prebuilt() *android.Prebuilt {
+ return &prebuilt.Prebuilt
+}
diff --git a/rust/proc_macro.go b/rust/proc_macro.go
index 804d79f..974c096 100644
--- a/rust/proc_macro.go
+++ b/rust/proc_macro.go
@@ -75,6 +75,7 @@
srcPath, _ := srcPathFromModuleSrcs(ctx, procMacro.baseCompiler.Properties.Srcs)
TransformSrctoProcMacro(ctx, srcPath, deps, flags, outputFile)
+ procMacro.baseCompiler.unstrippedOutputFile = outputFile
return outputFile
}
diff --git a/rust/project_json.go b/rust/project_json.go
index ae48312..fe259d6 100644
--- a/rust/project_json.go
+++ b/rust/project_json.go
@@ -211,6 +211,8 @@
comp = c.binaryDecorator.baseCompiler
case *procMacroDecorator:
comp = c.baseCompiler
+ case *toolchainLibraryDecorator:
+ comp = c.baseCompiler
default:
return nil, nil, false
}
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 c465cb6..778000d 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -156,13 +156,15 @@
sourceProvider SourceProvider
subAndroidMkOnce map[SubAndroidMkProvider]bool
- // Unstripped output. This is usually used when this module is linked to another module
- // as a library. The stripped output which is used for installation can be found via
- // compiler.strippedOutputFile if it exists.
- unstrippedOutputFile android.OptionalPath
- docTimestampFile android.OptionalPath
+ // Output file to be installed, may be stripped or unstripped.
+ outputFile android.OptionalPath
+
+ docTimestampFile android.OptionalPath
hideApexVariantFromMake bool
+
+ // For apex variants, this is set as apex.min_sdk_version
+ apexSdkVersion android.ApiLevel
}
func (mod *Module) Header() bool {
@@ -281,8 +283,8 @@
func (mod *Module) Toc() android.OptionalPath {
if mod.compiler != nil {
- if _, ok := mod.compiler.(libraryInterface); ok {
- return android.OptionalPath{}
+ if lib, ok := mod.compiler.(libraryInterface); ok {
+ return lib.toc()
}
}
panic(fmt.Errorf("Toc() called on non-library module: %q", mod.BaseModuleName()))
@@ -391,6 +393,10 @@
WholeStaticLibs []string
HeaderLibs []string
+ // Used for data dependencies adjacent to tests
+ DataLibs []string
+ DataBins []string
+
CrtBegin, CrtEnd string
}
@@ -465,6 +471,7 @@
stdLinkage(ctx *depsContext) RustLinkage
+ unstrippedOutputFilePath() android.Path
strippedOutputFilePath() android.OptionalPath
}
@@ -574,7 +581,7 @@
func (mod *Module) CcLibrary() bool {
if mod.compiler != nil {
- if _, ok := mod.compiler.(*libraryDecorator); ok {
+ if _, ok := mod.compiler.(libraryInterface); ok {
return true
}
}
@@ -593,8 +600,8 @@
}
func (mod *Module) UnstrippedOutputFile() android.Path {
- if mod.unstrippedOutputFile.Valid() {
- return mod.unstrippedOutputFile.Path()
+ if mod.compiler != nil {
+ return mod.compiler.unstrippedOutputFilePath()
}
return nil
}
@@ -651,10 +658,7 @@
}
func (mod *Module) OutputFile() android.OptionalPath {
- if mod.compiler != nil && mod.compiler.strippedOutputFilePath().Valid() {
- return mod.compiler.strippedOutputFilePath()
- }
- return mod.unstrippedOutputFile
+ return mod.outputFile
}
func (mod *Module) CoverageFiles() android.Paths {
@@ -678,6 +682,10 @@
return mod.OutputFile().Valid() && !mod.Properties.PreventInstall
}
+func (ctx moduleContext) apexVariationName() string {
+ return ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).ApexVariationName
+}
+
var _ cc.LinkableInterface = (*Module)(nil)
func (mod *Module) Init() android.Module {
@@ -885,11 +893,17 @@
if mod.compiler != nil && !mod.compiler.Disabled() {
mod.compiler.initialize(ctx)
- unstrippedOutputFile := mod.compiler.compile(ctx, flags, deps)
- mod.unstrippedOutputFile = android.OptionalPathForPath(unstrippedOutputFile)
- bloaty.MeasureSizeForPaths(ctx, mod.compiler.strippedOutputFilePath(), mod.unstrippedOutputFile)
+ outputFile := mod.compiler.compile(ctx, flags, deps)
+ if ctx.Failed() {
+ return
+ }
+ mod.outputFile = android.OptionalPathForPath(outputFile)
+ 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.
@@ -958,6 +972,7 @@
name string
library bool
procMacro bool
+ dynamic bool
}
// InstallDepNeeded returns true for rlibs, dylibs, and proc macros so that they or their transitive
@@ -968,13 +983,24 @@
var _ android.InstallNeededDependencyTag = dependencyTag{}
+func (d dependencyTag) LicenseAnnotations() []android.LicenseAnnotation {
+ if d.library && d.dynamic {
+ return []android.LicenseAnnotation{android.LicenseAnnotationSharedDependency}
+ }
+ return nil
+}
+
+var _ android.LicenseAnnotationsDependencyTag = dependencyTag{}
+
var (
customBindgenDepTag = dependencyTag{name: "customBindgenTag"}
rlibDepTag = dependencyTag{name: "rlibTag", library: true}
- dylibDepTag = dependencyTag{name: "dylib", library: true}
+ dylibDepTag = dependencyTag{name: "dylib", library: true, dynamic: true}
procMacroDepTag = dependencyTag{name: "procMacro", procMacro: true}
testPerSrcDepTag = dependencyTag{name: "rust_unit_tests"}
sourceDepTag = dependencyTag{name: "source"}
+ dataLibDepTag = dependencyTag{name: "data lib"}
+ dataBinDepTag = dependencyTag{name: "data bin"}
)
func IsDylibDepTag(depTag blueprint.DependencyTag) bool {
@@ -1012,6 +1038,13 @@
}
}
+func (mod *Module) Prebuilt() *android.Prebuilt {
+ if p, ok := mod.compiler.(*prebuiltLibraryDecorator); ok {
+ return p.prebuilt()
+ }
+ return nil
+}
+
func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
var depPaths PathDeps
@@ -1023,6 +1056,20 @@
directSrcProvidersDeps := []*Module{}
directSrcDeps := [](android.SourceFileProducer){}
+ // For the dependency from platform to apex, use the latest stubs
+ mod.apexSdkVersion = android.FutureApiLevel
+ apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+ if !apexInfo.IsForPlatform() {
+ mod.apexSdkVersion = apexInfo.MinSdkVersion
+ }
+
+ if android.InList("hwaddress", ctx.Config().SanitizeDevice()) {
+ // In hwasan build, we override apexSdkVersion to the FutureApiLevel(10000)
+ // so that even Q(29/Android10) apexes could use the dynamic unwinder by linking the newer stubs(e.g libc(R+)).
+ // (b/144430859)
+ mod.apexSdkVersion = android.FutureApiLevel
+ }
+
ctx.VisitDirectDeps(func(dep android.Module) {
depName := ctx.OtherModuleName(dep)
depTag := ctx.OtherModuleDependencyTag(dep)
@@ -1083,13 +1130,8 @@
}
if depTag == dylibDepTag || depTag == rlibDepTag || depTag == procMacroDepTag {
- linkFile := rustDep.unstrippedOutputFile
- if !linkFile.Valid() {
- ctx.ModuleErrorf("Invalid output file when adding dep %q to %q",
- depName, ctx.ModuleName())
- return
- }
- linkDir := linkPathFromFilePath(linkFile.Path())
+ linkFile := rustDep.UnstrippedOutputFile()
+ linkDir := linkPathFromFilePath(linkFile)
if lib, ok := mod.compiler.(exportedFlagsProducer); ok {
lib.exportLinkDirs(linkDir)
}
@@ -1198,15 +1240,15 @@
var rlibDepFiles RustLibraries
for _, dep := range directRlibDeps {
- rlibDepFiles = append(rlibDepFiles, RustLibrary{Path: dep.unstrippedOutputFile.Path(), CrateName: dep.CrateName()})
+ rlibDepFiles = append(rlibDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile(), CrateName: dep.CrateName()})
}
var dylibDepFiles RustLibraries
for _, dep := range directDylibDeps {
- dylibDepFiles = append(dylibDepFiles, RustLibrary{Path: dep.unstrippedOutputFile.Path(), CrateName: dep.CrateName()})
+ dylibDepFiles = append(dylibDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile(), CrateName: dep.CrateName()})
}
var procMacroDepFiles RustLibraries
for _, dep := range directProcMacroDeps {
- procMacroDepFiles = append(procMacroDepFiles, RustLibrary{Path: dep.unstrippedOutputFile.Path(), CrateName: dep.CrateName()})
+ procMacroDepFiles = append(procMacroDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile(), CrateName: dep.CrateName()})
}
var staticLibDepFiles android.Paths
@@ -1401,6 +1443,12 @@
}
}
+ actx.AddVariationDependencies([]blueprint.Variation{
+ {Mutator: "link", Variation: "shared"},
+ }, dataLibDepTag, deps.DataLibs...)
+
+ actx.AddVariationDependencies(nil, dataBinDepTag, deps.DataBins...)
+
// proc_macros are compiler plugins, and so we need the host arch variant as a dependendcy.
actx.AddFarVariationDependencies(ctx.Config().BuildOSTarget.Variations(), procMacroDepTag, deps.ProcMacros...)
}
@@ -1515,7 +1563,7 @@
// Overrides ApexModule.IsInstallabeToApex()
func (mod *Module) IsInstallableToApex() bool {
if mod.compiler != nil {
- if lib, ok := mod.compiler.(*libraryDecorator); ok && (lib.shared() || lib.dylib()) {
+ if lib, ok := mod.compiler.(libraryInterface); ok && (lib.shared() || lib.dylib()) {
return true
}
if _, ok := mod.compiler.(*binaryDecorator); ok {
diff --git a/rust/rust_test.go b/rust/rust_test.go
index 80f693e..97bd541 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -79,8 +79,10 @@
}
const (
- sharedVendorVariant = "android_vendor.29_arm64_armv8-a_shared"
- rlibVendorVariant = "android_vendor.29_arm64_armv8-a_rlib_rlib-std"
+ sharedVendorVariant = "android_vendor.29_arm64_armv8-a_shared"
+ rlibVendorVariant = "android_vendor.29_arm64_armv8-a_rlib_rlib-std"
+ sharedRecoveryVariant = "android_recovery_arm64_armv8-a_shared"
+ rlibRecoveryVariant = "android_recovery_arm64_armv8-a_rlib_rlib-std"
)
func testRustVndkFs(t *testing.T, bp string, fs android.MockFS) *android.TestContext {
@@ -101,7 +103,22 @@
),
).RunTestWithBp(t, bp)
return result.TestContext
+}
+func testRustRecoveryFsVersions(t *testing.T, bp string, fs android.MockFS, device_version, vndk_version, recovery_version string) *android.TestContext {
+ skipTestIfOsNotSupported(t)
+ result := android.GroupFixturePreparers(
+ prepareForRustTest,
+ fs.AddToFixture(),
+ android.FixtureModifyProductVariables(
+ func(variables android.FixtureProductVariables) {
+ variables.DeviceVndkVersion = StringPtr(device_version)
+ variables.RecoverySnapshotVersion = StringPtr(recovery_version)
+ variables.Platform_vndk_version = StringPtr(vndk_version)
+ },
+ ),
+ ).RunTestWithBp(t, bp)
+ return result.TestContext
}
// testRustCov returns a TestContext in which a basic environment has been
@@ -439,6 +456,13 @@
}`)
m := ctx.SingletonForTests("file_metrics")
+ m.Output("unstripped/libwaldo.dylib.so.bloaty.csv")
m.Output("libwaldo.dylib.so.bloaty.csv")
- m.Output("stripped/libwaldo.dylib.so.bloaty.csv")
+}
+
+func assertString(t *testing.T, got, expected string) {
+ t.Helper()
+ if got != expected {
+ t.Errorf("expected %q got %q", expected, got)
+ }
}
diff --git a/rust/sanitize.go b/rust/sanitize.go
index baa383d..be9dc42 100644
--- a/rust/sanitize.go
+++ b/rust/sanitize.go
@@ -15,20 +15,39 @@
package rust
import (
+ "fmt"
+ "strings"
+
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
+
"android/soong/android"
"android/soong/cc"
"android/soong/rust/config"
- "fmt"
- "github.com/google/blueprint"
)
+// TODO: When Rust has sanitizer-parity with CC, deduplicate this struct
type SanitizeProperties struct {
// enable AddressSanitizer, HWAddressSanitizer, and others.
Sanitize struct {
Address *bool `android:"arch_variant"`
Hwaddress *bool `android:"arch_variant"`
- Fuzzer *bool `android:"arch_variant"`
- Never *bool `android:"arch_variant"`
+
+ // Memory-tagging, only available on arm64
+ // if diag.memtag unset or false, enables async memory tagging
+ Memtag_heap *bool `android:"arch_variant"`
+ Fuzzer *bool `android:"arch_variant"`
+ Never *bool `android:"arch_variant"`
+
+ // Sanitizers to run in the diagnostic mode (as opposed to the release mode).
+ // Replaces abort() on error with a human-readable error message.
+ // Address and Thread sanitizers always run in diagnostic mode.
+ Diag struct {
+ // Memory-tagging, only available on arm64
+ // requires sanitizer.memtag: true
+ // if set, enables sync memory tagging
+ Memtag_heap *bool `android:"arch_variant"`
+ }
}
SanitizerEnabled bool `blueprint:"mutated"`
SanitizeDep bool `blueprint:"mutated"`
@@ -59,9 +78,18 @@
"-Z sanitizer=address",
}
+// See cc/sanitize.go's hwasanGlobalOptions for global hwasan options.
var hwasanFlags = []string{
"-Z sanitizer=hwaddress",
"-C target-feature=+tagged-globals",
+
+ // Flags from cc/sanitize.go hwasanFlags
+ "-C llvm-args=--aarch64-enable-global-isel-at-O=-1",
+ "-C llvm-args=-fast-isel=false",
+ "-C llvm-args=-instcombine-lower-dbg-declare=0",
+
+ // Additional flags for HWASAN-ified Rust/C interop
+ "-C llvm-args=--hwasan-with-ifunc",
}
func boolPtr(v bool) *bool {
@@ -79,7 +107,88 @@
}
func (sanitize *sanitize) begin(ctx BaseModuleContext) {
- s := sanitize.Properties.Sanitize
+ s := &sanitize.Properties.Sanitize
+
+ // Never always wins.
+ if Bool(s.Never) {
+ return
+ }
+
+ // rust_test targets default to SYNC MemTag unless explicitly set to ASYNC (via diag: {Memtag_heap}).
+ if binary, ok := ctx.RustModule().compiler.(binaryInterface); ok && binary.testBinary() {
+ if s.Memtag_heap == nil {
+ s.Memtag_heap = proptools.BoolPtr(true)
+ }
+ if s.Diag.Memtag_heap == nil {
+ s.Diag.Memtag_heap = proptools.BoolPtr(true)
+ }
+ }
+
+ var globalSanitizers []string
+ var globalSanitizersDiag []string
+
+ if ctx.Host() {
+ if !ctx.Windows() {
+ globalSanitizers = ctx.Config().SanitizeHost()
+ }
+ } else {
+ arches := ctx.Config().SanitizeDeviceArch()
+ if len(arches) == 0 || android.InList(ctx.Arch().ArchType.Name, arches) {
+ globalSanitizers = ctx.Config().SanitizeDevice()
+ globalSanitizersDiag = ctx.Config().SanitizeDeviceDiag()
+ }
+ }
+
+ if len(globalSanitizers) > 0 {
+ var found bool
+
+ // Global Sanitizers
+ if found, globalSanitizers = android.RemoveFromList("hwaddress", globalSanitizers); found && s.Hwaddress == nil {
+ // TODO(b/204776996): HWASan for static Rust binaries isn't supported yet.
+ if !ctx.RustModule().StaticExecutable() {
+ s.Hwaddress = proptools.BoolPtr(true)
+ }
+ }
+
+ if found, globalSanitizers = android.RemoveFromList("memtag_heap", globalSanitizers); found && s.Memtag_heap == nil {
+ if !ctx.Config().MemtagHeapDisabledForPath(ctx.ModuleDir()) {
+ s.Memtag_heap = proptools.BoolPtr(true)
+ }
+ }
+
+ if found, globalSanitizers = android.RemoveFromList("address", globalSanitizers); found && s.Address == nil {
+ s.Address = proptools.BoolPtr(true)
+ }
+
+ if found, globalSanitizers = android.RemoveFromList("fuzzer", globalSanitizers); found && s.Fuzzer == nil {
+ // TODO(b/204776996): HWASan for static Rust binaries isn't supported yet, and fuzzer enables HWAsan
+ if !ctx.RustModule().StaticExecutable() {
+ s.Fuzzer = proptools.BoolPtr(true)
+ }
+ }
+
+ // Global Diag Sanitizers
+ if found, globalSanitizersDiag = android.RemoveFromList("memtag_heap", globalSanitizersDiag); found &&
+ s.Diag.Memtag_heap == nil && Bool(s.Memtag_heap) {
+ s.Diag.Memtag_heap = proptools.BoolPtr(true)
+ }
+ }
+
+ // Enable Memtag for all components in the include paths (for Aarch64 only)
+ if ctx.Arch().ArchType == android.Arm64 {
+ if ctx.Config().MemtagHeapSyncEnabledForPath(ctx.ModuleDir()) {
+ if s.Memtag_heap == nil {
+ s.Memtag_heap = proptools.BoolPtr(true)
+ }
+ if s.Diag.Memtag_heap == nil {
+ s.Diag.Memtag_heap = proptools.BoolPtr(true)
+ }
+ } else if ctx.Config().MemtagHeapAsyncEnabledForPath(ctx.ModuleDir()) {
+ if s.Memtag_heap == nil {
+ s.Memtag_heap = proptools.BoolPtr(true)
+ }
+ }
+ }
// TODO:(b/178369775)
// For now sanitizing is only supported on devices
@@ -96,7 +205,22 @@
s.Hwaddress = nil
}
- if ctx.Os() == android.Android && Bool(s.Hwaddress) {
+ // HWASan ramdisk (which is built from recovery) goes over some bootloader limit.
+ // Keep libc instrumented so that ramdisk / vendor_ramdisk / recovery can run hwasan-instrumented code if necessary.
+ if (ctx.RustModule().InRamdisk() || ctx.RustModule().InVendorRamdisk() || ctx.RustModule().InRecovery()) && !strings.HasPrefix(ctx.ModuleDir(), "bionic/libc") {
+ s.Hwaddress = nil
+ }
+
+ if Bool(s.Hwaddress) {
+ s.Address = nil
+ }
+
+ // Memtag_heap is only implemented on AArch64.
+ if ctx.Arch().ArchType != android.Arm64 {
+ s.Memtag_heap = nil
+ }
+
+ if ctx.Os() == android.Android && (Bool(s.Hwaddress) || Bool(s.Address) || Bool(s.Memtag_heap)) {
sanitize.Properties.SanitizerEnabled = true
}
}
@@ -116,12 +240,10 @@
} else {
flags.RustFlags = append(flags.RustFlags, asanFlags...)
}
- }
- if Bool(sanitize.Properties.Sanitize.Address) {
- flags.RustFlags = append(flags.RustFlags, asanFlags...)
- }
- if Bool(sanitize.Properties.Sanitize.Hwaddress) {
+ } else if Bool(sanitize.Properties.Sanitize.Hwaddress) {
flags.RustFlags = append(flags.RustFlags, hwasanFlags...)
+ } else if Bool(sanitize.Properties.Sanitize.Address) {
+ flags.RustFlags = append(flags.RustFlags, asanFlags...)
}
return flags, deps
}
@@ -136,6 +258,26 @@
return
}
+ if Bool(mod.sanitize.Properties.Sanitize.Memtag_heap) && mod.Binary() {
+ noteDep := "note_memtag_heap_async"
+ if Bool(mod.sanitize.Properties.Sanitize.Diag.Memtag_heap) {
+ noteDep = "note_memtag_heap_sync"
+ }
+ // If we're using snapshots, redirect to snapshot whenever possible
+ // TODO(b/178470649): clean manual snapshot redirections
+ snapshot := mctx.Provider(cc.SnapshotInfoProvider).(cc.SnapshotInfo)
+ if lib, ok := snapshot.StaticLibs[noteDep]; ok {
+ noteDep = lib
+ }
+ depTag := cc.StaticDepTag(true)
+ variations := append(mctx.Target().Variations(),
+ blueprint.Variation{Mutator: "link", Variation: "static"})
+ if mod.Device() {
+ variations = append(variations, mod.ImageVariation())
+ }
+ mctx.AddFarVariationDependencies(variations, depTag, noteDep)
+ }
+
variations := mctx.Target().Variations()
var depTag blueprint.DependencyTag
var deps []string
@@ -148,27 +290,24 @@
deps = []string{config.LibclangRuntimeLibrary(mod.toolchain(mctx), "asan")}
} else if mod.IsSanitizerEnabled(cc.Hwasan) ||
(mod.IsSanitizerEnabled(cc.Fuzzer) && mctx.Arch().ArchType == android.Arm64) {
- // TODO(b/180495975): HWASan for static Rust binaries isn't supported yet.
- if binary, ok := mod.compiler.(*binaryDecorator); ok {
- if Bool(binary.Properties.Static_executable) {
+ // TODO(b/204776996): HWASan for static Rust binaries isn't supported yet.
+ if binary, ok := mod.compiler.(binaryInterface); ok {
+ if binary.staticallyLinked() {
mctx.ModuleErrorf("HWASan is not supported for static Rust executables yet.")
}
}
- if mod.StaticallyLinked() {
- variations = append(variations,
- blueprint.Variation{Mutator: "link", Variation: "static"})
- depTag = cc.StaticDepTag(false)
- deps = []string{config.LibclangRuntimeLibrary(mod.toolchain(mctx), "hwasan_static")}
- } else {
- variations = append(variations,
- blueprint.Variation{Mutator: "link", Variation: "shared"})
- depTag = cc.SharedDepTag()
- deps = []string{config.LibclangRuntimeLibrary(mod.toolchain(mctx), "hwasan")}
- }
+ // Always link against the shared library -- static binaries will pull in the static
+ // library during final link if necessary
+ variations = append(variations,
+ blueprint.Variation{Mutator: "link", Variation: "shared"})
+ depTag = cc.SharedDepTag()
+ deps = []string{config.LibclangRuntimeLibrary(mod.toolchain(mctx), "hwasan")}
}
- mctx.AddFarVariationDependencies(variations, depTag, deps...)
+ if len(deps) > 0 {
+ mctx.AddFarVariationDependencies(variations, depTag, deps...)
+ }
}
}
@@ -184,6 +323,9 @@
case cc.Hwasan:
sanitize.Properties.Sanitize.Hwaddress = boolPtr(b)
sanitizerSet = true
+ case cc.Memtag_heap:
+ sanitize.Properties.Sanitize.Memtag_heap = boolPtr(b)
+ sanitizerSet = true
default:
panic(fmt.Errorf("setting unsupported sanitizerType %d", t))
}
@@ -243,6 +385,8 @@
return sanitize.Properties.Sanitize.Address
case cc.Hwasan:
return sanitize.Properties.Sanitize.Hwaddress
+ case cc.Memtag_heap:
+ return sanitize.Properties.Sanitize.Memtag_heap
default:
return nil
}
@@ -268,6 +412,12 @@
case cc.Asan:
return true
case cc.Hwasan:
+ // TODO(b/180495975): HWASan for static Rust binaries isn't supported yet.
+ if mod.StaticExecutable() {
+ return false
+ }
+ return true
+ case cc.Memtag_heap:
return true
default:
return false
diff --git a/rust/sanitize_test.go b/rust/sanitize_test.go
new file mode 100644
index 0000000..d6a14b2
--- /dev/null
+++ b/rust/sanitize_test.go
@@ -0,0 +1,365 @@
+package rust
+
+import (
+ "fmt"
+ "strings"
+ "testing"
+
+ "android/soong/android"
+)
+
+type MemtagNoteType int
+
+const (
+ None MemtagNoteType = iota + 1
+ Sync
+ Async
+)
+
+func (t MemtagNoteType) str() string {
+ switch t {
+ case None:
+ return "none"
+ case Sync:
+ return "sync"
+ case Async:
+ return "async"
+ default:
+ panic("type_note_invalid")
+ }
+}
+
+func checkHasMemtagNote(t *testing.T, m android.TestingModule, expected MemtagNoteType) {
+ t.Helper()
+ note_async := "note_memtag_heap_async"
+ note_sync := "note_memtag_heap_sync"
+
+ found := None
+ implicits := m.Rule("rustc").Implicits
+ for _, lib := range implicits {
+ if strings.Contains(lib.Rel(), note_async) {
+ found = Async
+ break
+ } else if strings.Contains(lib.Rel(), note_sync) {
+ found = Sync
+ break
+ }
+ }
+
+ if found != expected {
+ t.Errorf("Wrong Memtag note in target %q: found %q, expected %q", m.Module().(*Module).Name(), found.str(), expected.str())
+ }
+}
+
+var prepareForTestWithMemtagHeap = android.GroupFixturePreparers(
+ android.FixtureModifyMockFS(func(fs android.MockFS) {
+ templateBp := `
+ rust_test {
+ name: "unset_test_%[1]s",
+ srcs: ["foo.rs"],
+ }
+
+ rust_test {
+ name: "no_memtag_test_%[1]s",
+ srcs: ["foo.rs"],
+ sanitize: { memtag_heap: false },
+ }
+
+ rust_test {
+ name: "set_memtag_test_%[1]s",
+ srcs: ["foo.rs"],
+ sanitize: { memtag_heap: true },
+ }
+
+ rust_test {
+ name: "set_memtag_set_async_test_%[1]s",
+ srcs: ["foo.rs"],
+ sanitize: { memtag_heap: true, diag: { memtag_heap: false } },
+ }
+
+ rust_test {
+ name: "set_memtag_set_sync_test_%[1]s",
+ srcs: ["foo.rs"],
+ sanitize: { memtag_heap: true, diag: { memtag_heap: true } },
+ }
+
+ rust_test {
+ name: "unset_memtag_set_sync_test_%[1]s",
+ srcs: ["foo.rs"],
+ sanitize: { diag: { memtag_heap: true } },
+ }
+
+ rust_binary {
+ name: "unset_binary_%[1]s",
+ srcs: ["foo.rs"],
+ }
+
+ rust_binary {
+ name: "no_memtag_binary_%[1]s",
+ srcs: ["foo.rs"],
+ sanitize: { memtag_heap: false },
+ }
+
+ rust_binary {
+ name: "set_memtag_binary_%[1]s",
+ srcs: ["foo.rs"],
+ sanitize: { memtag_heap: true },
+ }
+
+ rust_binary {
+ name: "set_memtag_set_async_binary_%[1]s",
+ srcs: ["foo.rs"],
+ sanitize: { memtag_heap: true, diag: { memtag_heap: false } },
+ }
+
+ rust_binary {
+ name: "set_memtag_set_sync_binary_%[1]s",
+ srcs: ["foo.rs"],
+ sanitize: { memtag_heap: true, diag: { memtag_heap: true } },
+ }
+
+ rust_binary {
+ name: "unset_memtag_set_sync_binary_%[1]s",
+ srcs: ["foo.rs"],
+ sanitize: { diag: { memtag_heap: true } },
+ }
+ `
+ subdirNoOverrideBp := fmt.Sprintf(templateBp, "no_override")
+ subdirOverrideDefaultDisableBp := fmt.Sprintf(templateBp, "override_default_disable")
+ subdirSyncBp := fmt.Sprintf(templateBp, "override_default_sync")
+ subdirAsyncBp := fmt.Sprintf(templateBp, "override_default_async")
+
+ fs.Merge(android.MockFS{
+ "subdir_no_override/Android.bp": []byte(subdirNoOverrideBp),
+ "subdir_override_default_disable/Android.bp": []byte(subdirOverrideDefaultDisableBp),
+ "subdir_sync/Android.bp": []byte(subdirSyncBp),
+ "subdir_async/Android.bp": []byte(subdirAsyncBp),
+ })
+ }),
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.MemtagHeapExcludePaths = []string{"subdir_override_default_disable"}
+ // "subdir_override_default_disable" is covered by both include and override_default_disable paths. override_default_disable wins.
+ variables.MemtagHeapSyncIncludePaths = []string{"subdir_sync", "subdir_override_default_disable"}
+ variables.MemtagHeapAsyncIncludePaths = []string{"subdir_async", "subdir_override_default_disable"}
+ }),
+)
+
+func TestSanitizeMemtagHeap(t *testing.T) {
+ variant := "android_arm64_armv8-a"
+
+ result := android.GroupFixturePreparers(
+ prepareForRustTest,
+ prepareForTestWithMemtagHeap,
+ ).RunTest(t)
+ ctx := result.TestContext
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_no_override", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_async", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_disable", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_sync", variant), None)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_no_override", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_async", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_disable", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_sync", variant), None)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_no_override", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_async", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_disable", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_no_override", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_async", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_disable", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_sync", variant), Async)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_no_override", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_async", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_disable", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_sync", variant), Async)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_no_override", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_disable", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_no_override", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_async", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_disable", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_sync", variant), Sync)
+}
+
+func TestSanitizeMemtagHeapWithSanitizeDevice(t *testing.T) {
+ variant := "android_arm64_armv8-a"
+
+ result := android.GroupFixturePreparers(
+ prepareForRustTest,
+ prepareForTestWithMemtagHeap,
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.SanitizeDevice = []string{"memtag_heap"}
+ }),
+ ).RunTest(t)
+ ctx := result.TestContext
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_no_override", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_async", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_disable", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_sync", variant), None)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_no_override", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_async", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_disable", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_sync", variant), None)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_no_override", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_async", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_disable", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_no_override", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_async", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_disable", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_sync", variant), Async)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_no_override", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_async", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_disable", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_sync", variant), Async)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_sync", variant), Sync)
+
+ // should sanitize: { diag: { memtag: true } } result in Sync instead of None here?
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_async", variant), Sync)
+ // should sanitize: { diag: { memtag: true } } result in Sync instead of None here?
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_disable", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_no_override", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_async", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_disable", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_sync", variant), Sync)
+}
+
+func TestSanitizeMemtagHeapWithSanitizeDeviceDiag(t *testing.T) {
+ variant := "android_arm64_armv8-a"
+
+ result := android.GroupFixturePreparers(
+ prepareForRustTest,
+ prepareForTestWithMemtagHeap,
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.SanitizeDevice = []string{"memtag_heap"}
+ variables.SanitizeDeviceDiag = []string{"memtag_heap"}
+ }),
+ ).RunTest(t)
+ ctx := result.TestContext
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_no_override", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_async", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_disable", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_sync", variant), None)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_no_override", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_async", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_disable", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_sync", variant), None)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_no_override", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_async", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_disable", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_sync", variant), Async)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_no_override", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_async", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_disable", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_sync", variant), Async)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_async", variant), Sync)
+ // should sanitize: { diag: { memtag: true } } result in Sync instead of None here?
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_disable", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_disable", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_sync", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_no_override", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_async", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_disable", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_sync", variant), Sync)
+}
diff --git a/rust/snapshot_prebuilt.go b/rust/snapshot_prebuilt.go
index 79eaab3..dfbc1d1 100644
--- a/rust/snapshot_prebuilt.go
+++ b/rust/snapshot_prebuilt.go
@@ -44,6 +44,8 @@
func registerRustSnapshotModules(ctx android.RegistrationContext) {
cc.VendorSnapshotImageSingleton.RegisterAdditionalModule(ctx,
"vendor_snapshot_rlib", VendorSnapshotRlibFactory)
+ cc.RecoverySnapshotImageSingleton.RegisterAdditionalModule(ctx,
+ "recovery_snapshot_rlib", RecoverySnapshotRlibFactory)
}
func snapshotLibraryFactory(image cc.SnapshotImage, moduleSuffix string) (*Module, *snapshotLibraryDecorator) {
@@ -85,8 +87,9 @@
if !library.MatchesWithDevice(ctx.DeviceConfig()) {
return nil
}
-
- return android.PathForModuleSrc(ctx, *library.properties.Src)
+ outputFile := android.PathForModuleSrc(ctx, *library.properties.Src)
+ library.unstrippedOutputFile = outputFile
+ return outputFile
}
func (library *snapshotLibraryDecorator) rustdoc(ctx ModuleContext, flags Flags, deps PathDeps) android.OptionalPath {
@@ -104,6 +107,13 @@
return module.Init()
}
+func RecoverySnapshotRlibFactory() android.Module {
+ module, prebuilt := snapshotLibraryFactory(cc.RecoverySnapshotImageSingleton, cc.SnapshotRlibSuffix)
+ prebuilt.libraryDecorator.BuildOnlyRlib()
+ prebuilt.libraryDecorator.setNoStdlibs()
+ return module.Init()
+}
+
func (library *snapshotLibraryDecorator) MatchesWithDevice(config android.DeviceConfig) bool {
arches := config.Arches()
if len(arches) == 0 || arches[0].ArchType.String() != library.Arch() {
diff --git a/rust/test.go b/rust/test.go
index 56da509..250b765 100644
--- a/rust/test.go
+++ b/rust/test.go
@@ -18,6 +18,7 @@
"github.com/google/blueprint/proptools"
"android/soong/android"
+ "android/soong/cc"
"android/soong/tradefed"
)
@@ -49,6 +50,12 @@
// the test
Data []string `android:"path,arch_variant"`
+ // list of shared library modules that should be installed alongside the test
+ Data_libs []string `android:"arch_variant"`
+
+ // list of binary modules that should be installed alongside the test
+ Data_bins []string `android:"arch_variant"`
+
// Flag to indicate whether or not to create test config automatically. If AndroidTest.xml
// doesn't exist next to the Android.bp, this attribute doesn't need to be set to true
// explicitly.
@@ -137,6 +144,32 @@
dataSrcPaths := android.PathsForModuleSrc(ctx, test.Properties.Data)
+ ctx.VisitDirectDepsWithTag(dataLibDepTag, func(dep android.Module) {
+ depName := ctx.OtherModuleName(dep)
+ linkableDep, ok := dep.(cc.LinkableInterface)
+ if !ok {
+ ctx.ModuleErrorf("data_lib %q is not a linkable module", depName)
+ }
+ if linkableDep.OutputFile().Valid() {
+ test.data = append(test.data,
+ android.DataPath{SrcPath: linkableDep.OutputFile().Path(),
+ RelativeInstallPath: linkableDep.RelativeInstallPath()})
+ }
+ })
+
+ ctx.VisitDirectDepsWithTag(dataBinDepTag, func(dep android.Module) {
+ depName := ctx.OtherModuleName(dep)
+ linkableDep, ok := dep.(cc.LinkableInterface)
+ if !ok {
+ ctx.ModuleErrorf("data_bin %q is not a linkable module", depName)
+ }
+ if linkableDep.OutputFile().Valid() {
+ test.data = append(test.data,
+ android.DataPath{SrcPath: linkableDep.OutputFile().Path(),
+ RelativeInstallPath: linkableDep.RelativeInstallPath()})
+ }
+ })
+
for _, dataSrcPath := range dataSrcPaths {
test.data = append(test.data, android.DataPath{SrcPath: dataSrcPath})
}
@@ -177,6 +210,12 @@
func RustTestFactory() android.Module {
module, _ := NewRustTest(android.HostAndDeviceSupported)
+
+ // NewRustTest will set MultilibBoth true, however the host variant
+ // cannot produce the non-primary target. Therefore, add the
+ // rustTestHostMultilib load hook to set MultilibFirst for the
+ // host target.
+ android.AddLoadHook(module, rustTestHostMultilib)
return module.Init()
}
@@ -194,5 +233,25 @@
deps.Rustlibs = append(deps.Rustlibs, "libtest")
+ deps.DataLibs = append(deps.DataLibs, test.Properties.Data_libs...)
+ deps.DataBins = append(deps.DataBins, test.Properties.Data_bins...)
+
return deps
}
+
+func (test *testDecorator) testBinary() bool {
+ return true
+}
+
+func rustTestHostMultilib(ctx android.LoadHookContext) {
+ type props struct {
+ Target struct {
+ Host struct {
+ Compile_multilib *string
+ }
+ }
+ }
+ p := &props{}
+ p.Target.Host.Compile_multilib = proptools.StringPtr("first")
+ ctx.AppendProperties(p)
+}
diff --git a/rust/test_test.go b/rust/test_test.go
index 892761a..1124176 100644
--- a/rust/test_test.go
+++ b/rust/test_test.go
@@ -74,3 +74,129 @@
t.Errorf("Device rust_test module 'my_test' does not link libstd as an rlib")
}
}
+
+func TestDataLibs(t *testing.T) {
+ bp := `
+ cc_library {
+ name: "test_lib",
+ srcs: ["test_lib.cpp"],
+ }
+
+ rust_binary {
+ name: "rusty",
+ srcs: ["foo.rs"],
+ compile_multilib: "both",
+ }
+
+ rust_ffi {
+ name: "librust_test_lib",
+ crate_name: "rust_test_lib",
+ srcs: ["test_lib.rs"],
+ relative_install_path: "foo/bar/baz",
+ compile_multilib: "64",
+ }
+
+ rust_test {
+ name: "main_test",
+ srcs: ["foo.rs"],
+ data_libs: ["test_lib"],
+ data_bins: ["rusty"],
+ }
+ `
+
+ ctx := testRust(t, bp)
+
+ module := ctx.ModuleForTests("main_test", "android_arm64_armv8-a").Module()
+ testBinary := module.(*Module).compiler.(*testDecorator)
+ outputFiles, err := module.(android.OutputFileProducer).OutputFiles("")
+ if err != nil {
+ t.Fatalf("Expected rust_test to produce output files, error: %s", err)
+ }
+ if len(outputFiles) != 1 {
+ t.Fatalf("expected exactly one output file. output files: [%s]", outputFiles)
+ }
+ if len(testBinary.dataPaths()) != 2 {
+ t.Fatalf("expected exactly two test data files. test data files: [%s]", testBinary.dataPaths())
+ }
+
+ outputPath := outputFiles[0].String()
+ dataLibraryPath := testBinary.dataPaths()[0].SrcPath.String()
+ dataBinaryPath := testBinary.dataPaths()[1].SrcPath.String()
+
+ if !strings.HasSuffix(outputPath, "/main_test") {
+ t.Errorf("expected test output file to be 'main_test', but was '%s'", outputPath)
+ }
+ if !strings.HasSuffix(dataLibraryPath, "/test_lib.so") {
+ t.Errorf("expected test data file to be 'test_lib.so', but was '%s'", dataLibraryPath)
+ }
+ if !strings.HasSuffix(dataBinaryPath, "/rusty") {
+ t.Errorf("expected test data file to be 'test_lib.so', but was '%s'", dataBinaryPath)
+ }
+}
+
+func TestDataLibsRelativeInstallPath(t *testing.T) {
+ bp := `
+ cc_library {
+ name: "test_lib",
+ srcs: ["test_lib.cpp"],
+ relative_install_path: "foo/bar/baz",
+ compile_multilib: "64",
+ }
+
+ rust_ffi {
+ name: "librust_test_lib",
+ crate_name: "rust_test_lib",
+ srcs: ["test_lib.rs"],
+ relative_install_path: "foo/bar/baz",
+ compile_multilib: "64",
+ }
+
+ rust_binary {
+ name: "rusty",
+ srcs: ["foo.rs"],
+ relative_install_path: "foo/bar/baz",
+ compile_multilib: "64",
+ }
+
+ rust_test {
+ name: "main_test",
+ srcs: ["foo.rs"],
+ data_libs: ["test_lib", "librust_test_lib"],
+ data_bins: ["rusty"],
+ compile_multilib: "64",
+ }
+ `
+
+ ctx := testRust(t, bp)
+ module := ctx.ModuleForTests("main_test", "android_arm64_armv8-a").Module()
+ testBinary := module.(*Module).compiler.(*testDecorator)
+ outputFiles, err := module.(android.OutputFileProducer).OutputFiles("")
+ if err != nil {
+ t.Fatalf("Expected rust_test to produce output files, error: %s", err)
+ }
+ if len(outputFiles) != 1 {
+ t.Fatalf("expected exactly one output file. output files: [%s]", outputFiles)
+ }
+ if len(testBinary.dataPaths()) != 3 {
+ t.Fatalf("expected exactly two test data files. test data files: [%s]", testBinary.dataPaths())
+ }
+
+ outputPath := outputFiles[0].String()
+
+ if !strings.HasSuffix(outputPath, "/main_test") {
+ t.Errorf("expected test output file to be 'main_test', but was '%s'", outputPath)
+ }
+ entries := android.AndroidMkEntriesForTest(t, ctx, module)[0]
+ if !strings.HasSuffix(entries.EntryMap["LOCAL_TEST_DATA"][0], ":test_lib.so:foo/bar/baz") {
+ t.Errorf("expected LOCAL_TEST_DATA to end with `:test_lib.so:foo/bar/baz`,"+
+ " but was '%s'", entries.EntryMap["LOCAL_TEST_DATA"][0])
+ }
+ if !strings.HasSuffix(entries.EntryMap["LOCAL_TEST_DATA"][1], ":librust_test_lib.so:foo/bar/baz") {
+ t.Errorf("expected LOCAL_TEST_DATA to end with `:librust_test_lib.so:foo/bar/baz`,"+
+ " but was '%s'", entries.EntryMap["LOCAL_TEST_DATA"][1])
+ }
+ if !strings.HasSuffix(entries.EntryMap["LOCAL_TEST_DATA"][2], ":rusty:foo/bar/baz") {
+ t.Errorf("expected LOCAL_TEST_DATA to end with `:rusty:foo/bar/baz`,"+
+ " but was '%s'", entries.EntryMap["LOCAL_TEST_DATA"][2])
+ }
+}
diff --git a/rust/testing.go b/rust/testing.go
index 94cdd9d..1b34dfe 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -53,74 +53,14 @@
func GatherRequiredDepsForTest() string {
bp := `
rust_prebuilt_library {
- name: "libstd_x86_64-unknown-linux-gnu",
- crate_name: "std",
- rlib: {
- srcs: ["libstd.rlib"],
- },
- dylib: {
- srcs: ["libstd.so"],
- },
- host_supported: true,
- sysroot: true,
- }
- rust_prebuilt_library {
- name: "libtest_x86_64-unknown-linux-gnu",
- crate_name: "test",
- rlib: {
- srcs: ["libtest.rlib"],
- },
- dylib: {
- srcs: ["libtest.so"],
- },
- host_supported: true,
- sysroot: true,
- }
- rust_prebuilt_library {
- name: "libstd_i686-unknown-linux-gnu",
- crate_name: "std",
- rlib: {
- srcs: ["libstd.rlib"],
- },
- dylib: {
- srcs: ["libstd.so"],
- },
- host_supported: true,
- sysroot: true,
- }
- rust_prebuilt_library {
- name: "libtest_i686-unknown-linux-gnu",
- crate_name: "test",
- rlib: {
- srcs: ["libtest.rlib"],
- },
- dylib: {
- srcs: ["libtest.so"],
- },
- host_supported: true,
- sysroot: true,
- }
- rust_prebuilt_library {
- name: "libstd_x86_64-apple-darwin",
- crate_name: "std",
- rlib: {
- srcs: ["libstd.rlib"],
- },
- dylib: {
- srcs: ["libstd.so"],
- },
- host_supported: true,
- sysroot: true,
- }
- rust_prebuilt_library {
- name: "libtest_x86_64-apple-darwin",
- crate_name: "test",
- rlib: {
- srcs: ["libtest.rlib"],
- },
- dylib: {
- srcs: ["libtest.so"],
- },
+ name: "libstd",
+ crate_name: "std",
+ rlib: {
+ srcs: ["libstd.rlib"],
+ },
+ dylib: {
+ srcs: ["libstd.so"],
+ },
host_supported: true,
sysroot: true,
}
@@ -135,6 +75,7 @@
apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
min_sdk_version: "29",
vendor_available: true,
+ recovery_available: true,
llndk: {
symbol_file: "liblog.map.txt",
},
@@ -151,7 +92,12 @@
no_libcrt: true,
nocrt: true,
system_shared_libs: [],
- export_include_dirs: ["libprotobuf-cpp-full-includes"],
+ }
+ cc_library {
+ name: "libclang_rt.hwasan_static-aarch64-android",
+ no_libcrt: true,
+ nocrt: true,
+ system_shared_libs: [],
}
rust_library {
name: "libstd",
@@ -161,6 +107,7 @@
host_supported: true,
vendor_available: true,
vendor_ramdisk_available: true,
+ recovery_available: true,
native_coverage: false,
sysroot: true,
apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
@@ -173,6 +120,7 @@
host_supported: true,
vendor_available: true,
vendor_ramdisk_available: true,
+ recovery_available: true,
native_coverage: false,
apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
min_sdk_version: "29",
@@ -246,5 +194,8 @@
ctx.BottomUp("rust_begin", BeginMutator).Parallel()
})
ctx.RegisterSingletonType("rust_project_generator", rustProjectGeneratorSingleton)
+ ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.BottomUp("rust_sanitizers", rustSanitizerRuntimeMutator).Parallel()
+ })
registerRustSnapshotModules(ctx)
}
diff --git a/rust/toolchain_library.go b/rust/toolchain_library.go
new file mode 100644
index 0000000..326d529
--- /dev/null
+++ b/rust/toolchain_library.go
@@ -0,0 +1,103 @@
+//
+// Copyright (C) 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 rust
+
+import (
+ "path"
+
+ "android/soong/android"
+ "android/soong/rust/config"
+)
+
+// This module is used to compile the rust toolchain libraries
+// When RUST_PREBUILTS_VERSION is set, the library will generated
+// from the given Rust version.
+func init() {
+ android.RegisterModuleType("rust_toolchain_library",
+ rustToolchainLibraryFactory)
+ android.RegisterModuleType("rust_toolchain_library_rlib",
+ rustToolchainLibraryRlibFactory)
+ android.RegisterModuleType("rust_toolchain_library_dylib",
+ rustToolchainLibraryDylibFactory)
+}
+
+type toolchainLibraryProperties struct {
+ // path to the toolchain source, relative to the top of the toolchain source
+ Toolchain_src *string `android:"arch_variant"`
+}
+
+type toolchainLibraryDecorator struct {
+ *libraryDecorator
+ Properties toolchainLibraryProperties
+}
+
+// rust_toolchain_library produces all rust variants.
+func rustToolchainLibraryFactory() android.Module {
+ module, library := NewRustLibrary(android.HostAndDeviceSupported)
+ library.BuildOnlyRust()
+
+ return initToolchainLibrary(module, library)
+}
+
+// rust_toolchain_library_dylib produces a dylib.
+func rustToolchainLibraryDylibFactory() android.Module {
+ module, library := NewRustLibrary(android.HostAndDeviceSupported)
+ library.BuildOnlyDylib()
+
+ return initToolchainLibrary(module, library)
+}
+
+// rust_toolchain_library_rlib produces an rlib.
+func rustToolchainLibraryRlibFactory() android.Module {
+ module, library := NewRustLibrary(android.HostAndDeviceSupported)
+ library.BuildOnlyRlib()
+
+ return initToolchainLibrary(module, library)
+}
+
+func initToolchainLibrary(module *Module, library *libraryDecorator) android.Module {
+ toolchainLibrary := &toolchainLibraryDecorator{
+ libraryDecorator: library,
+ }
+ module.compiler = toolchainLibrary
+ module.AddProperties(&toolchainLibrary.Properties)
+ android.AddLoadHook(module, rustSetToolchainSource)
+
+ return module.Init()
+}
+
+func rustSetToolchainSource(ctx android.LoadHookContext) {
+ if toolchainLib, ok := ctx.Module().(*Module).compiler.(*toolchainLibraryDecorator); ok {
+ prefix := "linux-x86/" + GetRustPrebuiltVersion(ctx)
+ newSrcs := []string{path.Join(prefix, android.String(toolchainLib.Properties.Toolchain_src))}
+
+ type props struct {
+ Srcs []string
+ }
+ p := &props{}
+ p.Srcs = newSrcs
+ ctx.AppendProperties(p)
+
+ } else {
+ ctx.ModuleErrorf("Called rustSetToolchainSource on a non-Rust Module.")
+ }
+}
+
+// GetRustPrebuiltVersion returns the RUST_PREBUILTS_VERSION env var, or the default version if it is not defined.
+func GetRustPrebuiltVersion(ctx android.LoadHookContext) string {
+ return ctx.AConfig().GetenvWithDefault("RUST_PREBUILTS_VERSION", config.RustDefaultVersion)
+}
diff --git a/rust/vendor_snapshot_test.go b/rust/vendor_snapshot_test.go
index 60ddb65..03bd867 100644
--- a/rust/vendor_snapshot_test.go
+++ b/rust/vendor_snapshot_test.go
@@ -562,6 +562,7 @@
"libvendor",
"libvndk",
"libclang_rt.builtins-aarch64-android",
+ "note_memtag_heap_sync",
],
shared_libs: [
"libvendor_available",
@@ -853,6 +854,20 @@
},
}
+ // Test sanitizers use the snapshot libraries
+ rust_binary {
+ name: "memtag_binary",
+ srcs: ["vendor/bin.rs"],
+ vendor: true,
+ compile_multilib: "64",
+ sanitize: {
+ memtag_heap: true,
+ diag: {
+ memtag_heap: true,
+ }
+ },
+ }
+
// old snapshot module which has to be ignored
vendor_snapshot_binary {
name: "bin",
@@ -880,11 +895,25 @@
},
},
}
+
+ vendor_snapshot_static {
+ name: "note_memtag_heap_sync",
+ vendor: true,
+ target_arch: "arm64",
+ version: "30",
+ arch: {
+ arm64: {
+ src: "note_memtag_heap_sync.a",
+ },
+ },
+ }
+
`
mockFS := android.MockFS{
"framework/Android.bp": []byte(frameworkBp),
"framework/bin.rs": nil,
+ "note_memtag_heap_sync.a": nil,
"vendor/Android.bp": []byte(vendorProprietaryBp),
"vendor/bin": nil,
"vendor/bin32": nil,
@@ -993,4 +1022,360 @@
if android.InList(binaryVariant, binVariants) {
t.Errorf("bin must not have variant %#v, but it does", sharedVariant)
}
+
+ memtagStaticLibs := ctx.ModuleForTests("memtag_binary", "android_vendor.30_arm64_armv8-a").Module().(*Module).Properties.AndroidMkStaticLibs
+ if g, w := memtagStaticLibs, []string{"libclang_rt.builtins-aarch64-android.vendor", "note_memtag_heap_sync.vendor"}; !reflect.DeepEqual(g, w) {
+ t.Errorf("wanted memtag_binary AndroidMkStaticLibs %q, got %q", w, g)
+ }
+}
+
+func TestRecoverySnapshotCapture(t *testing.T) {
+ bp := `
+ rust_ffi {
+ name: "librecovery",
+ recovery: true,
+ srcs: ["foo.rs"],
+ crate_name: "recovery",
+ }
+
+ rust_ffi {
+ name: "librecovery_available",
+ recovery_available: true,
+ srcs: ["foo.rs"],
+ crate_name: "recovery_available",
+ }
+
+ rust_library_rlib {
+ name: "librecovery_rlib",
+ recovery: true,
+ srcs: ["foo.rs"],
+ crate_name: "recovery_rlib",
+ }
+
+ rust_library_rlib {
+ name: "librecovery_available_rlib",
+ recovery_available: true,
+ srcs: ["foo.rs"],
+ crate_name: "recovery_available_rlib",
+ }
+
+ rust_binary {
+ name: "recovery_bin",
+ recovery: true,
+ srcs: ["foo.rs"],
+ }
+
+ rust_binary {
+ name: "recovery_available_bin",
+ recovery_available: true,
+ srcs: ["foo.rs"],
+ }
+
+`
+ // Check Recovery snapshot output.
+
+ ctx := testRustRecoveryFsVersions(t, bp, rustMockedFiles, "", "29", "current")
+ snapshotDir := "recovery-snapshot"
+ snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64")
+ snapshotSingleton := ctx.SingletonForTests("recovery-snapshot")
+
+ var jsonFiles []string
+
+ for _, arch := range [][]string{
+ []string{"arm64", "armv8-a"},
+ } {
+ archType := arch[0]
+ archVariant := arch[1]
+ archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
+
+ // For shared libraries, all recovery:true and recovery_available modules are captured.
+ sharedVariant := fmt.Sprintf("android_recovery_%s_%s_shared", archType, archVariant)
+ sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
+ cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery", "librecovery.so", sharedDir, sharedVariant)
+ cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_available", "librecovery_available.so", sharedDir, sharedVariant)
+ jsonFiles = append(jsonFiles,
+ filepath.Join(sharedDir, "librecovery.so.json"),
+ filepath.Join(sharedDir, "librecovery_available.so.json"))
+
+ // For static libraries, all recovery:true and recovery_available modules are captured.
+ staticVariant := fmt.Sprintf("android_recovery_%s_%s_static", archType, archVariant)
+ staticDir := filepath.Join(snapshotVariantPath, archDir, "static")
+ cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery", "librecovery.a", staticDir, staticVariant)
+ cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_available", "librecovery_available.a", staticDir, staticVariant)
+ jsonFiles = append(jsonFiles,
+ filepath.Join(staticDir, "librecovery.a.json"),
+ filepath.Join(staticDir, "librecovery_available.a.json"))
+
+ // For rlib libraries, all recovery:true and recovery_available modules are captured.
+ rlibVariant := fmt.Sprintf("android_recovery_%s_%s_rlib_rlib-std", archType, archVariant)
+ rlibDir := filepath.Join(snapshotVariantPath, archDir, "rlib")
+ cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_rlib", "librecovery_rlib.rlib", rlibDir, rlibVariant)
+ cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_available_rlib", "librecovery_available_rlib.rlib", rlibDir, rlibVariant)
+ jsonFiles = append(jsonFiles,
+ filepath.Join(rlibDir, "librecovery_rlib.rlib.json"),
+ filepath.Join(rlibDir, "librecovery_available_rlib.rlib.json"))
+
+ // For binary executables, all recovery:true and recovery_available modules are captured.
+ if archType == "arm64" {
+ binaryVariant := fmt.Sprintf("android_recovery_%s_%s", archType, archVariant)
+ binaryDir := filepath.Join(snapshotVariantPath, archDir, "binary")
+ cc.CheckSnapshot(t, ctx, snapshotSingleton, "recovery_bin", "recovery_bin", binaryDir, binaryVariant)
+ cc.CheckSnapshot(t, ctx, snapshotSingleton, "recovery_available_bin", "recovery_available_bin", binaryDir, binaryVariant)
+ jsonFiles = append(jsonFiles,
+ filepath.Join(binaryDir, "recovery_bin.json"),
+ filepath.Join(binaryDir, "recovery_available_bin.json"))
+ }
+ }
+
+ for _, jsonFile := range jsonFiles {
+ // verify all json files exist
+ if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil {
+ t.Errorf("%q expected but not found", jsonFile)
+ }
+ }
+}
+
+func TestRecoverySnapshotExclude(t *testing.T) {
+ // This test verifies that the exclude_from_recovery_snapshot property
+ // makes its way from the Android.bp source file into the module data
+ // structure. It also verifies that modules are correctly included or
+ // excluded in the recovery snapshot based on their path (framework or
+ // vendor) and the exclude_from_recovery_snapshot property.
+
+ frameworkBp := `
+ rust_ffi_shared {
+ name: "libinclude",
+ srcs: ["src/include.rs"],
+ recovery_available: true,
+ crate_name: "include",
+ }
+ rust_ffi_shared {
+ name: "libexclude",
+ srcs: ["src/exclude.rs"],
+ recovery: true,
+ exclude_from_recovery_snapshot: true,
+ crate_name: "exclude",
+ }
+ rust_ffi_shared {
+ name: "libavailable_exclude",
+ srcs: ["src/exclude.rs"],
+ recovery_available: true,
+ exclude_from_recovery_snapshot: true,
+ crate_name: "available_exclude",
+ }
+ rust_library_rlib {
+ name: "libinclude_rlib",
+ srcs: ["src/include.rs"],
+ recovery_available: true,
+ crate_name: "include_rlib",
+ }
+ rust_library_rlib {
+ name: "libexclude_rlib",
+ srcs: ["src/exclude.rs"],
+ recovery: true,
+ exclude_from_recovery_snapshot: true,
+ crate_name: "exclude_rlib",
+ }
+ rust_library_rlib {
+ name: "libavailable_exclude_rlib",
+ srcs: ["src/exclude.rs"],
+ recovery_available: true,
+ exclude_from_recovery_snapshot: true,
+ crate_name: "available_exclude_rlib",
+ }
+ `
+
+ vendorProprietaryBp := `
+ rust_ffi_shared {
+ name: "librecovery",
+ srcs: ["recovery.rs"],
+ recovery: true,
+ crate_name: "recovery",
+ }
+ rust_library_rlib {
+ name: "librecovery_rlib",
+ srcs: ["recovery.rs"],
+ recovery: true,
+ crate_name: "recovery_rlib",
+ }
+ `
+
+ mockFS := map[string][]byte{
+ "framework/Android.bp": []byte(frameworkBp),
+ "framework/include.rs": nil,
+ "framework/exclude.rs": nil,
+ "device/Android.bp": []byte(vendorProprietaryBp),
+ "device/recovery.rs": nil,
+ }
+
+ ctx := testRustRecoveryFsVersions(t, "", mockFS, "", "29", "current")
+
+ // Test an include and exclude framework module.
+ cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libinclude", false, sharedRecoveryVariant)
+ cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libexclude", true, sharedRecoveryVariant)
+ cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libavailable_exclude", true, sharedRecoveryVariant)
+ cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libinclude_rlib", false, rlibRecoveryVariant)
+ cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libexclude_rlib", true, rlibRecoveryVariant)
+ cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libavailable_exclude_rlib", true, rlibRecoveryVariant)
+
+ // A recovery module is excluded, but by its path not the exclude_from_recovery_snapshot property
+ // ('device/' and 'vendor/' are default excluded). See snapshot/recovery_snapshot.go for more detail.
+ cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "librecovery", false, sharedRecoveryVariant)
+ cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "librecovery_rlib", false, rlibRecoveryVariant)
+
+ // Verify the content of the recovery snapshot.
+
+ snapshotDir := "recovery-snapshot"
+ snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64")
+ snapshotSingleton := ctx.SingletonForTests("recovery-snapshot")
+
+ var includeJsonFiles []string
+ var excludeJsonFiles []string
+
+ for _, arch := range [][]string{
+ []string{"arm64", "armv8-a"},
+ } {
+ archType := arch[0]
+ archVariant := arch[1]
+ archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
+
+ sharedVariant := fmt.Sprintf("android_recovery_%s_%s_shared", archType, archVariant)
+ rlibVariant := fmt.Sprintf("android_recovery_%s_%s_rlib_rlib-std", archType, archVariant)
+ sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
+ rlibDir := filepath.Join(snapshotVariantPath, archDir, "rlib")
+
+ // Included modules
+ cc.CheckSnapshot(t, ctx, snapshotSingleton, "libinclude", "libinclude.so", sharedDir, sharedVariant)
+ includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libinclude.so.json"))
+ cc.CheckSnapshot(t, ctx, snapshotSingleton, "libinclude_rlib", "libinclude_rlib.rlib", rlibDir, rlibVariant)
+ includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "libinclude_rlib.rlib.json"))
+
+ // Excluded modules
+ cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "libexclude", "libexclude.so", sharedDir, sharedVariant)
+ excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libexclude.so.json"))
+ cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "librecovery", "librecovery.so", sharedDir, sharedVariant)
+ excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "librecovery.so.json"))
+ cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "libavailable_exclude", "libavailable_exclude.so", sharedDir, sharedVariant)
+ excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libavailable_exclude.so.json"))
+ cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "libexclude_rlib", "libexclude_rlib.rlib", rlibDir, rlibVariant)
+ excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "libexclude_rlib.rlib.json"))
+ cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "librecovery_rlib", "librecovery_rlib.rlib", rlibDir, rlibVariant)
+ excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "librecovery_rlib.rlib.json"))
+ cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "libavailable_exclude_rlib", "libavailable_exclude_rlib.rlib", rlibDir, rlibVariant)
+ excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "libavailable_exclude_rlib.rlib.json"))
+ }
+
+ // Verify that each json file for an included module has a rule.
+ for _, jsonFile := range includeJsonFiles {
+ if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil {
+ t.Errorf("include json file %q not found", jsonFile)
+ }
+ }
+
+ // Verify that each json file for an excluded module has no rule.
+ for _, jsonFile := range excludeJsonFiles {
+ if snapshotSingleton.MaybeOutput(jsonFile).Rule != nil {
+ t.Errorf("exclude json file %q found", jsonFile)
+ }
+ }
+}
+
+func TestRecoverySnapshotDirected(t *testing.T) {
+ bp := `
+ rust_ffi_shared {
+ name: "librecovery",
+ recovery: true,
+ crate_name: "recovery",
+ srcs: ["foo.rs"],
+ }
+
+ rust_ffi_shared {
+ name: "librecovery_available",
+ recovery_available: true,
+ crate_name: "recovery_available",
+ srcs: ["foo.rs"],
+ }
+
+ rust_library_rlib {
+ name: "librecovery_rlib",
+ recovery: true,
+ crate_name: "recovery",
+ srcs: ["foo.rs"],
+ }
+
+ rust_library_rlib {
+ name: "librecovery_available_rlib",
+ recovery_available: true,
+ crate_name: "recovery_available",
+ srcs: ["foo.rs"],
+ }
+
+ /* TODO: Uncomment when Rust supports the "prefer" property for prebuilts
+ rust_library_rlib {
+ name: "libfoo_rlib",
+ recovery: true,
+ crate_name: "foo",
+ }
+
+ rust_prebuilt_rlib {
+ name: "libfoo_rlib",
+ recovery: true,
+ prefer: true,
+ srcs: ["libfoo.rlib"],
+ crate_name: "foo",
+ }
+ */
+`
+ ctx := testRustRecoveryFsVersions(t, bp, rustMockedFiles, "current", "29", "current")
+ ctx.Config().TestProductVariables.RecoverySnapshotModules = make(map[string]bool)
+ ctx.Config().TestProductVariables.RecoverySnapshotModules["librecovery"] = true
+ ctx.Config().TestProductVariables.RecoverySnapshotModules["librecovery_rlib"] = true
+ ctx.Config().TestProductVariables.DirectedRecoverySnapshot = true
+
+ // Check recovery snapshot output.
+ snapshotDir := "recovery-snapshot"
+ snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64")
+ snapshotSingleton := ctx.SingletonForTests("recovery-snapshot")
+
+ var includeJsonFiles []string
+
+ for _, arch := range [][]string{
+ []string{"arm64", "armv8-a"},
+ } {
+ archType := arch[0]
+ archVariant := arch[1]
+ archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
+
+ sharedVariant := fmt.Sprintf("android_recovery_%s_%s_shared", archType, archVariant)
+ rlibVariant := fmt.Sprintf("android_recovery_%s_%s_rlib_rlib-std", archType, archVariant)
+ sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
+ rlibDir := filepath.Join(snapshotVariantPath, archDir, "rlib")
+
+ // Included modules
+ cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery", "librecovery.so", sharedDir, sharedVariant)
+ includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "librecovery.so.json"))
+ cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_rlib", "librecovery_rlib.rlib", rlibDir, rlibVariant)
+ includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "librecovery_rlib.rlib.json"))
+
+ // TODO: When Rust supports the "prefer" property for prebuilts, perform this check.
+ /*
+ // Check that snapshot captures "prefer: true" prebuilt
+ cc.CheckSnapshot(t, ctx, snapshotSingleton, "prebuilt_libfoo_rlib", "libfoo_rlib.rlib", rlibDir, rlibVariant)
+ includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libfoo_rlib.rlib.json"))
+ */
+
+ // Excluded modules. Modules not included in the directed recovery snapshot
+ // are still included as fake modules.
+ cc.CheckSnapshotRule(t, ctx, snapshotSingleton, "librecovery_available", "librecovery_available.so", sharedDir, sharedVariant)
+ includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "librecovery_available.so.json"))
+ cc.CheckSnapshotRule(t, ctx, snapshotSingleton, "librecovery_available_rlib", "librecovery_available_rlib.rlib", rlibDir, rlibVariant)
+ includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "librecovery_available_rlib.rlib.json"))
+ }
+
+ // Verify that each json file for an included module has a rule.
+ for _, jsonFile := range includeJsonFiles {
+ if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil {
+ t.Errorf("include json file %q not found, %#v", jsonFile, includeJsonFiles)
+ }
+ }
}
diff --git a/scripts/Android.bp b/scripts/Android.bp
index 635be10..4c847a1 100644
--- a/scripts/Android.bp
+++ b/scripts/Android.bp
@@ -1,5 +1,6 @@
package {
default_applicable_licenses: ["Android-Apache-2.0"],
+ default_visibility: ["//build/soong:__subpackages__"],
}
python_binary_host {
@@ -8,14 +9,6 @@
srcs: [
"check_boot_jars/check_boot_jars.py",
],
- version: {
- py2: {
- enabled: true,
- },
- py3: {
- enabled: false,
- },
- },
}
python_binary_host {
@@ -24,14 +17,6 @@
srcs: [
"manifest_fixer.py",
],
- version: {
- py2: {
- enabled: true,
- },
- py3: {
- enabled: false,
- },
- },
libs: [
"manifest_utils",
],
@@ -45,11 +30,8 @@
"manifest_fixer.py",
],
version: {
- py2: {
- enabled: true,
- },
py3: {
- enabled: false,
+ embedded_launcher: true,
},
},
libs: [
@@ -65,14 +47,7 @@
srcs: [
"manifest.py",
],
- version: {
- py2: {
- enabled: true,
- },
- py3: {
- enabled: false,
- },
- },
+ visibility: ["//system/apex/apexer:__pkg__"],
}
python_binary_host {
@@ -81,14 +56,6 @@
srcs: [
"manifest_check.py",
],
- version: {
- py2: {
- enabled: true,
- },
- py3: {
- enabled: false,
- },
- },
libs: [
"manifest_utils",
],
@@ -101,14 +68,6 @@
"manifest_check_test.py",
"manifest_check.py",
],
- version: {
- py2: {
- enabled: true,
- },
- py3: {
- enabled: false,
- },
- },
libs: [
"manifest_utils",
],
@@ -123,14 +82,6 @@
srcs: [
"jsonmodify.py",
],
- version: {
- py2: {
- enabled: true,
- },
- py3: {
- enabled: false,
- },
- },
}
python_binary_host {
@@ -139,14 +90,6 @@
srcs: [
"test_config_fixer.py",
],
- version: {
- py2: {
- enabled: true,
- },
- py3: {
- enabled: false,
- },
- },
libs: [
"manifest_utils",
],
@@ -159,14 +102,6 @@
"test_config_fixer_test.py",
"test_config_fixer.py",
],
- version: {
- py2: {
- enabled: true,
- },
- py3: {
- enabled: false,
- },
- },
libs: [
"manifest_utils",
],
@@ -179,14 +114,6 @@
srcs: [
"construct_context.py",
],
- version: {
- py2: {
- enabled: true,
- },
- py3: {
- enabled: false,
- },
- },
libs: [
"manifest_utils",
],
@@ -199,14 +126,6 @@
"construct_context_test.py",
"construct_context.py",
],
- version: {
- py2: {
- enabled: true,
- },
- py3: {
- enabled: false,
- },
- },
libs: [
"manifest_utils",
],
@@ -253,11 +172,7 @@
"conv_linker_config.py",
],
version: {
- py2: {
- enabled: false,
- },
py3: {
- enabled: true,
embedded_launcher: true,
},
},
@@ -272,12 +187,4 @@
srcs: [
"get_clang_version.py",
],
- version: {
- py2: {
- enabled: false,
- },
- py3: {
- enabled: true,
- },
- },
}
diff --git a/scripts/OWNERS b/scripts/OWNERS
index 1830a18..3f4f9c0 100644
--- a/scripts/OWNERS
+++ b/scripts/OWNERS
@@ -1,6 +1,5 @@
per-file system-clang-format,system-clang-format-2 = enh@google.com,smoreland@google.com
-per-file build-mainline-modules.sh = ngeoffray@google.com,paulduffin@google.com,mast@google.com
per-file build-aml-prebuilts.sh = ngeoffray@google.com,paulduffin@google.com,mast@google.com
per-file construct_context.py = ngeoffray@google.com,calin@google.com,skvadrik@google.com
per-file conv_linker_config.py = kiyoungkim@google.com, jiyong@google.com, jooyung@google.com
-per-file gen_ndk*.sh = sophiez@google.com, allenhair@google.com
+per-file gen_ndk*.sh,gen_java*.sh = sophiez@google.com, allenhair@google.com
\ No newline at end of file
diff --git a/scripts/build-mainline-modules.sh b/scripts/build-mainline-modules.sh
deleted file mode 100755
index f183c05..0000000
--- a/scripts/build-mainline-modules.sh
+++ /dev/null
@@ -1,109 +0,0 @@
-#!/bin/bash -e
-
-# Non exhaustive list of modules where we want prebuilts. More can be added as
-# needed.
-MAINLINE_MODULES=(
- com.android.art
- com.android.art.debug
- com.android.art.testing
- com.android.conscrypt
- com.android.i18n
- com.android.os.statsd
- com.android.runtime
- com.android.tzdata
-)
-
-# List of SDKs and module exports we know of.
-MODULES_SDK_AND_EXPORTS=(
- art-module-sdk
- art-module-test-exports
- compos-module-sdk
- conscrypt-module-host-exports
- conscrypt-module-sdk
- conscrypt-module-test-exports
- i18n-module-host-exports
- i18n-module-sdk
- i18n-module-test-exports
- platform-mainline-sdk
- platform-mainline-test-exports
- runtime-module-host-exports
- runtime-module-sdk
- statsd-module-sdk
- tzdata-module-test-exports
-)
-
-# List of libraries installed on the platform that are needed for ART chroot
-# testing.
-PLATFORM_LIBRARIES=(
- heapprofd_client_api
- libartpalette-system
- liblog
-)
-
-# We want to create apex modules for all supported architectures.
-PRODUCTS=(
- aosp_arm
- aosp_arm64
- aosp_x86
- aosp_x86_64
-)
-
-if [ ! -e "build/make/core/Makefile" ]; then
- echo "$0 must be run from the top of the tree"
- exit 1
-fi
-
-echo_and_run() {
- echo "$*"
- "$@"
-}
-
-lib_dir() {
- case $1 in
- (aosp_arm|aosp_x86) echo "lib";;
- (aosp_arm64|aosp_x86_64) echo "lib64";;
- esac
-}
-
-# Make sure this build builds from source, regardless of the default.
-export SOONG_CONFIG_art_module_source_build=true
-
-# This script does not intend to handle compressed APEX
-export OVERRIDE_PRODUCT_COMPRESSED_APEX=false
-
-OUT_DIR=$(source build/envsetup.sh > /dev/null; TARGET_PRODUCT= get_build_var OUT_DIR)
-DIST_DIR=$(source build/envsetup.sh > /dev/null; TARGET_PRODUCT= get_build_var DIST_DIR)
-
-for product in "${PRODUCTS[@]}"; do
- echo_and_run build/soong/soong_ui.bash --make-mode $@ \
- TARGET_PRODUCT=${product} \
- ${MAINLINE_MODULES[@]} \
- ${PLATFORM_LIBRARIES[@]}
-
- PRODUCT_OUT=$(source build/envsetup.sh > /dev/null; TARGET_PRODUCT=${product} get_build_var PRODUCT_OUT)
- TARGET_ARCH=$(source build/envsetup.sh > /dev/null; TARGET_PRODUCT=${product} get_build_var TARGET_ARCH)
- rm -rf ${DIST_DIR}/${TARGET_ARCH}/
- mkdir -p ${DIST_DIR}/${TARGET_ARCH}/
- for module in "${MAINLINE_MODULES[@]}"; do
- echo_and_run cp ${PWD}/${PRODUCT_OUT}/system/apex/${module}.apex ${DIST_DIR}/${TARGET_ARCH}/
- done
- for library in "${PLATFORM_LIBRARIES[@]}"; do
- libdir=$(lib_dir $product)
- echo_and_run cp ${PWD}/${PRODUCT_OUT}/system/${libdir}/${library}.so ${DIST_DIR}/${TARGET_ARCH}/
- done
-done
-
-# We use force building LLVM components flag (even though we actually don't
-# compile them) because we don't have bionic host prebuilts
-# for them.
-export FORCE_BUILD_LLVM_COMPONENTS=true
-
-# Create multi-archs SDKs in a different out directory. The multi-arch script
-# uses Soong in --soong-only mode which cannot use the same directory as normal
-# mode with make.
-export OUT_DIR=${OUT_DIR}/aml
-echo_and_run build/soong/scripts/build-aml-prebuilts.sh \
- TARGET_PRODUCT=mainline_sdk ${MODULES_SDK_AND_EXPORTS[@]}
-
-rm -rf ${DIST_DIR}/mainline-sdks
-echo_and_run cp -R ${OUT_DIR}/soong/mainline-sdks ${DIST_DIR}
diff --git a/scripts/check_boot_jars/package_allowed_list.txt b/scripts/check_boot_jars/package_allowed_list.txt
index ed63651..a02c195 100644
--- a/scripts/check_boot_jars/package_allowed_list.txt
+++ b/scripts/check_boot_jars/package_allowed_list.txt
@@ -72,6 +72,7 @@
jdk\.internal
jdk\.internal\.math
jdk\.internal\.misc
+jdk\.internal\.ref
jdk\.internal\.reflect
jdk\.internal\.util
jdk\.internal\.vm\.annotation
diff --git a/scripts/diff_build_graphs.sh b/scripts/diff_build_graphs.sh
index 81010f3..8d01124 100755
--- a/scripts/diff_build_graphs.sh
+++ b/scripts/diff_build_graphs.sh
@@ -98,7 +98,7 @@
# or in case it is affected by some of the changes we're testing
make blueprint_tools
# find multiproduct_kati and have it build the ninja files for each product
- builder="$(echo $OUT_DIR/soong/host/*/bin/multiproduct_kati)"
+ builder="$(echo $OUT_DIR/host/*/bin/multiproduct_kati)"
BUILD_NUMBER=sample "$builder" $PRODUCTS_ARG --keep --out "$OUT_DIR_TEMP" || true
echo
}
diff --git a/scripts/gen_java_usedby_apex.sh b/scripts/gen_java_usedby_apex.sh
new file mode 100755
index 0000000..e398541
--- /dev/null
+++ b/scripts/gen_java_usedby_apex.sh
@@ -0,0 +1,48 @@
+#!/bin/bash -e
+
+# Copyright 2020 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.
+
+printHelp() {
+ echo "**************************** Usage Instructions ****************************"
+ echo "This script is used to generate the Mainline modules used-by Java symbols."
+ echo ""
+ echo "To run this script use: ./gen_java_usedby_apex.sh \$BINARY_DEXDEPS_PATH \$OUTPUT_FILE_PATH \$JAR_AND_APK_LIST"
+ echo "For example: If all jar and apk files are '/myJar.jar /myApk.apk' and output write to /myModule.txt then the command would be:"
+ echo "./gen_java_usedby_apex.sh \$BINARY_DEXDEPS_PATH /myModule.txt /myJar.jar /myApk.apk"
+}
+
+genUsedByList() {
+ dexdeps="$1"
+ shift
+ out="$1"
+ shift
+ rm -f "$out"
+ touch "$out"
+ echo "<externals>" >> "$out"
+ for x in "$@"; do
+ "$dexdeps" "$x" >> "$out" || echo "</external>" >> "$out"
+ done
+ echo "</externals>" >> "$out"
+}
+
+if [[ "$1" == "help" ]]
+then
+ printHelp
+elif [[ "$#" -lt 2 ]]
+then
+ echo "Wrong argument length. Expecting at least 2 argument representing dexdeps path, output path, followed by a list of jar or apk files in the Mainline module."
+else
+ genUsedByList "$@"
+fi
\ No newline at end of file
diff --git a/scripts/manifest.py b/scripts/manifest.py
index 04f7405..81f9c61 100755
--- a/scripts/manifest.py
+++ b/scripts/manifest.py
@@ -123,4 +123,4 @@
def write_xml(f, doc):
f.write('<?xml version="1.0" encoding="utf-8"?>\n')
for node in doc.childNodes:
- f.write(node.toxml(encoding='utf-8') + '\n')
+ f.write(node.toxml() + '\n')
diff --git a/scripts/manifest_check.py b/scripts/manifest_check.py
index 8bed52a..c8d4f76 100755
--- a/scripts/manifest_check.py
+++ b/scripts/manifest_check.py
@@ -335,7 +335,7 @@
if is_apk:
aapt = args.aapt if args.aapt is not None else 'aapt'
manifest = subprocess.check_output(
- [aapt, 'dump', 'badging', args.input])
+ [aapt, 'dump', 'badging', args.input]).decode('utf-8')
else:
manifest = minidom.parse(args.input)
@@ -381,7 +381,7 @@
if is_apk:
raise RuntimeError('cannot save APK manifest as XML')
- with open(args.output, 'wb') as f:
+ with open(args.output, 'w') as f:
write_xml(f, manifest)
# pylint: disable=broad-except
diff --git a/scripts/manifest_fixer.py b/scripts/manifest_fixer.py
index 55d0fd1..d80a617 100755
--- a/scripts/manifest_fixer.py
+++ b/scripts/manifest_fixer.py
@@ -352,7 +352,7 @@
if args.extract_native_libs is not None:
add_extract_native_libs(doc, args.extract_native_libs)
- with open(args.output, 'wb') as f:
+ with open(args.output, 'w') as f:
write_xml(f, doc)
# pylint: disable=broad-except
diff --git a/scripts/manifest_fixer_test.py b/scripts/manifest_fixer_test.py
index 3a0a25d..f6fcaaf 100755
--- a/scripts/manifest_fixer_test.py
+++ b/scripts/manifest_fixer_test.py
@@ -16,16 +16,16 @@
#
"""Unit tests for manifest_fixer.py."""
-import StringIO
+import io
import sys
import unittest
from xml.dom import minidom
+import xml.etree.ElementTree as ET
import manifest_fixer
sys.dont_write_bytecode = True
-
class CompareVersionGtTest(unittest.TestCase):
"""Unit tests for compare_version_gt function."""
@@ -59,7 +59,7 @@
doc = minidom.parseString(input_manifest)
manifest_fixer.raise_min_sdk_version(doc, min_sdk_version,
target_sdk_version, library)
- output = StringIO.StringIO()
+ output = io.StringIO()
manifest_fixer.write_xml(output, doc)
return output.getvalue()
@@ -80,13 +80,16 @@
attrs += ' ' + extra
return ' <uses-sdk%s/>\n' % (attrs)
+ def assert_xml_equal(self, output, expected):
+ self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+
def test_no_uses_sdk(self):
"""Tests inserting a uses-sdk element into a manifest."""
manifest_input = self.manifest_tmpl % ''
expected = self.manifest_tmpl % self.uses_sdk(min='28', target='28')
output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_no_min(self):
"""Tests inserting a minSdkVersion attribute into a uses-sdk element."""
@@ -95,7 +98,7 @@
expected = self.manifest_tmpl % self.uses_sdk(min='28', target='28',
extra='extra="foo"')
output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_raise_min(self):
"""Tests inserting a minSdkVersion attribute into a uses-sdk element."""
@@ -103,7 +106,7 @@
manifest_input = self.manifest_tmpl % self.uses_sdk(min='27')
expected = self.manifest_tmpl % self.uses_sdk(min='28', target='28')
output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_raise(self):
"""Tests raising a minSdkVersion attribute."""
@@ -111,7 +114,7 @@
manifest_input = self.manifest_tmpl % self.uses_sdk(min='27')
expected = self.manifest_tmpl % self.uses_sdk(min='28', target='28')
output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_no_raise_min(self):
"""Tests a minSdkVersion that doesn't need raising."""
@@ -119,7 +122,7 @@
manifest_input = self.manifest_tmpl % self.uses_sdk(min='28')
expected = self.manifest_tmpl % self.uses_sdk(min='28', target='27')
output = self.raise_min_sdk_version_test(manifest_input, '27', '27', False)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_raise_codename(self):
"""Tests raising a minSdkVersion attribute to a codename."""
@@ -127,7 +130,7 @@
manifest_input = self.manifest_tmpl % self.uses_sdk(min='28')
expected = self.manifest_tmpl % self.uses_sdk(min='P', target='P')
output = self.raise_min_sdk_version_test(manifest_input, 'P', 'P', False)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_no_raise_codename(self):
"""Tests a minSdkVersion codename that doesn't need raising."""
@@ -135,7 +138,7 @@
manifest_input = self.manifest_tmpl % self.uses_sdk(min='P')
expected = self.manifest_tmpl % self.uses_sdk(min='P', target='28')
output = self.raise_min_sdk_version_test(manifest_input, '28', '28', False)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_target(self):
"""Tests an existing targetSdkVersion is preserved."""
@@ -143,7 +146,7 @@
manifest_input = self.manifest_tmpl % self.uses_sdk(min='26', target='27')
expected = self.manifest_tmpl % self.uses_sdk(min='28', target='27')
output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_no_target(self):
"""Tests inserting targetSdkVersion when minSdkVersion exists."""
@@ -151,7 +154,7 @@
manifest_input = self.manifest_tmpl % self.uses_sdk(min='27')
expected = self.manifest_tmpl % self.uses_sdk(min='28', target='29')
output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_target_no_min(self):
""""Tests inserting targetSdkVersion when minSdkVersion exists."""
@@ -159,7 +162,7 @@
manifest_input = self.manifest_tmpl % self.uses_sdk(target='27')
expected = self.manifest_tmpl % self.uses_sdk(min='28', target='27')
output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_no_target_no_min(self):
"""Tests inserting targetSdkVersion when minSdkVersion does not exist."""
@@ -167,7 +170,7 @@
manifest_input = self.manifest_tmpl % ''
expected = self.manifest_tmpl % self.uses_sdk(min='28', target='29')
output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_library_no_target(self):
"""Tests inserting targetSdkVersion when minSdkVersion exists."""
@@ -175,7 +178,7 @@
manifest_input = self.manifest_tmpl % self.uses_sdk(min='27')
expected = self.manifest_tmpl % self.uses_sdk(min='28', target='16')
output = self.raise_min_sdk_version_test(manifest_input, '28', '29', True)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_library_target_no_min(self):
"""Tests inserting targetSdkVersion when minSdkVersion exists."""
@@ -183,7 +186,7 @@
manifest_input = self.manifest_tmpl % self.uses_sdk(target='27')
expected = self.manifest_tmpl % self.uses_sdk(min='28', target='27')
output = self.raise_min_sdk_version_test(manifest_input, '28', '29', True)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_library_no_target_no_min(self):
"""Tests inserting targetSdkVersion when minSdkVersion does not exist."""
@@ -191,7 +194,7 @@
manifest_input = self.manifest_tmpl % ''
expected = self.manifest_tmpl % self.uses_sdk(min='28', target='16')
output = self.raise_min_sdk_version_test(manifest_input, '28', '29', True)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_extra(self):
"""Tests that extra attributes and elements are maintained."""
@@ -204,12 +207,12 @@
# pylint: disable=line-too-long
expected = self.manifest_tmpl % (
' <!-- comment -->\n'
- ' <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="29" extra="foo"/>\n'
+ ' <uses-sdk android:minSdkVersion="28" extra="foo" android:targetSdkVersion="29"/>\n'
' <application/>\n')
output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_indent(self):
"""Tests that an inserted element copies the existing indentation."""
@@ -223,17 +226,20 @@
output = self.raise_min_sdk_version_test(manifest_input, '28', '29', False)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
class AddLoggingParentTest(unittest.TestCase):
"""Unit tests for add_logging_parent function."""
+ def assert_xml_equal(self, output, expected):
+ self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+
def add_logging_parent_test(self, input_manifest, logging_parent=None):
doc = minidom.parseString(input_manifest)
if logging_parent:
manifest_fixer.add_logging_parent(doc, logging_parent)
- output = StringIO.StringIO()
+ output = io.StringIO()
manifest_fixer.write_xml(output, doc)
return output.getvalue()
@@ -257,23 +263,26 @@
manifest_input = self.manifest_tmpl % ''
expected = self.manifest_tmpl % self.uses_logging_parent()
output = self.add_logging_parent_test(manifest_input)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_logging_parent(self):
"""Tests manifest_fixer with no logging_parent."""
manifest_input = self.manifest_tmpl % ''
expected = self.manifest_tmpl % self.uses_logging_parent('FOO')
output = self.add_logging_parent_test(manifest_input, 'FOO')
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
class AddUsesLibrariesTest(unittest.TestCase):
"""Unit tests for add_uses_libraries function."""
+ def assert_xml_equal(self, output, expected):
+ self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+
def run_test(self, input_manifest, new_uses_libraries):
doc = minidom.parseString(input_manifest)
manifest_fixer.add_uses_libraries(doc, new_uses_libraries, True)
- output = StringIO.StringIO()
+ output = io.StringIO()
manifest_fixer.write_xml(output, doc)
return output.getvalue()
@@ -301,7 +310,7 @@
('bar', 'false')])
expected = manifest_input
output = self.run_test(manifest_input, [])
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_not_overwrite(self):
"""new_uses_libraries must not overwrite existing tags."""
@@ -310,7 +319,7 @@
('bar', 'false')])
expected = manifest_input
output = self.run_test(manifest_input, ['foo', 'bar'])
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_add(self):
"""New names are added with 'required:true'."""
@@ -323,7 +332,7 @@
('baz', 'true'),
('qux', 'true')])
output = self.run_test(manifest_input, ['bar', 'baz', 'qux'])
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_no_application(self):
"""When there is no <application> tag, the tag is added."""
@@ -336,7 +345,7 @@
('foo', 'true'),
('bar', 'true')])
output = self.run_test(manifest_input, ['foo', 'bar'])
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_empty_application(self):
"""Even when here is an empty <application/> tag, the libs are added."""
@@ -350,16 +359,19 @@
('foo', 'true'),
('bar', 'true')])
output = self.run_test(manifest_input, ['foo', 'bar'])
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
class AddUsesNonSdkApiTest(unittest.TestCase):
"""Unit tests for add_uses_libraries function."""
+ def assert_xml_equal(self, output, expected):
+ self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+
def run_test(self, input_manifest):
doc = minidom.parseString(input_manifest)
manifest_fixer.add_uses_non_sdk_api(doc)
- output = StringIO.StringIO()
+ output = io.StringIO()
manifest_fixer.write_xml(output, doc)
return output.getvalue()
@@ -377,23 +389,26 @@
manifest_input = self.manifest_tmpl % self.uses_non_sdk_api(False)
expected = self.manifest_tmpl % self.uses_non_sdk_api(True)
output = self.run_test(manifest_input)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_already_set(self):
"""new_uses_libraries must not overwrite existing tags."""
manifest_input = self.manifest_tmpl % self.uses_non_sdk_api(True)
expected = manifest_input
output = self.run_test(manifest_input)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
class UseEmbeddedDexTest(unittest.TestCase):
"""Unit tests for add_use_embedded_dex function."""
+ def assert_xml_equal(self, output, expected):
+ self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+
def run_test(self, input_manifest):
doc = minidom.parseString(input_manifest)
manifest_fixer.add_use_embedded_dex(doc)
- output = StringIO.StringIO()
+ output = io.StringIO()
manifest_fixer.write_xml(output, doc)
return output.getvalue()
@@ -410,13 +425,13 @@
manifest_input = self.manifest_tmpl % ''
expected = self.manifest_tmpl % self.use_embedded_dex('true')
output = self.run_test(manifest_input)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_manifest_with_use_embedded_dex(self):
manifest_input = self.manifest_tmpl % self.use_embedded_dex('true')
expected = manifest_input
output = self.run_test(manifest_input)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_manifest_with_not_use_embedded_dex(self):
manifest_input = self.manifest_tmpl % self.use_embedded_dex('false')
@@ -426,10 +441,13 @@
class AddExtractNativeLibsTest(unittest.TestCase):
"""Unit tests for add_extract_native_libs function."""
+ def assert_xml_equal(self, output, expected):
+ self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+
def run_test(self, input_manifest, value):
doc = minidom.parseString(input_manifest)
manifest_fixer.add_extract_native_libs(doc, value)
- output = StringIO.StringIO()
+ output = io.StringIO()
manifest_fixer.write_xml(output, doc)
return output.getvalue()
@@ -446,19 +464,19 @@
manifest_input = self.manifest_tmpl % ''
expected = self.manifest_tmpl % self.extract_native_libs('true')
output = self.run_test(manifest_input, True)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_set_false(self):
manifest_input = self.manifest_tmpl % ''
expected = self.manifest_tmpl % self.extract_native_libs('false')
output = self.run_test(manifest_input, False)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_match(self):
manifest_input = self.manifest_tmpl % self.extract_native_libs('true')
expected = manifest_input
output = self.run_test(manifest_input, True)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_conflict(self):
manifest_input = self.manifest_tmpl % self.extract_native_libs('true')
@@ -468,10 +486,13 @@
class AddNoCodeApplicationTest(unittest.TestCase):
"""Unit tests for set_has_code_to_false function."""
+ def assert_xml_equal(self, output, expected):
+ self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+
def run_test(self, input_manifest):
doc = minidom.parseString(input_manifest)
manifest_fixer.set_has_code_to_false(doc)
- output = StringIO.StringIO()
+ output = io.StringIO()
manifest_fixer.write_xml(output, doc)
return output.getvalue()
@@ -485,26 +506,26 @@
manifest_input = self.manifest_tmpl % ''
expected = self.manifest_tmpl % ' <application android:hasCode="false"/>\n'
output = self.run_test(manifest_input)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_has_application_no_has_code(self):
manifest_input = self.manifest_tmpl % ' <application/>\n'
expected = self.manifest_tmpl % ' <application android:hasCode="false"/>\n'
output = self.run_test(manifest_input)
- self.assertEqual(output, expected)
+ self.assert_xml_equal(output, expected)
def test_has_application_has_code_false(self):
""" Do nothing if there's already an application elemeent. """
manifest_input = self.manifest_tmpl % ' <application android:hasCode="false"/>\n'
output = self.run_test(manifest_input)
- self.assertEqual(output, manifest_input)
+ self.assert_xml_equal(output, manifest_input)
def test_has_application_has_code_true(self):
""" Do nothing if there's already an application elemeent even if its
hasCode attribute is true. """
manifest_input = self.manifest_tmpl % ' <application android:hasCode="true"/>\n'
output = self.run_test(manifest_input)
- self.assertEqual(output, manifest_input)
+ self.assert_xml_equal(output, manifest_input)
if __name__ == '__main__':
diff --git a/scripts/rbc-run b/scripts/rbc-run
index a0907cf..7243421 100755
--- a/scripts/rbc-run
+++ b/scripts/rbc-run
@@ -2,14 +2,16 @@
# Convert and run one configuration
# Args: a product/board makefile optionally followed by additional arguments
# that will be passed to rbcrun.
-[[ $# -gt 0 && -f "$1" ]] || { echo "Usage: ${0##*/} product.mk [Additional rbcrun arguments]" >&2; exit 1; }
+[[ $# -gt 1 && -f "$1" && -f "$2" ]] || { echo "Usage: ${0##*/} product.mk input_variables.mk [Additional rbcrun arguments]" >&2; exit 1; }
set -eu
-declare -r output_root=${OUT_DIR:-out}
-declare -r runner="$output_root/soong/.bootstrap/bin/rbcrun"
-declare -r converter="$output_root/soong/.bootstrap/bin/mk2rbc"
-declare -r launcher=$output_root/launchers/run.rbc
-declare -r makefile=$1
-shift
-$converter -mode=write -r --outdir $output_root --launcher=$launcher $makefile
-$runner RBC_OUT="make,global" RBC_DEBUG="${RBC_DEBUG:-}" $@ $launcher
+
+declare -r output_root="${OUT_DIR:-out}"
+declare -r runner="${output_root}/soong/rbcrun"
+declare -r converter="${output_root}/soong/mk2rbc"
+declare -r launcher="${output_root}/rbc/launcher.rbc"
+declare -r makefile="$1"
+declare -r input_variables="$2"
+shift 2
+"${converter}" -mode=write -r --outdir "${output_root}/rbc" --input_variables "${input_variables}" --launcher="${launcher}" "${makefile}"
+"${runner}" RBC_OUT="make,global" RBC_DEBUG="${RBC_DEBUG:-}" $@ "${launcher}"
diff --git a/scripts/reverse-deps.sh b/scripts/reverse-deps.sh
index 02b7dcb..410f5c0 100755
--- a/scripts/reverse-deps.sh
+++ b/scripts/reverse-deps.sh
@@ -67,6 +67,9 @@
$0 ~ /^\S\S*:$/ {
inoutput = 0
}
+ $1 == "validations:" {
+ inoutput = 0
+ }
inoutput != 0 {
print gensub(/^\s*/, "", "g")" "depth
}
diff --git a/scripts/test_config_fixer.py b/scripts/test_config_fixer.py
index 32d5b17..c150e8c 100644
--- a/scripts/test_config_fixer.py
+++ b/scripts/test_config_fixer.py
@@ -86,7 +86,7 @@
if args.test_file_name:
overwrite_test_file_name(doc, args.test_file_name)
- with open(args.output, 'wb') as f:
+ with open(args.output, 'w') as f:
write_xml(f, doc)
# pylint: disable=broad-except
diff --git a/scripts/test_config_fixer_test.py b/scripts/test_config_fixer_test.py
index 1272c6b..d00a593 100644
--- a/scripts/test_config_fixer_test.py
+++ b/scripts/test_config_fixer_test.py
@@ -16,7 +16,7 @@
#
"""Unit tests for test_config_fixer.py."""
-import StringIO
+import io
import sys
import unittest
from xml.dom import minidom
@@ -59,7 +59,7 @@
manifest = minidom.parseString(self.manifest)
test_config_fixer.overwrite_package_name(doc, manifest, "com.soong.foo")
- output = StringIO.StringIO()
+ output = io.StringIO()
test_config_fixer.write_xml(output, doc)
# Only the matching package name in a test node should be updated.
@@ -86,7 +86,7 @@
doc = minidom.parseString(self.test_config % ("foo.apk"))
test_config_fixer.overwrite_test_file_name(doc, "bar.apk")
- output = StringIO.StringIO()
+ output = io.StringIO()
test_config_fixer.write_xml(output, doc)
# Only the matching package name in a test node should be updated.
diff --git a/scripts/transitive-deps.sh b/scripts/transitive-deps.sh
index ba36ba4..cf9fb94 100755
--- a/scripts/transitive-deps.sh
+++ b/scripts/transitive-deps.sh
@@ -100,7 +100,7 @@
currFileName = ""
currExt = ""
}
- $1 == "outputs:" {
+ $1 == "outputs:" || $1 == "validations:" {
ininput = 0
}
ininput == 0 && $0 ~ /^\S\S*:$/ {
diff --git a/scripts/unpack-prebuilt-apex.sh b/scripts/unpack-prebuilt-apex.sh
index 1acdeb5..f34a480 100755
--- a/scripts/unpack-prebuilt-apex.sh
+++ b/scripts/unpack-prebuilt-apex.sh
@@ -29,8 +29,6 @@
shift 4
REQUIRED_PATHS=$@
-set -x 1
-
rm -fr $OUTPUT_DIR
mkdir -p $OUTPUT_DIR
diff --git a/scripts/update_out b/scripts/update_out
new file mode 100755
index 0000000..d3950cf
--- /dev/null
+++ b/scripts/update_out
@@ -0,0 +1,21 @@
+#! /bin/bash
+# Run given command application and update the contents of a given file.
+# Will not change the file if its contents has not changed.
+[[ $# -gt 1 ]] || { echo "Usage: ${0##*/} FILE COMMAND" >&2; exit 1; }
+set -u
+declare -r outfile="$1"
+shift
+if [[ ! -f $outfile ]]; then
+ $@ >$outfile
+ exit
+fi
+
+declare -r newout=${outfile}.new
+$@ >$newout
+rc=$?
+if cmp -s $newout $outfile; then
+ rm $newout
+else
+ mv -f $newout $outfile
+fi
+exit $rc
diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go
index ff2af43..2dacdb5 100644
--- a/sdk/bootclasspath_fragment_sdk_test.go
+++ b/sdk/bootclasspath_fragment_sdk_test.go
@@ -40,6 +40,7 @@
}
`, apex, fragment)),
android.FixtureAddFile("frameworks/base/config/boot-profile.txt", nil),
+ android.FixtureAddFile("frameworks/base/config/boot-image-profile.txt", nil),
android.FixtureAddFile("build/soong/scripts/check_boot_jars/package_allowed_list.txt", nil),
)
}
diff --git a/sh/sh_binary.go b/sh/sh_binary.go
index b22a5b7..b1d1bb2 100644
--- a/sh/sh_binary.go
+++ b/sh/sh_binary.go
@@ -42,8 +42,6 @@
pctx.Import("android/soong/android")
registerShBuildComponents(android.InitRegistrationContext)
-
- android.RegisterBp2BuildMutator("sh_binary", ShBinaryBp2Build)
}
func registerShBuildComponents(ctx android.RegistrationContext) {
@@ -271,13 +269,16 @@
s.generateAndroidBuildActions(ctx)
installDir := android.PathForModuleInstall(ctx, "bin", proptools.String(s.properties.Sub_dir))
s.installedFile = ctx.InstallExecutable(installDir, s.outputFilePath.Base(), s.outputFilePath)
+ for _, symlink := range s.Symlinks() {
+ ctx.InstallSymlink(installDir, symlink, s.installedFile)
+ }
}
func (s *ShBinary) AndroidMkEntries() []android.AndroidMkEntries {
return []android.AndroidMkEntries{android.AndroidMkEntries{
Class: "EXECUTABLES",
OutputFile: android.OptionalPathForPath(s.outputFilePath),
- Include: "$(BUILD_SYSTEM)/soong_cc_prebuilt.mk",
+ Include: "$(BUILD_SYSTEM)/soong_cc_rust_prebuilt.mk",
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
s.customAndroidMkEntries(entries)
@@ -426,11 +427,11 @@
return []android.AndroidMkEntries{android.AndroidMkEntries{
Class: "NATIVE_TESTS",
OutputFile: android.OptionalPathForPath(s.outputFilePath),
- Include: "$(BUILD_SYSTEM)/soong_cc_prebuilt.mk",
+ Include: "$(BUILD_SYSTEM)/soong_cc_rust_prebuilt.mk",
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
s.customAndroidMkEntries(entries)
- entries.SetPath("LOCAL_MODULE_PATH", s.installDir.ToMakePath())
+ entries.SetPath("LOCAL_MODULE_PATH", s.installDir)
entries.AddCompatibilityTestSuites(s.testProperties.Test_suites...)
if s.testConfig != nil {
entries.SetPath("LOCAL_FULL_TEST_CONFIG", s.testConfig)
@@ -509,7 +510,9 @@
}
type bazelShBinaryAttributes struct {
- Srcs bazel.LabelListAttribute
+ Srcs bazel.LabelListAttribute
+ Filename *string
+ Sub_dir *string
// Bazel also supports the attributes below, but (so far) these are not required for Bionic
// deps
// data
@@ -531,21 +534,29 @@
// visibility
}
-func ShBinaryBp2Build(ctx android.TopDownMutatorContext) {
- m, ok := ctx.Module().(*ShBinary)
- if !ok || !m.ConvertWithBp2build(ctx) {
- return
- }
-
+func (m *ShBinary) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
srcs := bazel.MakeLabelListAttribute(
android.BazelLabelForModuleSrc(ctx, []string{*m.properties.Src}))
+ var filename *string
+ if m.properties.Filename != nil {
+ filename = m.properties.Filename
+ }
+
+ var subDir *string
+ if m.properties.Sub_dir != nil {
+ subDir = m.properties.Sub_dir
+ }
+
attrs := &bazelShBinaryAttributes{
- Srcs: srcs,
+ Srcs: srcs,
+ Filename: filename,
+ Sub_dir: subDir,
}
props := bazel.BazelTargetModuleProperties{
- Rule_class: "sh_binary",
+ Rule_class: "sh_binary",
+ Bzl_load_location: "//build/bazel/rules:sh_binary.bzl",
}
ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
diff --git a/sh/sh_binary_test.go b/sh/sh_binary_test.go
index 865d5f3..28b6fb9 100644
--- a/sh/sh_binary_test.go
+++ b/sh/sh_binary_test.go
@@ -42,7 +42,10 @@
}
func TestShTestSubDir(t *testing.T) {
- ctx, config := testShBinary(t, `
+ result := android.GroupFixturePreparers(
+ prepareForShTest,
+ android.FixtureModifyConfig(android.SetKatiEnabledForTests),
+ ).RunTestWithBp(t, `
sh_test {
name: "foo",
src: "test.sh",
@@ -50,17 +53,20 @@
}
`)
- mod := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Module().(*ShTest)
+ mod := result.ModuleForTests("foo", "android_arm64_armv8-a").Module().(*ShTest)
- entries := android.AndroidMkEntriesForTest(t, ctx, mod)[0]
+ entries := android.AndroidMkEntriesForTest(t, result.TestContext, mod)[0]
expectedPath := "out/target/product/test_device/data/nativetest64/foo_test"
actualPath := entries.EntryMap["LOCAL_MODULE_PATH"][0]
- android.AssertStringPathRelativeToTopEquals(t, "LOCAL_MODULE_PATH[0]", config, expectedPath, actualPath)
+ android.AssertStringPathRelativeToTopEquals(t, "LOCAL_MODULE_PATH[0]", result.Config, expectedPath, actualPath)
}
func TestShTest(t *testing.T) {
- ctx, config := testShBinary(t, `
+ result := android.GroupFixturePreparers(
+ prepareForShTest,
+ android.FixtureModifyConfig(android.SetKatiEnabledForTests),
+ ).RunTestWithBp(t, `
sh_test {
name: "foo",
src: "test.sh",
@@ -72,13 +78,13 @@
}
`)
- mod := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Module().(*ShTest)
+ mod := result.ModuleForTests("foo", "android_arm64_armv8-a").Module().(*ShTest)
- entries := android.AndroidMkEntriesForTest(t, ctx, mod)[0]
+ entries := android.AndroidMkEntriesForTest(t, result.TestContext, mod)[0]
expectedPath := "out/target/product/test_device/data/nativetest64/foo"
actualPath := entries.EntryMap["LOCAL_MODULE_PATH"][0]
- android.AssertStringPathRelativeToTopEquals(t, "LOCAL_MODULE_PATH[0]", config, expectedPath, actualPath)
+ android.AssertStringPathRelativeToTopEquals(t, "LOCAL_MODULE_PATH[0]", result.Config, expectedPath, actualPath)
expectedData := []string{":testdata/data1", ":testdata/sub/data2"}
actualData := entries.EntryMap["LOCAL_TEST_DATA"]
diff --git a/shared/Android.bp b/shared/Android.bp
index deb17f8..3c84f55 100644
--- a/shared/Android.bp
+++ b/shared/Android.bp
@@ -9,11 +9,13 @@
"env.go",
"paths.go",
"debug.go",
+ "proto.go",
],
testSrcs: [
"paths_test.go",
],
deps: [
"soong-bazel",
+ "golang-protobuf-proto",
],
}
diff --git a/shared/proto.go b/shared/proto.go
new file mode 100644
index 0000000..232656b
--- /dev/null
+++ b/shared/proto.go
@@ -0,0 +1,41 @@
+// 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 shared
+
+import (
+ "io/ioutil"
+ "os"
+
+ "google.golang.org/protobuf/proto"
+)
+
+// Save takes a protobuf message, marshals to an array of bytes
+// and is then saved to a file.
+func Save(pb proto.Message, filepath string) (err error) {
+ data, err := proto.Marshal(pb)
+ if err != nil {
+ return err
+ }
+ tempFilepath := filepath + ".tmp"
+ if err := ioutil.WriteFile(tempFilepath, []byte(data), 0644 /* rw-r--r-- */); err != nil {
+ return err
+ }
+
+ if err := os.Rename(tempFilepath, filepath); err != nil {
+ return err
+ }
+
+ return nil
+}
diff --git a/snapshot/host_snapshot.go b/snapshot/host_snapshot.go
index 2a25a00..252cef8 100644
--- a/snapshot/host_snapshot.go
+++ b/snapshot/host_snapshot.go
@@ -180,7 +180,7 @@
DistFiles: android.MakeDefaultDistFiles(f.zipFile.Path()),
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
- entries.SetString("LOCAL_MODULE_PATH", f.installDir.ToMakePath().String())
+ entries.SetString("LOCAL_MODULE_PATH", f.installDir.String())
entries.SetString("LOCAL_INSTALLED_MODULE_STEM", f.installFileName())
},
},
diff --git a/snapshot/recovery_snapshot.go b/snapshot/recovery_snapshot.go
index 9b3919c..f1e31ca 100644
--- a/snapshot/recovery_snapshot.go
+++ b/snapshot/recovery_snapshot.go
@@ -71,6 +71,10 @@
ctx.RegisterSingletonType("recovery-snapshot", RecoverySnapshotSingleton)
}
+func (RecoverySnapshotImage) RegisterAdditionalModule(ctx android.RegistrationContext, name string, factory android.ModuleFactory) {
+ ctx.RegisterModuleType(name, factory)
+}
+
func (RecoverySnapshotImage) shouldGenerateSnapshot(ctx android.SingletonContext) bool {
// RECOVERY_SNAPSHOT_VERSION must be set to 'current' in order to generate a
// snapshot.
diff --git a/tests/androidmk_test.sh b/tests/androidmk_test.sh
new file mode 100755
index 0000000..331dc77
--- /dev/null
+++ b/tests/androidmk_test.sh
@@ -0,0 +1,135 @@
+#!/bin/bash -eu
+
+set -o pipefail
+
+# How to run: bash path-to-script/androidmk_test.sh
+# Tests of converting license functionality of the androidmk tool
+REAL_TOP="$(readlink -f "$(dirname "$0")"/../../..)"
+$REAL_TOP/build/soong/soong_ui.bash --make-mode androidmk
+
+source "$(dirname "$0")/lib.sh"
+
+# Expect to create a new license module
+function test_rewrite_license_property_inside_current_directory {
+ setup
+
+ # Create an Android.mk file
+ mkdir -p a/b
+ cat > a/b/Android.mk <<'EOF'
+include $(CLEAR_VARS)
+LOCAL_MODULE := foo
+LOCAL_LICENSE_KINDS := license_kind1 license_kind2
+LOCAL_LICENSE_CONDITIONS := license_condition
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/license_notice1 $(LOCAL_PATH)/license_notice2
+include $(BUILD_PACKAGE)
+EOF
+
+ # Create an expected Android.bp file for the module "foo"
+ cat > a/b/Android.bp <<'EOF'
+package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: [
+ "a_b_license",
+ ],
+}
+
+license {
+ name: "a_b_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "license_kind1",
+ "license_kind2",
+ ],
+ license_text: [
+ "license_notice1",
+ "license_notice2",
+ ],
+}
+
+android_app {
+ name: "foo",
+}
+EOF
+
+ run_androidmk_test "a/b/Android.mk" "a/b/Android.bp"
+}
+
+# Expect to reference to an existing license module
+function test_rewrite_license_property_outside_current_directory {
+ setup
+
+ # Create an Android.mk file
+ mkdir -p a/b/c/d
+ cat > a/b/c/d/Android.mk <<'EOF'
+include $(CLEAR_VARS)
+LOCAL_MODULE := foo
+LOCAL_LICENSE_KINDS := license_kind1 license_kind2
+LOCAL_LICENSE_CONDITIONS := license_condition
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../license_notice1 $(LOCAL_PATH)/../../license_notice2
+include $(BUILD_PACKAGE)
+EOF
+
+ # Create an expected (input) Android.bp file at a/b/
+ cat > a/b/Android.bp <<'EOF'
+package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: [
+ "a_b_license",
+ ],
+}
+
+license {
+ name: "a_b_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "license_kind1",
+ "license_kind2",
+ ],
+ license_text: [
+ "license_notice1",
+ "license_notice2",
+ ],
+}
+
+android_app {
+ name: "bar",
+}
+EOF
+
+ # Create an expected (output) Android.bp file for the module "foo"
+ cat > a/b/c/d/Android.bp <<'EOF'
+package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: [
+ "a_b_license",
+ ],
+}
+
+android_app {
+ name: "foo",
+}
+EOF
+
+ run_androidmk_test "a/b/c/d/Android.mk" "a/b/c/d/Android.bp"
+}
+
+run_androidmk_test () {
+ export ANDROID_BUILD_TOP="$MOCK_TOP"
+
+ local out=$($REAL_TOP/*/host/*/bin/androidmk "$1")
+ local expected=$(<"$2")
+
+ if [[ "$out" != "$expected" ]]; then
+ ANDROID_BUILD_TOP="$REAL_TOP"
+ cleanup_mock_top
+ fail "The output is not the same as the expected"
+ fi
+
+ ANDROID_BUILD_TOP="$REAL_TOP"
+ cleanup_mock_top
+ echo "Succeeded"
+}
+
+test_rewrite_license_property_inside_current_directory
+
+test_rewrite_license_property_outside_current_directory
diff --git a/tests/bootstrap_test.sh b/tests/bootstrap_test.sh
index a22adc5..e92a561 100755
--- a/tests/bootstrap_test.sh
+++ b/tests/bootstrap_test.sh
@@ -17,10 +17,10 @@
function test_null_build() {
setup
run_soong
- local bootstrap_mtime1=$(stat -c "%y" out/soong/.bootstrap/build.ninja)
+ local bootstrap_mtime1=$(stat -c "%y" out/soong/bootstrap.ninja)
local output_mtime1=$(stat -c "%y" out/soong/build.ninja)
run_soong
- local bootstrap_mtime2=$(stat -c "%y" out/soong/.bootstrap/build.ninja)
+ local bootstrap_mtime2=$(stat -c "%y" out/soong/bootstrap.ninja)
local output_mtime2=$(stat -c "%y" out/soong/build.ninja)
if [[ "$bootstrap_mtime1" == "$bootstrap_mtime2" ]]; then
@@ -36,12 +36,12 @@
function test_soong_build_rebuilt_if_blueprint_changes() {
setup
run_soong
- local mtime1=$(stat -c "%y" out/soong/.bootstrap/build.ninja)
+ local mtime1=$(stat -c "%y" out/soong/bootstrap.ninja)
sed -i 's/pluginGenSrcCmd/pluginGenSrcCmd2/g' build/blueprint/bootstrap/bootstrap.go
run_soong
- local mtime2=$(stat -c "%y" out/soong/.bootstrap/build.ninja)
+ local mtime2=$(stat -c "%y" out/soong/bootstrap.ninja)
if [[ "$mtime1" == "$mtime2" ]]; then
fail "Bootstrap Ninja file did not change"
@@ -541,7 +541,7 @@
function test_bp2build_smoke {
setup
run_soong bp2build
- [[ -e out/soong/.bootstrap/bp2build_workspace_marker ]] || fail "bp2build marker file not created"
+ [[ -e out/soong/bp2build_workspace_marker ]] || fail "bp2build marker file not created"
[[ -e out/soong/workspace ]] || fail "Bazel workspace not created"
}
@@ -551,7 +551,7 @@
run_soong bp2build
- if [[ ! -f "./out/soong/.bootstrap/bp2build_workspace_marker" ]]; then
+ if [[ ! -f "./out/soong/bp2build_workspace_marker" ]]; then
fail "Marker file was not generated"
fi
}
@@ -592,10 +592,10 @@
setup
run_soong bp2build
- local mtime1=$(stat -c "%y" out/soong/.bootstrap/bp2build_workspace_marker)
+ local mtime1=$(stat -c "%y" out/soong/bp2build_workspace_marker)
run_soong bp2build
- local mtime2=$(stat -c "%y" out/soong/.bootstrap/bp2build_workspace_marker)
+ local mtime2=$(stat -c "%y" out/soong/bp2build_workspace_marker)
if [[ "$mtime1" != "$mtime2" ]]; then
fail "Output Ninja file changed on null build"
@@ -626,7 +626,7 @@
function test_multiple_soong_build_modes() {
setup
run_soong json-module-graph bp2build nothing
- if [[ ! -f "out/soong/.bootstrap/bp2build_workspace_marker" ]]; then
+ if [[ ! -f "out/soong/bp2build_workspace_marker" ]]; then
fail "bp2build marker file was not generated"
fi
@@ -780,11 +780,11 @@
fail "Output Ninja file changed when switching to bp2build"
fi
- local marker_mtime1=$(stat -c "%y" out/soong/.bootstrap/bp2build_workspace_marker)
+ local marker_mtime1=$(stat -c "%y" out/soong/bp2build_workspace_marker)
run_soong
local output_mtime3=$(stat -c "%y" out/soong/build.ninja)
- local marker_mtime2=$(stat -c "%y" out/soong/.bootstrap/bp2build_workspace_marker)
+ local marker_mtime2=$(stat -c "%y" out/soong/bp2build_workspace_marker)
if [[ "$output_mtime1" != "$output_mtime3" ]]; then
fail "Output Ninja file changed when switching to regular build from bp2build"
fi
@@ -794,7 +794,7 @@
run_soong bp2build
local output_mtime4=$(stat -c "%y" out/soong/build.ninja)
- local marker_mtime3=$(stat -c "%y" out/soong/.bootstrap/bp2build_workspace_marker)
+ local marker_mtime3=$(stat -c "%y" out/soong/bp2build_workspace_marker)
if [[ "$output_mtime1" != "$output_mtime4" ]]; then
fail "Output Ninja file changed when switching back to bp2build"
fi
diff --git a/tests/bp2build_bazel_test.sh b/tests/bp2build_bazel_test.sh
index 379eb65..4f37c2b 100755
--- a/tests/bp2build_bazel_test.sh
+++ b/tests/bp2build_bazel_test.sh
@@ -11,10 +11,10 @@
function test_bp2build_null_build() {
setup
run_soong bp2build
- local output_mtime1=$(stat -c "%y" out/soong/.bootstrap/bp2build_workspace_marker)
+ local output_mtime1=$(stat -c "%y" out/soong/bp2build_workspace_marker)
run_soong bp2build
- local output_mtime2=$(stat -c "%y" out/soong/.bootstrap/bp2build_workspace_marker)
+ local output_mtime2=$(stat -c "%y" out/soong/bp2build_workspace_marker)
if [[ "$output_mtime1" != "$output_mtime2" ]]; then
fail "Output bp2build marker file changed on null build"
@@ -36,10 +36,10 @@
touch foo/bar/a.txt foo/bar/b.txt
run_soong bp2build
- local output_mtime1=$(stat -c "%y" out/soong/.bootstrap/bp2build_workspace_marker)
+ local output_mtime1=$(stat -c "%y" out/soong/bp2build_workspace_marker)
run_soong bp2build
- local output_mtime2=$(stat -c "%y" out/soong/.bootstrap/bp2build_workspace_marker)
+ local output_mtime2=$(stat -c "%y" out/soong/bp2build_workspace_marker)
if [[ "$output_mtime1" != "$output_mtime2" ]]; then
fail "Output bp2build marker file changed on null build"
@@ -105,7 +105,7 @@
# NOTE: We don't actually use the extra BUILD file for anything here
run_bazel build --package_path=out/soong/workspace //foo/...
- local the_answer_file="bazel-out/k8-fastbuild/bin/foo/convertible_soong_module/the_answer.txt"
+ local the_answer_file="bazel-out/android_target-fastbuild/bin/foo/convertible_soong_module/the_answer.txt"
if [[ ! -f "${the_answer_file}" ]]; then
fail "Expected '${the_answer_file}' to be generated, but was missing"
fi
diff --git a/tests/run_integration_tests.sh b/tests/run_integration_tests.sh
index 6304a11..76a918b 100755
--- a/tests/run_integration_tests.sh
+++ b/tests/run_integration_tests.sh
@@ -3,7 +3,9 @@
set -o pipefail
TOP="$(readlink -f "$(dirname "$0")"/../../..)"
+"$TOP/build/soong/tests/androidmk_test.sh"
"$TOP/build/soong/tests/bootstrap_test.sh"
"$TOP/build/soong/tests/mixed_mode_test.sh"
"$TOP/build/soong/tests/bp2build_bazel_test.sh"
"$TOP/build/soong/tests/soong_test.sh"
+"$TOP/build/bazel/ci/rbc_regression_test.sh" aosp_arm64-userdebug
diff --git a/ui/build/config.go b/ui/build/config.go
index 07ffb44..b6d0d27 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -721,10 +721,6 @@
}
func (c *configImpl) SoongBuildInvocationNeeded() bool {
- if c.Dist() {
- return true
- }
-
if len(c.Arguments()) > 0 {
// Explicit targets requested that are not special targets like b2pbuild
// or the JSON module graph
@@ -736,6 +732,11 @@
return true
}
+ // bp2build + dist may be used to dist bp2build logs but does not require SoongBuildInvocation
+ if c.Dist() && !c.Bp2Build() {
+ return true
+ }
+
// build.ninja doesn't need to be generated
return false
}
@@ -784,12 +785,17 @@
panic("Unknown GOOS")
}
}
+
func (c *configImpl) HostToolDir() string {
- return filepath.Join(c.SoongOutDir(), "host", c.PrebuiltOS(), "bin")
+ if c.SkipKatiNinja() {
+ return filepath.Join(c.SoongOutDir(), "host", c.PrebuiltOS(), "bin")
+ } else {
+ return filepath.Join(c.OutDir(), "host", c.PrebuiltOS(), "bin")
+ }
}
func (c *configImpl) NamedGlobFile(name string) string {
- return shared.JoinPath(c.SoongOutDir(), ".bootstrap/build-globs."+name+".ninja")
+ return shared.JoinPath(c.SoongOutDir(), "globs-"+name+".ninja")
}
func (c *configImpl) UsedEnvFile(tag string) string {
@@ -797,7 +803,7 @@
}
func (c *configImpl) Bp2BuildMarkerFile() string {
- return shared.JoinPath(c.SoongOutDir(), ".bootstrap/bp2build_workspace_marker")
+ return shared.JoinPath(c.SoongOutDir(), "bp2build_workspace_marker")
}
func (c *configImpl) SoongDocsHtml() string {
@@ -1250,16 +1256,22 @@
return c.metricsUploader
}
-// LogsDir returns the logs directory where build log and metrics
-// files are located. By default, the logs directory is the out
+// LogsDir returns the absolute path to the logs directory where build log and
+// metrics files are located. By default, the logs directory is the out
// directory. If the argument dist is specified, the logs directory
// is <dist_dir>/logs.
func (c *configImpl) LogsDir() string {
+ dir := c.OutDir()
if c.Dist() {
// Always write logs to the real dist dir, even if Bazel is using a rigged dist dir for other files
- return filepath.Join(c.RealDistDir(), "logs")
+ dir = filepath.Join(c.RealDistDir(), "logs")
}
- return c.OutDir()
+ absDir, err := filepath.Abs(dir)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "\nError making log dir '%s' absolute: %s\n", dir, err.Error())
+ os.Exit(1)
+ }
+ return absDir
}
// BazelMetricsDir returns the <logs dir>/bazel_metrics directory
diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go
index afec829..3f10f75 100644
--- a/ui/build/dumpvars.go
+++ b/ui/build/dumpvars.go
@@ -263,9 +263,9 @@
}, exportEnvVars...), BannerVars...)
// We need Roboleaf converter and runner in the mixed mode
- runMicrofactory(ctx, config, ".bootstrap/bin/mk2rbc", "android/soong/mk2rbc/cmd",
+ runMicrofactory(ctx, config, "mk2rbc", "android/soong/mk2rbc/cmd",
map[string]string{"android/soong": "build/soong"})
- runMicrofactory(ctx, config, ".bootstrap/bin/rbcrun", "rbcrun/cmd",
+ runMicrofactory(ctx, config, "rbcrun", "rbcrun/cmd",
map[string]string{"go.starlark.net": "external/starlark-go", "rbcrun": "build/make/tools/rbcrun"})
makeVars, err := dumpMakeVars(ctx, config, config.Arguments(), allVars, true, "")
diff --git a/ui/build/soong.go b/ui/build/soong.go
index 1c7fbac..8133762 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -49,7 +49,7 @@
// version of bootstrap and needs cleaning before continuing the build. Increment this for
// incompatible changes, for example when moving the location of the bpglob binary that is
// executed during bootstrap before the primary builder has had a chance to update the path.
- bootstrapEpoch = 0
+ bootstrapEpoch = 1
)
func writeEnvironmentFile(ctx Context, envFile string, envDeps map[string]string) error {
@@ -153,7 +153,12 @@
return true, nil
}
-func primaryBuilderInvocation(config Config, name string, output string, specificArgs []string) bootstrap.PrimaryBuilderInvocation {
+func primaryBuilderInvocation(
+ config Config,
+ name string,
+ output string,
+ specificArgs []string,
+ description string) bootstrap.PrimaryBuilderInvocation {
commonArgs := make([]string, 0, 0)
if !config.skipSoongTests {
@@ -161,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)
@@ -178,9 +195,16 @@
allArgs = append(allArgs, "Android.bp")
return bootstrap.PrimaryBuilderInvocation{
- Inputs: []string{"Android.bp"},
- Outputs: []string{output},
- Args: allArgs,
+ Inputs: []string{"Android.bp"},
+ 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,
}
}
@@ -232,7 +256,9 @@
config,
soongBuildTag,
config.SoongNinjaFile(),
- mainSoongBuildExtraArgs)
+ mainSoongBuildExtraArgs,
+ fmt.Sprintf("analyzing Android.bp files and generating ninja file at %s", config.SoongNinjaFile()),
+ )
if config.bazelBuildMode() == mixedBuild {
// Mixed builds call Bazel from soong_build and they therefore need the
@@ -248,7 +274,9 @@
config.Bp2BuildMarkerFile(),
[]string{
"--bp2build_marker", config.Bp2BuildMarkerFile(),
- })
+ },
+ fmt.Sprintf("converting Android.bp files to BUILD files at %s/bp2build", config.SoongOutDir()),
+ )
jsonModuleGraphInvocation := primaryBuilderInvocation(
config,
@@ -256,15 +284,20 @@
config.ModuleGraphFile(),
[]string{
"--module_graph_file", config.ModuleGraphFile(),
- })
+ },
+ fmt.Sprintf("generating the Soong module graph at %s", config.ModuleGraphFile()),
+ )
+ queryviewDir := filepath.Join(config.SoongOutDir(), "queryview")
queryviewInvocation := primaryBuilderInvocation(
config,
queryviewTag,
config.QueryviewMarkerFile(),
[]string{
- "--bazel_queryview_dir", filepath.Join(config.SoongOutDir(), "queryview"),
- })
+ "--bazel_queryview_dir", queryviewDir,
+ },
+ fmt.Sprintf("generating the Soong module graph as a Bazel workspace at %s", queryviewDir),
+ )
soongDocsInvocation := primaryBuilderInvocation(
config,
@@ -272,7 +305,9 @@
config.SoongDocsHtml(),
[]string{
"--soong_docs", config.SoongDocsHtml(),
- })
+ },
+ fmt.Sprintf("generating Soong docs at %s", config.SoongDocsHtml()),
+ )
globFiles := []string{
config.NamedGlobFile(soongBuildTag),
@@ -292,7 +327,7 @@
var blueprintArgs bootstrap.Args
blueprintArgs.ModuleListFile = filepath.Join(config.FileListDir(), "Android.bp.list")
- blueprintArgs.OutFile = shared.JoinPath(config.SoongOutDir(), ".bootstrap/build.ninja")
+ blueprintArgs.OutFile = shared.JoinPath(config.SoongOutDir(), "bootstrap.ninja")
blueprintArgs.EmptyNinjaFile = false
blueprintCtx := blueprint.NewContext()
@@ -314,7 +349,7 @@
}
bootstrapDeps := bootstrap.RunBlueprint(blueprintArgs, bootstrap.DoEverything, blueprintCtx, blueprintConfig)
- bootstrapDepFile := shared.JoinPath(config.SoongOutDir(), ".bootstrap/build.ninja.d")
+ bootstrapDepFile := shared.JoinPath(config.SoongOutDir(), "bootstrap.ninja.d")
err := deptools.WriteDepFile(bootstrapDepFile, blueprintArgs.OutFile, bootstrapDeps)
if err != nil {
ctx.Fatalf("Error writing depfile '%s': %s", bootstrapDepFile, err)
@@ -342,11 +377,6 @@
// unused variables were changed?
envFile := filepath.Join(config.SoongOutDir(), availableEnvFile)
- dir := filepath.Join(config.SoongOutDir(), ".bootstrap")
- if err := os.MkdirAll(dir, 0755); err != nil {
- ctx.Fatalf("Cannot mkdir " + dir)
- }
-
buildMode := config.bazelBuildMode()
integratedBp2Build := buildMode == mixedBuild
@@ -361,6 +391,7 @@
soongBuildEnv.Set("BAZEL_OUTPUT_BASE", filepath.Join(config.BazelOutDir(), "output"))
soongBuildEnv.Set("BAZEL_WORKSPACE", absPath(ctx, "."))
soongBuildEnv.Set("BAZEL_METRICS_DIR", config.BazelMetricsDir())
+ soongBuildEnv.Set("LOG_DIR", config.LogsDir())
// For Soong bootstrapping tests
if os.Getenv("ALLOW_MISSING_DEPENDENCIES") == "true" {
@@ -457,7 +488,7 @@
targets = append(targets, config.SoongNinjaFile())
}
- ninja("bootstrap", ".bootstrap/build.ninja", targets...)
+ ninja("bootstrap", "bootstrap.ninja", targets...)
var soongBuildMetrics *soong_metrics_proto.SoongBuildMetrics
if shouldCollectBuildSoongMetrics(config) {
@@ -477,8 +508,7 @@
}
}
-func runMicrofactory(ctx Context, config Config, relExePath string, pkg string, mapping map[string]string) {
- name := filepath.Base(relExePath)
+func runMicrofactory(ctx Context, config Config, name string, pkg string, mapping map[string]string) {
ctx.BeginTrace(metrics.RunSoong, name)
defer ctx.EndTrace()
cfg := microfactory.Config{TrimPath: absPath(ctx, ".")}
@@ -486,7 +516,7 @@
cfg.Map(pkgPrefix, pathPrefix)
}
- exePath := filepath.Join(config.SoongOutDir(), relExePath)
+ exePath := filepath.Join(config.SoongOutDir(), name)
dir := filepath.Dir(exePath)
if err := os.MkdirAll(dir, 0777); err != nil {
ctx.Fatalf("cannot create %s: %s", dir, err)
diff --git a/ui/build/test_build.go b/ui/build/test_build.go
index f9a60b6..86c8568 100644
--- a/ui/build/test_build.go
+++ b/ui/build/test_build.go
@@ -63,7 +63,6 @@
cmd.StartOrFatal()
outDir := config.OutDir()
- bootstrapDir := filepath.Join(outDir, "soong", ".bootstrap")
modulePathsDir := filepath.Join(outDir, ".module_paths")
variablesFilePath := filepath.Join(outDir, "soong", "soong.variables")
@@ -77,6 +76,9 @@
// out/build_date.txt is considered a "source file"
buildDatetimeFilePath := filepath.Join(outDir, "build_date.txt")
+ // bpglob is built explicitly using Microfactory
+ bpglob := filepath.Join(config.SoongOutDir(), "bpglob")
+
danglingRules := make(map[string]bool)
scanner := bufio.NewScanner(stdout)
@@ -86,11 +88,11 @@
// Leaf node is not in the out directory.
continue
}
- if strings.HasPrefix(line, bootstrapDir) ||
- strings.HasPrefix(line, modulePathsDir) ||
+ if strings.HasPrefix(line, modulePathsDir) ||
line == variablesFilePath ||
line == dexpreoptConfigFilePath ||
- line == buildDatetimeFilePath {
+ line == buildDatetimeFilePath ||
+ line == bpglob {
// Leaf node is in one of Soong's bootstrap directories, which do not have
// full build rules in the primary build.ninja file.
continue
diff --git a/ui/metrics/Android.bp b/ui/metrics/Android.bp
index 1590ab0..3ba3907 100644
--- a/ui/metrics/Android.bp
+++ b/ui/metrics/Android.bp
@@ -23,7 +23,9 @@
"golang-protobuf-proto",
"soong-ui-metrics_upload_proto",
"soong-ui-metrics_proto",
+ "soong-ui-bp2build_metrics_proto",
"soong-ui-tracer",
+ "soong-shared",
],
srcs: [
"metrics.go",
@@ -57,3 +59,15 @@
"upload_proto/upload.pb.go",
],
}
+
+bootstrap_go_package {
+ name: "soong-ui-bp2build_metrics_proto",
+ pkgPath: "android/soong/ui/metrics/bp2build_metrics_proto",
+ deps: [
+ "golang-protobuf-reflect-protoreflect",
+ "golang-protobuf-runtime-protoimpl",
+ ],
+ srcs: [
+ "bp2build_metrics_proto/bp2build_metrics.pb.go",
+ ],
+}
diff --git a/ui/metrics/bp2build_metrics_proto/bp2build_metrics.pb.go b/ui/metrics/bp2build_metrics_proto/bp2build_metrics.pb.go
new file mode 100644
index 0000000..11177e4
--- /dev/null
+++ b/ui/metrics/bp2build_metrics_proto/bp2build_metrics.pb.go
@@ -0,0 +1,222 @@
+// 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.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.27.1
+// protoc v3.9.1
+// source: bp2build_metrics.proto
+
+package bp2build_metrics_proto
+
+import (
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ reflect "reflect"
+ sync "sync"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type Bp2BuildMetrics struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // Total number of Soong modules converted to generated targets
+ GeneratedModuleCount uint64 `protobuf:"varint,1,opt,name=generatedModuleCount,proto3" json:"generatedModuleCount,omitempty"`
+ // Total number of Soong modules converted to handcrafted targets
+ HandCraftedModuleCount uint64 `protobuf:"varint,2,opt,name=handCraftedModuleCount,proto3" json:"handCraftedModuleCount,omitempty"`
+ // Total number of unconverted Soong modules
+ UnconvertedModuleCount uint64 `protobuf:"varint,3,opt,name=unconvertedModuleCount,proto3" json:"unconvertedModuleCount,omitempty"`
+ // Counts of generated Bazel targets per Bazel rule class
+ RuleClassCount map[string]uint64 `protobuf:"bytes,4,rep,name=ruleClassCount,proto3" json:"ruleClassCount,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"`
+ // List of converted modules
+ ConvertedModules []string `protobuf:"bytes,5,rep,name=convertedModules,proto3" json:"convertedModules,omitempty"`
+}
+
+func (x *Bp2BuildMetrics) Reset() {
+ *x = Bp2BuildMetrics{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_bp2build_metrics_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *Bp2BuildMetrics) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Bp2BuildMetrics) ProtoMessage() {}
+
+func (x *Bp2BuildMetrics) ProtoReflect() protoreflect.Message {
+ mi := &file_bp2build_metrics_proto_msgTypes[0]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use Bp2BuildMetrics.ProtoReflect.Descriptor instead.
+func (*Bp2BuildMetrics) Descriptor() ([]byte, []int) {
+ return file_bp2build_metrics_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *Bp2BuildMetrics) GetGeneratedModuleCount() uint64 {
+ if x != nil {
+ return x.GeneratedModuleCount
+ }
+ return 0
+}
+
+func (x *Bp2BuildMetrics) GetHandCraftedModuleCount() uint64 {
+ if x != nil {
+ return x.HandCraftedModuleCount
+ }
+ return 0
+}
+
+func (x *Bp2BuildMetrics) GetUnconvertedModuleCount() uint64 {
+ if x != nil {
+ return x.UnconvertedModuleCount
+ }
+ return 0
+}
+
+func (x *Bp2BuildMetrics) GetRuleClassCount() map[string]uint64 {
+ if x != nil {
+ return x.RuleClassCount
+ }
+ return nil
+}
+
+func (x *Bp2BuildMetrics) GetConvertedModules() []string {
+ if x != nil {
+ return x.ConvertedModules
+ }
+ return nil
+}
+
+var File_bp2build_metrics_proto protoreflect.FileDescriptor
+
+var file_bp2build_metrics_proto_rawDesc = []byte{
+ 0x0a, 0x16, 0x62, 0x70, 0x32, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69,
+ 0x63, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1c, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f,
+ 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x62, 0x70, 0x32, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d,
+ 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x22, 0x8f, 0x03, 0x0a, 0x0f, 0x42, 0x70, 0x32, 0x42, 0x75,
+ 0x69, 0x6c, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x32, 0x0a, 0x14, 0x67, 0x65,
+ 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x43, 0x6f, 0x75,
+ 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x14, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61,
+ 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x36,
+ 0x0a, 0x16, 0x68, 0x61, 0x6e, 0x64, 0x43, 0x72, 0x61, 0x66, 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64,
+ 0x75, 0x6c, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x16,
+ 0x68, 0x61, 0x6e, 0x64, 0x43, 0x72, 0x61, 0x66, 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c,
+ 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x36, 0x0a, 0x16, 0x75, 0x6e, 0x63, 0x6f, 0x6e, 0x76,
+ 0x65, 0x72, 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74,
+ 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x16, 0x75, 0x6e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72,
+ 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x69,
+ 0x0a, 0x0e, 0x72, 0x75, 0x6c, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74,
+ 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62,
+ 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x62, 0x70, 0x32, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65,
+ 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x42, 0x70, 0x32, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x4d, 0x65,
+ 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x52, 0x75, 0x6c, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x43,
+ 0x6f, 0x75, 0x6e, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0e, 0x72, 0x75, 0x6c, 0x65, 0x43,
+ 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x2a, 0x0a, 0x10, 0x63, 0x6f, 0x6e,
+ 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x05, 0x20,
+ 0x03, 0x28, 0x09, 0x52, 0x10, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x4d, 0x6f,
+ 0x64, 0x75, 0x6c, 0x65, 0x73, 0x1a, 0x41, 0x0a, 0x13, 0x52, 0x75, 0x6c, 0x65, 0x43, 0x6c, 0x61,
+ 0x73, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03,
+ 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14,
+ 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x76,
+ 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x31, 0x5a, 0x2f, 0x61, 0x6e, 0x64, 0x72,
+ 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x75, 0x69, 0x2f, 0x6d, 0x65, 0x74,
+ 0x72, 0x69, 0x63, 0x73, 0x2f, 0x62, 0x70, 0x32, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65,
+ 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x33,
+}
+
+var (
+ file_bp2build_metrics_proto_rawDescOnce sync.Once
+ file_bp2build_metrics_proto_rawDescData = file_bp2build_metrics_proto_rawDesc
+)
+
+func file_bp2build_metrics_proto_rawDescGZIP() []byte {
+ file_bp2build_metrics_proto_rawDescOnce.Do(func() {
+ file_bp2build_metrics_proto_rawDescData = protoimpl.X.CompressGZIP(file_bp2build_metrics_proto_rawDescData)
+ })
+ return file_bp2build_metrics_proto_rawDescData
+}
+
+var file_bp2build_metrics_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
+var file_bp2build_metrics_proto_goTypes = []interface{}{
+ (*Bp2BuildMetrics)(nil), // 0: soong_build_bp2build_metrics.Bp2BuildMetrics
+ nil, // 1: soong_build_bp2build_metrics.Bp2BuildMetrics.RuleClassCountEntry
+}
+var file_bp2build_metrics_proto_depIdxs = []int32{
+ 1, // 0: soong_build_bp2build_metrics.Bp2BuildMetrics.ruleClassCount:type_name -> soong_build_bp2build_metrics.Bp2BuildMetrics.RuleClassCountEntry
+ 1, // [1:1] is the sub-list for method output_type
+ 1, // [1:1] is the sub-list for method input_type
+ 1, // [1:1] is the sub-list for extension type_name
+ 1, // [1:1] is the sub-list for extension extendee
+ 0, // [0:1] is the sub-list for field type_name
+}
+
+func init() { file_bp2build_metrics_proto_init() }
+func file_bp2build_metrics_proto_init() {
+ if File_bp2build_metrics_proto != nil {
+ return
+ }
+ if !protoimpl.UnsafeEnabled {
+ file_bp2build_metrics_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*Bp2BuildMetrics); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: file_bp2build_metrics_proto_rawDesc,
+ NumEnums: 0,
+ NumMessages: 2,
+ NumExtensions: 0,
+ NumServices: 0,
+ },
+ GoTypes: file_bp2build_metrics_proto_goTypes,
+ DependencyIndexes: file_bp2build_metrics_proto_depIdxs,
+ MessageInfos: file_bp2build_metrics_proto_msgTypes,
+ }.Build()
+ File_bp2build_metrics_proto = out.File
+ file_bp2build_metrics_proto_rawDesc = nil
+ file_bp2build_metrics_proto_goTypes = nil
+ file_bp2build_metrics_proto_depIdxs = nil
+}
diff --git a/ui/metrics/bp2build_metrics_proto/bp2build_metrics.proto b/ui/metrics/bp2build_metrics_proto/bp2build_metrics.proto
new file mode 100644
index 0000000..5e88966
--- /dev/null
+++ b/ui/metrics/bp2build_metrics_proto/bp2build_metrics.proto
@@ -0,0 +1,35 @@
+// 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.
+
+syntax = "proto3";
+
+package soong_build_bp2build_metrics;
+option go_package = "android/soong/ui/metrics/bp2build_metrics_proto";
+
+message Bp2BuildMetrics {
+ // Total number of Soong modules converted to generated targets
+ uint64 generatedModuleCount = 1;
+
+ // Total number of Soong modules converted to handcrafted targets
+ uint64 handCraftedModuleCount = 2;
+
+ // Total number of unconverted Soong modules
+ uint64 unconvertedModuleCount = 3;
+
+ // Counts of generated Bazel targets per Bazel rule class
+ map<string, uint64> ruleClassCount = 4;
+
+ // List of converted modules
+ repeated string convertedModules = 5;
+}
diff --git a/ui/metrics/bp2build_metrics_proto/regen.sh b/ui/metrics/bp2build_metrics_proto/regen.sh
new file mode 100755
index 0000000..bfe4294
--- /dev/null
+++ b/ui/metrics/bp2build_metrics_proto/regen.sh
@@ -0,0 +1,29 @@
+#!/bin/bash -e
+
+# 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.
+
+# Generates the golang source file of bp2build_metrics.proto protobuf file.
+
+function die() { echo "ERROR: $1" >&2; exit 1; }
+
+readonly error_msg="Maybe you need to run 'lunch aosp_arm-eng && m aprotoc blueprint_tools'?"
+
+if ! hash aprotoc &>/dev/null; then
+ die "could not find aprotoc. ${error_msg}"
+fi
+
+if ! aprotoc --go_out=paths=source_relative:. bp2build_metrics.proto; then
+ die "build failed. ${error_msg}"
+fi
diff --git a/ui/metrics/metrics.go b/ui/metrics/metrics.go
index f1bb862..80f8c1a 100644
--- a/ui/metrics/metrics.go
+++ b/ui/metrics/metrics.go
@@ -32,12 +32,12 @@
// of what an event is and how the metrics system is a stack based system.
import (
- "io/ioutil"
"os"
"runtime"
"strings"
"time"
+ "android/soong/shared"
"google.golang.org/protobuf/proto"
soong_metrics_proto "android/soong/ui/metrics/metrics_proto"
@@ -196,7 +196,7 @@
}
m.metrics.HostOs = proto.String(runtime.GOOS)
- return save(&m.metrics, out)
+ return shared.Save(&m.metrics, out)
}
// SetSoongBuildMetrics sets the metrics collected from the soong_build
@@ -228,25 +228,5 @@
// Dump saves the collected CUJs metrics to the raw protobuf file.
func (c *CriticalUserJourneysMetrics) Dump(filename string) (err error) {
- return save(&c.cujs, filename)
-}
-
-// save takes a protobuf message, marshals to an array of bytes
-// and is then saved to a file.
-func save(pb proto.Message, filename string) (err error) {
- data, err := proto.Marshal(pb)
- if err != nil {
- return err
- }
-
- tempFilename := filename + ".tmp"
- if err := ioutil.WriteFile(tempFilename, []byte(data), 0644 /* rw-r--r-- */); err != nil {
- return err
- }
-
- if err := os.Rename(tempFilename, filename); err != nil {
- return err
- }
-
- return nil
+ return shared.Save(&c.cujs, filename)
}
diff --git a/ui/terminal/simple_status.go b/ui/terminal/simple_status.go
index 936b275..3157813 100644
--- a/ui/terminal/simple_status.go
+++ b/ui/terminal/simple_status.go
@@ -22,32 +22,41 @@
)
type simpleStatusOutput struct {
- writer io.Writer
- formatter formatter
- keepANSI bool
+ writer io.Writer
+ formatter formatter
+ keepANSI bool
+ outputLevel status.MsgLevel
}
// NewSimpleStatusOutput returns a StatusOutput that represents the
// current build status similarly to Ninja's built-in terminal
// output.
-func NewSimpleStatusOutput(w io.Writer, formatter formatter, keepANSI bool) status.StatusOutput {
+func NewSimpleStatusOutput(w io.Writer, formatter formatter, keepANSI bool, quietBuild bool) status.StatusOutput {
+ level := status.StatusLvl
+ if quietBuild {
+ level = status.PrintLvl
+ }
return &simpleStatusOutput{
- writer: w,
- formatter: formatter,
- keepANSI: keepANSI,
+ writer: w,
+ formatter: formatter,
+ keepANSI: keepANSI,
+ outputLevel: level,
}
}
func (s *simpleStatusOutput) Message(level status.MsgLevel, message string) {
- if level >= status.StatusLvl {
+ if level >= s.outputLevel {
fmt.Fprintln(s.writer, s.formatter.message(level, message))
}
}
-func (s *simpleStatusOutput) StartAction(action *status.Action, counts status.Counts) {
+func (s *simpleStatusOutput) StartAction(_ *status.Action, _ status.Counts) {
}
func (s *simpleStatusOutput) FinishAction(result status.ActionResult, counts status.Counts) {
+ if s.outputLevel > status.StatusLvl {
+ return
+ }
str := result.Description
if str == "" {
str = result.Command
diff --git a/ui/terminal/status.go b/ui/terminal/status.go
index 2ad174f..ff0af47 100644
--- a/ui/terminal/status.go
+++ b/ui/terminal/status.go
@@ -29,9 +29,9 @@
func NewStatusOutput(w io.Writer, statusFormat string, forceSimpleOutput, quietBuild, forceKeepANSI bool) status.StatusOutput {
formatter := newFormatter(statusFormat, quietBuild)
- if !forceSimpleOutput && isSmartTerminal(w) {
- return NewSmartStatusOutput(w, formatter)
+ if forceSimpleOutput || quietBuild || !isSmartTerminal(w) {
+ return NewSimpleStatusOutput(w, formatter, forceKeepANSI, quietBuild)
} else {
- return NewSimpleStatusOutput(w, formatter, forceKeepANSI)
+ return NewSmartStatusOutput(w, formatter)
}
}