Merge "Combine bp2build handling of static/shared props"
diff --git a/android/bazel.go b/android/bazel.go
index f56c24e..ef770bf 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -138,7 +138,6 @@
// e.g. ERROR: Analysis of target '@soong_injection//mixed_builds:buildroot' failed
"external/bazelbuild-rules_android":/* recursive = */ true,
- "prebuilts/clang/host/linux-x86":/* recursive = */ false,
"prebuilts/sdk":/* recursive = */ false,
"prebuilts/sdk/tools":/* recursive = */ false,
}
@@ -155,6 +154,7 @@
"external/fmtlib": Bp2BuildDefaultTrueRecursively,
"external/arm-optimized-routines": Bp2BuildDefaultTrueRecursively,
"external/scudo": Bp2BuildDefaultTrueRecursively,
+ "prebuilts/clang/host/linux-x86": Bp2BuildDefaultTrueRecursively,
}
// Per-module denylist to always opt modules out of both bp2build and mixed builds.
diff --git a/android/variable.go b/android/variable.go
index 672576a..cf74933 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -467,7 +467,7 @@
// ProductVariableProperties returns a ProductConfigProperties containing only the properties which
// have been set for the module in the given context.
-func ProductVariableProperties(ctx ProductConfigContext) ProductConfigProperties {
+func ProductVariableProperties(ctx BaseMutatorContext) ProductConfigProperties {
module := ctx.Module()
moduleBase := module.base()
@@ -477,7 +477,28 @@
return productConfigProperties
}
- variableValues := reflect.ValueOf(moduleBase.variableProperties).Elem().FieldByName("Product_variables")
+ productVariableValues(moduleBase.variableProperties, "", &productConfigProperties)
+
+ for arch, targetProps := range moduleBase.GetArchProperties(ctx, moduleBase.variableProperties) {
+ // GetArchProperties is creating an instance of the requested type
+ // and productVariablesValues expects an interface, so no need to cast
+ productVariableValues(targetProps, arch.Name, &productConfigProperties)
+ }
+
+ for os, targetProps := range moduleBase.GetTargetProperties(ctx, moduleBase.variableProperties) {
+ // GetTargetProperties is creating an instance of the requested type
+ // and productVariablesValues expects an interface, so no need to cast
+ productVariableValues(targetProps, os.Name, &productConfigProperties)
+ }
+
+ return productConfigProperties
+}
+
+func productVariableValues(variableProps interface{}, suffix string, productConfigProperties *ProductConfigProperties) {
+ if suffix != "" {
+ suffix = "-" + suffix
+ }
+ variableValues := reflect.ValueOf(variableProps).Elem().FieldByName("Product_variables")
for i := 0; i < variableValues.NumField(); i++ {
variableValue := variableValues.Field(i)
// Check if any properties were set for the module
@@ -495,15 +516,13 @@
// e.g. Asflags, Cflags, Enabled, etc.
propertyName := variableValue.Type().Field(j).Name
- productConfigProperties[propertyName] = append(productConfigProperties[propertyName],
+ (*productConfigProperties)[propertyName] = append((*productConfigProperties)[propertyName],
ProductConfigProperty{
- ProductConfigVariable: productVariableName,
+ ProductConfigVariable: productVariableName + suffix,
Property: property.Interface(),
})
}
}
-
- return productConfigProperties
}
func VariableMutator(mctx BottomUpMutatorContext) {
diff --git a/apex/bootclasspath_fragment_test.go b/apex/bootclasspath_fragment_test.go
index 9965f83..7aecff6 100644
--- a/apex/bootclasspath_fragment_test.go
+++ b/apex/bootclasspath_fragment_test.go
@@ -62,6 +62,7 @@
apex {
name: "com.android.art",
key: "com.android.art.key",
+ bootclasspath_fragments: ["art-bootclasspath-fragment"],
java_libs: [
"baz",
"quuz",
@@ -100,32 +101,12 @@
"com.android.art",
],
}
-
- bootclasspath_fragment {
- name: "framework-bootclasspath-fragment",
- image_name: "boot",
- }
`,
)
- // Make sure that the framework-bootclasspath-fragment is using the correct configuration.
- checkBootclasspathFragment(t, result, "framework-bootclasspath-fragment", "platform:foo,platform:bar", `
-test_device/dex_bootjars/android/system/framework/arm/boot-foo.art
-test_device/dex_bootjars/android/system/framework/arm/boot-foo.oat
-test_device/dex_bootjars/android/system/framework/arm/boot-foo.vdex
-test_device/dex_bootjars/android/system/framework/arm/boot-bar.art
-test_device/dex_bootjars/android/system/framework/arm/boot-bar.oat
-test_device/dex_bootjars/android/system/framework/arm/boot-bar.vdex
-test_device/dex_bootjars/android/system/framework/arm64/boot-foo.art
-test_device/dex_bootjars/android/system/framework/arm64/boot-foo.oat
-test_device/dex_bootjars/android/system/framework/arm64/boot-foo.vdex
-test_device/dex_bootjars/android/system/framework/arm64/boot-bar.art
-test_device/dex_bootjars/android/system/framework/arm64/boot-bar.oat
-test_device/dex_bootjars/android/system/framework/arm64/boot-bar.vdex
-`)
-
// Make sure that the art-bootclasspath-fragment is using the correct configuration.
- checkBootclasspathFragment(t, result, "art-bootclasspath-fragment", "com.android.art:baz,com.android.art:quuz", `
+ checkBootclasspathFragment(t, result, "art-bootclasspath-fragment", "android_common_apex10000",
+ "com.android.art:baz,com.android.art:quuz", `
test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art
test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.oat
test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.vdex
@@ -263,10 +244,10 @@
checkSdkKindStubs("other", otherInfo, android.SdkCorePlatform)
}
-func checkBootclasspathFragment(t *testing.T, result *android.TestResult, moduleName string, expectedConfiguredModules string, expectedBootclasspathFragmentFiles string) {
+func checkBootclasspathFragment(t *testing.T, result *android.TestResult, moduleName, variantName string, expectedConfiguredModules string, expectedBootclasspathFragmentFiles string) {
t.Helper()
- bootclasspathFragment := result.ModuleForTests(moduleName, "android_common").Module().(*java.BootclasspathFragmentModule)
+ bootclasspathFragment := result.ModuleForTests(moduleName, variantName).Module().(*java.BootclasspathFragmentModule)
bootclasspathFragmentInfo := result.ModuleProvider(bootclasspathFragment, java.BootclasspathFragmentApexContentInfoProvider).(java.BootclasspathFragmentApexContentInfo)
modules := bootclasspathFragmentInfo.Modules()
@@ -401,7 +382,7 @@
).RunTest(t)
ensureExactContents(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{
- "etc/classpaths/mybootclasspathfragment.pb",
+ "etc/classpaths/bootclasspath.pb",
"javalib/arm/boot.art",
"javalib/arm/boot.oat",
"javalib/arm/boot.vdex",
@@ -613,7 +594,7 @@
ensureExactContents(t, result.TestContext, "myapex", "android_common_myapex_image", []string{
// This does not include art, oat or vdex files as they are only included for the art boot
// image.
- "etc/classpaths/mybootclasspathfragment.pb",
+ "etc/classpaths/bootclasspath.pb",
"javalib/bar.jar",
"javalib/foo.jar",
})
diff --git a/apex/systemserver_classpath_fragment_test.go b/apex/systemserver_classpath_fragment_test.go
index e1a101a..95b6e23 100644
--- a/apex/systemserver_classpath_fragment_test.go
+++ b/apex/systemserver_classpath_fragment_test.go
@@ -67,7 +67,7 @@
`)
ensureExactContents(t, result.TestContext, "myapex", "android_common_myapex_image", []string{
- "etc/classpaths/mysystemserverclasspathfragment.pb",
+ "etc/classpaths/systemserverclasspath.pb",
"javalib/foo.jar",
})
diff --git a/bazel/properties.go b/bazel/properties.go
index 3e778bb..84dca7e 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -19,6 +19,7 @@
"path/filepath"
"regexp"
"sort"
+ "strings"
)
// BazelTargetModuleProperties contain properties and metadata used for
@@ -200,6 +201,10 @@
// config variable default key in an Android.bp file, although there's no
// integration with Soong config variables (yet).
CONDITIONS_DEFAULT = "conditions_default"
+
+ ConditionsDefaultSelectKey = "//conditions:default"
+
+ productVariableBazelPackage = "//build/bazel/product_variables"
)
var (
@@ -215,7 +220,7 @@
ARCH_ARM64: "//build/bazel/platforms/arch:arm64",
ARCH_X86: "//build/bazel/platforms/arch:x86",
ARCH_X86_64: "//build/bazel/platforms/arch:x86_64",
- CONDITIONS_DEFAULT: "//conditions:default", // The default condition of as arch select map.
+ CONDITIONS_DEFAULT: ConditionsDefaultSelectKey, // The default condition of as arch select map.
}
// A map of target operating systems to the Bazel label of the
@@ -227,7 +232,7 @@
OS_LINUX: "//build/bazel/platforms/os:linux",
OS_LINUX_BIONIC: "//build/bazel/platforms/os:linux_bionic",
OS_WINDOWS: "//build/bazel/platforms/os:windows",
- CONDITIONS_DEFAULT: "//conditions:default", // The default condition of an os select map.
+ CONDITIONS_DEFAULT: ConditionsDefaultSelectKey, // The default condition of an os select map.
}
)
@@ -435,6 +440,10 @@
// are generated in a select statement and appended to the non-os specific
// label list Value.
OsValues stringListOsValues
+
+ // list of product-variable string list values. Optional. if used, each will generate a select
+ // statement appended to the label list Value.
+ ProductValues []ProductVariableValues
}
// MakeStringListAttribute initializes a StringListAttribute with the non-arch specific value.
@@ -466,6 +475,18 @@
ConditionsDefault []string
}
+// Product Variable values for StringListAttribute
+type ProductVariableValues struct {
+ ProductVariable string
+
+ Values []string
+}
+
+// SelectKey returns the appropriate select key for the receiving ProductVariableValues.
+func (p ProductVariableValues) SelectKey() string {
+ return fmt.Sprintf("%s:%s", productVariableBazelPackage, strings.ToLower(p.ProductVariable))
+}
+
// HasConfigurableValues returns true if the attribute contains
// architecture-specific string_list values.
func (attrs StringListAttribute) HasConfigurableValues() bool {
@@ -480,7 +501,8 @@
return true
}
}
- return false
+
+ return len(attrs.ProductValues) > 0
}
func (attrs *StringListAttribute) archValuePtrs() map[string]*[]string {
@@ -541,6 +563,12 @@
*v = value
}
+func (attrs *StringListAttribute) SortedProductVariables() []ProductVariableValues {
+ vals := attrs.ProductValues[:]
+ sort.Slice(vals, func(i, j int) bool { return vals[i].ProductVariable < vals[j].ProductVariable })
+ return vals
+}
+
// Append appends all values, including os and arch specific ones, from another
// StringListAttribute to this StringListAttribute
func (attrs *StringListAttribute) Append(other StringListAttribute) {
@@ -558,6 +586,21 @@
attrs.SetValueForOS(os, this)
}
+ productValues := make(map[string][]string, 0)
+ for _, pv := range attrs.ProductValues {
+ productValues[pv.ProductVariable] = pv.Values
+ }
+ for _, pv := range other.ProductValues {
+ productValues[pv.ProductVariable] = append(productValues[pv.ProductVariable], pv.Values...)
+ }
+ attrs.ProductValues = make([]ProductVariableValues, 0, len(productValues))
+ for pv, vals := range productValues {
+ attrs.ProductValues = append(attrs.ProductValues, ProductVariableValues{
+ ProductVariable: pv,
+ Values: vals,
+ })
+ }
+
attrs.Value = append(attrs.Value, other.Value...)
}
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index bddc524..7a73e18 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -19,6 +19,7 @@
"android/soong/bazel"
"fmt"
"reflect"
+ "sort"
"strings"
"github.com/google/blueprint"
@@ -34,6 +35,7 @@
content string
ruleClass string
bzlLoadLocation string
+ handcrafted bool
}
// IsLoadedFromStarlark determines if the BazelTarget's rule class is loaded from a .bzl file,
@@ -45,12 +47,47 @@
// BazelTargets is a typedef for a slice of BazelTarget objects.
type BazelTargets []BazelTarget
+// HasHandcraftedTargetsreturns true if a set of bazel targets contain
+// handcrafted ones.
+func (targets BazelTargets) hasHandcraftedTargets() bool {
+ for _, target := range targets {
+ if target.handcrafted {
+ return true
+ }
+ }
+ return false
+}
+
+// sort a list of BazelTargets in-place, by name, and by generated/handcrafted types.
+func (targets BazelTargets) sort() {
+ sort.Slice(targets, func(i, j int) bool {
+ if targets[i].handcrafted != targets[j].handcrafted {
+ // Handcrafted targets will be generated after the bp2build generated targets.
+ return targets[j].handcrafted
+ }
+ // This will cover all bp2build generated targets.
+ return targets[i].name < targets[j].name
+ })
+}
+
// String returns the string representation of BazelTargets, without load
// statements (use LoadStatements for that), since the targets are usually not
// adjacent to the load statements at the top of the BUILD file.
func (targets BazelTargets) String() string {
var res string
for i, target := range targets {
+ // There is only at most 1 handcrafted "target", because its contents
+ // represent the entire BUILD file content from the tree. See
+ // build_conversion.go#getHandcraftedBuildContent for more information.
+ //
+ // Add a header to make it easy to debug where the handcrafted targets
+ // are in a generated BUILD file.
+ if target.handcrafted {
+ res += "# -----------------------------\n"
+ res += "# Section: Handcrafted targets. \n"
+ res += "# -----------------------------\n\n"
+ }
+
res += target.content
if i != len(targets)-1 {
res += "\n\n"
@@ -267,7 +304,8 @@
}
// TODO(b/181575318): once this is more targeted, we need to include name, rule class, etc
return BazelTarget{
- content: c,
+ content: c,
+ handcrafted: true,
}, nil
}
@@ -294,6 +332,7 @@
targetName,
attributes,
),
+ handcrafted: false,
}
}
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index 71660a8..b1c342c 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -1452,53 +1452,61 @@
dir := "."
for _, testCase := range testCases {
- fs := make(map[string][]byte)
- toParse := []string{
- "Android.bp",
- }
- for f, content := range testCase.fs {
- if strings.HasSuffix(f, "Android.bp") {
- toParse = append(toParse, f)
+ t.Run(testCase.description, func(t *testing.T) {
+ fs := make(map[string][]byte)
+ toParse := []string{
+ "Android.bp",
}
- fs[f] = []byte(content)
- }
- config := android.TestConfig(buildDir, nil, testCase.bp, fs)
- ctx := android.NewTestContext(config)
- ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
- for _, m := range testCase.depsMutators {
- ctx.DepsBp2BuildMutators(m)
- }
- ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator)
- ctx.RegisterForBazelConversion()
+ for f, content := range testCase.fs {
+ if strings.HasSuffix(f, "Android.bp") {
+ toParse = append(toParse, f)
+ }
+ fs[f] = []byte(content)
+ }
+ config := android.TestConfig(buildDir, nil, testCase.bp, fs)
+ ctx := android.NewTestContext(config)
+ ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
+ for _, m := range testCase.depsMutators {
+ ctx.DepsBp2BuildMutators(m)
+ }
+ ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator)
+ ctx.RegisterForBazelConversion()
- _, errs := ctx.ParseFileList(dir, toParse)
- if errored(t, testCase.description, errs) {
- continue
- }
- _, errs = ctx.ResolveDependencies(config)
- if errored(t, testCase.description, errs) {
- continue
- }
+ _, errs := ctx.ParseFileList(dir, toParse)
+ if errored(t, testCase.description, errs) {
+ return
+ }
+ _, errs = ctx.ResolveDependencies(config)
+ if errored(t, testCase.description, errs) {
+ return
+ }
- checkDir := dir
- if testCase.dir != "" {
- checkDir = testCase.dir
- }
- bazelTargets := generateBazelTargetsForDir(NewCodegenContext(config, *ctx.Context, Bp2Build), checkDir)
- 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 {
+ checkDir := dir
+ if testCase.dir != "" {
+ checkDir = testCase.dir
+ }
+ bazelTargets := generateBazelTargetsForDir(NewCodegenContext(config, *ctx.Context, Bp2Build), checkDir)
+ bazelTargets.sort()
+ actualCount := len(bazelTargets)
+ expectedCount := len(testCase.expectedBazelTargets)
+ if actualCount != expectedCount {
+ t.Errorf("Expected %d bazel target, got %d\n%s", expectedCount, actualCount, bazelTargets)
+ }
+ if !strings.Contains(bazelTargets.String(), "Section: Handcrafted targets. ") {
+ t.Errorf("Expected string representation of bazelTargets to contain handcrafted section header.")
+ }
for i, target := range bazelTargets {
- if w, g := testCase.expectedBazelTargets[i], target.content; w != g {
+ actualContent := target.content
+ expectedContent := testCase.expectedBazelTargets[i]
+ if expectedContent != actualContent {
t.Errorf(
- "%s: Expected generated Bazel target to be '%s', got '%s'",
- testCase.description,
- w,
- g,
+ "Expected generated Bazel target to be '%s', got '%s'",
+ expectedContent,
+ actualContent,
)
}
}
- }
+ })
}
}
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index 0a72937..6e19e13 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -41,6 +41,7 @@
)
func runCcLibraryTestCase(t *testing.T, tc bp2buildTestCase) {
+ t.Helper()
runBp2BuildTestCase(t, registerCcLibraryModuleTypes, tc)
}
@@ -52,6 +53,7 @@
}
func runBp2BuildTestCase(t *testing.T, registerModuleTypes func(ctx android.RegistrationContext), tc bp2buildTestCase) {
+ t.Helper()
dir := "."
filesystem := make(map[string][]byte)
toParse := []string{
diff --git a/bp2build/cc_library_headers_conversion_test.go b/bp2build/cc_library_headers_conversion_test.go
index 2859bab..264ba6b 100644
--- a/bp2build/cc_library_headers_conversion_test.go
+++ b/bp2build/cc_library_headers_conversion_test.go
@@ -84,6 +84,7 @@
}
func runCcLibraryHeadersTestCase(t *testing.T, tc bp2buildTestCase) {
+ t.Helper()
runBp2BuildTestCase(t, registerCcLibraryHeadersModuleTypes, tc)
}
diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go
index 62084a5..e6f1fbc 100644
--- a/bp2build/cc_library_static_conversion_test.go
+++ b/bp2build/cc_library_static_conversion_test.go
@@ -76,6 +76,7 @@
}
func runCcLibraryStaticTestCase(t *testing.T, tc bp2buildTestCase) {
+ t.Helper()
runBp2BuildTestCase(t, registerCcLibraryStaticModuleTypes, tc)
}
@@ -1156,3 +1157,120 @@
)`},
})
}
+
+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,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ filesystem: map[string]string{},
+ blueprint: soongCcLibraryStaticPreamble + `
+cc_library_static {
+ name: "foo_static",
+ srcs: ["common.c"],
+ product_variables: {
+ malloc_not_svelte: {
+ cflags: ["-Wmalloc_not_svelte"],
+ },
+ malloc_zero_contents: {
+ cflags: ["-Wmalloc_zero_contents"],
+ },
+ binder32bit: {
+ cflags: ["-Wbinder32bit"],
+ },
+ },
+} `,
+ expectedBazelTargets: []string{`cc_library_static(
+ name = "foo_static",
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ] + select({
+ "//build/bazel/product_variables:binder32bit": ["-Wbinder32bit"],
+ "//conditions:default": [],
+ }) + select({
+ "//build/bazel/product_variables:malloc_not_svelte": ["-Wmalloc_not_svelte"],
+ "//conditions:default": [],
+ }) + select({
+ "//build/bazel/product_variables:malloc_zero_contents": ["-Wmalloc_zero_contents"],
+ "//conditions:default": [],
+ }),
+ linkstatic = True,
+ srcs = ["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,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ filesystem: map[string]string{},
+ blueprint: soongCcLibraryStaticPreamble + `
+cc_library_static {
+ name: "foo_static",
+ srcs: ["common.c"],
+ product_variables: {
+ malloc_not_svelte: {
+ cflags: ["-Wmalloc_not_svelte"],
+ },
+ },
+ arch: {
+ arm64: {
+ product_variables: {
+ malloc_not_svelte: {
+ cflags: ["-Warm64_malloc_not_svelte"],
+ },
+ },
+ },
+ },
+ multilib: {
+ lib32: {
+ product_variables: {
+ malloc_not_svelte: {
+ cflags: ["-Wlib32_malloc_not_svelte"],
+ },
+ },
+ },
+ },
+ target: {
+ android: {
+ product_variables: {
+ malloc_not_svelte: {
+ cflags: ["-Wandroid_malloc_not_svelte"],
+ },
+ },
+ }
+ },
+} `,
+ expectedBazelTargets: []string{`cc_library_static(
+ name = "foo_static",
+ copts = [
+ "-I.",
+ "-I$(BINDIR)/.",
+ ] + select({
+ "//build/bazel/product_variables:malloc_not_svelte": ["-Wmalloc_not_svelte"],
+ "//conditions:default": [],
+ }) + select({
+ "//build/bazel/product_variables:malloc_not_svelte-android": ["-Wandroid_malloc_not_svelte"],
+ "//conditions:default": [],
+ }) + select({
+ "//build/bazel/product_variables:malloc_not_svelte-arm": ["-Wlib32_malloc_not_svelte"],
+ "//conditions:default": [],
+ }) + select({
+ "//build/bazel/product_variables:malloc_not_svelte-arm64": ["-Warm64_malloc_not_svelte"],
+ "//conditions:default": [],
+ }) + select({
+ "//build/bazel/product_variables:malloc_not_svelte-x86": ["-Wlib32_malloc_not_svelte"],
+ "//conditions:default": [],
+ }),
+ linkstatic = True,
+ srcs = ["common.c"],
+)`},
+ })
+}
diff --git a/bp2build/cc_object_conversion_test.go b/bp2build/cc_object_conversion_test.go
index b69135b..f7e94c2 100644
--- a/bp2build/cc_object_conversion_test.go
+++ b/bp2build/cc_object_conversion_test.go
@@ -27,6 +27,7 @@
}
func runCcObjectTestCase(t *testing.T, tc bp2buildTestCase) {
+ t.Helper()
runBp2BuildTestCase(t, registerCcObjectModuleTypes, tc)
}
@@ -208,7 +209,10 @@
`,
expectedBazelTargets: []string{`cc_object(
name = "foo",
- asflags = ["-DPLATFORM_SDK_VERSION={Platform_sdk_version}"],
+ asflags = select({
+ "//build/bazel/product_variables:platform_sdk_version": ["-DPLATFORM_SDK_VERSION={Platform_sdk_version}"],
+ "//conditions:default": [],
+ }),
copts = ["-fno-addrsig"],
)`,
},
diff --git a/bp2build/configurability.go b/bp2build/configurability.go
index 2b8f6cc..9869c5d 100644
--- a/bp2build/configurability.go
+++ b/bp2build/configurability.go
@@ -11,26 +11,42 @@
type selects map[string]reflect.Value
-func getStringListValues(list bazel.StringListAttribute) (reflect.Value, selects, selects) {
+func getStringListValues(list bazel.StringListAttribute) (reflect.Value, []selects) {
value := reflect.ValueOf(list.Value)
if !list.HasConfigurableValues() {
- return value, nil, nil
+ return value, []selects{}
}
+ selectValues := make([]selects, 0)
archSelects := map[string]reflect.Value{}
for arch, selectKey := range bazel.PlatformArchMap {
archSelects[selectKey] = reflect.ValueOf(list.GetValueForArch(arch))
}
+ if len(archSelects) > 0 {
+ selectValues = append(selectValues, archSelects)
+ }
osSelects := map[string]reflect.Value{}
for os, selectKey := range bazel.PlatformOsMap {
osSelects[selectKey] = reflect.ValueOf(list.GetValueForOS(os))
}
+ if len(osSelects) > 0 {
+ selectValues = append(selectValues, osSelects)
+ }
- return value, archSelects, osSelects
+ for _, pv := range list.SortedProductVariables() {
+ s := make(selects)
+ if len(pv.Values) > 0 {
+ s[pv.SelectKey()] = reflect.ValueOf(pv.Values)
+ s[bazel.ConditionsDefaultSelectKey] = reflect.ValueOf([]string{})
+ selectValues = append(selectValues, s)
+ }
+ }
+
+ return value, selectValues
}
-func getLabelValue(label bazel.LabelAttribute) (reflect.Value, selects, selects) {
+func getLabelValue(label bazel.LabelAttribute) (reflect.Value, []selects) {
var value reflect.Value
var archSelects selects
@@ -43,13 +59,13 @@
value = reflect.ValueOf(label.Value)
}
- return value, archSelects, nil
+ return value, []selects{archSelects}
}
-func getLabelListValues(list bazel.LabelListAttribute) (reflect.Value, selects, selects) {
+func getLabelListValues(list bazel.LabelListAttribute) (reflect.Value, []selects) {
value := reflect.ValueOf(list.Value.Includes)
if !list.HasConfigurableValues() {
- return value, nil, nil
+ return value, []selects{}
}
archSelects := map[string]reflect.Value{}
@@ -62,29 +78,30 @@
osSelects[selectKey] = reflect.ValueOf(list.GetValueForOS(os).Includes)
}
- return value, archSelects, osSelects
+ return value, []selects{archSelects, osSelects}
}
// prettyPrintAttribute converts an Attribute to its Bazel syntax. May contain
// select statements.
func prettyPrintAttribute(v bazel.Attribute, indent int) (string, error) {
var value reflect.Value
- var archSelects, osSelects selects
+ var configurableAttrs []selects
var defaultSelectValue string
switch list := v.(type) {
case bazel.StringListAttribute:
- value, archSelects, osSelects = getStringListValues(list)
+ value, configurableAttrs = getStringListValues(list)
defaultSelectValue = "[]"
case bazel.LabelListAttribute:
- value, archSelects, osSelects = getLabelListValues(list)
+ value, configurableAttrs = getLabelListValues(list)
defaultSelectValue = "[]"
case bazel.LabelAttribute:
- value, archSelects, osSelects = getLabelValue(list)
+ value, configurableAttrs = getLabelValue(list)
defaultSelectValue = "None"
default:
return "", fmt.Errorf("Not a supported Bazel attribute type: %s", v)
}
+ var err error
ret := ""
if value.Kind() != reflect.Invalid {
s, err := prettyPrint(value, indent)
@@ -108,13 +125,14 @@
return s, nil
}
- ret, err := appendSelects(archSelects, defaultSelectValue, ret)
- if err != nil {
- return "", err
+ for _, configurableAttr := range configurableAttrs {
+ ret, err = appendSelects(configurableAttr, defaultSelectValue, ret)
+ if err != nil {
+ return "", err
+ }
}
- ret, err = appendSelects(osSelects, defaultSelectValue, ret)
- return ret, err
+ return ret, nil
}
// prettyPrintSelectMap converts a map of select keys to reflected Values as a generic way
@@ -125,11 +143,10 @@
}
// addConditionsDefault := false
- conditionsDefaultKey := bazel.PlatformArchMap[bazel.CONDITIONS_DEFAULT]
var selects string
for _, selectKey := range android.SortedStringKeys(selectMap) {
- if selectKey == conditionsDefaultKey {
+ if selectKey == bazel.ConditionsDefaultSelectKey {
// Handle default condition later.
continue
}
@@ -159,14 +176,14 @@
ret += selects
// Handle the default condition
- s, err := prettyPrintSelectEntry(selectMap[conditionsDefaultKey], conditionsDefaultKey, indent)
+ s, err := prettyPrintSelectEntry(selectMap[bazel.ConditionsDefaultSelectKey], bazel.ConditionsDefaultSelectKey, indent)
if err != nil {
return "", err
}
if s == "" {
// Print an explicit empty list (the default value) even if the value is
// empty, to avoid errors about not finding a configuration that matches.
- ret += fmt.Sprintf("%s\"%s\": %s,\n", makeIndent(indent+1), "//conditions:default", defaultValue)
+ ret += fmt.Sprintf("%s\"%s\": %s,\n", makeIndent(indent+1), bazel.ConditionsDefaultSelectKey, defaultValue)
} else {
// Print the custom default value.
ret += s
diff --git a/bp2build/conversion.go b/bp2build/conversion.go
index 101ad3d..bced4c1 100644
--- a/bp2build/conversion.go
+++ b/bp2build/conversion.go
@@ -5,7 +5,6 @@
"android/soong/cc/config"
"fmt"
"reflect"
- "sort"
"strings"
"github.com/google/blueprint/proptools"
@@ -64,22 +63,28 @@
continue
}
targets := buildToTargets[dir]
- sort.Slice(targets, func(i, j int) bool {
- // this will cover all bp2build generated targets
- if targets[i].name < targets[j].name {
- return true
- }
- // give a strict ordering to content from hand-crafted targets
- return targets[i].content < targets[j].content
- })
- content := soongModuleLoad
+ targets.sort()
+
+ var content string
if mode == Bp2Build {
- content = `# This file was automatically generated by bp2build for the Bazel migration project.
-# Feel free to edit or test it, but do *not* check it into your version control system.`
- content += "\n\n"
- content += "package(default_visibility = [\"//visibility:public\"])"
- content += "\n\n"
+ content = `# READ THIS FIRST:
+# This file was automatically generated by bp2build for the Bazel migration project.
+# Feel free to edit or test it, but do *not* check it into your version control system.
+`
+ if targets.hasHandcraftedTargets() {
+ // For BUILD files with both handcrafted and generated targets,
+ // don't hardcode actual content, like package() declarations.
+ // Leave that responsibility to the checked-in BUILD file
+ // instead.
+ content += `# This file contains generated targets and handcrafted targets that are manually managed in the source tree.`
+ } else {
+ // For fully-generated BUILD files, hardcode the default visibility.
+ content += "package(default_visibility = [\"//visibility:public\"])"
+ }
+ content += "\n"
content += targets.LoadStatements()
+ } else if mode == QueryView {
+ content = soongModuleLoad
}
if content != "" {
// If there are load statements, add a couple of newlines.
diff --git a/bp2build/python_binary_conversion_test.go b/bp2build/python_binary_conversion_test.go
index 95bce3c..7bedf71 100644
--- a/bp2build/python_binary_conversion_test.go
+++ b/bp2build/python_binary_conversion_test.go
@@ -8,6 +8,7 @@
)
func runPythonTestCase(t *testing.T, tc bp2buildTestCase) {
+ t.Helper()
runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc)
}
diff --git a/bp2build/sh_conversion_test.go b/bp2build/sh_conversion_test.go
index 91bba54..82e0a14 100644
--- a/bp2build/sh_conversion_test.go
+++ b/bp2build/sh_conversion_test.go
@@ -49,6 +49,7 @@
}
func runShBinaryTestCase(t *testing.T, tc bp2buildTestCase) {
+ t.Helper()
runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc)
}
diff --git a/cc/bp2build.go b/cc/bp2build.go
index f18829b..162af99 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -296,6 +296,21 @@
}
}
+ productVariableProps := android.ProductVariableProperties(ctx)
+ if props, exists := productVariableProps["Cflags"]; exists {
+ for _, prop := range props {
+ flags, ok := prop.Property.([]string)
+ if !ok {
+ ctx.ModuleErrorf("Could not convert product variable cflag property")
+ }
+ newFlags, _ := bazel.TryVariableSubstitutions(flags, prop.ProductConfigVariable)
+ copts.ProductValues = append(copts.ProductValues, bazel.ProductVariableValues{
+ ProductVariable: prop.ProductConfigVariable,
+ Values: newFlags,
+ })
+ }
+ }
+
return compilerAttributes{
srcs: srcs,
copts: copts,
diff --git a/cc/cc_test.go b/cc/cc_test.go
index d82619a..5acafbe 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -554,6 +554,13 @@
}
}
+ cc_library {
+ name: "libclang_rt.hwasan-llndk",
+ llndk: {
+ symbol_file: "libclang_rt.hwasan.map.txt",
+ }
+ }
+
cc_library_headers {
name: "libllndk_headers",
llndk: {
@@ -661,7 +668,7 @@
"VNDK-product: libvndk_product.so",
"VNDK-product: libvndk_sp_product_private-x.so",
})
- checkVndkLibrariesOutput(t, ctx, "llndk.libraries.txt", []string{"libc.so", "libdl.so", "libft2.so", "libllndk.so", "libm.so"})
+ checkVndkLibrariesOutput(t, ctx, "llndk.libraries.txt", []string{"libc.so", "libclang_rt.hwasan-llndk.so", "libdl.so", "libft2.so", "libllndk.so", "libm.so"})
checkVndkLibrariesOutput(t, ctx, "vndkcore.libraries.txt", []string{"libvndk-private.so", "libvndk.so", "libvndk_product.so"})
checkVndkLibrariesOutput(t, ctx, "vndksp.libraries.txt", []string{"libc++.so", "libvndk_sp-x.so", "libvndk_sp_private-x.so", "libvndk_sp_product_private-x.so"})
checkVndkLibrariesOutput(t, ctx, "vndkprivate.libraries.txt", []string{"libft2.so", "libvndk-private.so", "libvndk_sp_private-x.so", "libvndk_sp_product_private-x.so"})
diff --git a/cc/object.go b/cc/object.go
index d8f1aba..704cb69 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -116,7 +116,7 @@
Hdrs bazel.LabelListAttribute
Deps bazel.LabelListAttribute
Copts bazel.StringListAttribute
- Asflags []string
+ Asflags bazel.StringListAttribute
}
type bazelObject struct {
@@ -157,7 +157,7 @@
// Set arch-specific configurable attributes
compilerAttrs := bp2BuildParseCompilerProps(ctx, m)
- var asFlags []string
+ var asFlags bazel.StringListAttribute
var deps bazel.LabelListAttribute
for _, props := range m.linker.linkerProps() {
@@ -176,10 +176,11 @@
ctx.ModuleErrorf("Could not convert product variable asflag property")
return
}
- // TODO(b/183595873) handle other product variable usages -- as selects?
- if newFlags, subbed := bazel.TryVariableSubstitutions(flags, prop.ProductConfigVariable); subbed {
- asFlags = append(asFlags, newFlags...)
- }
+ newFlags, _ := bazel.TryVariableSubstitutions(flags, prop.ProductConfigVariable)
+ asFlags.ProductValues = append(asFlags.ProductValues, bazel.ProductVariableValues{
+ ProductVariable: prop.ProductConfigVariable,
+ Values: newFlags,
+ })
}
}
// TODO(b/183595872) warn/error if we're not handling product variables
diff --git a/cc/vndk.go b/cc/vndk.go
index 0254edc..6a56c34 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -234,7 +234,6 @@
var (
llndkLibraries = vndkModuleLister(func(m *Module) bool { return m.VendorProperties.IsLLNDK && !m.Header() })
- llndkLibrariesWithoutHWASAN = vndkModuleListRemover(llndkLibraries, "libclang_rt.hwasan-")
vndkSPLibraries = vndkModuleLister(func(m *Module) bool { return m.VendorProperties.IsVNDKSP })
vndkCoreLibraries = vndkModuleLister(func(m *Module) bool { return m.VendorProperties.IsVNDKCore })
vndkPrivateLibraries = vndkModuleLister(func(m *Module) bool { return m.VendorProperties.IsVNDKPrivate })
@@ -419,10 +418,6 @@
}
func RegisterVndkLibraryTxtTypes(ctx android.RegistrationContext) {
- // Make uses LLNDK_LIBRARIES to determine which libraries to install.
- // HWASAN is only part of the LL-NDK in builds in which libc depends on HWASAN.
- // Therefore, by removing the library here, we cause it to only be installed if libc
- // depends on it.
ctx.RegisterSingletonModuleType("llndk_libraries_txt", llndkLibrariesTxtFactory)
ctx.RegisterSingletonModuleType("vndksp_libraries_txt", vndkSPLibrariesTxtFactory)
ctx.RegisterSingletonModuleType("vndkcore_libraries_txt", vndkCoreLibrariesTxtFactory)
@@ -434,8 +429,9 @@
type vndkLibrariesTxt struct {
android.SingletonModuleBase
- lister moduleListerFunc
- makeVarName string
+ lister moduleListerFunc
+ makeVarName string
+ filterOutFromMakeVar string
properties VndkLibrariesTxtProperties
@@ -454,8 +450,12 @@
// llndk_libraries_txt is a singleton module whose content is a list of LLNDK libraries
// generated by Soong but can be referenced by other modules.
// For example, apex_vndk can depend on these files as prebuilt.
+// Make uses LLNDK_LIBRARIES to determine which libraries to install.
+// HWASAN is only part of the LL-NDK in builds in which libc depends on HWASAN.
+// Therefore, by removing the library here, we cause it to only be installed if libc
+// depends on it.
func llndkLibrariesTxtFactory() android.SingletonModule {
- return newVndkLibrariesTxt(llndkLibrariesWithoutHWASAN, "LLNDK_LIBRARIES")
+ return newVndkLibrariesWithMakeVarFilter(llndkLibraries, "LLNDK_LIBRARIES", "libclang_rt.hwasan-")
}
// vndksp_libraries_txt is a singleton module whose content is a list of VNDKSP libraries
@@ -493,16 +493,21 @@
return newVndkLibrariesTxt(vndkUsingCoreVariantLibraries, "VNDK_USING_CORE_VARIANT_LIBRARIES")
}
-func newVndkLibrariesTxt(lister moduleListerFunc, makeVarName string) android.SingletonModule {
+func newVndkLibrariesWithMakeVarFilter(lister moduleListerFunc, makeVarName string, filter string) android.SingletonModule {
m := &vndkLibrariesTxt{
- lister: lister,
- makeVarName: makeVarName,
+ lister: lister,
+ makeVarName: makeVarName,
+ filterOutFromMakeVar: filter,
}
m.AddProperties(&m.properties)
android.InitAndroidModule(m)
return m
}
+func newVndkLibrariesTxt(lister moduleListerFunc, makeVarName string) android.SingletonModule {
+ return newVndkLibrariesWithMakeVarFilter(lister, makeVarName, "")
+}
+
func insertVndkVersion(filename string, vndkVersion string) string {
if index := strings.LastIndex(filename, "."); index != -1 {
return filename[:index] + "." + vndkVersion + filename[index:]
@@ -542,8 +547,21 @@
}
func (txt *vndkLibrariesTxt) MakeVars(ctx android.MakeVarsContext) {
- ctx.Strict(txt.makeVarName, strings.Join(txt.moduleNames, " "))
-
+ filter := func(modules []string, prefix string) []string {
+ if prefix == "" {
+ return modules
+ }
+ var result []string
+ for _, module := range modules {
+ if strings.HasPrefix(module, prefix) {
+ continue
+ } else {
+ result = append(result, module)
+ }
+ }
+ return result
+ }
+ ctx.Strict(txt.makeVarName, strings.Join(filter(txt.moduleNames, txt.filterOutFromMakeVar), " "))
}
// PrebuiltEtcModule interface
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 70c8856..7abb67f 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -175,6 +175,9 @@
writeFakeNinjaFile(extraNinjaDeps, configuration.BuildDir())
}
+// doChosenActivity runs Soong for a specific activity, like bp2build, queryview
+// or the actual Soong build for the build.ninja file. Returns the top level
+// output file of the specific activity.
func doChosenActivity(configuration android.Config, extraNinjaDeps []string) string {
bazelConversionRequested := bp2buildMarker != ""
mixedModeBuild := configuration.BazelContext.BazelEnabled()
@@ -187,11 +190,7 @@
// Run the alternate pipeline of bp2build mutators and singleton to convert
// Blueprint to BUILD files before everything else.
runBp2Build(configuration, extraNinjaDeps)
- if bp2buildMarker != "" {
- return bp2buildMarker
- } else {
- return bootstrap.CmdlineArgs.OutFile
- }
+ return bp2buildMarker
}
ctx := newContext(configuration, prepareBuildActions)
@@ -327,13 +326,13 @@
ninjaFileName := "build.ninja"
ninjaFile := shared.JoinPath(topDir, buildDir, ninjaFileName)
- ninjaFileD := shared.JoinPath(topDir, buildDir, ninjaFileName)
+ ninjaFileD := shared.JoinPath(topDir, buildDir, ninjaFileName+".d")
// A workaround to create the 'nothing' ninja target so `m nothing` works,
// since bp2build runs without Kati, and the 'nothing' target is declared in
// a Makefile.
ioutil.WriteFile(ninjaFile, []byte("build nothing: phony\n phony_output = true\n"), 0666)
ioutil.WriteFile(ninjaFileD,
- []byte(fmt.Sprintf("%s: \\\n %s\n", ninjaFileName, extraNinjaDepsString)),
+ []byte(fmt.Sprintf("%s: \\\n %s\n", ninjaFile, extraNinjaDepsString)),
0666)
}
@@ -520,9 +519,14 @@
os.Exit(1)
}
- if bp2buildMarker != "" {
- touch(shared.JoinPath(topDir, bp2buildMarker))
- } else {
- writeFakeNinjaFile(extraNinjaDeps, codegenContext.Config().BuildDir())
- }
+ // Create an empty bp2build marker file.
+ touch(shared.JoinPath(topDir, bp2buildMarker))
+
+ // bp2build *always* writes a fake Ninja file containing just the nothing
+ // phony target if it ever re-runs. This allows bp2build to exit early with
+ // GENERATE_BAZEL_FILES=1 m nothing.
+ //
+ // If bp2build is invoked as part of an integrated mixed build, the fake
+ // build.ninja file will be rewritten later into the real file anyway.
+ writeFakeNinjaFile(extraNinjaDeps, codegenContext.Config().BuildDir())
}
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index db49df8..188d362 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -168,61 +168,70 @@
// necessary.
func bootclasspathFragmentInitContentsFromImage(ctx android.EarlyModuleContext, m *BootclasspathFragmentModule) {
contents := m.properties.Contents
- if m.properties.Image_name == nil && len(contents) == 0 {
- ctx.ModuleErrorf(`neither of the "image_name" and "contents" properties have been supplied, please supply exactly one`)
+ if len(contents) == 0 {
+ ctx.PropertyErrorf("contents", "required property is missing")
+ return
+ }
+
+ if m.properties.Image_name == nil {
+ // Nothing to do.
+ return
}
imageName := proptools.String(m.properties.Image_name)
- if imageName == "art" {
- // TODO(b/177892522): Prebuilts (versioned or not) should not use the image_name property.
- if android.IsModuleInVersionedSdk(m) {
- // The module is a versioned prebuilt so ignore it. This is done for a couple of reasons:
- // 1. There is no way to use this at the moment so ignoring it is safe.
- // 2. Attempting to initialize the contents property from the configuration will end up having
- // the versioned prebuilt depending on the unversioned prebuilt. That will cause problems
- // as the unversioned prebuilt could end up with an APEX variant created for the source
- // APEX which will prevent it from having an APEX variant for the prebuilt APEX which in
- // turn will prevent it from accessing the dex implementation jar from that which will
- // break hidden API processing, amongst others.
- return
- }
-
- // Get the configuration for the art apex jars. Do not use getImageConfig(ctx) here as this is
- // too early in the Soong processing for that to work.
- global := dexpreopt.GetGlobalConfig(ctx)
- modules := global.ArtApexJars
-
- // Make sure that the apex specified in the configuration is consistent and is one for which
- // this boot image is available.
- commonApex := ""
- for i := 0; i < modules.Len(); i++ {
- apex := modules.Apex(i)
- jar := modules.Jar(i)
- if apex == "platform" {
- ctx.ModuleErrorf("ArtApexJars is invalid as it requests a platform variant of %q", jar)
- continue
- }
- if !m.AvailableFor(apex) {
- ctx.ModuleErrorf("ArtApexJars configuration incompatible with this module, ArtApexJars expects this to be in apex %q but this is only in apexes %q",
- apex, m.ApexAvailable())
- continue
- }
- if commonApex == "" {
- commonApex = apex
- } else if commonApex != apex {
- ctx.ModuleErrorf("ArtApexJars configuration is inconsistent, expected all jars to be in the same apex but it specifies apex %q and %q",
- commonApex, apex)
- }
- }
-
- if len(contents) != 0 {
- // Nothing to do.
- return
- }
-
- // Store the jars in the Contents property so that they can be used to add dependencies.
- m.properties.Contents = modules.CopyOfJars()
+ if imageName != "art" {
+ ctx.PropertyErrorf("image_name", `unknown image name %q, expected "art"`, imageName)
+ return
}
+
+ // TODO(b/177892522): Prebuilts (versioned or not) should not use the image_name property.
+ if android.IsModuleInVersionedSdk(m) {
+ // The module is a versioned prebuilt so ignore it. This is done for a couple of reasons:
+ // 1. There is no way to use this at the moment so ignoring it is safe.
+ // 2. Attempting to initialize the contents property from the configuration will end up having
+ // the versioned prebuilt depending on the unversioned prebuilt. That will cause problems
+ // as the unversioned prebuilt could end up with an APEX variant created for the source
+ // APEX which will prevent it from having an APEX variant for the prebuilt APEX which in
+ // turn will prevent it from accessing the dex implementation jar from that which will
+ // break hidden API processing, amongst others.
+ return
+ }
+
+ // Get the configuration for the art apex jars. Do not use getImageConfig(ctx) here as this is
+ // too early in the Soong processing for that to work.
+ global := dexpreopt.GetGlobalConfig(ctx)
+ modules := global.ArtApexJars
+
+ // Make sure that the apex specified in the configuration is consistent and is one for which
+ // this boot image is available.
+ commonApex := ""
+ for i := 0; i < modules.Len(); i++ {
+ apex := modules.Apex(i)
+ jar := modules.Jar(i)
+ if apex == "platform" {
+ ctx.ModuleErrorf("ArtApexJars is invalid as it requests a platform variant of %q", jar)
+ continue
+ }
+ if !m.AvailableFor(apex) {
+ ctx.ModuleErrorf("ArtApexJars configuration incompatible with this module, ArtApexJars expects this to be in apex %q but this is only in apexes %q",
+ apex, m.ApexAvailable())
+ continue
+ }
+ if commonApex == "" {
+ commonApex = apex
+ } else if commonApex != apex {
+ ctx.ModuleErrorf("ArtApexJars configuration is inconsistent, expected all jars to be in the same apex but it specifies apex %q and %q",
+ commonApex, apex)
+ }
+ }
+
+ if len(contents) != 0 {
+ // Nothing to do.
+ return
+ }
+
+ // Store the jars in the Contents property so that they can be used to add dependencies.
+ m.properties.Contents = modules.CopyOfJars()
}
// bootclasspathImageNameContentsConsistencyCheck checks that the configuration that applies to this
@@ -270,11 +279,12 @@
// BootclasspathFragmentApexContentInfo contains the bootclasspath_fragments contributions to the
// apex contents.
type BootclasspathFragmentApexContentInfo struct {
- // The image config, internal to this module (and the dex_bootjars singleton).
- //
- // Will be nil if the BootclasspathFragmentApexContentInfo has not been provided for a specific module. That can occur
- // when SkipDexpreoptBootJars(ctx) returns true.
- imageConfig *bootImageConfig
+ // The configured modules, will be empty if this is from a bootclasspath_fragment that does not
+ // set image_name: "art".
+ modules android.ConfiguredJarList
+
+ // Map from arch type to the boot image files.
+ bootImageFilesByArch map[android.ArchType]android.OutputPaths
// Map from the name of the context module (as returned by Name()) to the hidden API encoded dex
// jar path.
@@ -282,24 +292,14 @@
}
func (i BootclasspathFragmentApexContentInfo) Modules() android.ConfiguredJarList {
- return i.imageConfig.modules
+ return i.modules
}
// Get a map from ArchType to the associated boot image's contents for Android.
//
// Extension boot images only return their own files, not the files of the boot images they extend.
func (i BootclasspathFragmentApexContentInfo) AndroidBootImageFilesByArchType() map[android.ArchType]android.OutputPaths {
- files := map[android.ArchType]android.OutputPaths{}
- if i.imageConfig != nil {
- for _, variant := range i.imageConfig.variants {
- // We also generate boot images for host (for testing), but we don't need those in the apex.
- // TODO(b/177892522) - consider changing this to check Os.OsClass = android.Device
- if variant.target.Os == android.Android {
- files[variant.target.Arch.ArchType] = variant.imagesDeps
- }
- }
- }
- return files
+ return i.bootImageFilesByArch
}
// DexBootJarPathForContentModule returns the path to the dex boot jar for specified module.
@@ -412,20 +412,33 @@
// modules.
func (b *BootclasspathFragmentModule) provideApexContentInfo(ctx android.ModuleContext, imageConfig *bootImageConfig, contents []android.Module, hiddenAPIFlagOutput *HiddenAPIFlagOutput) {
// Construct the apex content info from the config.
- info := BootclasspathFragmentApexContentInfo{
- imageConfig: imageConfig,
- }
+ info := BootclasspathFragmentApexContentInfo{}
// Populate the apex content info with paths to the dex jars.
b.populateApexContentInfoDexJars(ctx, &info, contents, hiddenAPIFlagOutput)
- if !SkipDexpreoptBootJars(ctx) {
- // Force the GlobalSoongConfig to be created and cached for use by the dex_bootjars
- // GenerateSingletonBuildActions method as it cannot create it for itself.
- dexpreopt.GetGlobalSoongConfig(ctx)
+ if imageConfig != nil {
+ info.modules = imageConfig.modules
- // Only generate the boot image if the configuration does not skip it.
- b.generateBootImageBuildActions(ctx, contents)
+ if !SkipDexpreoptBootJars(ctx) {
+ // Force the GlobalSoongConfig to be created and cached for use by the dex_bootjars
+ // GenerateSingletonBuildActions method as it cannot create it for itself.
+ dexpreopt.GetGlobalSoongConfig(ctx)
+
+ // Only generate the boot image if the configuration does not skip it.
+ if b.generateBootImageBuildActions(ctx, contents, imageConfig) {
+ // Allow the apex to access the boot image files.
+ files := map[android.ArchType]android.OutputPaths{}
+ for _, variant := range imageConfig.variants {
+ // We also generate boot images for host (for testing), but we don't need those in the apex.
+ // TODO(b/177892522) - consider changing this to check Os.OsClass = android.Device
+ if variant.target.Os == android.Android {
+ files[variant.target.Arch.ArchType] = variant.imagesDeps
+ }
+ }
+ info.bootImageFilesByArch = files
+ }
+ }
}
// Make the apex content info available for other modules.
@@ -589,32 +602,23 @@
// generateBootImageBuildActions generates ninja rules to create the boot image if required for this
// module.
-func (b *BootclasspathFragmentModule) generateBootImageBuildActions(ctx android.ModuleContext, contents []android.Module) {
+//
+// Returns true if the boot image is created, false otherwise.
+func (b *BootclasspathFragmentModule) generateBootImageBuildActions(ctx android.ModuleContext, contents []android.Module, imageConfig *bootImageConfig) bool {
global := dexpreopt.GetGlobalConfig(ctx)
if !shouldBuildBootImages(ctx.Config(), global) {
- return
- }
-
- // Bootclasspath fragment modules that are not preferred do not produce a boot image.
- if !isActiveModule(ctx.Module()) {
- return
- }
-
- // Bootclasspath fragment modules that have no image_name property do not produce a boot image.
- imageConfig := b.getImageConfig(ctx)
- if imageConfig == nil {
- return
+ return false
}
// Bootclasspath fragment modules that are for the platform do not produce a boot image.
apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
if apexInfo.IsForPlatform() {
- return
+ return false
}
// Bootclasspath fragment modules that are versioned do not produce a boot image.
if android.IsModuleInVersionedSdk(ctx.Module()) {
- return
+ return false
}
// Copy the dex jars of this fragment's content modules to their predefined locations.
@@ -623,6 +627,8 @@
// Build a profile for the image config and then use that to build the boot image.
profile := bootImageProfileRule(ctx, imageConfig)
buildBootImage(ctx, imageConfig, profile)
+
+ return true
}
type bootclasspathFragmentMemberType struct {
diff --git a/java/bootclasspath_fragment_test.go b/java/bootclasspath_fragment_test.go
index 581625d..fba7d1a 100644
--- a/java/bootclasspath_fragment_test.go
+++ b/java/bootclasspath_fragment_test.go
@@ -29,38 +29,28 @@
dexpreopt.PrepareForTestByEnablingDexpreopt,
)
-func TestUnknownBootclasspathFragment(t *testing.T) {
+func TestBootclasspathFragment_UnknownImageName(t *testing.T) {
prepareForTestWithBootclasspathFragment.
ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
- `\Qimage_name: Unknown image name "unknown", expected one of art, boot\E`)).
+ `\Qimage_name: unknown image name "unknown", expected "art"\E`)).
RunTestWithBp(t, `
bootclasspath_fragment {
name: "unknown-bootclasspath-fragment",
image_name: "unknown",
+ contents: ["foo"],
}
`)
}
-func TestUnknownBootclasspathFragmentImageName(t *testing.T) {
+func TestPrebuiltBootclasspathFragment_UnknownImageName(t *testing.T) {
prepareForTestWithBootclasspathFragment.
ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
- `\Qimage_name: Unknown image name "unknown", expected one of art, boot\E`)).
- RunTestWithBp(t, `
- bootclasspath_fragment {
- name: "unknown-bootclasspath-fragment",
- image_name: "unknown",
- }
- `)
-}
-
-func TestUnknownPrebuiltBootclasspathFragment(t *testing.T) {
- prepareForTestWithBootclasspathFragment.
- ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
- `\Qimage_name: Unknown image name "unknown", expected one of art, boot\E`)).
+ `\Qimage_name: unknown image name "unknown", expected "art"\E`)).
RunTestWithBp(t, `
prebuilt_bootclasspath_fragment {
name: "unknown-bootclasspath-fragment",
image_name: "unknown",
+ contents: ["foo"],
}
`)
}
@@ -76,6 +66,7 @@
bootclasspath_fragment {
name: "bootclasspath-fragment",
image_name: "art",
+ contents: ["foo", "bar"],
apex_available: [
"apex",
],
@@ -94,6 +85,7 @@
bootclasspath_fragment {
name: "bootclasspath-fragment",
image_name: "art",
+ contents: ["foo", "bar"],
apex_available: [
"apex1",
"apex2",
@@ -102,17 +94,6 @@
`)
}
-func TestBootclasspathFragmentWithoutImageNameOrContents(t *testing.T) {
- prepareForTestWithBootclasspathFragment.
- ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
- `\Qneither of the "image_name" and "contents" properties\E`)).
- RunTestWithBp(t, `
- bootclasspath_fragment {
- name: "bootclasspath-fragment",
- }
- `)
-}
-
func TestBootclasspathFragment_Coverage(t *testing.T) {
prepareForTestWithFrameworkCoverage := android.FixtureMergeEnv(map[string]string{
"EMMA_INSTRUMENT": "true",
diff --git a/java/classpath_fragment.go b/java/classpath_fragment.go
index bc0416a..0e14d24 100644
--- a/java/classpath_fragment.go
+++ b/java/classpath_fragment.go
@@ -105,7 +105,7 @@
}
func (c *ClasspathFragmentBase) generateClasspathProtoBuildActions(ctx android.ModuleContext, jars []classpathJar) {
- outputFilename := ctx.ModuleName() + ".pb"
+ outputFilename := strings.ToLower(c.classpathType.String()) + ".pb"
c.outputFilepath = android.PathForModuleOut(ctx, outputFilename).OutputPath
c.installDirPath = android.PathForModuleInstall(ctx, "etc", "classpaths")
diff --git a/java/droidstubs.go b/java/droidstubs.go
index 566f7e3..9531056 100644
--- a/java/droidstubs.go
+++ b/java/droidstubs.go
@@ -546,7 +546,8 @@
`\n` +
`If it is not possible to do so, there are workarounds:\n` +
`\n` +
- `1. You can suppress the errors with @SuppressLint("<id>")\n`
+ `1. You can suppress the errors with @SuppressLint("<id>")\n` +
+ ` where the <id> is given in brackets in the error message above.\n`
if baselineFile.Valid() {
cmd.FlagWithInput("--baseline:api-lint ", baselineFile.Path())
diff --git a/java/platform_bootclasspath_test.go b/java/platform_bootclasspath_test.go
index d332f63..ed5549d 100644
--- a/java/platform_bootclasspath_test.go
+++ b/java/platform_bootclasspath_test.go
@@ -287,7 +287,7 @@
).RunTest(t)
p := result.Module("platform-bootclasspath", "android_common").(*platformBootclasspathModule)
- android.AssertStringEquals(t, "output filepath", p.Name()+".pb", p.ClasspathFragmentBase.outputFilepath.Base())
+ android.AssertStringEquals(t, "output filepath", "bootclasspath.pb", p.ClasspathFragmentBase.outputFilepath.Base())
android.AssertPathRelativeToTopEquals(t, "install filepath", "out/soong/target/product/test_device/system/etc/classpaths", p.ClasspathFragmentBase.installDirPath)
}
@@ -327,7 +327,7 @@
want := map[string][]string{
"LOCAL_MODULE": {"platform-bootclasspath"},
"LOCAL_MODULE_CLASS": {"ETC"},
- "LOCAL_INSTALLED_MODULE_STEM": {"platform-bootclasspath.pb"},
+ "LOCAL_INSTALLED_MODULE_STEM": {"bootclasspath.pb"},
// Output and Install paths are tested separately in TestPlatformBootclasspath_ClasspathFragmentPaths
}
diff --git a/java/systemserver_classpath_fragment.go b/java/systemserver_classpath_fragment.go
index a72b3f6..9111c30 100644
--- a/java/systemserver_classpath_fragment.go
+++ b/java/systemserver_classpath_fragment.go
@@ -53,13 +53,7 @@
func (p *platformSystemServerClasspathModule) ClasspathFragmentToConfiguredJarList(ctx android.ModuleContext) android.ConfiguredJarList {
global := dexpreopt.GetGlobalConfig(ctx)
-
- jars := global.SystemServerJars
- // TODO(satayev): split apex jars into separate configs.
- for i := 0; i < global.UpdatableSystemServerJars.Len(); i++ {
- jars = jars.Append(global.UpdatableSystemServerJars.Apex(i), global.UpdatableSystemServerJars.Jar(i))
- }
- return jars
+ return global.SystemServerJars
}
type SystemServerClasspathModule struct {
@@ -101,8 +95,12 @@
}
func (s *SystemServerClasspathModule) ClasspathFragmentToConfiguredJarList(ctx android.ModuleContext) android.ConfiguredJarList {
- // TODO(satayev): populate with actual content
- return android.EmptyConfiguredJarList()
+ global := dexpreopt.GetGlobalConfig(ctx)
+
+ // Only create configs for updatable boot jars. Non-updatable system server jars must be part of the
+ // platform_systemserverclasspath's classpath proto config to guarantee that they come before any
+ // updatable jars at runtime.
+ return global.UpdatableSystemServerJars.Filter(s.properties.Contents)
}
type systemServerClasspathFragmentContentDependencyTag struct {
diff --git a/java/systemserver_classpath_fragment_test.go b/java/systemserver_classpath_fragment_test.go
index 5272f27..9ad50dd 100644
--- a/java/systemserver_classpath_fragment_test.go
+++ b/java/systemserver_classpath_fragment_test.go
@@ -24,7 +24,7 @@
PrepareForTestWithJavaDefaultModules,
)
-func TestPlatformSystemserverClasspathVariant(t *testing.T) {
+func TestPlatformSystemServerClasspathVariant(t *testing.T) {
result := android.GroupFixturePreparers(
prepareForTestWithSystemServerClasspath,
android.FixtureWithRootAndroidBp(`
@@ -38,7 +38,7 @@
android.AssertIntEquals(t, "expect 1 variant", 1, len(variants))
}
-func TestPlatformSystemserverClasspath_ClasspathFragmentPaths(t *testing.T) {
+func TestPlatformSystemServerClasspath_ClasspathFragmentPaths(t *testing.T) {
result := android.GroupFixturePreparers(
prepareForTestWithSystemServerClasspath,
android.FixtureWithRootAndroidBp(`
@@ -49,11 +49,11 @@
).RunTest(t)
p := result.Module("platform-systemserverclasspath", "android_common").(*platformSystemServerClasspathModule)
- android.AssertStringEquals(t, "output filepath", p.Name()+".pb", p.ClasspathFragmentBase.outputFilepath.Base())
+ android.AssertStringEquals(t, "output filepath", "systemserverclasspath.pb", p.ClasspathFragmentBase.outputFilepath.Base())
android.AssertPathRelativeToTopEquals(t, "install filepath", "out/soong/target/product/test_device/system/etc/classpaths", p.ClasspathFragmentBase.installDirPath)
}
-func TestPlatformSystemserverClasspathModule_AndroidMkEntries(t *testing.T) {
+func TestPlatformSystemServerClasspathModule_AndroidMkEntries(t *testing.T) {
preparer := android.GroupFixturePreparers(
prepareForTestWithSystemServerClasspath,
android.FixtureWithRootAndroidBp(`
@@ -78,8 +78,8 @@
want := map[string][]string{
"LOCAL_MODULE": {"platform-systemserverclasspath"},
"LOCAL_MODULE_CLASS": {"ETC"},
- "LOCAL_INSTALLED_MODULE_STEM": {"platform-systemserverclasspath.pb"},
- // Output and Install paths are tested separately in TestSystemserverClasspath_ClasspathFragmentPaths
+ "LOCAL_INSTALLED_MODULE_STEM": {"systemserverclasspath.pb"},
+ // Output and Install paths are tested separately in TestPlatformSystemServerClasspath_ClasspathFragmentPaths
}
p := result.Module("platform-systemserverclasspath", "android_common").(*platformSystemServerClasspathModule)
@@ -96,7 +96,7 @@
})
}
-func TestSystemserverclasspathFragmentWithoutContents(t *testing.T) {
+func TestSystemServerClasspathFragmentWithoutContents(t *testing.T) {
prepareForTestWithSystemServerClasspath.
ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
`\Qempty contents are not allowed\E`)).
diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go
index bd69f06..d9fe281 100644
--- a/sdk/bootclasspath_fragment_sdk_test.go
+++ b/sdk/bootclasspath_fragment_sdk_test.go
@@ -424,6 +424,7 @@
android.GroupFixturePreparers(
prepareForSdkTestWithApex,
prepareForSdkTestWithJava,
+ android.FixtureAddFile("java/mybootlib.jar", nil),
android.FixtureWithRootAndroidBp(`
sdk {
name: "mysdk",
@@ -433,16 +434,27 @@
bootclasspath_fragment {
name: "mybootclasspathfragment",
image_name: "art",
+ contents: ["mybootlib"],
apex_available: ["myapex"],
}
+ java_library {
+ name: "mybootlib",
+ apex_available: ["myapex"],
+ srcs: ["Test.java"],
+ system_modules: "none",
+ sdk_version: "none",
+ min_sdk_version: "1",
+ compile_dex: true,
+ }
+
sdk_snapshot {
name: "mysdk@1",
- bootclasspath_fragments: ["mybootclasspathfragment_mysdk_1"],
+ bootclasspath_fragments: ["mysdk_mybootclasspathfragment@1"],
}
prebuilt_bootclasspath_fragment {
- name: "mybootclasspathfragment_mysdk_1",
+ name: "mysdk_mybootclasspathfragment@1",
sdk_member_name: "mybootclasspathfragment",
prefer: false,
visibility: ["//visibility:public"],
@@ -450,6 +462,15 @@
"myapex",
],
image_name: "art",
+ contents: ["mysdk_mybootlib@1"],
+ }
+
+ java_import {
+ name: "mysdk_mybootlib@1",
+ sdk_member_name: "mybootlib",
+ visibility: ["//visibility:public"],
+ apex_available: ["com.android.art"],
+ jars: ["java/mybootlib.jar"],
}
`),
).RunTest(t)
diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go
index 12545d6..a13b0d7 100644
--- a/sdk/sdk_test.go
+++ b/sdk/sdk_test.go
@@ -564,4 +564,101 @@
`),
)
})
+
+ t.Run("SOONG_SDK_SNAPSHOT_VERSION=unversioned", func(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ preparer,
+ android.FixtureMergeEnv(map[string]string{
+ "SOONG_SDK_SNAPSHOT_VERSION": "unversioned",
+ }),
+ ).RunTest(t)
+
+ checkZipFile(t, result, "out/soong/.intermediates/mysdk/common_os/mysdk.zip")
+
+ CheckSnapshot(t, result, "mysdk", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+java_import {
+ name: "myjavalib",
+ prefer: false,
+ visibility: ["//visibility:public"],
+ apex_available: ["//apex_available:platform"],
+ jars: ["java/myjavalib.jar"],
+}
+ `),
+ )
+ })
+
+ t.Run("SOONG_SDK_SNAPSHOT_VERSION=current", func(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ preparer,
+ android.FixtureMergeEnv(map[string]string{
+ "SOONG_SDK_SNAPSHOT_VERSION": "current",
+ }),
+ ).RunTest(t)
+
+ checkZipFile(t, result, "out/soong/.intermediates/mysdk/common_os/mysdk-current.zip")
+
+ CheckSnapshot(t, result, "mysdk", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+java_import {
+ name: "mysdk_myjavalib@current",
+ sdk_member_name: "myjavalib",
+ visibility: ["//visibility:public"],
+ apex_available: ["//apex_available:platform"],
+ jars: ["java/myjavalib.jar"],
+}
+
+java_import {
+ name: "myjavalib",
+ prefer: false,
+ visibility: ["//visibility:public"],
+ apex_available: ["//apex_available:platform"],
+ jars: ["java/myjavalib.jar"],
+}
+
+sdk_snapshot {
+ name: "mysdk@current",
+ visibility: ["//visibility:public"],
+ java_header_libs: ["mysdk_myjavalib@current"],
+}
+ `),
+ )
+ })
+
+ t.Run("SOONG_SDK_SNAPSHOT_VERSION=2", func(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ preparer,
+ android.FixtureMergeEnv(map[string]string{
+ "SOONG_SDK_SNAPSHOT_VERSION": "2",
+ }),
+ ).RunTest(t)
+
+ checkZipFile(t, result, "out/soong/.intermediates/mysdk/common_os/mysdk-2.zip")
+
+ CheckSnapshot(t, result, "mysdk", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+java_import {
+ name: "mysdk_myjavalib@2",
+ sdk_member_name: "myjavalib",
+ visibility: ["//visibility:public"],
+ apex_available: ["//apex_available:platform"],
+ jars: ["java/myjavalib.jar"],
+}
+
+sdk_snapshot {
+ name: "mysdk@2",
+ visibility: ["//visibility:public"],
+ java_header_libs: ["mysdk_myjavalib@2"],
+}
+ `),
+ // A versioned snapshot cannot be used on its own so add the source back in.
+ snapshotTestPreparer(checkSnapshotWithoutSource, android.FixtureWithRootAndroidBp(bp)),
+ )
+ })
}
diff --git a/sdk/testing.go b/sdk/testing.go
index f4e85c0..3254cf9 100644
--- a/sdk/testing.go
+++ b/sdk/testing.go
@@ -131,6 +131,7 @@
info := &snapshotBuildInfo{
t: t,
r: result,
+ version: sdk.builderForTests.version,
androidBpContents: sdk.GetAndroidBpContentsForTests(),
androidUnversionedBpContents: sdk.GetUnversionedAndroidBpContentsForTests(),
androidVersionedBpContents: sdk.GetVersionedAndroidBpContentsForTests(),
@@ -236,8 +237,13 @@
if dir != "" {
dir = filepath.Clean(dir) + "/"
}
- android.AssertStringEquals(t, "Snapshot zip file in wrong place",
- fmt.Sprintf(".intermediates/%s%s/%s/%s-current.zip", dir, name, variant, name), actual)
+ suffix := ""
+ if snapshotBuildInfo.version != soongSdkSnapshotVersionUnversioned {
+ suffix = "-" + snapshotBuildInfo.version
+ }
+
+ expectedZipPath := fmt.Sprintf(".intermediates/%s%s/%s/%s%s.zip", dir, name, variant, name, suffix)
+ android.AssertStringEquals(t, "Snapshot zip file in wrong place", expectedZipPath, actual)
// Populate a mock filesystem with the files that would have been copied by
// the rules.
@@ -432,6 +438,11 @@
// The result from RunTest()
r *android.TestResult
+ // The version of the generated snapshot.
+ //
+ // See snapshotBuilder.version for more information about this field.
+ version string
+
// The contents of the generated Android.bp file
androidBpContents string
diff --git a/sdk/update.go b/sdk/update.go
index 85dfc4a..36b564f 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -36,6 +36,20 @@
// By default every unversioned module in the generated snapshot has prefer: false. Building it
// with SOONG_SDK_SNAPSHOT_PREFER=true will force them to use prefer: true.
//
+// SOONG_SDK_SNAPSHOT_VERSION
+// This provides control over the version of the generated snapshot.
+//
+// SOONG_SDK_SNAPSHOT_VERSION=current will generate unversioned and versioned prebuilts and a
+// versioned snapshot module. This is the default behavior. The zip file containing the
+// generated snapshot will be <sdk-name>-current.zip.
+//
+// SOONG_SDK_SNAPSHOT_VERSION=unversioned will generate unversioned prebuilts only and the zip
+// file containing the generated snapshot will be <sdk-name>.zip.
+//
+// SOONG_SDK_SNAPSHOT_VERSION=<number> will generate versioned prebuilts and a versioned
+// snapshot module only. The zip file containing the generated snapshot will be
+// <sdk-name>-<number>.zip.
+//
var pctx = android.NewPackageContext("android/soong/sdk")
@@ -69,6 +83,11 @@
})
)
+const (
+ soongSdkSnapshotVersionUnversioned = "unversioned"
+ soongSdkSnapshotVersionCurrent = "current"
+)
+
type generatedContents struct {
content strings.Builder
indentLevel int
@@ -257,10 +276,26 @@
modules: make(map[string]*bpModule),
}
+ config := ctx.Config()
+ version := config.GetenvWithDefault("SOONG_SDK_SNAPSHOT_VERSION", "current")
+
+ // Generate versioned modules in the snapshot unless an unversioned snapshot has been requested.
+ generateVersioned := version != soongSdkSnapshotVersionUnversioned
+
+ // Generate unversioned modules in the snapshot unless a numbered snapshot has been requested.
+ //
+ // Unversioned modules are not required in that case because the numbered version will be a
+ // finalized version of the snapshot that is intended to be kept separate from the
+ generateUnversioned := version == soongSdkSnapshotVersionUnversioned || version == soongSdkSnapshotVersionCurrent
+ snapshotZipFileSuffix := ""
+ if generateVersioned {
+ snapshotZipFileSuffix = "-" + version
+ }
+
builder := &snapshotBuilder{
ctx: ctx,
sdk: s,
- version: "current",
+ version: version,
snapshotDir: snapshotDir.OutputPath,
copies: make(map[string]string),
filesToZip: []android.Path{bp.path},
@@ -314,20 +349,26 @@
// Prune any empty property sets.
unversioned = unversioned.transform(pruneEmptySetTransformer{})
- // Copy the unversioned module so it can be modified to make it versioned.
- versioned := unversioned.deepCopy()
+ if generateVersioned {
+ // Copy the unversioned module so it can be modified to make it versioned.
+ versioned := unversioned.deepCopy()
- // Transform the unversioned module into a versioned one.
- versioned.transform(unversionedToVersionedTransformer)
- bpFile.AddModule(versioned)
+ // Transform the unversioned module into a versioned one.
+ versioned.transform(unversionedToVersionedTransformer)
+ bpFile.AddModule(versioned)
+ }
- // Transform the unversioned module to make it suitable for use in the snapshot.
- unversioned.transform(unversionedTransformer)
- bpFile.AddModule(unversioned)
+ if generateUnversioned {
+ // Transform the unversioned module to make it suitable for use in the snapshot.
+ unversioned.transform(unversionedTransformer)
+ bpFile.AddModule(unversioned)
+ }
}
- // Add the sdk/module_exports_snapshot module to the bp file.
- s.addSnapshotModule(ctx, builder, sdkVariants, memberVariantDeps)
+ if generateVersioned {
+ // Add the sdk/module_exports_snapshot module to the bp file.
+ s.addSnapshotModule(ctx, builder, sdkVariants, memberVariantDeps)
+ }
// generate Android.bp
bp = newGeneratedFile(ctx, "snapshot", "Android.bp")
@@ -341,7 +382,8 @@
filesToZip := builder.filesToZip
// zip them all
- outputZipFile := android.PathForModuleOut(ctx, ctx.ModuleName()+"-current.zip").OutputPath
+ zipPath := fmt.Sprintf("%s%s.zip", ctx.ModuleName(), snapshotZipFileSuffix)
+ outputZipFile := android.PathForModuleOut(ctx, zipPath).OutputPath
outputDesc := "Building snapshot for " + ctx.ModuleName()
// If there are no zips to merge then generate the output zip directly.
@@ -353,7 +395,8 @@
zipFile = outputZipFile
desc = outputDesc
} else {
- zipFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"-current.unmerged.zip").OutputPath
+ intermediatePath := fmt.Sprintf("%s%s.unmerged.zip", ctx.ModuleName(), snapshotZipFileSuffix)
+ zipFile = android.PathForModuleOut(ctx, intermediatePath).OutputPath
desc = "Building intermediate snapshot for " + ctx.ModuleName()
}
@@ -801,9 +844,15 @@
}
type snapshotBuilder struct {
- ctx android.ModuleContext
- sdk *sdk
- version string
+ ctx android.ModuleContext
+ sdk *sdk
+
+ // The version of the generated snapshot.
+ //
+ // See the documentation of SOONG_SDK_SNAPSHOT_VERSION above for details of the valid values of
+ // this field.
+ version string
+
snapshotDir android.OutputPath
bpFile *bpFile
diff --git a/sh/sh_binary.go b/sh/sh_binary.go
index 42d5680..4805846 100644
--- a/sh/sh_binary.go
+++ b/sh/sh_binary.go
@@ -104,6 +104,12 @@
Recovery_available *bool
}
+// Test option struct.
+type TestOptions struct {
+ // If the test is a hostside(no device required) unittest that shall be run during presubmit check.
+ Unit_test *bool
+}
+
type TestProperties struct {
// list of compatibility suites (for example "cts", "vts") that the module should be
// installed into.
@@ -143,6 +149,9 @@
// list of device library modules that should be installed alongside the test.
// Only available for host sh_test modules.
Data_device_libs []string `android:"path,arch_variant"`
+
+ // Test options.
+ Test_options TestOptions
}
type ShBinary struct {
@@ -440,6 +449,9 @@
dir := strings.TrimSuffix(s.dataModules[relPath].String(), relPath)
entries.AddStrings("LOCAL_TEST_DATA", dir+":"+relPath)
}
+ if Bool(s.testProperties.Test_options.Unit_test) {
+ entries.SetBool("LOCAL_IS_UNIT_TEST", true)
+ }
},
},
}}
diff --git a/sh/sh_binary_test.go b/sh/sh_binary_test.go
index 9e7e594..20317d8 100644
--- a/sh/sh_binary_test.go
+++ b/sh/sh_binary_test.go
@@ -3,6 +3,7 @@
import (
"os"
"path/filepath"
+ "strconv"
"testing"
"android/soong/android"
@@ -148,6 +149,9 @@
"testdata/data1",
"testdata/sub/data2",
],
+ test_options: {
+ unit_test: true,
+ },
}
`)
@@ -156,6 +160,9 @@
if !mod.Host() {
t.Errorf("host bit is not set for a sh_test_host module.")
}
+ entries := android.AndroidMkEntriesForTest(t, ctx, mod)[0]
+ actualData, _ := strconv.ParseBool(entries.EntryMap["LOCAL_IS_UNIT_TEST"][0])
+ android.AssertBoolEquals(t, "LOCAL_IS_UNIT_TEST", true, actualData)
}
func TestShTestHost_dataDeviceModules(t *testing.T) {
diff --git a/tests/bootstrap_test.sh b/tests/bootstrap_test.sh
index 42363e9..8c8dc82 100755
--- a/tests/bootstrap_test.sh
+++ b/tests/bootstrap_test.sh
@@ -493,6 +493,21 @@
[[ -e out/soong/workspace ]] || fail "Bazel workspace not created"
}
+function test_bp2build_generates_fake_ninja_file {
+ setup
+ create_mock_bazel
+
+ run_bp2build
+
+ if [[ ! -f "./out/soong/build.ninja" ]]; then
+ fail "./out/soong/build.ninja was not generated"
+ fi
+
+ if ! grep "build nothing: phony" "./out/soong/build.ninja"; then
+ fail "missing phony nothing target in out/soong/build.ninja"
+ fi
+}
+
function test_bp2build_add_android_bp {
setup
@@ -678,6 +693,7 @@
test_soong_build_rerun_iff_environment_changes
test_dump_json_module_graph
test_bp2build_smoke
+test_bp2build_generates_fake_ninja_file
test_bp2build_null_build
test_bp2build_add_android_bp
test_bp2build_add_to_glob
diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go
index fe0aca9..54aeda0 100644
--- a/ui/build/dumpvars.go
+++ b/ui/build/dumpvars.go
@@ -162,6 +162,8 @@
"OUT_DIR",
"AUX_OS_VARIANT_LIST",
"PRODUCT_SOONG_NAMESPACES",
+ "SOONG_SDK_SNAPSHOT_PREFER",
+ "SOONG_SDK_SNAPSHOT_VERSION",
}
func Banner(make_vars map[string]string) string {
diff --git a/ui/build/soong.go b/ui/build/soong.go
index a41dbe1..cd645eb 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -155,9 +155,9 @@
Outputs: []string{bp2BuildMarkerFile},
Args: bp2buildArgs,
}
- args.PrimaryBuilderInvocations = []bootstrap.PrimaryBuilderInvocation{
- bp2buildInvocation,
- mainSoongBuildInvocation,
+ args.PrimaryBuilderInvocations = []bootstrap.PrimaryBuilderInvocation{bp2buildInvocation}
+ if config.bazelBuildMode() == mixedBuild {
+ args.PrimaryBuilderInvocations = append(args.PrimaryBuilderInvocations, mainSoongBuildInvocation)
}
} else {
args.PrimaryBuilderInvocations = []bootstrap.PrimaryBuilderInvocation{mainSoongBuildInvocation}