Merge "Rename generate proto config file to match classpath type."
diff --git a/android/bazel.go b/android/bazel.go
index 2d4755f..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.
@@ -220,19 +220,16 @@
// Per-module denylist to opt modules out of mixed builds. Such modules will
// still be generated via bp2build.
mixedBuildsDisabledList = []string{
- "libc_bionic_ndk", // cparsons@ cc_library_static, depends on //bionic/libc:libsystemproperties
"libc_common", // cparsons@ cc_library_static, depends on //bionic/libc:libc_nopthread
"libc_common_static", // cparsons@ cc_library_static, depends on //bionic/libc:libc_common
"libc_common_shared", // cparsons@ cc_library_static, depends on //bionic/libc:libc_common
"libc_netbsd", // lberki@, cc_library_static, version script assignment of 'LIBC_PRIVATE' to symbol 'SHA1Final' failed: symbol not defined
- "libc_nopthread", // cparsons@ cc_library_static, depends on //bionic/libc:libc_bionic_ndk
+ "libc_nopthread", // cparsons@ cc_library_static, version script assignment of 'LIBC' to symbol 'memcmp' failed: symbol not defined
"libc_openbsd", // ruperts@, cc_library_static, OK for bp2build but error: duplicate symbol: strcpy for mixed builds
- "libsystemproperties", // cparsons@, cc_library_static, wrong include paths
- "libpropertyinfoparser", // cparsons@, cc_library_static, wrong include paths
"libarm-optimized-routines-string", // jingwen@, cc_library_static, OK for bp2build but b/186615213 (asflags not handled in bp2build), version script assignment of 'LIBC' to symbol 'memcmp' failed: symbol not defined (also for memrchr, strnlen)
"fmtlib_ndk", // http://b/187040371, cc_library_static, OK for bp2build but format-inl.h:11:10: fatal error: 'cassert' file not found for mixed builds
"libc_nomalloc", // cc_library_static, OK for bp2build but ld.lld: error: undefined symbol: pthread_mutex_lock (and others)
- }
+ }
// Used for quicker lookups
bp2buildModuleDoNotConvert = map[string]bool{}
diff --git a/android/defaults.go b/android/defaults.go
index aacfbac..be80cf1 100644
--- a/android/defaults.go
+++ b/android/defaults.go
@@ -104,6 +104,7 @@
EarlyModuleContext
CreateModule(ModuleFactory, ...interface{}) Module
+ AddMissingDependencies(missingDeps []string)
}
type DefaultableHook func(ctx DefaultableHookContext)
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/apex.go b/apex/apex.go
index da4f472..3448327 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -741,20 +741,22 @@
}
}
- // For prebuilt_etc, use the first variant (64 on 64/32bit device, 32 on 32bit device)
- // regardless of the TARGET_PREFER_* setting. See b/144532908
- archForPrebuiltEtc := config.Arches()[0]
- for _, arch := range config.Arches() {
- // Prefer 64-bit arch if there is any
- if arch.ArchType.Multilib == "lib64" {
- archForPrebuiltEtc = arch
- break
+ if prebuilts := a.properties.Prebuilts; len(prebuilts) > 0 {
+ // For prebuilt_etc, use the first variant (64 on 64/32bit device, 32 on 32bit device)
+ // regardless of the TARGET_PREFER_* setting. See b/144532908
+ archForPrebuiltEtc := config.Arches()[0]
+ for _, arch := range config.Arches() {
+ // Prefer 64-bit arch if there is any
+ if arch.ArchType.Multilib == "lib64" {
+ archForPrebuiltEtc = arch
+ break
+ }
}
+ ctx.AddFarVariationDependencies([]blueprint.Variation{
+ {Mutator: "os", Variation: ctx.Os().String()},
+ {Mutator: "arch", Variation: archForPrebuiltEtc.String()},
+ }, prebuiltTag, prebuilts...)
}
- ctx.AddFarVariationDependencies([]blueprint.Variation{
- {Mutator: "os", Variation: ctx.Os().String()},
- {Mutator: "arch", Variation: archForPrebuiltEtc.String()},
- }, prebuiltTag, a.properties.Prebuilts...)
// Common-arch dependencies come next
commonVariation := ctx.Config().AndroidCommonTarget.Variations()
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 68182a7..364013f 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -7589,6 +7589,28 @@
}
}
+func TestHostApexInHostOnlyBuild(t *testing.T) {
+ testApex(t, `
+ apex {
+ name: "myapex",
+ host_supported: true,
+ key: "myapex.key",
+ updatable: false,
+ payload_type: "zip",
+ }
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+ `,
+ android.FixtureModifyConfig(func(config android.Config) {
+ // We may not have device targets in all builds, e.g. in
+ // prebuilts/build-tools/build-prebuilts.sh
+ config.Targets[android.Android] = []android.Target{}
+ }))
+}
+
func TestMain(m *testing.M) {
os.Exit(m.Run())
}
diff --git a/apex/bootclasspath_fragment_test.go b/apex/bootclasspath_fragment_test.go
index 02b4829..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
@@ -141,10 +122,132 @@
`)
}
-func checkBootclasspathFragment(t *testing.T, result *android.TestResult, moduleName string, expectedConfiguredModules string, expectedBootclasspathFragmentFiles string) {
+func TestBootclasspathFragments_FragmentDependency(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForTestWithBootclasspathFragment,
+ // Configure some libraries in the art bootclasspath_fragment and platform_bootclasspath.
+ java.FixtureConfigureBootJars("com.android.art:baz", "com.android.art:quuz", "platform:foo", "platform:bar"),
+ prepareForTestWithArtApex,
+
+ java.PrepareForTestWithJavaSdkLibraryFiles,
+ java.FixtureWithLastReleaseApis("foo", "baz"),
+ ).RunTestWithBp(t, `
+ java_sdk_library {
+ name: "foo",
+ srcs: ["b.java"],
+ shared_library: false,
+ public: {
+ enabled: true,
+ },
+ system: {
+ enabled: true,
+ },
+ }
+
+ java_library {
+ name: "bar",
+ srcs: ["b.java"],
+ installable: true,
+ }
+
+ apex {
+ name: "com.android.art",
+ key: "com.android.art.key",
+ bootclasspath_fragments: ["art-bootclasspath-fragment"],
+ updatable: false,
+ }
+
+ apex_key {
+ name: "com.android.art.key",
+ public_key: "com.android.art.avbpubkey",
+ private_key: "com.android.art.pem",
+ }
+
+ java_sdk_library {
+ name: "baz",
+ apex_available: [
+ "com.android.art",
+ ],
+ srcs: ["b.java"],
+ shared_library: false,
+ public: {
+ enabled: true,
+ },
+ system: {
+ enabled: true,
+ },
+ test: {
+ enabled: true,
+ },
+ }
+
+ java_library {
+ name: "quuz",
+ apex_available: [
+ "com.android.art",
+ ],
+ srcs: ["b.java"],
+ compile_dex: true,
+ }
+
+ bootclasspath_fragment {
+ name: "art-bootclasspath-fragment",
+ image_name: "art",
+ // Must match the "com.android.art:" entries passed to FixtureConfigureBootJars above.
+ contents: ["baz", "quuz"],
+ apex_available: [
+ "com.android.art",
+ ],
+ }
+
+ bootclasspath_fragment {
+ name: "other-bootclasspath-fragment",
+ contents: ["foo", "bar"],
+ fragments: [
+ {
+ apex: "com.android.art",
+ module: "art-bootclasspath-fragment",
+ },
+ ],
+ }
+`,
+ )
+
+ checkSdkKindStubs := func(message string, info java.HiddenAPIInfo, kind android.SdkKind, expectedPaths ...string) {
+ t.Helper()
+ android.AssertPathsRelativeToTopEquals(t, fmt.Sprintf("%s %s", message, kind), expectedPaths, info.TransitiveStubDexJarsByKind[kind])
+ }
+
+ // Check stub dex paths exported by art.
+ artFragment := result.Module("art-bootclasspath-fragment", "android_common")
+ artInfo := result.ModuleProvider(artFragment, java.HiddenAPIInfoProvider).(java.HiddenAPIInfo)
+
+ bazPublicStubs := "out/soong/.intermediates/baz.stubs/android_common/dex/baz.stubs.jar"
+ bazSystemStubs := "out/soong/.intermediates/baz.stubs.system/android_common/dex/baz.stubs.system.jar"
+ bazTestStubs := "out/soong/.intermediates/baz.stubs.test/android_common/dex/baz.stubs.test.jar"
+
+ checkSdkKindStubs("art", artInfo, android.SdkPublic, bazPublicStubs)
+ checkSdkKindStubs("art", artInfo, android.SdkSystem, bazSystemStubs)
+ checkSdkKindStubs("art", artInfo, android.SdkTest, bazTestStubs)
+ checkSdkKindStubs("art", artInfo, android.SdkCorePlatform)
+
+ // Check stub dex paths exported by other.
+ otherFragment := result.Module("other-bootclasspath-fragment", "android_common")
+ otherInfo := result.ModuleProvider(otherFragment, java.HiddenAPIInfoProvider).(java.HiddenAPIInfo)
+
+ fooPublicStubs := "out/soong/.intermediates/foo.stubs/android_common/dex/foo.stubs.jar"
+ fooSystemStubs := "out/soong/.intermediates/foo.stubs.system/android_common/dex/foo.stubs.system.jar"
+
+ checkSdkKindStubs("other", otherInfo, android.SdkPublic, bazPublicStubs, fooPublicStubs)
+ checkSdkKindStubs("other", otherInfo, android.SdkSystem, bazSystemStubs, fooSystemStubs)
+ checkSdkKindStubs("other", otherInfo, android.SdkTest, bazTestStubs, fooSystemStubs)
+ checkSdkKindStubs("other", otherInfo, android.SdkCorePlatform)
+}
+
+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()
@@ -522,8 +625,8 @@
android.AssertStringDoesContain(t, name+" apex copy command", copyCommands, expectedCopyCommand)
}
- checkFragmentExportedDexJar("foo", "out/soong/.intermediates/foo/android_common_apex10000/hiddenapi/foo.jar")
- checkFragmentExportedDexJar("bar", "out/soong/.intermediates/bar/android_common_apex10000/hiddenapi/bar.jar")
+ checkFragmentExportedDexJar("foo", "out/soong/.intermediates/mybootclasspathfragment/android_common_apex10000/hiddenapi-modular/encoded/foo.jar")
+ checkFragmentExportedDexJar("bar", "out/soong/.intermediates/mybootclasspathfragment/android_common_apex10000/hiddenapi-modular/encoded/bar.jar")
}
// TODO(b/177892522) - add test for host apex.
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 a1ffabc..0a72937 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -40,43 +40,98 @@
}`
)
-func TestCcLibraryBp2Build(t *testing.T) {
- testCases := []struct {
- description string
- moduleTypeUnderTest string
- moduleTypeUnderTestFactory android.ModuleFactory
- moduleTypeUnderTestBp2BuildMutator func(android.TopDownMutatorContext)
- bp string
- expectedBazelTargets []string
- filesystem map[string]string
- dir string
- depsMutators []android.RegisterMutatorFunc
- }{
- {
- description: "cc_library - simple example",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
- filesystem: map[string]string{
- "android.cpp": "",
- "darwin.cpp": "",
- // Refer to cc.headerExts for the supported header extensions in Soong.
- "header.h": "",
- "header.hh": "",
- "header.hpp": "",
- "header.hxx": "",
- "header.h++": "",
- "header.inl": "",
- "header.inc": "",
- "header.ipp": "",
- "header.h.generic": "",
- "impl.cpp": "",
- "linux.cpp": "",
- "x86.cpp": "",
- "x86_64.cpp": "",
- "foo-dir/a.h": "",
- },
- bp: soongCcLibraryPreamble + `
+func runCcLibraryTestCase(t *testing.T, tc bp2buildTestCase) {
+ runBp2BuildTestCase(t, registerCcLibraryModuleTypes, tc)
+}
+
+func registerCcLibraryModuleTypes(ctx android.RegistrationContext) {
+ cc.RegisterCCBuildComponents(ctx)
+ ctx.RegisterModuleType("cc_library_static", cc.LibraryStaticFactory)
+ ctx.RegisterModuleType("toolchain_library", cc.ToolchainLibraryFactory)
+ ctx.RegisterModuleType("cc_library_headers", cc.LibraryHeaderFactory)
+}
+
+func runBp2BuildTestCase(t *testing.T, registerModuleTypes func(ctx android.RegistrationContext), tc bp2buildTestCase) {
+ dir := "."
+ filesystem := make(map[string][]byte)
+ toParse := []string{
+ "Android.bp",
+ }
+ for f, content := range tc.filesystem {
+ if strings.HasSuffix(f, "Android.bp") {
+ toParse = append(toParse, f)
+ }
+ filesystem[f] = []byte(content)
+ }
+ config := android.TestConfig(buildDir, nil, tc.blueprint, filesystem)
+ ctx := android.NewTestContext(config)
+
+ registerModuleTypes(ctx)
+ ctx.RegisterModuleType(tc.moduleTypeUnderTest, tc.moduleTypeUnderTestFactory)
+ ctx.RegisterBp2BuildConfig(bp2buildConfig)
+ for _, m := range tc.depsMutators {
+ ctx.DepsBp2BuildMutators(m)
+ }
+ ctx.RegisterBp2BuildMutator(tc.moduleTypeUnderTest, tc.moduleTypeUnderTestBp2BuildMutator)
+ ctx.RegisterForBazelConversion()
+
+ _, errs := ctx.ParseFileList(dir, toParse)
+ if errored(t, tc.description, errs) {
+ return
+ }
+ _, errs = ctx.ResolveDependencies(config)
+ if errored(t, tc.description, errs) {
+ return
+ }
+
+ checkDir := dir
+ if tc.dir != "" {
+ checkDir = tc.dir
+ }
+ codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
+ bazelTargets := generateBazelTargetsForDir(codegenCtx, checkDir)
+ if actualCount, expectedCount := len(bazelTargets), len(tc.expectedBazelTargets); actualCount != expectedCount {
+ t.Errorf("%s: Expected %d bazel target, got %d", tc.description, expectedCount, actualCount)
+ } else {
+ for i, target := range bazelTargets {
+ if w, g := tc.expectedBazelTargets[i], target.content; w != g {
+ t.Errorf(
+ "%s: Expected generated Bazel target to be '%s', got '%s'",
+ tc.description,
+ w,
+ g,
+ )
+ }
+ }
+ }
+}
+
+func TestCcLibrarySimple(t *testing.T) {
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ description: "cc_library - simple example",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ filesystem: map[string]string{
+ "android.cpp": "",
+ "darwin.cpp": "",
+ // Refer to cc.headerExts for the supported header extensions in Soong.
+ "header.h": "",
+ "header.hh": "",
+ "header.hpp": "",
+ "header.hxx": "",
+ "header.h++": "",
+ "header.inl": "",
+ "header.inc": "",
+ "header.ipp": "",
+ "header.h.generic": "",
+ "impl.cpp": "",
+ "linux.cpp": "",
+ "x86.cpp": "",
+ "x86_64.cpp": "",
+ "foo-dir/a.h": "",
+ },
+ blueprint: soongCcLibraryPreamble + `
cc_library_headers { name: "some-headers" }
cc_library {
name: "foo-lib",
@@ -108,14 +163,14 @@
},
}
`,
- expectedBazelTargets: []string{`cc_library(
+ expectedBazelTargets: []string{`cc_library(
name = "foo-lib",
copts = [
"-Wall",
"-I.",
"-I$(BINDIR)/.",
],
- deps = [":some-headers"],
+ implementation_deps = [":some-headers"],
includes = ["foo-dir"],
linkopts = ["-Wl,--exclude-libs=bar.a"] + select({
"//build/bazel/platforms/arch:x86": ["-Wl,--exclude-libs=baz.a"],
@@ -132,21 +187,23 @@
"//build/bazel/platforms/os:linux": ["linux.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,
+ filesystem: map[string]string{
+ "ld-android.cpp": "",
+ "linked_list.h": "",
+ "linker.h": "",
+ "linker_block_allocator.h": "",
+ "linker_cfi.h": "",
},
- {
- description: "cc_library - trimmed example of //bionic/linker:ld-android",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
- filesystem: map[string]string{
- "ld-android.cpp": "",
- "linked_list.h": "",
- "linker.h": "",
- "linker_block_allocator.h": "",
- "linker_cfi.h": "",
- },
- bp: soongCcLibraryPreamble + `
+ blueprint: soongCcLibraryPreamble + `
cc_library_headers { name: "libc_headers" }
cc_library {
name: "fake-ld-android",
@@ -176,7 +233,7 @@
},
}
`,
- expectedBazelTargets: []string{`cc_library(
+ expectedBazelTargets: []string{`cc_library(
name = "fake-ld-android",
copts = [
"-Wall",
@@ -186,7 +243,7 @@
"-I.",
"-I$(BINDIR)/.",
],
- deps = [":libc_headers"],
+ implementation_deps = [":libc_headers"],
linkopts = [
"-Wl,--exclude-libs=libgcc.a",
"-Wl,--exclude-libs=libgcc_stripped.a",
@@ -201,20 +258,23 @@
}),
srcs = ["ld_android.cpp"],
)`},
- },
- {
- 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",
- filesystem: map[string]string{
- "external/math/cosf.c": "",
- "external/math/erf.c": "",
- "external/math/erf_data.c": "",
- "external/math/erff.c": "",
- "external/math/erff_data.c": "",
- "external/Android.bp": `
+ })
+}
+
+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",
+ filesystem: map[string]string{
+ "external/math/cosf.c": "",
+ "external/math/erf.c": "",
+ "external/math/erf_data.c": "",
+ "external/math/erff.c": "",
+ "external/math/erff_data.c": "",
+ "external/Android.bp": `
cc_library {
name: "fake-libarm-optimized-routines-math",
exclude_srcs: [
@@ -240,9 +300,9 @@
bazel_module: { bp2build_available: true },
}
`,
- },
- bp: soongCcLibraryPreamble,
- expectedBazelTargets: []string{`cc_library(
+ },
+ blueprint: soongCcLibraryPreamble,
+ expectedBazelTargets: []string{`cc_library(
name = "fake-libarm-optimized-routines-math",
copts = [
"-Iexternal",
@@ -253,19 +313,22 @@
}),
srcs = ["math/cosf.c"],
)`},
- },
- {
- description: "cc_library shared/static props",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
- depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
- dir: "foo/bar",
- filesystem: map[string]string{
- "foo/bar/both.cpp": "",
- "foo/bar/sharedonly.cpp": "",
- "foo/bar/staticonly.cpp": "",
- "foo/bar/Android.bp": `
+ })
+}
+
+func TestCcLibrarySharedStaticProps(t *testing.T) {
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ description: "cc_library shared/static props",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ dir: "foo/bar",
+ filesystem: map[string]string{
+ "foo/bar/both.cpp": "",
+ "foo/bar/sharedonly.cpp": "",
+ "foo/bar/staticonly.cpp": "",
+ "foo/bar/Android.bp": `
cc_library {
name: "a",
srcs: ["both.cpp"],
@@ -308,19 +371,19 @@
cc_library { name: "shared_dep_for_both" }
`,
- },
- bp: soongCcLibraryPreamble,
- expectedBazelTargets: []string{`cc_library(
+ },
+ blueprint: soongCcLibraryPreamble,
+ expectedBazelTargets: []string{`cc_library(
name = "a",
copts = [
"bothflag",
"-Ifoo/bar",
"-I$(BINDIR)/foo/bar",
],
- deps = [":static_dep_for_both"],
dynamic_deps = [":shared_dep_for_both"],
dynamic_deps_for_shared = [":shared_dep_for_shared"],
dynamic_deps_for_static = [":shared_dep_for_static"],
+ implementation_deps = [":static_dep_for_both"],
shared_copts = ["sharedflag"],
shared_srcs = ["sharedonly.cpp"],
srcs = ["both.cpp"],
@@ -332,16 +395,19 @@
whole_archive_deps_for_shared = [":whole_static_lib_for_shared"],
whole_archive_deps_for_static = [":whole_static_lib_for_static"],
)`},
- },
- {
- description: "cc_library non-configured version script",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
- depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
- dir: "foo/bar",
- filesystem: map[string]string{
- "foo/bar/Android.bp": `
+ })
+}
+
+func TestCcLibraryNonConfiguredVersionScript(t *testing.T) {
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ description: "cc_library non-configured version script",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ dir: "foo/bar",
+ filesystem: map[string]string{
+ "foo/bar/Android.bp": `
cc_library {
name: "a",
srcs: ["a.cpp"],
@@ -349,9 +415,9 @@
bazel_module: { bp2build_available: true },
}
`,
- },
- bp: soongCcLibraryPreamble,
- expectedBazelTargets: []string{`cc_library(
+ },
+ blueprint: soongCcLibraryPreamble,
+ expectedBazelTargets: []string{`cc_library(
name = "a",
copts = [
"-Ifoo/bar",
@@ -360,16 +426,19 @@
srcs = ["a.cpp"],
version_script = "v.map",
)`},
- },
- {
- description: "cc_library configured version script",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
- depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
- dir: "foo/bar",
- filesystem: map[string]string{
- "foo/bar/Android.bp": `
+ })
+}
+
+func TestCcLibraryConfiguredVersionScript(t *testing.T) {
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ description: "cc_library configured version script",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ dir: "foo/bar",
+ filesystem: map[string]string{
+ "foo/bar/Android.bp": `
cc_library {
name: "a",
srcs: ["a.cpp"],
@@ -385,9 +454,9 @@
bazel_module: { bp2build_available: true },
}
`,
- },
- bp: soongCcLibraryPreamble,
- expectedBazelTargets: []string{`cc_library(
+ },
+ blueprint: soongCcLibraryPreamble,
+ expectedBazelTargets: []string{`cc_library(
name = "a",
copts = [
"-Ifoo/bar",
@@ -400,16 +469,19 @@
"//conditions:default": None,
}),
)`},
- },
- {
- description: "cc_library shared_libs",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
- depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
- dir: "foo/bar",
- filesystem: map[string]string{
- "foo/bar/Android.bp": `
+ })
+}
+
+func TestCcLibrarySharedLibs(t *testing.T) {
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ description: "cc_library shared_libs",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ dir: "foo/bar",
+ filesystem: map[string]string{
+ "foo/bar/Android.bp": `
cc_library {
name: "mylib",
bazel_module: { bp2build_available: true },
@@ -421,9 +493,9 @@
bazel_module: { bp2build_available: true },
}
`,
- },
- bp: soongCcLibraryPreamble,
- expectedBazelTargets: []string{`cc_library(
+ },
+ blueprint: soongCcLibraryPreamble,
+ expectedBazelTargets: []string{`cc_library(
name = "a",
copts = [
"-Ifoo/bar",
@@ -437,16 +509,19 @@
"-I$(BINDIR)/foo/bar",
],
)`},
- },
- {
- description: "cc_library pack_relocations test",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
- depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
- dir: "foo/bar",
- filesystem: map[string]string{
- "foo/bar/Android.bp": `
+ })
+}
+
+func TestCcLibraryPackRelocations(t *testing.T) {
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ description: "cc_library pack_relocations test",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ dir: "foo/bar",
+ filesystem: map[string]string{
+ "foo/bar/Android.bp": `
cc_library {
name: "a",
srcs: ["a.cpp"],
@@ -475,9 +550,9 @@
},
bazel_module: { bp2build_available: true },
}`,
- },
- bp: soongCcLibraryPreamble,
- expectedBazelTargets: []string{`cc_library(
+ },
+ blueprint: soongCcLibraryPreamble,
+ expectedBazelTargets: []string{`cc_library(
name = "a",
copts = [
"-Ifoo/bar",
@@ -508,25 +583,28 @@
}),
srcs = ["c.cpp"],
)`},
- },
- {
- description: "cc_library spaces in copts",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
- depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
- dir: "foo/bar",
- filesystem: map[string]string{
- "foo/bar/Android.bp": `
+ })
+}
+
+func TestCcLibrarySpacesInCopts(t *testing.T) {
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ description: "cc_library spaces in copts",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ dir: "foo/bar",
+ filesystem: map[string]string{
+ "foo/bar/Android.bp": `
cc_library {
name: "a",
cflags: ["-include header.h",],
bazel_module: { bp2build_available: true },
}
`,
- },
- bp: soongCcLibraryPreamble,
- expectedBazelTargets: []string{`cc_library(
+ },
+ blueprint: soongCcLibraryPreamble,
+ expectedBazelTargets: []string{`cc_library(
name = "a",
copts = [
"-include",
@@ -535,16 +613,19 @@
"-I$(BINDIR)/foo/bar",
],
)`},
- },
- {
- description: "cc_library cppflags goes into copts",
- moduleTypeUnderTest: "cc_library",
- moduleTypeUnderTestFactory: cc.LibraryFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
- depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
- dir: "foo/bar",
- filesystem: map[string]string{
- "foo/bar/Android.bp": `cc_library {
+ })
+}
+
+func TestCcLibraryCppFlagsGoesIntoCopts(t *testing.T) {
+ runCcLibraryTestCase(t, bp2buildTestCase{
+ description: "cc_library cppflags goes into copts",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ dir: "foo/bar",
+ filesystem: map[string]string{
+ "foo/bar/Android.bp": `cc_library {
name: "a",
srcs: ["a.cpp"],
cflags: [
@@ -567,9 +648,9 @@
bazel_module: { bp2build_available: true },
}
`,
- },
- bp: soongCcLibraryPreamble,
- expectedBazelTargets: []string{`cc_library(
+ },
+ blueprint: soongCcLibraryPreamble,
+ expectedBazelTargets: []string{`cc_library(
name = "a",
copts = [
"-Wall",
@@ -586,64 +667,5 @@
}),
srcs = ["a.cpp"],
)`},
- },
- }
-
- dir := "."
- for _, testCase := range testCases {
- filesystem := make(map[string][]byte)
- toParse := []string{
- "Android.bp",
- }
- for f, content := range testCase.filesystem {
- if strings.HasSuffix(f, "Android.bp") {
- toParse = append(toParse, f)
- }
- filesystem[f] = []byte(content)
- }
- config := android.TestConfig(buildDir, nil, testCase.bp, filesystem)
- ctx := android.NewTestContext(config)
-
- cc.RegisterCCBuildComponents(ctx)
- ctx.RegisterModuleType("cc_library_static", cc.LibraryStaticFactory)
- ctx.RegisterModuleType("toolchain_library", cc.ToolchainLibraryFactory)
- ctx.RegisterModuleType("cc_library_headers", cc.LibraryHeaderFactory)
- ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
- ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator)
- ctx.RegisterBp2BuildConfig(bp2buildConfig) // TODO(jingwen): make this the default for all tests
- for _, m := range testCase.depsMutators {
- ctx.DepsBp2BuildMutators(m)
- }
- 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
- }
-
- checkDir := dir
- if testCase.dir != "" {
- checkDir = testCase.dir
- }
- codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
- bazelTargets := generateBazelTargetsForDir(codegenCtx, checkDir)
- 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,
- )
- }
- }
- }
- }
+ })
}
diff --git a/bp2build/cc_library_headers_conversion_test.go b/bp2build/cc_library_headers_conversion_test.go
index a3965ed..2859bab 100644
--- a/bp2build/cc_library_headers_conversion_test.go
+++ b/bp2build/cc_library_headers_conversion_test.go
@@ -15,10 +15,10 @@
package bp2build
import (
+ "testing"
+
"android/soong/android"
"android/soong/cc"
- "strings"
- "testing"
)
const (
@@ -40,6 +40,18 @@
}`
)
+type bp2buildTestCase struct {
+ description string
+ moduleTypeUnderTest string
+ moduleTypeUnderTestFactory android.ModuleFactory
+ moduleTypeUnderTestBp2BuildMutator func(android.TopDownMutatorContext)
+ depsMutators []android.RegisterMutatorFunc
+ blueprint string
+ expectedBazelTargets []string
+ filesystem map[string]string
+ dir string
+}
+
func TestCcLibraryHeadersLoadStatement(t *testing.T) {
testCases := []struct {
bazelTargets BazelTargets
@@ -64,41 +76,37 @@
t.Fatalf("Expected load statements to be %s, got %s", expected, actual)
}
}
-
}
-func TestCcLibraryHeadersBp2Build(t *testing.T) {
- testCases := []struct {
- description string
- moduleTypeUnderTest string
- moduleTypeUnderTestFactory android.ModuleFactory
- moduleTypeUnderTestBp2BuildMutator func(android.TopDownMutatorContext)
- preArchMutators []android.RegisterMutatorFunc
- depsMutators []android.RegisterMutatorFunc
- bp string
- expectedBazelTargets []string
- filesystem map[string]string
- dir string
- }{
- {
- description: "cc_library_headers test",
- moduleTypeUnderTest: "cc_library_headers",
- moduleTypeUnderTestFactory: cc.LibraryHeaderFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryHeadersBp2Build,
- filesystem: map[string]string{
- "lib-1/lib1a.h": "",
- "lib-1/lib1b.h": "",
- "lib-2/lib2a.h": "",
- "lib-2/lib2b.h": "",
- "dir-1/dir1a.h": "",
- "dir-1/dir1b.h": "",
- "dir-2/dir2a.h": "",
- "dir-2/dir2b.h": "",
- "arch_arm64_exported_include_dir/a.h": "",
- "arch_x86_exported_include_dir/b.h": "",
- "arch_x86_64_exported_include_dir/c.h": "",
- },
- bp: soongCcLibraryHeadersPreamble + `
+func registerCcLibraryHeadersModuleTypes(ctx android.RegistrationContext) {
+ cc.RegisterCCBuildComponents(ctx)
+ ctx.RegisterModuleType("toolchain_library", cc.ToolchainLibraryFactory)
+}
+
+func runCcLibraryHeadersTestCase(t *testing.T, tc bp2buildTestCase) {
+ runBp2BuildTestCase(t, registerCcLibraryHeadersModuleTypes, tc)
+}
+
+func TestCcLibraryHeadersSimple(t *testing.T) {
+ runCcLibraryHeadersTestCase(t, bp2buildTestCase{
+ description: "cc_library_headers test",
+ moduleTypeUnderTest: "cc_library_headers",
+ moduleTypeUnderTestFactory: cc.LibraryHeaderFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryHeadersBp2Build,
+ filesystem: map[string]string{
+ "lib-1/lib1a.h": "",
+ "lib-1/lib1b.h": "",
+ "lib-2/lib2a.h": "",
+ "lib-2/lib2b.h": "",
+ "dir-1/dir1a.h": "",
+ "dir-1/dir1b.h": "",
+ "dir-2/dir2a.h": "",
+ "dir-2/dir2b.h": "",
+ "arch_arm64_exported_include_dir/a.h": "",
+ "arch_x86_exported_include_dir/b.h": "",
+ "arch_x86_64_exported_include_dir/c.h": "",
+ },
+ blueprint: soongCcLibraryHeadersPreamble + `
cc_library_headers {
name: "lib-1",
export_include_dirs: ["lib-1"],
@@ -129,13 +137,13 @@
// TODO: Also support export_header_lib_headers
}`,
- expectedBazelTargets: []string{`cc_library_headers(
+ expectedBazelTargets: []string{`cc_library_headers(
name = "foo_headers",
copts = [
"-I.",
"-I$(BINDIR)/.",
],
- deps = [
+ implementation_deps = [
":lib-1",
":lib-2",
],
@@ -163,15 +171,18 @@
],
includes = ["lib-2"],
)`},
- },
- {
- description: "cc_library_headers test with os-specific header_libs props",
- moduleTypeUnderTest: "cc_library_headers",
- moduleTypeUnderTestFactory: cc.LibraryHeaderFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryHeadersBp2Build,
- depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
- filesystem: map[string]string{},
- bp: soongCcLibraryPreamble + `
+ })
+}
+
+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,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ filesystem: map[string]string{},
+ blueprint: soongCcLibraryPreamble + `
cc_library_headers { name: "android-lib" }
cc_library_headers { name: "base-lib" }
cc_library_headers { name: "darwin-lib" }
@@ -192,7 +203,7 @@
},
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`cc_library_headers(
+ expectedBazelTargets: []string{`cc_library_headers(
name = "android-lib",
copts = [
"-I.",
@@ -216,7 +227,7 @@
"-I.",
"-I$(BINDIR)/.",
],
- deps = [":base-lib"] + select({
+ implementation_deps = [":base-lib"] + select({
"//build/bazel/platforms/os:android": [":android-lib"],
"//build/bazel/platforms/os:darwin": [":darwin-lib"],
"//build/bazel/platforms/os:fuchsia": [":fuchsia-lib"],
@@ -250,15 +261,18 @@
"-I$(BINDIR)/.",
],
)`},
- },
- {
- 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,
- depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
- filesystem: map[string]string{},
- bp: soongCcLibraryPreamble + `
+ })
+}
+
+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,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ filesystem: map[string]string{},
+ blueprint: soongCcLibraryPreamble + `
cc_library_headers { name: "android-lib" }
cc_library_headers { name: "exported-lib" }
cc_library_headers {
@@ -267,7 +281,7 @@
android: { header_libs: ["android-lib"], export_header_lib_headers: ["exported-lib"] },
},
}`,
- expectedBazelTargets: []string{`cc_library_headers(
+ expectedBazelTargets: []string{`cc_library_headers(
name = "android-lib",
copts = [
"-I.",
@@ -286,22 +300,26 @@
"-I$(BINDIR)/.",
],
deps = select({
- "//build/bazel/platforms/os:android": [
- ":android-lib",
- ":exported-lib",
- ],
+ "//build/bazel/platforms/os:android": [":exported-lib"],
+ "//conditions:default": [],
+ }),
+ implementation_deps = select({
+ "//build/bazel/platforms/os:android": [":android-lib"],
"//conditions:default": [],
}),
)`},
- },
- {
- 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,
- depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
- filesystem: map[string]string{},
- bp: soongCcLibraryPreamble + `cc_library_headers {
+ })
+}
+
+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,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ filesystem: map[string]string{},
+ blueprint: soongCcLibraryPreamble + `cc_library_headers {
name: "foo_headers",
export_system_include_dirs: [
"shared_include_dir",
@@ -336,7 +354,7 @@
},
},
}`,
- expectedBazelTargets: []string{`cc_library_headers(
+ expectedBazelTargets: []string{`cc_library_headers(
name = "foo_headers",
copts = [
"-I.",
@@ -353,65 +371,5 @@
"//conditions:default": [],
}),
)`},
- },
- }
-
- dir := "."
- for _, testCase := range testCases {
- filesystem := make(map[string][]byte)
- toParse := []string{
- "Android.bp",
- }
- for f, content := range testCase.filesystem {
- if strings.HasSuffix(f, "Android.bp") {
- toParse = append(toParse, f)
- }
- filesystem[f] = []byte(content)
- }
- config := android.TestConfig(buildDir, nil, testCase.bp, filesystem)
- ctx := android.NewTestContext(config)
-
- // TODO(jingwen): make this default for all bp2build tests
- ctx.RegisterBp2BuildConfig(bp2buildConfig)
-
- cc.RegisterCCBuildComponents(ctx)
- ctx.RegisterModuleType("toolchain_library", cc.ToolchainLibraryFactory)
-
- 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
- }
-
- checkDir := dir
- if testCase.dir != "" {
- checkDir = testCase.dir
- }
- codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
- bazelTargets := generateBazelTargetsForDir(codegenCtx, checkDir)
- 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,
- )
- }
- }
- }
- }
+ })
}
diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go
index 4fcf5e4..229b1c2 100644
--- a/bp2build/cc_library_static_conversion_test.go
+++ b/bp2build/cc_library_static_conversion_test.go
@@ -19,7 +19,6 @@
"android/soong/cc"
"android/soong/genrule"
- "strings"
"testing"
)
@@ -69,45 +68,44 @@
}
-func TestCcLibraryStaticBp2Build(t *testing.T) {
- testCases := []struct {
- description string
- moduleTypeUnderTest string
- moduleTypeUnderTestFactory android.ModuleFactory
- moduleTypeUnderTestBp2BuildMutator func(android.TopDownMutatorContext)
- preArchMutators []android.RegisterMutatorFunc
- depsMutators []android.RegisterMutatorFunc
- bp string
- expectedBazelTargets []string
- filesystem map[string]string
- dir string
- }{
- {
- description: "cc_library_static test",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- filesystem: map[string]string{
- // NOTE: include_dir headers *should not* appear in Bazel hdrs later (?)
- "include_dir_1/include_dir_1_a.h": "",
- "include_dir_1/include_dir_1_b.h": "",
- "include_dir_2/include_dir_2_a.h": "",
- "include_dir_2/include_dir_2_b.h": "",
- // NOTE: local_include_dir headers *should not* appear in Bazel hdrs later (?)
- "local_include_dir_1/local_include_dir_1_a.h": "",
- "local_include_dir_1/local_include_dir_1_b.h": "",
- "local_include_dir_2/local_include_dir_2_a.h": "",
- "local_include_dir_2/local_include_dir_2_b.h": "",
- // NOTE: export_include_dir headers *should* appear in Bazel hdrs later
- "export_include_dir_1/export_include_dir_1_a.h": "",
- "export_include_dir_1/export_include_dir_1_b.h": "",
- "export_include_dir_2/export_include_dir_2_a.h": "",
- "export_include_dir_2/export_include_dir_2_b.h": "",
- // NOTE: Soong implicitly includes headers in the current directory
- "implicit_include_1.h": "",
- "implicit_include_2.h": "",
- },
- bp: soongCcLibraryStaticPreamble + `
+func registerCcLibraryStaticModuleTypes(ctx android.RegistrationContext) {
+ cc.RegisterCCBuildComponents(ctx)
+ ctx.RegisterModuleType("toolchain_library", cc.ToolchainLibraryFactory)
+ ctx.RegisterModuleType("cc_library_headers", cc.LibraryHeaderFactory)
+ ctx.RegisterModuleType("genrule", genrule.GenRuleFactory)
+}
+
+func runCcLibraryStaticTestCase(t *testing.T, tc bp2buildTestCase) {
+ 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,
+ filesystem: map[string]string{
+ // NOTE: include_dir headers *should not* appear in Bazel hdrs later (?)
+ "include_dir_1/include_dir_1_a.h": "",
+ "include_dir_1/include_dir_1_b.h": "",
+ "include_dir_2/include_dir_2_a.h": "",
+ "include_dir_2/include_dir_2_b.h": "",
+ // NOTE: local_include_dir headers *should not* appear in Bazel hdrs later (?)
+ "local_include_dir_1/local_include_dir_1_a.h": "",
+ "local_include_dir_1/local_include_dir_1_b.h": "",
+ "local_include_dir_2/local_include_dir_2_a.h": "",
+ "local_include_dir_2/local_include_dir_2_b.h": "",
+ // NOTE: export_include_dir headers *should* appear in Bazel hdrs later
+ "export_include_dir_1/export_include_dir_1_a.h": "",
+ "export_include_dir_1/export_include_dir_1_b.h": "",
+ "export_include_dir_2/export_include_dir_2_a.h": "",
+ "export_include_dir_2/export_include_dir_2_b.h": "",
+ // NOTE: Soong implicitly includes headers in the current directory
+ "implicit_include_1.h": "",
+ "implicit_include_2.h": "",
+ },
+ blueprint: soongCcLibraryStaticPreamble + `
cc_library_headers {
name: "header_lib_1",
export_include_dirs: ["header_lib_1"],
@@ -165,8 +163,8 @@
"local_include_dir_2",
],
export_include_dirs: [
- "export_include_dir_1",
- "export_include_dir_2"
+ "export_include_dir_1",
+ "export_include_dir_2"
],
header_libs: [
"header_lib_1",
@@ -175,7 +173,7 @@
// TODO: Also support export_header_lib_headers
}`,
- expectedBazelTargets: []string{`cc_library_static(
+ expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
copts = [
"-Dflag1",
@@ -191,7 +189,7 @@
"-I.",
"-I$(BINDIR)/.",
],
- deps = [
+ implementation_deps = [
":header_lib_1",
":header_lib_2",
":static_lib_1",
@@ -243,27 +241,30 @@
linkstatic = True,
srcs = ["whole_static_lib_2.cc"],
)`},
+ })
+}
+
+func TestCcLibraryStaticSubpackage(t *testing.T) {
+ runCcLibraryStaticTestCase(t, bp2buildTestCase{
+ description: "cc_library_static subpackage test",
+ moduleTypeUnderTest: "cc_library_static",
+ moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
+ filesystem: map[string]string{
+ // subpackage with subdirectory
+ "subpackage/Android.bp": "",
+ "subpackage/subpackage_header.h": "",
+ "subpackage/subdirectory/subdirectory_header.h": "",
+ // subsubpackage with subdirectory
+ "subpackage/subsubpackage/Android.bp": "",
+ "subpackage/subsubpackage/subsubpackage_header.h": "",
+ "subpackage/subsubpackage/subdirectory/subdirectory_header.h": "",
+ // subsubsubpackage with subdirectory
+ "subpackage/subsubpackage/subsubsubpackage/Android.bp": "",
+ "subpackage/subsubpackage/subsubsubpackage/subsubsubpackage_header.h": "",
+ "subpackage/subsubpackage/subsubsubpackage/subdirectory/subdirectory_header.h": "",
},
- {
- description: "cc_library_static subpackage test",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- filesystem: map[string]string{
- // subpackage with subdirectory
- "subpackage/Android.bp": "",
- "subpackage/subpackage_header.h": "",
- "subpackage/subdirectory/subdirectory_header.h": "",
- // subsubpackage with subdirectory
- "subpackage/subsubpackage/Android.bp": "",
- "subpackage/subsubpackage/subsubpackage_header.h": "",
- "subpackage/subsubpackage/subdirectory/subdirectory_header.h": "",
- // subsubsubpackage with subdirectory
- "subpackage/subsubpackage/subsubsubpackage/Android.bp": "",
- "subpackage/subsubpackage/subsubsubpackage/subsubsubpackage_header.h": "",
- "subpackage/subsubpackage/subsubsubpackage/subdirectory/subdirectory_header.h": "",
- },
- bp: soongCcLibraryStaticPreamble + `
+ blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
srcs: [
@@ -272,7 +273,7 @@
"subpackage",
],
}`,
- expectedBazelTargets: []string{`cc_library_static(
+ expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
copts = [
"-Isubpackage",
@@ -282,24 +283,27 @@
],
linkstatic = True,
)`},
+ })
+}
+
+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,
+ filesystem: map[string]string{
+ // subpackage with subdirectory
+ "subpackage/Android.bp": "",
+ "subpackage/subpackage_header.h": "",
+ "subpackage/subdirectory/subdirectory_header.h": "",
},
- {
- description: "cc_library_static export include dir",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- filesystem: map[string]string{
- // subpackage with subdirectory
- "subpackage/Android.bp": "",
- "subpackage/subpackage_header.h": "",
- "subpackage/subdirectory/subdirectory_header.h": "",
- },
- bp: soongCcLibraryStaticPreamble + `
+ blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
export_include_dirs: ["subpackage"],
}`,
- expectedBazelTargets: []string{`cc_library_static(
+ expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
copts = [
"-I.",
@@ -308,24 +312,27 @@
includes = ["subpackage"],
linkstatic = True,
)`},
+ })
+}
+
+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,
+ filesystem: map[string]string{
+ // subpackage with subdirectory
+ "subpackage/Android.bp": "",
+ "subpackage/subpackage_header.h": "",
+ "subpackage/subdirectory/subdirectory_header.h": "",
},
- {
- description: "cc_library_static export system include dir",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- filesystem: map[string]string{
- // subpackage with subdirectory
- "subpackage/Android.bp": "",
- "subpackage/subpackage_header.h": "",
- "subpackage/subdirectory/subdirectory_header.h": "",
- },
- bp: soongCcLibraryStaticPreamble + `
+ blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
export_system_include_dirs: ["subpackage"],
}`,
- expectedBazelTargets: []string{`cc_library_static(
+ expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
copts = [
"-I.",
@@ -334,16 +341,19 @@
includes = ["subpackage"],
linkstatic = True,
)`},
- },
- {
- 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",
- filesystem: map[string]string{
- // subpackage with subdirectory
- "subpackage/Android.bp": `
+ })
+}
+
+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",
+ filesystem: map[string]string{
+ // subpackage with subdirectory
+ "subpackage/Android.bp": `
cc_library_static {
name: "foo_static",
// include_dirs are workspace/root relative
@@ -357,14 +367,14 @@
include_build_directory: true,
bazel_module: { bp2build_available: true },
}`,
- "subpackage/subsubpackage/header.h": "",
- "subpackage/subsubpackage2/header.h": "",
- "subpackage/exported_subsubpackage/header.h": "",
- "subpackage2/header.h": "",
- "subpackage3/subsubpackage/header.h": "",
- },
- bp: soongCcLibraryStaticPreamble,
- expectedBazelTargets: []string{`cc_library_static(
+ "subpackage/subsubpackage/header.h": "",
+ "subpackage/subsubpackage2/header.h": "",
+ "subpackage/exported_subsubpackage/header.h": "",
+ "subpackage2/header.h": "",
+ "subpackage3/subsubpackage/header.h": "",
+ },
+ blueprint: soongCcLibraryStaticPreamble,
+ expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
copts = [
"-Isubpackage/subsubpackage",
@@ -381,26 +391,29 @@
includes = ["./exported_subsubpackage"],
linkstatic = True,
)`},
+ })
+}
+
+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,
+ filesystem: map[string]string{
+ // subpackage with subdirectory
+ "subpackage/Android.bp": "",
+ "subpackage/subpackage_header.h": "",
+ "subpackage/subdirectory/subdirectory_header.h": "",
},
- {
- description: "cc_library_static include_build_directory disabled",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- filesystem: map[string]string{
- // subpackage with subdirectory
- "subpackage/Android.bp": "",
- "subpackage/subpackage_header.h": "",
- "subpackage/subdirectory/subdirectory_header.h": "",
- },
- bp: soongCcLibraryStaticPreamble + `
+ blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
include_dirs: ["subpackage"], // still used, but local_include_dirs is recommended
local_include_dirs: ["subpackage2"],
include_build_directory: false,
}`,
- expectedBazelTargets: []string{`cc_library_static(
+ expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
copts = [
"-Isubpackage",
@@ -410,28 +423,31 @@
],
linkstatic = True,
)`},
+ })
+}
+
+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,
+ filesystem: map[string]string{
+ // subpackage with subdirectory
+ "subpackage/Android.bp": "",
+ "subpackage/subpackage_header.h": "",
+ "subpackage2/Android.bp": "",
+ "subpackage2/subpackage2_header.h": "",
+ "subpackage/subdirectory/subdirectory_header.h": "",
},
- {
- description: "cc_library_static include_build_directory enabled",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- filesystem: map[string]string{
- // subpackage with subdirectory
- "subpackage/Android.bp": "",
- "subpackage/subpackage_header.h": "",
- "subpackage2/Android.bp": "",
- "subpackage2/subpackage2_header.h": "",
- "subpackage/subdirectory/subdirectory_header.h": "",
- },
- bp: soongCcLibraryStaticPreamble + `
+ blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
include_dirs: ["subpackage"], // still used, but local_include_dirs is recommended
local_include_dirs: ["subpackage2"],
include_build_directory: true,
}`,
- expectedBazelTargets: []string{`cc_library_static(
+ expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
copts = [
"-Isubpackage",
@@ -443,28 +459,31 @@
],
linkstatic = True,
)`},
- },
- {
- description: "cc_library_static arch-specific static_libs",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
- filesystem: map[string]string{},
- bp: soongCcLibraryStaticPreamble + `
+ })
+}
+
+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,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ filesystem: map[string]string{},
+ blueprint: soongCcLibraryStaticPreamble + `
cc_library_static { name: "static_dep" }
cc_library_static { name: "static_dep2" }
cc_library_static {
name: "foo_static",
arch: { arm64: { static_libs: ["static_dep"], whole_static_libs: ["static_dep2"] } },
}`,
- expectedBazelTargets: []string{`cc_library_static(
+ expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
copts = [
"-I.",
"-I$(BINDIR)/.",
],
- deps = select({
+ implementation_deps = select({
"//build/bazel/platforms/arch:arm64": [":static_dep"],
"//conditions:default": [],
}),
@@ -488,28 +507,31 @@
],
linkstatic = True,
)`},
- },
- {
- description: "cc_library_static os-specific static_libs",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
- filesystem: map[string]string{},
- bp: soongCcLibraryStaticPreamble + `
+ })
+}
+
+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,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ filesystem: map[string]string{},
+ blueprint: soongCcLibraryStaticPreamble + `
cc_library_static { name: "static_dep" }
cc_library_static { name: "static_dep2" }
cc_library_static {
name: "foo_static",
target: { android: { static_libs: ["static_dep"], whole_static_libs: ["static_dep2"] } },
}`,
- expectedBazelTargets: []string{`cc_library_static(
+ expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
copts = [
"-I.",
"-I$(BINDIR)/.",
],
- deps = select({
+ implementation_deps = select({
"//build/bazel/platforms/os:android": [":static_dep"],
"//conditions:default": [],
}),
@@ -533,15 +555,18 @@
],
linkstatic = True,
)`},
- },
- {
- description: "cc_library_static base, arch and os-specific static_libs",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
- filesystem: map[string]string{},
- bp: soongCcLibraryStaticPreamble + `
+ })
+}
+
+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,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ filesystem: map[string]string{},
+ blueprint: soongCcLibraryStaticPreamble + `
cc_library_static { name: "static_dep" }
cc_library_static { name: "static_dep2" }
cc_library_static { name: "static_dep3" }
@@ -553,13 +578,13 @@
target: { android: { static_libs: ["static_dep3"] } },
arch: { arm64: { static_libs: ["static_dep4"] } },
}`,
- expectedBazelTargets: []string{`cc_library_static(
+ expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
copts = [
"-I.",
"-I$(BINDIR)/.",
],
- deps = [":static_dep"] + select({
+ implementation_deps = [":static_dep"] + select({
"//build/bazel/platforms/arch:arm64": [":static_dep4"],
"//conditions:default": [],
}) + select({
@@ -597,25 +622,28 @@
],
linkstatic = True,
)`},
+ })
+}
+
+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,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ filesystem: map[string]string{
+ "common.c": "",
+ "foo-a.c": "",
+ "foo-excluded.c": "",
},
- {
- description: "cc_library_static simple exclude_srcs",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
- filesystem: map[string]string{
- "common.c": "",
- "foo-a.c": "",
- "foo-excluded.c": "",
- },
- bp: soongCcLibraryStaticPreamble + `
+ blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
srcs: ["common.c", "foo-*.c"],
exclude_srcs: ["foo-excluded.c"],
}`,
- expectedBazelTargets: []string{`cc_library_static(
+ expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
copts = [
"-I.",
@@ -627,24 +655,27 @@
"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,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ filesystem: map[string]string{
+ "common.c": "",
+ "foo-arm.c": "",
},
- {
- description: "cc_library_static one arch specific srcs",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
- filesystem: map[string]string{
- "common.c": "",
- "foo-arm.c": "",
- },
- bp: soongCcLibraryStaticPreamble + `
+ blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
srcs: ["common.c"],
arch: { arm: { srcs: ["foo-arm.c"] } }
}`,
- expectedBazelTargets: []string{`cc_library_static(
+ expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
copts = [
"-I.",
@@ -656,20 +687,23 @@
"//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,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ filesystem: map[string]string{
+ "common.c": "",
+ "for-arm.c": "",
+ "not-for-arm.c": "",
+ "not-for-anything.c": "",
},
- {
- description: "cc_library_static one arch specific srcs and exclude_srcs",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
- filesystem: map[string]string{
- "common.c": "",
- "for-arm.c": "",
- "not-for-arm.c": "",
- "not-for-anything.c": "",
- },
- bp: soongCcLibraryStaticPreamble + `
+ blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
srcs: ["common.c", "not-for-*.c"],
@@ -678,7 +712,7 @@
arm: { srcs: ["for-arm.c"], exclude_srcs: ["not-for-arm.c"] },
},
}`,
- expectedBazelTargets: []string{`cc_library_static(
+ expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
copts = [
"-I.",
@@ -690,21 +724,24 @@
"//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,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ filesystem: map[string]string{
+ "common.c": "",
+ "for-arm.c": "",
+ "for-x86.c": "",
+ "not-for-arm.c": "",
+ "not-for-x86.c": "",
},
- {
- description: "cc_library_static arch specific exclude_srcs for 2 architectures",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
- filesystem: map[string]string{
- "common.c": "",
- "for-arm.c": "",
- "for-x86.c": "",
- "not-for-arm.c": "",
- "not-for-x86.c": "",
- },
- bp: soongCcLibraryStaticPreamble + `
+ blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
srcs: ["common.c", "not-for-*.c"],
@@ -714,7 +751,7 @@
x86: { srcs: ["for-x86.c"], exclude_srcs: ["not-for-x86.c"] },
},
} `,
- expectedBazelTargets: []string{`cc_library_static(
+ expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
copts = [
"-I.",
@@ -736,26 +773,28 @@
],
}),
)`},
+ })
+}
+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,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ filesystem: map[string]string{
+ "common.c": "",
+ "for-arm.c": "",
+ "for-arm64.c": "",
+ "for-x86.c": "",
+ "for-x86_64.c": "",
+ "not-for-arm.c": "",
+ "not-for-arm64.c": "",
+ "not-for-x86.c": "",
+ "not-for-x86_64.c": "",
+ "not-for-everything.c": "",
},
- {
- description: "cc_library_static arch specific exclude_srcs for 4 architectures",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
- filesystem: map[string]string{
- "common.c": "",
- "for-arm.c": "",
- "for-arm64.c": "",
- "for-x86.c": "",
- "for-x86_64.c": "",
- "not-for-arm.c": "",
- "not-for-arm64.c": "",
- "not-for-x86.c": "",
- "not-for-x86_64.c": "",
- "not-for-everything.c": "",
- },
- bp: soongCcLibraryStaticPreamble + `
+ blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
srcs: ["common.c", "not-for-*.c"],
@@ -767,7 +806,7 @@
x86_64: { srcs: ["for-x86_64.c"], exclude_srcs: ["not-for-x86_64.c"] },
},
} `,
- expectedBazelTargets: []string{`cc_library_static(
+ expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
copts = [
"-I.",
@@ -807,27 +846,30 @@
],
}),
)`},
- },
- {
- description: "cc_library_static multiple dep same name panic",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
- filesystem: map[string]string{},
- bp: soongCcLibraryStaticPreamble + `
+ })
+}
+
+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,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ filesystem: map[string]string{},
+ blueprint: soongCcLibraryStaticPreamble + `
cc_library_static { name: "static_dep" }
cc_library_static {
name: "foo_static",
static_libs: ["static_dep", "static_dep"],
}`,
- expectedBazelTargets: []string{`cc_library_static(
+ expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
copts = [
"-I.",
"-I$(BINDIR)/.",
],
- deps = [":static_dep"],
+ implementation_deps = [":static_dep"],
linkstatic = True,
)`, `cc_library_static(
name = "static_dep",
@@ -837,19 +879,22 @@
],
linkstatic = True,
)`},
+ })
+}
+
+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,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ filesystem: map[string]string{
+ "common.c": "",
+ "for-lib32.c": "",
+ "not-for-lib32.c": "",
},
- {
- description: "cc_library_static 1 multilib srcs and exclude_srcs",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
- filesystem: map[string]string{
- "common.c": "",
- "for-lib32.c": "",
- "not-for-lib32.c": "",
- },
- bp: soongCcLibraryStaticPreamble + `
+ blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
srcs: ["common.c", "not-for-*.c"],
@@ -857,7 +902,7 @@
lib32: { srcs: ["for-lib32.c"], exclude_srcs: ["not-for-lib32.c"] },
},
} `,
- expectedBazelTargets: []string{`cc_library_static(
+ expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
copts = [
"-I.",
@@ -870,21 +915,24 @@
"//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,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ filesystem: map[string]string{
+ "common.c": "",
+ "for-lib32.c": "",
+ "for-lib64.c": "",
+ "not-for-lib32.c": "",
+ "not-for-lib64.c": "",
},
- {
- description: "cc_library_static 2 multilib srcs and exclude_srcs",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
- filesystem: map[string]string{
- "common.c": "",
- "for-lib32.c": "",
- "for-lib64.c": "",
- "not-for-lib32.c": "",
- "not-for-lib64.c": "",
- },
- bp: soongCcLibraryStaticPreamble + `
+ blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static2",
srcs: ["common.c", "not-for-*.c"],
@@ -893,7 +941,7 @@
lib64: { srcs: ["for-lib64.c"], exclude_srcs: ["not-for-lib64.c"] },
},
} `,
- expectedBazelTargets: []string{`cc_library_static(
+ expectedBazelTargets: []string{`cc_library_static(
name = "foo_static2",
copts = [
"-I.",
@@ -923,30 +971,33 @@
],
}),
)`},
+ })
+}
+
+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,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ filesystem: map[string]string{
+ "common.c": "",
+ "for-arm.c": "",
+ "for-arm64.c": "",
+ "for-x86.c": "",
+ "for-x86_64.c": "",
+ "for-lib32.c": "",
+ "for-lib64.c": "",
+ "not-for-arm.c": "",
+ "not-for-arm64.c": "",
+ "not-for-x86.c": "",
+ "not-for-x86_64.c": "",
+ "not-for-lib32.c": "",
+ "not-for-lib64.c": "",
+ "not-for-everything.c": "",
},
- {
- description: "cc_library_static arch and multilib srcs and exclude_srcs",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
- filesystem: map[string]string{
- "common.c": "",
- "for-arm.c": "",
- "for-arm64.c": "",
- "for-x86.c": "",
- "for-x86_64.c": "",
- "for-lib32.c": "",
- "for-lib64.c": "",
- "not-for-arm.c": "",
- "not-for-arm64.c": "",
- "not-for-x86.c": "",
- "not-for-x86_64.c": "",
- "not-for-lib32.c": "",
- "not-for-lib64.c": "",
- "not-for-everything.c": "",
- },
- bp: soongCcLibraryStaticPreamble + `
+ blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static3",
srcs: ["common.c", "not-for-*.c"],
@@ -962,7 +1013,7 @@
lib64: { srcs: ["for-lib64.c"], exclude_srcs: ["not-for-lib64.c"] },
},
}`,
- expectedBazelTargets: []string{`cc_library_static(
+ expectedBazelTargets: []string{`cc_library_static(
name = "foo_static3",
copts = [
"-I.",
@@ -1012,19 +1063,22 @@
],
}),
)`},
- },
- {
- description: "cc_library_static arch srcs/exclude_srcs with generated files",
- moduleTypeUnderTest: "cc_library_static",
- moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
- depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
- filesystem: map[string]string{
- "common.c": "",
- "for-x86.c": "",
- "not-for-x86.c": "",
- "not-for-everything.c": "",
- "dep/Android.bp": `
+ })
+}
+
+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,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ filesystem: map[string]string{
+ "common.c": "",
+ "for-x86.c": "",
+ "not-for-x86.c": "",
+ "not-for-everything.c": "",
+ "dep/Android.bp": `
genrule {
name: "generated_src_other_pkg",
out: ["generated_src_other_pkg.cpp"],
@@ -1042,8 +1096,8 @@
out: ["generated_hdr_other_pkg_x86.cpp"],
cmd: "nothing to see here",
}`,
- },
- bp: soongCcLibraryStaticPreamble + `
+ },
+ blueprint: soongCcLibraryStaticPreamble + `
genrule {
name: "generated_src",
out: ["generated_src.cpp"],
@@ -1078,7 +1132,7 @@
},
}
`,
- expectedBazelTargets: []string{`cc_library_static(
+ expectedBazelTargets: []string{`cc_library_static(
name = "foo_static3",
copts = [
"-I.",
@@ -1100,65 +1154,122 @@
"//conditions:default": ["not-for-x86.c"],
}),
)`},
+ })
+}
+
+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"],
+ },
+ },
+ },
},
- }
-
- dir := "."
- for _, testCase := range testCases {
- filesystem := make(map[string][]byte)
- toParse := []string{
- "Android.bp",
- }
- for f, content := range testCase.filesystem {
- if strings.HasSuffix(f, "Android.bp") {
- toParse = append(toParse, f)
- }
- filesystem[f] = []byte(content)
- }
- config := android.TestConfig(buildDir, nil, testCase.bp, filesystem)
- ctx := android.NewTestContext(config)
-
- cc.RegisterCCBuildComponents(ctx)
- ctx.RegisterModuleType("toolchain_library", cc.ToolchainLibraryFactory)
- ctx.RegisterModuleType("cc_library_headers", cc.LibraryHeaderFactory)
- ctx.RegisterModuleType("genrule", genrule.GenRuleFactory)
-
- ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
- for _, m := range testCase.depsMutators {
- ctx.DepsBp2BuildMutators(m)
- }
- ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator)
- ctx.RegisterBp2BuildConfig(bp2buildConfig)
- 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
- }
-
- checkDir := dir
- if testCase.dir != "" {
- checkDir = testCase.dir
- }
- codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
- bazelTargets := generateBazelTargetsForDir(codegenCtx, checkDir)
- 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,
- )
+ 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 ebc9c94..d4eeb7c 100644
--- a/bp2build/cc_object_conversion_test.go
+++ b/bp2build/cc_object_conversion_test.go
@@ -15,35 +15,34 @@
package bp2build
import (
+ "testing"
+
"android/soong/android"
"android/soong/cc"
- "fmt"
- "strings"
- "testing"
)
-func TestCcObjectBp2Build(t *testing.T) {
- testCases := []struct {
- description string
- moduleTypeUnderTest string
- moduleTypeUnderTestFactory android.ModuleFactory
- moduleTypeUnderTestBp2BuildMutator func(android.TopDownMutatorContext)
- blueprint string
- expectedBazelTargets []string
- filesystem map[string]string
- }{
- {
- description: "simple cc_object generates cc_object with include header dep",
- moduleTypeUnderTest: "cc_object",
- moduleTypeUnderTestFactory: cc.ObjectFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
- filesystem: map[string]string{
- "a/b/foo.h": "",
- "a/b/bar.h": "",
- "a/b/exclude.c": "",
- "a/b/c.c": "",
- },
- blueprint: `cc_object {
+func registerCcObjectModuleTypes(ctx android.RegistrationContext) {
+ // Always register cc_defaults module factory
+ ctx.RegisterModuleType("cc_defaults", func() android.Module { return cc.DefaultsFactory() })
+}
+
+func runCcObjectTestCase(t *testing.T, tc bp2buildTestCase) {
+ 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,
+ filesystem: map[string]string{
+ "a/b/foo.h": "",
+ "a/b/bar.h": "",
+ "a/b/exclude.c": "",
+ "a/b/c.c": "",
+ },
+ blueprint: `cc_object {
name: "foo",
local_include_dirs: ["include"],
cflags: [
@@ -57,7 +56,7 @@
exclude_srcs: ["a/b/exclude.c"],
}
`,
- expectedBazelTargets: []string{`cc_object(
+ expectedBazelTargets: []string{`cc_object(
name = "foo",
copts = [
"-fno-addrsig",
@@ -71,14 +70,17 @@
],
srcs = ["a/b/c.c"],
)`,
- },
},
- {
- description: "simple cc_object with defaults",
- moduleTypeUnderTest: "cc_object",
- moduleTypeUnderTestFactory: cc.ObjectFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
- blueprint: `cc_object {
+ })
+}
+
+func TestCcObjectDefaults(t *testing.T) {
+ runCcObjectTestCase(t, bp2buildTestCase{
+ description: "simple cc_object with defaults",
+ moduleTypeUnderTest: "cc_object",
+ moduleTypeUnderTestFactory: cc.ObjectFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
+ blueprint: `cc_object {
name: "foo",
local_include_dirs: ["include"],
srcs: [
@@ -103,7 +105,7 @@
],
}
`,
- expectedBazelTargets: []string{`cc_object(
+ expectedBazelTargets: []string{`cc_object(
name = "foo",
copts = [
"-Wno-gcc-compat",
@@ -117,18 +119,20 @@
],
srcs = ["a/b/c.c"],
)`,
- },
+ }})
+}
+
+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,
+ filesystem: map[string]string{
+ "a/b/c.c": "",
+ "x/y/z.c": "",
},
- {
- description: "cc_object with cc_object deps in objs props",
- moduleTypeUnderTest: "cc_object",
- moduleTypeUnderTestFactory: cc.ObjectFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
- filesystem: map[string]string{
- "a/b/c.c": "",
- "x/y/z.c": "",
- },
- blueprint: `cc_object {
+ blueprint: `cc_object {
name: "foo",
srcs: ["a/b/c.c"],
objs: ["bar"],
@@ -139,7 +143,7 @@
srcs: ["x/y/z.c"],
}
`,
- expectedBazelTargets: []string{`cc_object(
+ expectedBazelTargets: []string{`cc_object(
name = "bar",
copts = [
"-fno-addrsig",
@@ -157,36 +161,42 @@
deps = [":bar"],
srcs = ["a/b/c.c"],
)`,
- },
},
- {
- description: "cc_object with include_build_dir: false",
- moduleTypeUnderTest: "cc_object",
- moduleTypeUnderTestFactory: cc.ObjectFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
- filesystem: map[string]string{
- "a/b/c.c": "",
- "x/y/z.c": "",
- },
- blueprint: `cc_object {
+ })
+}
+
+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,
+ filesystem: map[string]string{
+ "a/b/c.c": "",
+ "x/y/z.c": "",
+ },
+ blueprint: `cc_object {
name: "foo",
srcs: ["a/b/c.c"],
include_build_directory: false,
}
`,
- expectedBazelTargets: []string{`cc_object(
+ expectedBazelTargets: []string{`cc_object(
name = "foo",
copts = ["-fno-addrsig"],
srcs = ["a/b/c.c"],
)`,
- },
},
- {
- description: "cc_object with product variable",
- moduleTypeUnderTest: "cc_object",
- moduleTypeUnderTestFactory: cc.ObjectFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
- blueprint: `cc_object {
+ })
+}
+
+func TestCcObjectProductVariable(t *testing.T) {
+ runCcObjectTestCase(t, bp2buildTestCase{
+ description: "cc_object with product variable",
+ moduleTypeUnderTest: "cc_object",
+ moduleTypeUnderTestFactory: cc.ObjectFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
+ blueprint: `cc_object {
name: "foo",
include_build_directory: false,
product_variables: {
@@ -196,82 +206,25 @@
},
}
`,
- expectedBazelTargets: []string{`cc_object(
+ 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"],
)`,
- },
},
- }
-
- dir := "."
- for _, testCase := range testCases {
- filesystem := make(map[string][]byte)
- toParse := []string{
- "Android.bp",
- }
- for f, content := range testCase.filesystem {
- if strings.HasSuffix(f, "Android.bp") {
- toParse = append(toParse, f)
- }
- filesystem[f] = []byte(content)
- }
- config := android.TestConfig(buildDir, nil, testCase.blueprint, filesystem)
- ctx := android.NewTestContext(config)
- // Always register cc_defaults module factory
- ctx.RegisterModuleType("cc_defaults", func() android.Module { return cc.DefaultsFactory() })
-
- ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
- ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator)
- ctx.RegisterBp2BuildConfig(bp2buildConfig)
- 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
- }
-
- codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
- bazelTargets := generateBazelTargetsForDir(codegenCtx, dir)
- if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount {
- fmt.Println(bazelTargets)
- 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,
- )
- }
- }
- }
- }
+ })
}
-func TestCcObjectConfigurableAttributesBp2Build(t *testing.T) {
- testCases := []struct {
- description string
- moduleTypeUnderTest string
- moduleTypeUnderTestFactory android.ModuleFactory
- moduleTypeUnderTestBp2BuildMutator func(android.TopDownMutatorContext)
- blueprint string
- expectedBazelTargets []string
- filesystem map[string]string
- }{
- {
- description: "cc_object setting cflags for one arch",
- moduleTypeUnderTest: "cc_object",
- moduleTypeUnderTestFactory: cc.ObjectFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
- blueprint: `cc_object {
+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,
+ blueprint: `cc_object {
name: "foo",
srcs: ["a.cpp"],
arch: {
@@ -284,8 +237,8 @@
},
}
`,
- expectedBazelTargets: []string{
- `cc_object(
+ expectedBazelTargets: []string{
+ `cc_object(
name = "foo",
copts = [
"-fno-addrsig",
@@ -300,14 +253,17 @@
"//conditions:default": [],
}),
)`,
- },
},
- {
- description: "cc_object setting cflags for 4 architectures",
- moduleTypeUnderTest: "cc_object",
- moduleTypeUnderTestFactory: cc.ObjectFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
- blueprint: `cc_object {
+ })
+}
+
+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,
+ blueprint: `cc_object {
name: "foo",
srcs: ["base.cpp"],
arch: {
@@ -330,8 +286,8 @@
},
}
`,
- expectedBazelTargets: []string{
- `cc_object(
+ expectedBazelTargets: []string{
+ `cc_object(
name = "foo",
copts = [
"-fno-addrsig",
@@ -352,14 +308,17 @@
"//conditions:default": [],
}),
)`,
- },
},
- {
- description: "cc_object setting cflags for multiple OSes",
- moduleTypeUnderTest: "cc_object",
- moduleTypeUnderTestFactory: cc.ObjectFactory,
- moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
- blueprint: `cc_object {
+ })
+}
+
+func TestCcObjectCflagsMultiOs(t *testing.T) {
+ runCcObjectTestCase(t, bp2buildTestCase{
+ description: "cc_object setting cflags for multiple OSes",
+ moduleTypeUnderTest: "cc_object",
+ moduleTypeUnderTestFactory: cc.ObjectFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
+ blueprint: `cc_object {
name: "foo",
srcs: ["base.cpp"],
target: {
@@ -375,8 +334,8 @@
},
}
`,
- expectedBazelTargets: []string{
- `cc_object(
+ expectedBazelTargets: []string{
+ `cc_object(
name = "foo",
copts = [
"-fno-addrsig",
@@ -390,51 +349,6 @@
}),
srcs = ["base.cpp"],
)`,
- },
},
- }
-
- dir := "."
- for _, testCase := range testCases {
- filesystem := make(map[string][]byte)
- toParse := []string{
- "Android.bp",
- }
- config := android.TestConfig(buildDir, nil, testCase.blueprint, filesystem)
- ctx := android.NewTestContext(config)
- // Always register cc_defaults module factory
- ctx.RegisterModuleType("cc_defaults", func() android.Module { return cc.DefaultsFactory() })
-
- ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
- ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator)
- ctx.RegisterBp2BuildConfig(bp2buildConfig)
- 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
- }
-
- codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
- bazelTargets := generateBazelTargetsForDir(codegenCtx, dir)
- if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount {
- fmt.Println(bazelTargets)
- 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,
- )
- }
- }
- }
- }
+ })
}
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 ed509bf..95bce3c 100644
--- a/bp2build/python_binary_conversion_test.go
+++ b/bp2build/python_binary_conversion_test.go
@@ -1,36 +1,30 @@
package bp2build
import (
+ "testing"
+
"android/soong/android"
"android/soong/python"
- "fmt"
- "strings"
- "testing"
)
-func TestPythonBinaryHost(t *testing.T) {
- testCases := []struct {
- description string
- moduleTypeUnderTest string
- moduleTypeUnderTestFactory android.ModuleFactory
- moduleTypeUnderTestBp2BuildMutator func(android.TopDownMutatorContext)
- blueprint string
- expectedBazelTargets []string
- filesystem map[string]string
- }{
- {
- description: "simple python_binary_host converts to a native py_binary",
- moduleTypeUnderTest: "python_binary_host",
- moduleTypeUnderTestFactory: python.PythonBinaryHostFactory,
- moduleTypeUnderTestBp2BuildMutator: python.PythonBinaryBp2Build,
- filesystem: map[string]string{
- "a.py": "",
- "b/c.py": "",
- "b/d.py": "",
- "b/e.py": "",
- "files/data.txt": "",
- },
- blueprint: `python_binary_host {
+func runPythonTestCase(t *testing.T, tc bp2buildTestCase) {
+ runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc)
+}
+
+func TestPythonBinaryHostSimple(t *testing.T) {
+ runPythonTestCase(t, bp2buildTestCase{
+ description: "simple python_binary_host converts to a native py_binary",
+ moduleTypeUnderTest: "python_binary_host",
+ moduleTypeUnderTestFactory: python.PythonBinaryHostFactory,
+ moduleTypeUnderTestBp2BuildMutator: python.PythonBinaryBp2Build,
+ filesystem: map[string]string{
+ "a.py": "",
+ "b/c.py": "",
+ "b/d.py": "",
+ "b/e.py": "",
+ "files/data.txt": "",
+ },
+ blueprint: `python_binary_host {
name: "foo",
main: "a.py",
srcs: ["**/*.py"],
@@ -39,7 +33,7 @@
bazel_module: { bp2build_available: true },
}
`,
- expectedBazelTargets: []string{`py_binary(
+ expectedBazelTargets: []string{`py_binary(
name = "foo",
data = ["files/data.txt"],
main = "a.py",
@@ -49,14 +43,17 @@
"b/d.py",
],
)`,
- },
},
- {
- description: "py2 python_binary_host",
- moduleTypeUnderTest: "python_binary_host",
- moduleTypeUnderTestFactory: python.PythonBinaryHostFactory,
- moduleTypeUnderTestBp2BuildMutator: python.PythonBinaryBp2Build,
- blueprint: `python_binary_host {
+ })
+}
+
+func TestPythonBinaryHostPy2(t *testing.T) {
+ runPythonTestCase(t, bp2buildTestCase{
+ description: "py2 python_binary_host",
+ moduleTypeUnderTest: "python_binary_host",
+ moduleTypeUnderTestFactory: python.PythonBinaryHostFactory,
+ moduleTypeUnderTestBp2BuildMutator: python.PythonBinaryBp2Build,
+ blueprint: `python_binary_host {
name: "foo",
srcs: ["a.py"],
version: {
@@ -71,19 +68,22 @@
bazel_module: { bp2build_available: true },
}
`,
- expectedBazelTargets: []string{`py_binary(
+ expectedBazelTargets: []string{`py_binary(
name = "foo",
python_version = "PY2",
srcs = ["a.py"],
)`,
- },
},
- {
- description: "py3 python_binary_host",
- moduleTypeUnderTest: "python_binary_host",
- moduleTypeUnderTestFactory: python.PythonBinaryHostFactory,
- moduleTypeUnderTestBp2BuildMutator: python.PythonBinaryBp2Build,
- blueprint: `python_binary_host {
+ })
+}
+
+func TestPythonBinaryHostPy3(t *testing.T) {
+ runPythonTestCase(t, bp2buildTestCase{
+ description: "py3 python_binary_host",
+ moduleTypeUnderTest: "python_binary_host",
+ moduleTypeUnderTestFactory: python.PythonBinaryHostFactory,
+ moduleTypeUnderTestBp2BuildMutator: python.PythonBinaryBp2Build,
+ blueprint: `python_binary_host {
name: "foo",
srcs: ["a.py"],
version: {
@@ -98,60 +98,12 @@
bazel_module: { bp2build_available: true },
}
`,
- expectedBazelTargets: []string{
- // python_version is PY3 by default.
- `py_binary(
+ expectedBazelTargets: []string{
+ // python_version is PY3 by default.
+ `py_binary(
name = "foo",
srcs = ["a.py"],
)`,
- },
},
- }
-
- dir := "."
- for _, testCase := range testCases {
- filesystem := make(map[string][]byte)
- toParse := []string{
- "Android.bp",
- }
- for f, content := range testCase.filesystem {
- if strings.HasSuffix(f, "Android.bp") {
- toParse = append(toParse, f)
- }
- filesystem[f] = []byte(content)
- }
- config := android.TestConfig(buildDir, nil, testCase.blueprint, filesystem)
- 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.description, errs) {
- continue
- }
- _, errs = ctx.ResolveDependencies(config)
- if errored(t, testCase.description, errs) {
- continue
- }
-
- codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
- bazelTargets := generateBazelTargetsForDir(codegenCtx, dir)
- if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount {
- fmt.Println(bazelTargets)
- 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,
- )
- }
- }
- }
- }
+ })
}
diff --git a/bp2build/sh_conversion_test.go b/bp2build/sh_conversion_test.go
index 575bf58..91bba54 100644
--- a/bp2build/sh_conversion_test.go
+++ b/bp2build/sh_conversion_test.go
@@ -15,10 +15,10 @@
package bp2build
import (
+ "testing"
+
"android/soong/android"
"android/soong/sh"
- "strings"
- "testing"
)
func TestShBinaryLoadStatement(t *testing.T) {
@@ -46,88 +46,26 @@
t.Fatalf("Expected load statements to be %s, got %s", expected, actual)
}
}
-
}
-func TestShBinaryBp2Build(t *testing.T) {
- testCases := []struct {
- description string
- moduleTypeUnderTest string
- moduleTypeUnderTestFactory android.ModuleFactory
- moduleTypeUnderTestBp2BuildMutator func(android.TopDownMutatorContext)
- preArchMutators []android.RegisterMutatorFunc
- depsMutators []android.RegisterMutatorFunc
- bp string
- expectedBazelTargets []string
- filesystem map[string]string
- dir string
- }{
- {
- description: "sh_binary test",
- moduleTypeUnderTest: "sh_binary",
- moduleTypeUnderTestFactory: sh.ShBinaryFactory,
- moduleTypeUnderTestBp2BuildMutator: sh.ShBinaryBp2Build,
- bp: `sh_binary {
+func runShBinaryTestCase(t *testing.T, tc bp2buildTestCase) {
+ runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc)
+}
+
+func TestShBinarySimple(t *testing.T) {
+ runShBinaryTestCase(t, bp2buildTestCase{
+ description: "sh_binary test",
+ moduleTypeUnderTest: "sh_binary",
+ moduleTypeUnderTestFactory: sh.ShBinaryFactory,
+ moduleTypeUnderTestBp2BuildMutator: sh.ShBinaryBp2Build,
+ blueprint: `sh_binary {
name: "foo",
src: "foo.sh",
bazel_module: { bp2build_available: true },
}`,
- expectedBazelTargets: []string{`sh_binary(
+ expectedBazelTargets: []string{`sh_binary(
name = "foo",
srcs = ["foo.sh"],
)`},
- },
- }
-
- dir := "."
- for _, testCase := range testCases {
- filesystem := make(map[string][]byte)
- toParse := []string{
- "Android.bp",
- }
- for f, content := range testCase.filesystem {
- if strings.HasSuffix(f, "Android.bp") {
- toParse = append(toParse, f)
- }
- filesystem[f] = []byte(content)
- }
- config := android.TestConfig(buildDir, nil, testCase.bp, filesystem)
- 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
- }
-
- checkDir := dir
- if testCase.dir != "" {
- checkDir = testCase.dir
- }
- codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
- bazelTargets := generateBazelTargetsForDir(codegenCtx, checkDir)
- 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,
- )
- }
- }
- }
- }
+ })
}
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 75543ac..0c827c5 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -318,6 +318,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,
@@ -329,6 +344,7 @@
deps bazel.LabelListAttribute
dynamicDeps bazel.LabelListAttribute
wholeArchiveDeps bazel.LabelListAttribute
+ exportedDeps bazel.LabelListAttribute
linkopts bazel.StringListAttribute
versionScript bazel.LabelAttribute
}
@@ -346,6 +362,7 @@
// configurable attribute values.
func bp2BuildParseLinkerProps(ctx android.TopDownMutatorContext, module *Module) linkerAttributes {
var deps bazel.LabelListAttribute
+ var exportedDeps bazel.LabelListAttribute
var dynamicDeps bazel.LabelListAttribute
var wholeArchiveDeps bazel.LabelListAttribute
var linkopts bazel.StringListAttribute
@@ -354,11 +371,12 @@
for _, linkerProps := range module.linker.linkerProps() {
if baseLinkerProps, ok := linkerProps.(*BaseLinkerProperties); ok {
libs := baseLinkerProps.Header_libs
- libs = append(libs, baseLinkerProps.Export_header_lib_headers...)
libs = append(libs, baseLinkerProps.Static_libs...)
+ exportedLibs := baseLinkerProps.Export_header_lib_headers
wholeArchiveLibs := baseLinkerProps.Whole_static_libs
libs = android.SortedUniqueStrings(libs)
deps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, libs))
+ exportedDeps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, exportedLibs))
linkopts.Value = getBp2BuildLinkerFlags(baseLinkerProps)
wholeArchiveDeps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, wholeArchiveLibs))
@@ -376,11 +394,12 @@
for arch, p := range module.GetArchProperties(ctx, &BaseLinkerProperties{}) {
if baseLinkerProps, ok := p.(*BaseLinkerProperties); ok {
libs := baseLinkerProps.Header_libs
- libs = append(libs, baseLinkerProps.Export_header_lib_headers...)
libs = append(libs, baseLinkerProps.Static_libs...)
+ exportedLibs := baseLinkerProps.Export_header_lib_headers
wholeArchiveLibs := baseLinkerProps.Whole_static_libs
libs = android.SortedUniqueStrings(libs)
deps.SetValueForArch(arch.Name, android.BazelLabelForModuleDeps(ctx, libs))
+ exportedDeps.SetValueForArch(arch.Name, android.BazelLabelForModuleDeps(ctx, exportedLibs))
linkopts.SetValueForArch(arch.Name, getBp2BuildLinkerFlags(baseLinkerProps))
wholeArchiveDeps.SetValueForArch(arch.Name, android.BazelLabelForModuleDeps(ctx, wholeArchiveLibs))
@@ -397,12 +416,13 @@
for os, p := range module.GetTargetProperties(ctx, &BaseLinkerProperties{}) {
if baseLinkerProps, ok := p.(*BaseLinkerProperties); ok {
libs := baseLinkerProps.Header_libs
- libs = append(libs, baseLinkerProps.Export_header_lib_headers...)
libs = append(libs, baseLinkerProps.Static_libs...)
+ exportedLibs := baseLinkerProps.Export_header_lib_headers
wholeArchiveLibs := baseLinkerProps.Whole_static_libs
libs = android.SortedUniqueStrings(libs)
wholeArchiveDeps.SetValueForOS(os.Name, android.BazelLabelForModuleDeps(ctx, wholeArchiveLibs))
deps.SetValueForOS(os.Name, android.BazelLabelForModuleDeps(ctx, libs))
+ exportedDeps.SetValueForOS(os.Name, android.BazelLabelForModuleDeps(ctx, exportedLibs))
linkopts.SetValueForOS(os.Name, getBp2BuildLinkerFlags(baseLinkerProps))
@@ -413,6 +433,7 @@
return linkerAttributes{
deps: deps,
+ exportedDeps: exportedDeps,
dynamicDeps: dynamicDeps,
wholeArchiveDeps: wholeArchiveDeps,
linkopts: linkopts,
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/coverage.go b/cc/coverage.go
index b2788ec..baf4226 100644
--- a/cc/coverage.go
+++ b/cc/coverage.go
@@ -96,7 +96,8 @@
// flags that the module may use.
flags.Local.CFlags = append(flags.Local.CFlags, "-Wno-frame-larger-than=", "-O0")
} else if clangCoverage {
- flags.Local.CommonFlags = append(flags.Local.CommonFlags, profileInstrFlag, "-fcoverage-mapping", "-Wno-pass-failed")
+ flags.Local.CommonFlags = append(flags.Local.CommonFlags, profileInstrFlag,
+ "-fcoverage-mapping", "-Wno-pass-failed", "-D__ANDROID_CLANG_COVERAGE__")
}
}
diff --git a/cc/library.go b/cc/library.go
index 1ba3597..c918b96 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -221,17 +221,19 @@
// For bp2build conversion.
type bazelCcLibraryAttributes struct {
// Attributes pertaining to both static and shared variants.
- Srcs bazel.LabelListAttribute
- Hdrs bazel.LabelListAttribute
- Deps bazel.LabelListAttribute
- Dynamic_deps bazel.LabelListAttribute
- Whole_archive_deps bazel.LabelListAttribute
- Copts bazel.StringListAttribute
- Includes bazel.StringListAttribute
- Linkopts bazel.StringListAttribute
+ Srcs bazel.LabelListAttribute
+ Hdrs bazel.LabelListAttribute
+ Deps bazel.LabelListAttribute
+ Implementation_deps bazel.LabelListAttribute
+ Dynamic_deps bazel.LabelListAttribute
+ Whole_archive_deps bazel.LabelListAttribute
+ Copts bazel.StringListAttribute
+ Includes bazel.StringListAttribute
+ Linkopts bazel.StringListAttribute
// Attributes pertaining to shared variant.
Shared_copts bazel.StringListAttribute
Shared_srcs bazel.LabelListAttribute
+ Exported_deps_for_shared bazel.LabelListAttribute
Static_deps_for_shared bazel.LabelListAttribute
Dynamic_deps_for_shared bazel.LabelListAttribute
Whole_archive_deps_for_shared bazel.LabelListAttribute
@@ -240,6 +242,7 @@
// Attributes pertaining to static variant.
Static_copts bazel.StringListAttribute
Static_srcs bazel.LabelListAttribute
+ Exported_deps_for_static bazel.LabelListAttribute
Static_deps_for_static bazel.LabelListAttribute
Dynamic_deps_for_static bazel.LabelListAttribute
Whole_archive_deps_for_static bazel.LabelListAttribute
@@ -292,7 +295,8 @@
attrs := &bazelCcLibraryAttributes{
Srcs: srcs,
- Deps: linkerAttrs.deps,
+ Implementation_deps: linkerAttrs.deps,
+ Deps: linkerAttrs.exportedDeps,
Dynamic_deps: linkerAttrs.dynamicDeps,
Whole_archive_deps: linkerAttrs.wholeArchiveDeps,
Copts: compilerAttrs.copts,
@@ -2217,14 +2221,15 @@
}
type bazelCcLibraryStaticAttributes struct {
- Copts bazel.StringListAttribute
- Srcs bazel.LabelListAttribute
- Deps bazel.LabelListAttribute
- Whole_archive_deps bazel.LabelListAttribute
- Linkopts bazel.StringListAttribute
- Linkstatic bool
- Includes bazel.StringListAttribute
- Hdrs bazel.LabelListAttribute
+ Copts bazel.StringListAttribute
+ Srcs bazel.LabelListAttribute
+ Implementation_deps bazel.LabelListAttribute
+ Deps bazel.LabelListAttribute
+ Whole_archive_deps bazel.LabelListAttribute
+ Linkopts bazel.StringListAttribute
+ Linkstatic bool
+ Includes bazel.StringListAttribute
+ Hdrs bazel.LabelListAttribute
}
type bazelCcLibraryStatic struct {
@@ -2245,10 +2250,11 @@
exportedIncludes := bp2BuildParseExportedIncludes(ctx, module)
attrs := &bazelCcLibraryStaticAttributes{
- Copts: compilerAttrs.copts,
- Srcs: compilerAttrs.srcs,
- Deps: linkerAttrs.deps,
- Whole_archive_deps: linkerAttrs.wholeArchiveDeps,
+ Copts: compilerAttrs.copts,
+ Srcs: compilerAttrs.srcs,
+ Implementation_deps: linkerAttrs.deps,
+ Deps: linkerAttrs.exportedDeps,
+ Whole_archive_deps: linkerAttrs.wholeArchiveDeps,
Linkopts: linkerAttrs.linkopts,
Linkstatic: true,
diff --git a/cc/library_headers.go b/cc/library_headers.go
index 0aba8de..2065929 100644
--- a/cc/library_headers.go
+++ b/cc/library_headers.go
@@ -109,10 +109,11 @@
}
type bazelCcLibraryHeadersAttributes struct {
- Copts bazel.StringListAttribute
- Hdrs bazel.LabelListAttribute
- Includes bazel.StringListAttribute
- Deps bazel.LabelListAttribute
+ Copts bazel.StringListAttribute
+ Hdrs bazel.LabelListAttribute
+ Includes bazel.StringListAttribute
+ Deps bazel.LabelListAttribute
+ Implementation_deps bazel.LabelListAttribute
}
type bazelCcLibraryHeaders struct {
@@ -147,9 +148,10 @@
linkerAttrs := bp2BuildParseLinkerProps(ctx, module)
attrs := &bazelCcLibraryHeadersAttributes{
- Copts: compilerAttrs.copts,
- Includes: exportedIncludes,
- Deps: linkerAttrs.deps,
+ Copts: compilerAttrs.copts,
+ Includes: exportedIncludes,
+ Implementation_deps: linkerAttrs.deps,
+ Deps: linkerAttrs.exportedDeps,
}
props := bazel.BazelTargetModuleProperties{
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/Android.bp b/java/Android.bp
index 623a6c5..680f3a1 100644
--- a/java/Android.bp
+++ b/java/Android.bp
@@ -45,6 +45,7 @@
"genrule.go",
"hiddenapi.go",
"hiddenapi_modular.go",
+ "hiddenapi_monolithic.go",
"hiddenapi_singleton.go",
"jacoco.go",
"java.go",
diff --git a/java/app_import.go b/java/app_import.go
index 839051e..6fe6204 100644
--- a/java/app_import.go
+++ b/java/app_import.go
@@ -99,6 +99,9 @@
// If set, create package-export.apk, which other packages can
// use to get PRODUCT-agnostic resource data like IDs and type definitions.
Export_package_resources *bool
+
+ // Optional. Install to a subdirectory of the default install path for the module
+ Relative_install_path *string
}
func (a *AndroidAppImport) IsInstallable() bool {
@@ -263,20 +266,25 @@
jnisUncompressed := android.PathForModuleOut(ctx, "jnis-uncompressed", ctx.ModuleName()+".apk")
a.uncompressEmbeddedJniLibs(ctx, srcApk, jnisUncompressed.OutputPath)
- var installDir android.InstallPath
+ var pathFragments []string
+ relInstallPath := String(a.properties.Relative_install_path)
if a.isPrebuiltFrameworkRes() {
// framework-res.apk is installed as system/framework/framework-res.apk
- installDir = android.PathForModuleInstall(ctx, "framework")
+ if relInstallPath != "" {
+ ctx.PropertyErrorf("relative_install_path", "Relative_install_path cannot be set for framework-res")
+ }
+ pathFragments = []string{"framework"}
a.preprocessed = true
} else if Bool(a.properties.Privileged) {
- installDir = android.PathForModuleInstall(ctx, "priv-app", a.BaseModuleName())
+ pathFragments = []string{"priv-app", relInstallPath, a.BaseModuleName()}
} else if ctx.InstallInTestcases() {
- installDir = android.PathForModuleInstall(ctx, a.BaseModuleName(), ctx.DeviceConfig().DeviceArch())
+ pathFragments = []string{relInstallPath, a.BaseModuleName(), ctx.DeviceConfig().DeviceArch()}
} else {
- installDir = android.PathForModuleInstall(ctx, "app", a.BaseModuleName())
+ pathFragments = []string{"app", relInstallPath, a.BaseModuleName()}
}
+ installDir := android.PathForModuleInstall(ctx, pathFragments...)
a.dexpreopter.isApp = true
a.dexpreopter.installPath = installDir.Join(ctx, a.BaseModuleName()+".apk")
a.dexpreopter.isPresignedPrebuilt = Bool(a.properties.Presigned)
diff --git a/java/app_import_test.go b/java/app_import_test.go
index 147ae45..024a3df 100644
--- a/java/app_import_test.go
+++ b/java/app_import_test.go
@@ -493,6 +493,69 @@
}
}
+func TestAndroidAppImport_relativeInstallPath(t *testing.T) {
+ bp := `
+ android_app_import {
+ name: "no_relative_install_path",
+ apk: "prebuilts/apk/app.apk",
+ presigned: true,
+ }
+
+ android_app_import {
+ name: "relative_install_path",
+ apk: "prebuilts/apk/app.apk",
+ presigned: true,
+ relative_install_path: "my/path",
+ }
+
+ android_app_import {
+ name: "framework-res",
+ apk: "prebuilts/apk/app.apk",
+ presigned: true,
+ prefer: true,
+ }
+
+ android_app_import {
+ name: "privileged_relative_install_path",
+ apk: "prebuilts/apk/app.apk",
+ presigned: true,
+ privileged: true,
+ relative_install_path: "my/path"
+ }
+ `
+ testCases := []struct {
+ name string
+ expectedInstallPath string
+ errorMessage string
+ }{
+ {
+ name: "no_relative_install_path",
+ expectedInstallPath: "out/soong/target/product/test_device/system/app/no_relative_install_path/no_relative_install_path.apk",
+ errorMessage: "Install path is not correct when relative_install_path is missing",
+ },
+ {
+ name: "relative_install_path",
+ expectedInstallPath: "out/soong/target/product/test_device/system/app/my/path/relative_install_path/relative_install_path.apk",
+ errorMessage: "Install path is not correct for app when relative_install_path is present",
+ },
+ {
+ name: "prebuilt_framework-res",
+ expectedInstallPath: "out/soong/target/product/test_device/system/framework/framework-res.apk",
+ errorMessage: "Install path is not correct for framework-res",
+ },
+ {
+ name: "privileged_relative_install_path",
+ expectedInstallPath: "out/soong/target/product/test_device/system/priv-app/my/path/privileged_relative_install_path/privileged_relative_install_path.apk",
+ errorMessage: "Install path is not correct for privileged app when relative_install_path is present",
+ },
+ }
+ for _, testCase := range testCases {
+ ctx, _ := testJava(t, bp)
+ mod := ctx.ModuleForTests(testCase.name, "android_common").Module().(*AndroidAppImport)
+ android.AssertPathRelativeToTopEquals(t, testCase.errorMessage, testCase.expectedInstallPath, mod.installPath)
+ }
+}
+
func TestAndroidTestImport(t *testing.T) {
ctx, _ := testJava(t, `
android_test_import {
diff --git a/java/bootclasspath.go b/java/bootclasspath.go
index 634959a..eddcc83 100644
--- a/java/bootclasspath.go
+++ b/java/bootclasspath.go
@@ -235,12 +235,3 @@
m[android.SdkCorePlatform] = p.Core_platform_api.Stub_libs
return m
}
-
-// bootclasspathApiInfo contains paths resolved from BootclasspathAPIProperties
-type bootclasspathApiInfo struct {
- // stubJarsByKind maps from the android.SdkKind to the paths containing dex stub jars for each
- // kind.
- stubJarsByKind map[android.SdkKind]android.Paths
-}
-
-var bootclasspathApiInfoProvider = blueprint.NewProvider(bootclasspathApiInfo{})
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index 318ea44..188d362 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -133,10 +133,12 @@
type commonBootclasspathFragment interface {
// produceHiddenAPIAllFlagsFile produces the all-flags.csv and intermediate files.
//
- // Updates the supplied flagFileInfo with the paths to the generated files set.
- produceHiddenAPIAllFlagsFile(ctx android.ModuleContext, contents []hiddenAPIModule, stubJarsByKind map[android.SdkKind]android.Paths, flagFileInfo *hiddenAPIFlagFileInfo)
+ // Updates the supplied hiddenAPIInfo with the paths to the generated files set.
+ produceHiddenAPIAllFlagsFile(ctx android.ModuleContext, contents []hiddenAPIModule, input HiddenAPIFlagInput) *HiddenAPIFlagOutput
}
+var _ commonBootclasspathFragment = (*BootclasspathFragmentModule)(nil)
+
func bootclasspathFragmentFactory() android.Module {
m := &BootclasspathFragmentModule{}
m.AddProperties(&m.properties)
@@ -166,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
@@ -268,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.
@@ -280,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.
@@ -365,6 +367,11 @@
dexpreopt.RegisterToolDeps(ctx)
}
+func (b *BootclasspathFragmentModule) BootclasspathDepsMutator(ctx android.BottomUpMutatorContext) {
+ // Add dependencies on all the fragments.
+ b.properties.BootclasspathFragmentsDepsProperties.addDependenciesOntoFragments(ctx)
+}
+
func (b *BootclasspathFragmentModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
// Only perform a consistency check if this module is the active module. That will prevent an
// unused prebuilt that was created without instrumentation from breaking an instrumentation
@@ -385,8 +392,10 @@
}
})
+ fragments := gatherApexModulePairDepsWithTag(ctx, bootclasspathFragmentDepTag)
+
// Perform hidden API processing.
- b.generateHiddenAPIBuildActions(ctx, contents)
+ hiddenAPIFlagOutput := b.generateHiddenAPIBuildActions(ctx, contents, fragments)
// Verify that the image_name specified on a bootclasspath_fragment is valid even if this is a
// prebuilt which will not use the image config.
@@ -395,28 +404,41 @@
// A prebuilt fragment cannot contribute to the apex.
if !android.IsModulePrebuilt(ctx.Module()) {
// Provide the apex content info.
- b.provideApexContentInfo(ctx, imageConfig, contents)
+ b.provideApexContentInfo(ctx, imageConfig, contents, hiddenAPIFlagOutput)
}
}
// provideApexContentInfo creates, initializes and stores the apex content info for use by other
// modules.
-func (b *BootclasspathFragmentModule) provideApexContentInfo(ctx android.ModuleContext, imageConfig *bootImageConfig, contents []android.Module) {
+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)
+ 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.
@@ -425,12 +447,33 @@
// populateApexContentInfoDexJars adds paths to the dex jars provided by this fragment to the
// apex content info.
-func (b *BootclasspathFragmentModule) populateApexContentInfoDexJars(ctx android.ModuleContext, info *BootclasspathFragmentApexContentInfo, contents []android.Module) {
+func (b *BootclasspathFragmentModule) populateApexContentInfoDexJars(ctx android.ModuleContext, info *BootclasspathFragmentApexContentInfo, contents []android.Module, hiddenAPIFlagOutput *HiddenAPIFlagOutput) {
+
info.contentModuleDexJarPaths = map[string]android.Path{}
- for _, m := range contents {
- j := m.(UsesLibraryDependency)
- dexJar := j.DexJarBuildPath()
- info.contentModuleDexJarPaths[m.Name()] = dexJar
+ if hiddenAPIFlagOutput != nil {
+ // Hidden API encoding has been performed.
+ flags := hiddenAPIFlagOutput.AllFlagsPath
+ for _, m := range contents {
+ h := m.(hiddenAPIModule)
+ unencodedDex := h.bootDexJar()
+ if unencodedDex == nil {
+ // This is an error. Sometimes Soong will report the error directly, other times it will
+ // defer the error reporting to happen only when trying to use the missing file in ninja.
+ // Either way it is handled by extractBootDexJarsFromHiddenAPIModules which must have been
+ // called before this as it generates the flags that are used to encode these files.
+ continue
+ }
+
+ outputDir := android.PathForModuleOut(ctx, "hiddenapi-modular/encoded").OutputPath
+ encodedDex := hiddenAPIEncodeDex(ctx, unencodedDex, flags, *h.uncompressDex(), outputDir)
+ info.contentModuleDexJarPaths[m.Name()] = encodedDex
+ }
+ } else {
+ for _, m := range contents {
+ j := m.(UsesLibraryDependency)
+ dexJar := j.DexJarBuildPath()
+ info.contentModuleDexJarPaths[m.Name()] = dexJar
+ }
}
}
@@ -478,107 +521,104 @@
return imageConfig
}
-// canPerformHiddenAPIProcessing determines whether hidden API processing should be performed.
-//
-// A temporary workaround to avoid existing bootclasspath_fragments that do not provide the
-// appropriate information needed for hidden API processing breaking the build.
-// TODO(b/179354495): Remove this workaround.
-func (b *BootclasspathFragmentModule) canPerformHiddenAPIProcessing(ctx android.ModuleContext) bool {
- // Hidden API processing is always enabled in tests.
- if ctx.Config().TestProductVariables != nil {
- return true
- }
- // A module that has fragments should have access to the information it needs in order to perform
- // hidden API processing.
- if len(b.properties.Fragments) != 0 {
- return true
+// generateHiddenAPIBuildActions generates all the hidden API related build rules.
+func (b *BootclasspathFragmentModule) generateHiddenAPIBuildActions(ctx android.ModuleContext, contents []android.Module, fragments []android.Module) *HiddenAPIFlagOutput {
+
+ // Create hidden API input structure.
+ input := b.createHiddenAPIFlagInput(ctx, contents, fragments)
+
+ var output *HiddenAPIFlagOutput
+
+ // Hidden API processing is conditional as a temporary workaround as not all
+ // bootclasspath_fragments provide the appropriate information needed for hidden API processing
+ // which leads to breakages of the build.
+ // TODO(b/179354495): Stop hidden API processing being conditional once all bootclasspath_fragment
+ // modules have been updated to support it.
+ if input.canPerformHiddenAPIProcessing(ctx, b.properties) {
+ // Get the content modules that contribute to the hidden API processing.
+ hiddenAPIModules := gatherHiddenAPIModuleFromContents(ctx, contents)
+
+ // Delegate the production of the hidden API all-flags.csv file to a module type specific method.
+ common := ctx.Module().(commonBootclasspathFragment)
+ output = common.produceHiddenAPIAllFlagsFile(ctx, hiddenAPIModules, input)
}
- // The art bootclasspath fragment does not depend on any other fragments but already supports
- // hidden API processing.
- imageName := proptools.String(b.properties.Image_name)
- if imageName == "art" {
- return true
+ // Initialize a HiddenAPIInfo structure.
+ hiddenAPIInfo := HiddenAPIInfo{
+ // The monolithic hidden API processing needs access to the flag files that override the default
+ // flags from all the fragments whether or not they actually perform their own hidden API flag
+ // generation. That is because the monolithic hidden API processing uses those flag files to
+ // perform its own flag generation.
+ FlagFilesByCategory: input.FlagFilesByCategory,
+
+ // Other bootclasspath_fragments that depend on this need the transitive set of stub dex jars
+ // from this to resolve any references from their code to classes provided by this fragment
+ // and the fragments this depends upon.
+ TransitiveStubDexJarsByKind: input.transitiveStubDexJarsByKind(),
}
- // Disable it for everything else.
- return false
+ if output != nil {
+ // The monolithic hidden API processing also needs access to all the output files produced by
+ // hidden API processing of this fragment.
+ hiddenAPIInfo.HiddenAPIFlagOutput = *output
+ }
+
+ // Provide it for use by other modules.
+ ctx.SetProvider(HiddenAPIInfoProvider, hiddenAPIInfo)
+
+ return output
}
-// generateHiddenAPIBuildActions generates all the hidden API related build rules.
-func (b *BootclasspathFragmentModule) generateHiddenAPIBuildActions(ctx android.ModuleContext, contents []android.Module) {
+// createHiddenAPIFlagInput creates a HiddenAPIFlagInput struct and initializes it with information derived
+// from the properties on this module and its dependencies.
+func (b *BootclasspathFragmentModule) createHiddenAPIFlagInput(ctx android.ModuleContext, contents []android.Module, fragments []android.Module) HiddenAPIFlagInput {
- // A temporary workaround to avoid existing bootclasspath_fragments that do not provide the
- // appropriate information needed for hidden API processing breaking the build.
- if !b.canPerformHiddenAPIProcessing(ctx) {
- // Nothing to do.
- return
- }
+ // Merge the HiddenAPIInfo from all the fragment dependencies.
+ dependencyHiddenApiInfo := newHiddenAPIInfo()
+ dependencyHiddenApiInfo.mergeFromFragmentDeps(ctx, fragments)
- // Convert the kind specific lists of modules into kind specific lists of jars.
- stubJarsByKind := hiddenAPIGatherStubLibDexJarPaths(ctx, contents)
+ // Create hidden API flag input structure.
+ input := newHiddenAPIFlagInput()
- // Performing hidden API processing without stubs is not supported and it is unlikely to ever be
- // required as the whole point of adding something to the bootclasspath fragment is to add it to
- // the bootclasspath in order to be used by something else in the system. Without any stubs it
- // cannot do that.
- if len(stubJarsByKind) == 0 {
- return
- }
+ // Update the input structure with information obtained from the stub libraries.
+ input.gatherStubLibInfo(ctx, contents)
- // Store the information for use by other modules.
- bootclasspathApiInfo := bootclasspathApiInfo{stubJarsByKind: stubJarsByKind}
- ctx.SetProvider(bootclasspathApiInfoProvider, bootclasspathApiInfo)
+ // Populate with flag file paths from the properties.
+ input.extractFlagFilesFromProperties(ctx, &b.properties.Hidden_api)
- // Resolve the properties to paths.
- flagFileInfo := b.properties.Hidden_api.hiddenAPIFlagFileInfo(ctx)
+ // Store the stub dex jars from this module's fragment dependencies.
+ input.DependencyStubDexJarsByKind = dependencyHiddenApiInfo.TransitiveStubDexJarsByKind
- hiddenAPIModules := gatherHiddenAPIModuleFromContents(ctx, contents)
-
- // Delegate the production of the hidden API all flags file to a module type specific method.
- common := ctx.Module().(commonBootclasspathFragment)
- common.produceHiddenAPIAllFlagsFile(ctx, hiddenAPIModules, stubJarsByKind, &flagFileInfo)
-
- // Store the information for use by platform_bootclasspath.
- ctx.SetProvider(hiddenAPIFlagFileInfoProvider, flagFileInfo)
+ return input
}
// produceHiddenAPIAllFlagsFile produces the hidden API all-flags.csv file (and supporting files)
// for the fragment.
-func (b *BootclasspathFragmentModule) produceHiddenAPIAllFlagsFile(ctx android.ModuleContext, contents []hiddenAPIModule, stubJarsByKind map[android.SdkKind]android.Paths, flagFileInfo *hiddenAPIFlagFileInfo) {
- // Generate the rules to create the hidden API flags and update the supplied flagFileInfo with the
+func (b *BootclasspathFragmentModule) produceHiddenAPIAllFlagsFile(ctx android.ModuleContext, contents []hiddenAPIModule, input HiddenAPIFlagInput) *HiddenAPIFlagOutput {
+ // Generate the rules to create the hidden API flags and update the supplied hiddenAPIInfo with the
// paths to the created files.
- hiddenAPIGenerateAllFlagsForBootclasspathFragment(ctx, contents, stubJarsByKind, flagFileInfo)
+ return hiddenAPIGenerateAllFlagsForBootclasspathFragment(ctx, contents, input)
}
// 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.
@@ -587,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 {
@@ -628,7 +670,7 @@
Core_platform_stub_libs []string
// Flag files by *hiddenAPIFlagFileCategory
- Flag_files_by_category map[*hiddenAPIFlagFileCategory]android.Paths
+ Flag_files_by_category FlagFilesByCategory
// The path to the generated stub-flags.csv file.
Stub_flags_path android.OptionalPath
@@ -646,34 +688,23 @@
All_flags_path android.OptionalPath
}
-func pathsToOptionalPath(paths android.Paths) android.OptionalPath {
- switch len(paths) {
- case 0:
- return android.OptionalPath{}
- case 1:
- return android.OptionalPathForPath(paths[0])
- default:
- panic(fmt.Errorf("expected 0 or 1 paths, found %q", paths))
- }
-}
-
func (b *bootclasspathFragmentSdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
module := variant.(*BootclasspathFragmentModule)
b.Image_name = module.properties.Image_name
b.Contents = module.properties.Contents
- // Get the flag file information from the module.
+ // Get the hidden API information from the module.
mctx := ctx.SdkModuleContext()
- flagFileInfo := mctx.OtherModuleProvider(module, hiddenAPIFlagFileInfoProvider).(hiddenAPIFlagFileInfo)
- b.Flag_files_by_category = flagFileInfo.categoryToPaths
+ hiddenAPIInfo := mctx.OtherModuleProvider(module, HiddenAPIInfoProvider).(HiddenAPIInfo)
+ b.Flag_files_by_category = hiddenAPIInfo.FlagFilesByCategory
// Copy all the generated file paths.
- b.Stub_flags_path = pathsToOptionalPath(flagFileInfo.StubFlagsPaths)
- b.Annotation_flags_path = pathsToOptionalPath(flagFileInfo.AnnotationFlagsPaths)
- b.Metadata_path = pathsToOptionalPath(flagFileInfo.MetadataPaths)
- b.Index_path = pathsToOptionalPath(flagFileInfo.IndexPaths)
- b.All_flags_path = pathsToOptionalPath(flagFileInfo.AllFlagsPaths)
+ b.Stub_flags_path = android.OptionalPathForPath(hiddenAPIInfo.StubFlagsPath)
+ b.Annotation_flags_path = android.OptionalPathForPath(hiddenAPIInfo.AnnotationFlagsPath)
+ b.Metadata_path = android.OptionalPathForPath(hiddenAPIInfo.MetadataPath)
+ b.Index_path = android.OptionalPathForPath(hiddenAPIInfo.IndexPath)
+ b.All_flags_path = android.OptionalPathForPath(hiddenAPIInfo.AllFlagsPath)
// Copy stub_libs properties.
b.Stub_libs = module.properties.Api.Stub_libs
@@ -783,20 +814,24 @@
// produceHiddenAPIAllFlagsFile returns a path to the prebuilt all-flags.csv or nil if none is
// specified.
-func (module *prebuiltBootclasspathFragmentModule) produceHiddenAPIAllFlagsFile(ctx android.ModuleContext, contents []hiddenAPIModule, stubJarsByKind map[android.SdkKind]android.Paths, flagFileInfo *hiddenAPIFlagFileInfo) {
- pathsForOptionalSrc := func(src *string) android.Paths {
+func (module *prebuiltBootclasspathFragmentModule) produceHiddenAPIAllFlagsFile(ctx android.ModuleContext, contents []hiddenAPIModule, _ HiddenAPIFlagInput) *HiddenAPIFlagOutput {
+ pathForOptionalSrc := func(src *string) android.Path {
if src == nil {
// TODO(b/179354495): Fail if this is not provided once prebuilts have been updated.
return nil
}
- return android.Paths{android.PathForModuleSrc(ctx, *src)}
+ return android.PathForModuleSrc(ctx, *src)
}
- flagFileInfo.StubFlagsPaths = pathsForOptionalSrc(module.prebuiltProperties.Hidden_api.Stub_flags)
- flagFileInfo.AnnotationFlagsPaths = pathsForOptionalSrc(module.prebuiltProperties.Hidden_api.Annotation_flags)
- flagFileInfo.MetadataPaths = pathsForOptionalSrc(module.prebuiltProperties.Hidden_api.Metadata)
- flagFileInfo.IndexPaths = pathsForOptionalSrc(module.prebuiltProperties.Hidden_api.Index)
- flagFileInfo.AllFlagsPaths = pathsForOptionalSrc(module.prebuiltProperties.Hidden_api.All_flags)
+ output := HiddenAPIFlagOutput{
+ StubFlagsPath: pathForOptionalSrc(module.prebuiltProperties.Hidden_api.Stub_flags),
+ AnnotationFlagsPath: pathForOptionalSrc(module.prebuiltProperties.Hidden_api.Annotation_flags),
+ MetadataPath: pathForOptionalSrc(module.prebuiltProperties.Hidden_api.Metadata),
+ IndexPath: pathForOptionalSrc(module.prebuiltProperties.Hidden_api.Index),
+ AllFlagsPath: pathForOptionalSrc(module.prebuiltProperties.Hidden_api.All_flags),
+ }
+
+ return &output
}
var _ commonBootclasspathFragment = (*prebuiltBootclasspathFragmentModule)(nil)
diff --git a/java/bootclasspath_fragment_test.go b/java/bootclasspath_fragment_test.go
index db284c9..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",
@@ -252,7 +233,7 @@
`)
fragment := result.Module("myfragment", "android_common")
- info := result.ModuleProvider(fragment, bootclasspathApiInfoProvider).(bootclasspathApiInfo)
+ info := result.ModuleProvider(fragment, HiddenAPIInfoProvider).(HiddenAPIInfo)
stubsJar := "out/soong/.intermediates/mystublib/android_common/dex/mystublib.jar"
@@ -264,17 +245,17 @@
otherPublicStubsJar := "out/soong/.intermediates/myothersdklibrary.stubs/android_common/dex/myothersdklibrary.stubs.jar"
// Check that SdkPublic uses public stubs for all sdk libraries.
- android.AssertPathsRelativeToTopEquals(t, "public dex stubs jar", []string{otherPublicStubsJar, publicStubsJar, stubsJar}, info.stubJarsByKind[android.SdkPublic])
+ android.AssertPathsRelativeToTopEquals(t, "public dex stubs jar", []string{otherPublicStubsJar, publicStubsJar, stubsJar}, info.TransitiveStubDexJarsByKind[android.SdkPublic])
// Check that SdkSystem uses system stubs for mysdklibrary and public stubs for myothersdklibrary
// as it does not provide system stubs.
- android.AssertPathsRelativeToTopEquals(t, "system dex stubs jar", []string{otherPublicStubsJar, systemStubsJar, stubsJar}, info.stubJarsByKind[android.SdkSystem])
+ android.AssertPathsRelativeToTopEquals(t, "system dex stubs jar", []string{otherPublicStubsJar, systemStubsJar, stubsJar}, info.TransitiveStubDexJarsByKind[android.SdkSystem])
// Check that SdkTest also uses system stubs for mysdklibrary as it does not provide test stubs
// and public stubs for myothersdklibrary as it does not provide test stubs either.
- android.AssertPathsRelativeToTopEquals(t, "test dex stubs jar", []string{otherPublicStubsJar, systemStubsJar, stubsJar}, info.stubJarsByKind[android.SdkTest])
+ android.AssertPathsRelativeToTopEquals(t, "test dex stubs jar", []string{otherPublicStubsJar, systemStubsJar, stubsJar}, info.TransitiveStubDexJarsByKind[android.SdkTest])
// Check that SdkCorePlatform uses public stubs from the mycoreplatform library.
corePlatformStubsJar := "out/soong/.intermediates/mycoreplatform.stubs/android_common/dex/mycoreplatform.stubs.jar"
- android.AssertPathsRelativeToTopEquals(t, "core platform dex stubs jar", []string{corePlatformStubsJar}, info.stubJarsByKind[android.SdkCorePlatform])
+ android.AssertPathsRelativeToTopEquals(t, "core platform dex stubs jar", []string{corePlatformStubsJar}, info.TransitiveStubDexJarsByKind[android.SdkCorePlatform])
}
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/hiddenapi.go b/java/hiddenapi.go
index c9e3c29..e9693c6 100644
--- a/java/hiddenapi.go
+++ b/java/hiddenapi.go
@@ -145,15 +145,13 @@
}
uncompressDex := *h.uncompressDexState
- hiddenAPIJar := android.PathForModuleOut(ctx, "hiddenapi", dexJar.Base()).OutputPath
-
// Create a copy of the dex jar which has been encoded with hiddenapi flags.
- hiddenAPIEncodeDex(ctx, hiddenAPIJar, dexJar, uncompressDex)
+ flagsCSV := hiddenAPISingletonPaths(ctx).flags
+ outputDir := android.PathForModuleOut(ctx, "hiddenapi").OutputPath
+ encodedDex := hiddenAPIEncodeDex(ctx, dexJar, flagsCSV, uncompressDex, outputDir)
// Use the encoded dex jar from here onwards.
- dexJar = hiddenAPIJar
-
- return dexJar
+ return encodedDex
}
// buildRuleToGenerateAnnotationFlags builds a ninja rule to generate the annotation-flags.csv file
@@ -243,35 +241,37 @@
},
}, "flagsCsv", "hiddenapiFlags", "tmpDir", "soongZipFlags")
-func hiddenAPIEncodeDex(ctx android.ModuleContext, output android.WritablePath, dexInput android.Path,
- uncompressDex bool) {
+// hiddenAPIEncodeDex generates the build rule that will encode the supplied dex jar and place the
+// encoded dex jar in a file of the same name in the output directory.
+//
+// The encode dex rule requires unzipping, encoding and rezipping the classes.dex files along with
+// all the resources from the input jar. It also ensures that if it was uncompressed in the input
+// it stays uncompressed in the output.
+func hiddenAPIEncodeDex(ctx android.ModuleContext, dexInput, flagsCSV android.Path, uncompressDex bool, outputDir android.OutputPath) android.OutputPath {
- flagsCSV := hiddenAPISingletonPaths(ctx).flags
+ // The output file has the same name as the input file and is in the output directory.
+ output := outputDir.Join(ctx, dexInput.Base())
- // The encode dex rule requires unzipping and rezipping the classes.dex files, ensure that if it was uncompressed
- // in the input it stays uncompressed in the output.
+ // Create a jar specific temporary directory in which to do the work just in case this is called
+ // with the same output directory for multiple modules.
+ tmpDir := outputDir.Join(ctx, dexInput.Base()+"-tmp")
+
+ // If the input is uncompressed then generate the output of the encode rule to an intermediate
+ // file as the final output will need further processing after encoding.
soongZipFlags := ""
- hiddenapiFlags := ""
- tmpOutput := output
- tmpDir := android.PathForModuleOut(ctx, "hiddenapi", "dex")
+ encodeRuleOutput := output
if uncompressDex {
soongZipFlags = "-L 0"
- tmpOutput = android.PathForModuleOut(ctx, "hiddenapi", "unaligned", "unaligned.jar")
- tmpDir = android.PathForModuleOut(ctx, "hiddenapi", "unaligned")
+ encodeRuleOutput = outputDir.Join(ctx, "unaligned", dexInput.Base())
}
- enforceHiddenApiFlagsToAllMembers := true
-
// b/149353192: when a module is instrumented, jacoco adds synthetic members
// $jacocoData and $jacocoInit. Since they don't exist when building the hidden API flags,
// don't complain when we don't find hidden API flags for the synthetic members.
+ hiddenapiFlags := ""
if j, ok := ctx.Module().(interface {
shouldInstrument(android.BaseModuleContext) bool
}); ok && j.shouldInstrument(ctx) {
- enforceHiddenApiFlagsToAllMembers = false
- }
-
- if !enforceHiddenApiFlagsToAllMembers {
hiddenapiFlags = "--no-force-assign-all"
}
@@ -279,7 +279,7 @@
Rule: hiddenAPIEncodeDexRule,
Description: "hiddenapi encode dex",
Input: dexInput,
- Output: tmpOutput,
+ Output: encodeRuleOutput,
Implicit: flagsCSV,
Args: map[string]string{
"flagsCsv": flagsCSV.String(),
@@ -290,8 +290,10 @@
})
if uncompressDex {
- TransformZipAlign(ctx, output, tmpOutput)
+ TransformZipAlign(ctx, output, encodeRuleOutput)
}
+
+ return output
}
type hiddenApiAnnotationsDependencyTag struct {
diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go
index f5afe5d..f2649d3 100644
--- a/java/hiddenapi_modular.go
+++ b/java/hiddenapi_modular.go
@@ -20,6 +20,7 @@
"android/soong/android"
"github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
)
// Contains support for processing hiddenAPI in a modular fashion.
@@ -66,6 +67,12 @@
// hiddenAPIRelevantSdkKinds lists all the android.SdkKind instances that are needed by the hidden
// API processing.
+//
+// These are in order from narrowest API surface to widest. Widest means the API stubs with the
+// biggest API surface, e.g. test is wider than system is wider than public. Core platform is
+// considered wider than test even though it has no relationship with test because the libraries
+// that provide core platform API don't provide test. While the core platform API is being converted
+// to a system API the system API is still a subset of core platform.
var hiddenAPIRelevantSdkKinds = []android.SdkKind{
android.SdkPublic,
android.SdkSystem,
@@ -127,42 +134,6 @@
}
}
-// hiddenAPIGatherStubLibDexJarPaths gathers the paths to the dex jars from the dependencies added
-// in hiddenAPIAddStubLibDependencies.
-func hiddenAPIGatherStubLibDexJarPaths(ctx android.ModuleContext, contents []android.Module) map[android.SdkKind]android.Paths {
- m := map[android.SdkKind]android.Paths{}
-
- // If the contents includes any java_sdk_library modules then add them to the stubs.
- for _, module := range contents {
- if _, ok := module.(SdkLibraryDependency); ok {
- for _, kind := range []android.SdkKind{android.SdkPublic, android.SdkSystem, android.SdkTest} {
- dexJar := hiddenAPIRetrieveDexJarBuildPath(ctx, module, kind)
- if dexJar != nil {
- m[kind] = append(m[kind], dexJar)
- }
- }
- }
- }
-
- ctx.VisitDirectDepsIf(isActiveModule, func(module android.Module) {
- tag := ctx.OtherModuleDependencyTag(module)
- if hiddenAPIStubsTag, ok := tag.(hiddenAPIStubsDependencyTag); ok {
- kind := hiddenAPIStubsTag.sdkKind
- dexJar := hiddenAPIRetrieveDexJarBuildPath(ctx, module, kind)
- if dexJar != nil {
- m[kind] = append(m[kind], dexJar)
- }
- }
- })
-
- // Normalize the paths, i.e. remove duplicates and sort.
- for k, v := range m {
- m[k] = android.SortedUniquePaths(v)
- }
-
- return m
-}
-
// hiddenAPIRetrieveDexJarBuildPath retrieves the DexJarBuildPath from the specified module, if
// available, or reports an error.
func hiddenAPIRetrieveDexJarBuildPath(ctx android.ModuleContext, module android.Module, kind android.SdkKind) android.Path {
@@ -193,20 +164,36 @@
//
// The rule is initialized but not built so that the caller can modify it and select an appropriate
// name.
-func ruleToGenerateHiddenAPIStubFlagsFile(ctx android.BuilderContext, outputPath android.WritablePath, bootDexJars android.Paths, sdkKindToPathList map[android.SdkKind]android.Paths) *android.RuleBuilder {
+func ruleToGenerateHiddenAPIStubFlagsFile(ctx android.BuilderContext, outputPath android.WritablePath, bootDexJars android.Paths, input HiddenAPIFlagInput) *android.RuleBuilder {
// Singleton rule which applies hiddenapi on all boot class path dex files.
rule := android.NewRuleBuilder(pctx, ctx)
tempPath := tempPathForRestat(ctx, outputPath)
+ // Find the widest API stubs provided by the fragments on which this depends, if any.
+ var dependencyStubDexJars android.Paths
+ for i := len(hiddenAPIRelevantSdkKinds) - 1; i >= 0; i-- {
+ kind := hiddenAPIRelevantSdkKinds[i]
+ stubsForKind := input.DependencyStubDexJarsByKind[kind]
+ if len(stubsForKind) != 0 {
+ dependencyStubDexJars = stubsForKind
+ break
+ }
+ }
+
command := rule.Command().
Tool(ctx.Config().HostToolPath(ctx, "hiddenapi")).
Text("list").
+ FlagForEachInput("--dependency-stub-dex=", dependencyStubDexJars).
FlagForEachInput("--boot-dex=", bootDexJars)
// Iterate over the sdk kinds in a fixed order.
for _, sdkKind := range hiddenAPIRelevantSdkKinds {
- paths := sdkKindToPathList[sdkKind]
+ // Merge in the stub dex jar paths for this kind from the fragments on which it depends. They
+ // will be needed to resolve dependencies from this fragment's stubs to classes in the other
+ // fragment's APIs.
+ dependencyPaths := input.DependencyStubDexJarsByKind[sdkKind]
+ paths := append(dependencyPaths, input.StubDexJarsByKind[sdkKind]...)
if len(paths) > 0 {
option := sdkKindToHiddenapiListOption[sdkKind]
command.FlagWithInputList("--"+option+"=", paths, ":")
@@ -260,15 +247,6 @@
Unsupported_packages []string `android:"path"`
}
-func (p *HiddenAPIFlagFileProperties) hiddenAPIFlagFileInfo(ctx android.ModuleContext) hiddenAPIFlagFileInfo {
- info := hiddenAPIFlagFileInfo{categoryToPaths: map[*hiddenAPIFlagFileCategory]android.Paths{}}
- for _, category := range hiddenAPIFlagFileCategories {
- paths := android.PathsForModuleSrc(ctx, category.propertyValueReader(p))
- info.categoryToPaths[category] = paths
- }
- return info
-}
-
type hiddenAPIFlagFileCategory struct {
// propertyName is the name of the property for this category.
propertyName string
@@ -282,6 +260,22 @@
commandMutator func(command *android.RuleBuilderCommand, path android.Path)
}
+// The flag file category for removed members of the API.
+//
+// This is extracted from hiddenAPIFlagFileCategories as it is needed to add the dex signatures
+// list of removed API members that are generated automatically from the removed.txt files provided
+// by API stubs.
+var hiddenAPIRemovedFlagFileCategory = &hiddenAPIFlagFileCategory{
+ // See HiddenAPIFlagFileProperties.Removed
+ propertyName: "removed",
+ propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
+ return properties.Removed
+ },
+ commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
+ command.FlagWithInput("--unsupported ", path).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "removed")
+ },
+}
+
var hiddenAPIFlagFileCategories = []*hiddenAPIFlagFileCategory{
// See HiddenAPIFlagFileProperties.Unsupported
{
@@ -293,16 +287,7 @@
command.FlagWithInput("--unsupported ", path)
},
},
- // See HiddenAPIFlagFileProperties.Removed
- {
- propertyName: "removed",
- propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
- return properties.Removed
- },
- commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
- command.FlagWithInput("--unsupported ", path).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "removed")
- },
- },
+ hiddenAPIRemovedFlagFileCategory,
// See HiddenAPIFlagFileProperties.Max_target_r_low_priority
{
propertyName: "max_target_r_low_priority",
@@ -365,45 +350,226 @@
},
}
-// hiddenAPIFlagFileInfo contains paths resolved from HiddenAPIFlagFileProperties and also generated
-// by hidden API processing.
-//
-// This is used both for an individual bootclasspath_fragment to provide it to other modules and
-// for a module to collate the files from the fragments it depends upon. That is why the fields are
-// all Paths even though they are initialized with a single path.
-type hiddenAPIFlagFileInfo struct {
- // categoryToPaths maps from the flag file category to the paths containing information for that
- // category.
- categoryToPaths map[*hiddenAPIFlagFileCategory]android.Paths
+// FlagFilesByCategory maps a hiddenAPIFlagFileCategory to the paths to the files in that category.
+type FlagFilesByCategory map[*hiddenAPIFlagFileCategory]android.Paths
- // The paths to the generated stub-flags.csv files.
- StubFlagsPaths android.Paths
-
- // The paths to the generated annotation-flags.csv files.
- AnnotationFlagsPaths android.Paths
-
- // The paths to the generated metadata.csv files.
- MetadataPaths android.Paths
-
- // The paths to the generated index.csv files.
- IndexPaths android.Paths
-
- // The paths to the generated all-flags.csv files.
- AllFlagsPaths android.Paths
-}
-
-func (i *hiddenAPIFlagFileInfo) append(other hiddenAPIFlagFileInfo) {
+// append appends the supplied flags files to the corresponding category in this map.
+func (s FlagFilesByCategory) append(other FlagFilesByCategory) {
for _, category := range hiddenAPIFlagFileCategories {
- i.categoryToPaths[category] = append(i.categoryToPaths[category], other.categoryToPaths[category]...)
+ s[category] = append(s[category], other[category]...)
}
- i.StubFlagsPaths = append(i.StubFlagsPaths, other.StubFlagsPaths...)
- i.AnnotationFlagsPaths = append(i.AnnotationFlagsPaths, other.AnnotationFlagsPaths...)
- i.MetadataPaths = append(i.MetadataPaths, other.MetadataPaths...)
- i.IndexPaths = append(i.IndexPaths, other.IndexPaths...)
- i.AllFlagsPaths = append(i.AllFlagsPaths, other.AllFlagsPaths...)
}
-var hiddenAPIFlagFileInfoProvider = blueprint.NewProvider(hiddenAPIFlagFileInfo{})
+// dedup removes duplicates in the flag files, while maintaining the order in which they were
+// appended.
+func (s FlagFilesByCategory) dedup() {
+ for category, paths := range s {
+ s[category] = android.FirstUniquePaths(paths)
+ }
+}
+
+// HiddenAPIInfo contains information provided by the hidden API processing.
+//
+// That includes paths resolved from HiddenAPIFlagFileProperties and also generated by hidden API
+// processing.
+type HiddenAPIInfo struct {
+ // FlagFilesByCategory maps from the flag file category to the paths containing information for
+ // that category.
+ FlagFilesByCategory FlagFilesByCategory
+
+ // The paths to the stub dex jars for each of the android.SdkKind in hiddenAPIRelevantSdkKinds.
+ TransitiveStubDexJarsByKind StubDexJarsByKind
+
+ // The output from the hidden API processing needs to be made available to other modules.
+ HiddenAPIFlagOutput
+}
+
+func newHiddenAPIInfo() *HiddenAPIInfo {
+ info := HiddenAPIInfo{
+ FlagFilesByCategory: FlagFilesByCategory{},
+ TransitiveStubDexJarsByKind: StubDexJarsByKind{},
+ }
+ return &info
+}
+
+func (i *HiddenAPIInfo) mergeFromFragmentDeps(ctx android.ModuleContext, fragments []android.Module) {
+ // Merge all the information from the fragments. The fragments form a DAG so it is possible that
+ // this will introduce duplicates so they will be resolved after processing all the fragments.
+ for _, fragment := range fragments {
+ if ctx.OtherModuleHasProvider(fragment, HiddenAPIInfoProvider) {
+ info := ctx.OtherModuleProvider(fragment, HiddenAPIInfoProvider).(HiddenAPIInfo)
+ i.TransitiveStubDexJarsByKind.append(info.TransitiveStubDexJarsByKind)
+ }
+ }
+
+ // Dedup and sort paths.
+ i.TransitiveStubDexJarsByKind.dedupAndSort()
+}
+
+var HiddenAPIInfoProvider = blueprint.NewProvider(HiddenAPIInfo{})
+
+// StubDexJarsByKind maps an android.SdkKind to the paths to stub dex jars appropriate for that
+// level. See hiddenAPIRelevantSdkKinds for a list of the acceptable android.SdkKind values.
+type StubDexJarsByKind map[android.SdkKind]android.Paths
+
+// append appends the supplied kind specific stub dex jar pargs to the corresponding kind in this
+// map.
+func (s StubDexJarsByKind) append(other StubDexJarsByKind) {
+ for _, kind := range hiddenAPIRelevantSdkKinds {
+ s[kind] = append(s[kind], other[kind]...)
+ }
+}
+
+// dedupAndSort removes duplicates in the stub dex jar paths and sorts them into a consistent and
+// deterministic order.
+func (s StubDexJarsByKind) dedupAndSort() {
+ for kind, paths := range s {
+ s[kind] = android.SortedUniquePaths(paths)
+ }
+}
+
+// HiddenAPIFlagInput encapsulates information obtained from a module and its dependencies that are
+// needed for hidden API flag generation.
+type HiddenAPIFlagInput struct {
+ // FlagFilesByCategory contains the flag files that override the initial flags that are derived
+ // from the stub dex files.
+ FlagFilesByCategory FlagFilesByCategory
+
+ // StubDexJarsByKind contains the stub dex jars for different android.SdkKind and which determine
+ // the initial flags for each dex member.
+ StubDexJarsByKind StubDexJarsByKind
+
+ // DependencyStubDexJarsByKind contains the stub dex jars provided by the fragments on which this
+ // depends. It is the result of merging HiddenAPIInfo.TransitiveStubDexJarsByKind from each
+ // fragment on which this depends.
+ DependencyStubDexJarsByKind StubDexJarsByKind
+
+ // RemovedTxtFiles is the list of removed.txt files provided by java_sdk_library modules that are
+ // specified in the bootclasspath_fragment's stub_libs and contents properties.
+ RemovedTxtFiles android.Paths
+}
+
+// newHiddenAPIFlagInput creates a new initialize HiddenAPIFlagInput struct.
+func newHiddenAPIFlagInput() HiddenAPIFlagInput {
+ input := HiddenAPIFlagInput{
+ FlagFilesByCategory: FlagFilesByCategory{},
+ StubDexJarsByKind: StubDexJarsByKind{},
+ }
+
+ return input
+}
+
+// canPerformHiddenAPIProcessing determines whether hidden API processing should be performed.
+//
+// A temporary workaround to avoid existing bootclasspath_fragments that do not provide the
+// appropriate information needed for hidden API processing breaking the build.
+// TODO(b/179354495): Remove this workaround.
+func (i *HiddenAPIFlagInput) canPerformHiddenAPIProcessing(ctx android.ModuleContext, properties bootclasspathFragmentProperties) bool {
+ // Performing hidden API processing without stubs is not supported and it is unlikely to ever be
+ // required as the whole point of adding something to the bootclasspath fragment is to add it to
+ // the bootclasspath in order to be used by something else in the system. Without any stubs it
+ // cannot do that.
+ if len(i.StubDexJarsByKind) == 0 {
+ return false
+ }
+
+ // Hidden API processing is always enabled in tests.
+ if ctx.Config().TestProductVariables != nil {
+ return true
+ }
+
+ // A module that has fragments should have access to the information it needs in order to perform
+ // hidden API processing.
+ if len(properties.Fragments) != 0 {
+ return true
+ }
+
+ // The art bootclasspath fragment does not depend on any other fragments but already supports
+ // hidden API processing.
+ imageName := proptools.String(properties.Image_name)
+ if imageName == "art" {
+ return true
+ }
+
+ // Disable it for everything else.
+ return false
+}
+
+// gatherStubLibInfo gathers information from the stub libs needed by hidden API processing from the
+// dependencies added in hiddenAPIAddStubLibDependencies.
+//
+// That includes paths to the stub dex jars as well as paths to the *removed.txt files.
+func (i *HiddenAPIFlagInput) gatherStubLibInfo(ctx android.ModuleContext, contents []android.Module) {
+ addFromModule := func(ctx android.ModuleContext, module android.Module, kind android.SdkKind) {
+ dexJar := hiddenAPIRetrieveDexJarBuildPath(ctx, module, kind)
+ if dexJar != nil {
+ i.StubDexJarsByKind[kind] = append(i.StubDexJarsByKind[kind], dexJar)
+ }
+
+ if sdkLibrary, ok := module.(SdkLibraryDependency); ok {
+ removedTxtFile := sdkLibrary.SdkRemovedTxtFile(ctx, kind)
+ i.RemovedTxtFiles = append(i.RemovedTxtFiles, removedTxtFile.AsPaths()...)
+ }
+ }
+
+ // If the contents includes any java_sdk_library modules then add them to the stubs.
+ for _, module := range contents {
+ if _, ok := module.(SdkLibraryDependency); ok {
+ // Add information for every possible kind needed by hidden API. SdkCorePlatform is not used
+ // as the java_sdk_library does not have special support for core_platform API, instead it is
+ // implemented as a customized form of SdkPublic.
+ for _, kind := range []android.SdkKind{android.SdkPublic, android.SdkSystem, android.SdkTest} {
+ addFromModule(ctx, module, kind)
+ }
+ }
+ }
+
+ ctx.VisitDirectDepsIf(isActiveModule, func(module android.Module) {
+ tag := ctx.OtherModuleDependencyTag(module)
+ if hiddenAPIStubsTag, ok := tag.(hiddenAPIStubsDependencyTag); ok {
+ kind := hiddenAPIStubsTag.sdkKind
+ addFromModule(ctx, module, kind)
+ }
+ })
+
+ // Normalize the paths, i.e. remove duplicates and sort.
+ i.StubDexJarsByKind.dedupAndSort()
+ i.RemovedTxtFiles = android.SortedUniquePaths(i.RemovedTxtFiles)
+}
+
+// extractFlagFilesFromProperties extracts the paths to flag files that are specified in the
+// supplied properties and stores them in this struct.
+func (i *HiddenAPIFlagInput) extractFlagFilesFromProperties(ctx android.ModuleContext, p *HiddenAPIFlagFileProperties) {
+ for _, category := range hiddenAPIFlagFileCategories {
+ paths := android.PathsForModuleSrc(ctx, category.propertyValueReader(p))
+ i.FlagFilesByCategory[category] = paths
+ }
+}
+
+func (i *HiddenAPIFlagInput) transitiveStubDexJarsByKind() StubDexJarsByKind {
+ transitive := i.DependencyStubDexJarsByKind
+ transitive.append(i.StubDexJarsByKind)
+ return transitive
+}
+
+// HiddenAPIFlagOutput contains paths to output files from the hidden API flag generation for a
+// bootclasspath_fragment module.
+type HiddenAPIFlagOutput struct {
+ // The path to the generated stub-flags.csv file.
+ StubFlagsPath android.Path
+
+ // The path to the generated annotation-flags.csv file.
+ AnnotationFlagsPath android.Path
+
+ // The path to the generated metadata.csv file.
+ MetadataPath android.Path
+
+ // The path to the generated index.csv file.
+ IndexPath android.Path
+
+ // The path to the generated all-flags.csv file.
+ AllFlagsPath android.Path
+}
// pathForValidation creates a path of the same type as the supplied type but with a name of
// <path>.valid.
@@ -426,16 +592,18 @@
// annotationFlags is the path to the annotation flags file generated from annotation information
// in each module.
//
-// flagFileInfo is a struct containing paths to files that augment the information provided by
+// hiddenAPIInfo is a struct containing paths to files that augment the information provided by
// the annotationFlags.
-func buildRuleToGenerateHiddenApiFlags(ctx android.BuilderContext, name, desc string, outputPath android.WritablePath, baseFlagsPath android.Path, annotationFlags android.Path, flagFileInfo *hiddenAPIFlagFileInfo) {
+func buildRuleToGenerateHiddenApiFlags(ctx android.BuilderContext, name, desc string,
+ outputPath android.WritablePath, baseFlagsPath android.Path, annotationFlags android.Path,
+ flagFilesByCategory FlagFilesByCategory, allFlagsPaths android.Paths, generatedRemovedDexSignatures android.OptionalPath) {
// The file which is used to record that the flags file is valid.
var validFile android.WritablePath
// If there are flag files that have been generated by fragments on which this depends then use
// them to validate the flag file generated by the rules created by this method.
- if allFlagsPaths := flagFileInfo.AllFlagsPaths; len(allFlagsPaths) > 0 {
+ if len(allFlagsPaths) > 0 {
// The flags file generated by the rule created by this method needs to be validated to ensure
// that it is consistent with the flag files generated by the individual fragments.
@@ -463,12 +631,18 @@
// Add the options for the different categories of flag files.
for _, category := range hiddenAPIFlagFileCategories {
- paths := flagFileInfo.categoryToPaths[category]
+ paths := flagFilesByCategory[category]
for _, path := range paths {
category.commandMutator(command, path)
}
}
+ // If available then pass the automatically generated file containing dex signatures of removed
+ // API members to the rule so they can be marked as removed.
+ if generatedRemovedDexSignatures.Valid() {
+ hiddenAPIRemovedFlagFileCategory.commandMutator(command, generatedRemovedDexSignatures.Path())
+ }
+
commitChangeForRestat(rule, tempPath, outputPath)
if validFile != nil {
@@ -496,13 +670,15 @@
// * metadata.csv
// * index.csv
// * all-flags.csv
-func hiddenAPIGenerateAllFlagsForBootclasspathFragment(ctx android.ModuleContext, contents []hiddenAPIModule, stubJarsByKind map[android.SdkKind]android.Paths, flagFileInfo *hiddenAPIFlagFileInfo) {
+func hiddenAPIGenerateAllFlagsForBootclasspathFragment(ctx android.ModuleContext, contents []hiddenAPIModule, input HiddenAPIFlagInput) *HiddenAPIFlagOutput {
hiddenApiSubDir := "modular-hiddenapi"
- // Generate the stub-flags.csv.
+ // Gather the dex files for the boot libraries provided by this fragment.
bootDexJars := extractBootDexJarsFromHiddenAPIModules(ctx, contents)
+
+ // Generate the stub-flags.csv.
stubFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "stub-flags.csv")
- rule := ruleToGenerateHiddenAPIStubFlagsFile(ctx, stubFlagsCSV, bootDexJars, stubJarsByKind)
+ rule := ruleToGenerateHiddenAPIStubFlagsFile(ctx, stubFlagsCSV, bootDexJars, input)
rule.Build("modularHiddenAPIStubFlagsFile", "modular hiddenapi stub flags")
// Extract the classes jars from the contents.
@@ -520,24 +696,45 @@
indexCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "index.csv")
buildRuleToGenerateIndex(ctx, "modular hiddenapi index", classesJars, indexCSV)
- // Removed APIs need to be marked and in order to do that the flagFileInfo needs to specify files
+ // Removed APIs need to be marked and in order to do that the hiddenAPIInfo needs to specify files
// containing dex signatures of all the removed APIs. In the monolithic files that is done by
// manually combining all the removed.txt files for each API and then converting them to dex
- // signatures, see the combined-removed-dex module. That will all be done automatically in future.
- // For now removed APIs are ignored.
- // TODO(b/179354495): handle removed apis automatically.
+ // signatures, see the combined-removed-dex module. This does that automatically by using the
+ // *removed.txt files retrieved from the java_sdk_library modules that are specified in the
+ // stub_libs and contents properties of a bootclasspath_fragment.
+ removedDexSignatures := buildRuleToGenerateRemovedDexSignatures(ctx, input.RemovedTxtFiles)
// Generate the all-flags.csv which are the flags that will, in future, be encoded into the dex
// files.
outputPath := android.PathForModuleOut(ctx, hiddenApiSubDir, "all-flags.csv")
- buildRuleToGenerateHiddenApiFlags(ctx, "modularHiddenApiAllFlags", "modular hiddenapi all flags", outputPath, stubFlagsCSV, annotationFlagsCSV, flagFileInfo)
+ buildRuleToGenerateHiddenApiFlags(ctx, "modularHiddenApiAllFlags", "modular hiddenapi all flags", outputPath, stubFlagsCSV, annotationFlagsCSV, input.FlagFilesByCategory, nil, removedDexSignatures)
// Store the paths in the info for use by other modules and sdk snapshot generation.
- flagFileInfo.StubFlagsPaths = android.Paths{stubFlagsCSV}
- flagFileInfo.AnnotationFlagsPaths = android.Paths{annotationFlagsCSV}
- flagFileInfo.MetadataPaths = android.Paths{metadataCSV}
- flagFileInfo.IndexPaths = android.Paths{indexCSV}
- flagFileInfo.AllFlagsPaths = android.Paths{outputPath}
+ output := HiddenAPIFlagOutput{
+ StubFlagsPath: stubFlagsCSV,
+ AnnotationFlagsPath: annotationFlagsCSV,
+ MetadataPath: metadataCSV,
+ IndexPath: indexCSV,
+ AllFlagsPath: outputPath,
+ }
+ return &output
+}
+
+func buildRuleToGenerateRemovedDexSignatures(ctx android.ModuleContext, removedTxtFiles android.Paths) android.OptionalPath {
+ if len(removedTxtFiles) == 0 {
+ return android.OptionalPath{}
+ }
+
+ output := android.PathForModuleOut(ctx, "modular-hiddenapi/removed-dex-signatures.txt")
+
+ rule := android.NewRuleBuilder(pctx, ctx)
+ rule.Command().
+ BuiltTool("metalava").
+ Flag("--no-banner").
+ Inputs(removedTxtFiles).
+ FlagWithOutput("--dex-api ", output)
+ rule.Build("modular-hiddenapi-removed-dex-signatures", "modular hiddenapi removed dex signatures")
+ return android.OptionalPathForPath(output)
}
// gatherHiddenAPIModuleFromContents gathers the hiddenAPIModule from the supplied contents.
diff --git a/java/hiddenapi_monolithic.go b/java/hiddenapi_monolithic.go
new file mode 100644
index 0000000..a6bf8c7
--- /dev/null
+++ b/java/hiddenapi_monolithic.go
@@ -0,0 +1,102 @@
+// 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 java
+
+import (
+ "android/soong/android"
+ "github.com/google/blueprint"
+)
+
+// MonolithicHiddenAPIInfo contains information needed/provided by the hidden API generation of the
+// monolithic hidden API files.
+//
+// Each list of paths includes all the equivalent paths from each of the bootclasspath_fragment
+// modules that contribute to the platform-bootclasspath.
+type MonolithicHiddenAPIInfo struct {
+ // FlagsFilesByCategory maps from the flag file category to the paths containing information for
+ // that category.
+ FlagsFilesByCategory FlagFilesByCategory
+
+ // The paths to the generated stub-flags.csv files.
+ StubFlagsPaths android.Paths
+
+ // The paths to the generated annotation-flags.csv files.
+ AnnotationFlagsPaths android.Paths
+
+ // The paths to the generated metadata.csv files.
+ MetadataPaths android.Paths
+
+ // The paths to the generated index.csv files.
+ IndexPaths android.Paths
+
+ // The paths to the generated all-flags.csv files.
+ AllFlagsPaths android.Paths
+}
+
+// newMonolithicHiddenAPIInfo creates a new MonolithicHiddenAPIInfo from the flagFilesByCategory
+// plus information provided by each of the fragments.
+func newMonolithicHiddenAPIInfo(ctx android.ModuleContext, flagFilesByCategory FlagFilesByCategory, fragments []android.Module) MonolithicHiddenAPIInfo {
+ monolithicInfo := MonolithicHiddenAPIInfo{}
+
+ monolithicInfo.FlagsFilesByCategory = flagFilesByCategory
+
+ // Merge all the information from the fragments. The fragments form a DAG so it is possible that
+ // this will introduce duplicates so they will be resolved after processing all the fragments.
+ for _, fragment := range fragments {
+ if ctx.OtherModuleHasProvider(fragment, HiddenAPIInfoProvider) {
+ info := ctx.OtherModuleProvider(fragment, HiddenAPIInfoProvider).(HiddenAPIInfo)
+ monolithicInfo.append(&info)
+ }
+ }
+
+ // Dedup paths.
+ monolithicInfo.dedup()
+
+ return monolithicInfo
+}
+
+// append appends all the files from the supplied info to the corresponding files in this struct.
+func (i *MonolithicHiddenAPIInfo) append(other *HiddenAPIInfo) {
+ i.FlagsFilesByCategory.append(other.FlagFilesByCategory)
+
+ // The output may not be set if the bootclasspath_fragment has not yet been updated to support
+ // hidden API processing.
+ // TODO(b/179354495): Switch back to append once all bootclasspath_fragment modules have been
+ // updated to support hidden API processing properly.
+ appendIfNotNil := func(paths android.Paths, path android.Path) android.Paths {
+ if path == nil {
+ return paths
+ }
+ return append(paths, path)
+ }
+ i.StubFlagsPaths = appendIfNotNil(i.StubFlagsPaths, other.StubFlagsPath)
+ i.AnnotationFlagsPaths = appendIfNotNil(i.AnnotationFlagsPaths, other.AnnotationFlagsPath)
+ i.MetadataPaths = appendIfNotNil(i.MetadataPaths, other.MetadataPath)
+ i.IndexPaths = appendIfNotNil(i.IndexPaths, other.IndexPath)
+ i.AllFlagsPaths = appendIfNotNil(i.AllFlagsPaths, other.AllFlagsPath)
+}
+
+// dedup removes duplicates in all the paths, while maintaining the order in which they were
+// appended.
+func (i *MonolithicHiddenAPIInfo) dedup() {
+ i.FlagsFilesByCategory.dedup()
+ i.StubFlagsPaths = android.FirstUniquePaths(i.StubFlagsPaths)
+ i.AnnotationFlagsPaths = android.FirstUniquePaths(i.AnnotationFlagsPaths)
+ i.MetadataPaths = android.FirstUniquePaths(i.MetadataPaths)
+ i.IndexPaths = android.FirstUniquePaths(i.IndexPaths)
+ i.AllFlagsPaths = android.FirstUniquePaths(i.AllFlagsPaths)
+}
+
+var monolithicHiddenAPIInfoProvider = blueprint.NewProvider(MonolithicHiddenAPIInfo{})
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go
index 5db2efe..87c695c 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -279,25 +279,24 @@
return
}
- flagFileInfo := b.properties.Hidden_api.hiddenAPIFlagFileInfo(ctx)
- for _, fragment := range fragments {
- if ctx.OtherModuleHasProvider(fragment, hiddenAPIFlagFileInfoProvider) {
- info := ctx.OtherModuleProvider(fragment, hiddenAPIFlagFileInfoProvider).(hiddenAPIFlagFileInfo)
- flagFileInfo.append(info)
- }
- }
+ monolithicInfo := b.createAndProvideMonolithicHiddenAPIInfo(ctx, fragments)
- // Store the information for testing.
- ctx.SetProvider(hiddenAPIFlagFileInfoProvider, flagFileInfo)
+ // Create the input to pass to ruleToGenerateHiddenAPIStubFlagsFile
+ input := newHiddenAPIFlagInput()
+
+ // Gather stub library information from the dependencies on modules provided by
+ // hiddenAPIComputeMonolithicStubLibModules.
+ input.gatherStubLibInfo(ctx, nil)
+
+ // Use the flag files from this module and all the fragments.
+ input.FlagFilesByCategory = monolithicInfo.FlagsFilesByCategory
hiddenAPIModules := gatherHiddenAPIModuleFromContents(ctx, modules)
- sdkKindToStubPaths := hiddenAPIGatherStubLibDexJarPaths(ctx, nil)
-
// Generate the monolithic stub-flags.csv file.
bootDexJars := extractBootDexJarsFromHiddenAPIModules(ctx, hiddenAPIModules)
stubFlags := hiddenAPISingletonPaths(ctx).stubFlags
- rule := ruleToGenerateHiddenAPIStubFlagsFile(ctx, stubFlags, bootDexJars, sdkKindToStubPaths)
+ rule := ruleToGenerateHiddenAPIStubFlagsFile(ctx, stubFlags, bootDexJars, input)
rule.Build("platform-bootclasspath-monolithic-hiddenapi-stub-flags", "monolithic hidden API stub flags")
// Extract the classes jars from the contents.
@@ -309,7 +308,7 @@
// Generate the monotlithic hiddenapi-flags.csv file.
allFlags := hiddenAPISingletonPaths(ctx).flags
- buildRuleToGenerateHiddenApiFlags(ctx, "hiddenAPIFlagsFile", "hiddenapi flags", allFlags, stubFlags, annotationFlags, &flagFileInfo)
+ buildRuleToGenerateHiddenApiFlags(ctx, "hiddenAPIFlagsFile", "hiddenapi flags", allFlags, stubFlags, annotationFlags, monolithicInfo.FlagsFilesByCategory, monolithicInfo.AllFlagsPaths, android.OptionalPath{})
// Generate an intermediate monolithic hiddenapi-metadata.csv file directly from the annotations
// in the source code.
@@ -328,6 +327,25 @@
buildRuleToGenerateIndex(ctx, "monolithic hidden API index", classesJars, indexCSV)
}
+// createAndProvideMonolithicHiddenAPIInfo creates a MonolithicHiddenAPIInfo and provides it for
+// testing.
+func (b *platformBootclasspathModule) createAndProvideMonolithicHiddenAPIInfo(ctx android.ModuleContext, fragments []android.Module) MonolithicHiddenAPIInfo {
+ // Create a temporary input structure in which to collate information provided directly by this
+ // module, either through properties or direct dependencies.
+ temporaryInput := newHiddenAPIFlagInput()
+
+ // Create paths to the flag files specified in the properties.
+ temporaryInput.extractFlagFilesFromProperties(ctx, &b.properties.Hidden_api)
+
+ // Create the monolithic info, by starting with the flag files specified on this and then merging
+ // in information from all the fragment dependencies of this.
+ monolithicInfo := newMonolithicHiddenAPIInfo(ctx, temporaryInput.FlagFilesByCategory, fragments)
+
+ // Store the information for testing.
+ ctx.SetProvider(monolithicHiddenAPIInfoProvider, monolithicInfo)
+ return monolithicInfo
+}
+
func (b *platformBootclasspathModule) buildRuleMergeCSV(ctx android.ModuleContext, desc string, inputPaths android.Paths, outputPath android.WritablePath) {
rule := android.NewRuleBuilder(pctx, ctx)
rule.Command().
diff --git a/java/platform_bootclasspath_test.go b/java/platform_bootclasspath_test.go
index 9fffa0a..ed5549d 100644
--- a/java/platform_bootclasspath_test.go
+++ b/java/platform_bootclasspath_test.go
@@ -245,14 +245,14 @@
).RunTest(t)
pbcp := result.Module("platform-bootclasspath", "android_common")
- info := result.ModuleProvider(pbcp, hiddenAPIFlagFileInfoProvider).(hiddenAPIFlagFileInfo)
+ info := result.ModuleProvider(pbcp, monolithicHiddenAPIInfoProvider).(MonolithicHiddenAPIInfo)
for _, category := range hiddenAPIFlagFileCategories {
name := category.propertyName
message := fmt.Sprintf("category %s", name)
filename := strings.ReplaceAll(name, "_", "-")
expected := []string{fmt.Sprintf("%s.txt", filename), fmt.Sprintf("bar-%s.txt", filename)}
- android.AssertPathsRelativeToTopEquals(t, message, expected, info.categoryToPaths[category])
+ android.AssertPathsRelativeToTopEquals(t, message, expected, info.FlagsFilesByCategory[category])
}
android.AssertPathsRelativeToTopEquals(t, "stub flags", []string{"out/soong/.intermediates/bar-fragment/android_common/modular-hiddenapi/stub-flags.csv"}, info.StubFlagsPaths)
diff --git a/java/sdk_library.go b/java/sdk_library.go
index b5b6232..8f36758 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -845,19 +845,7 @@
// closest kind which is a subset of the requested kind. e.g. if requesting android.SdkModule then
// it will return *scopePaths for android.SdkSystem if available or android.SdkPublic of not.
func (c *commonToSdkLibraryAndImport) selectScopePaths(ctx android.BaseModuleContext, kind android.SdkKind) *scopePaths {
- var apiScope *apiScope
- switch kind {
- case android.SdkSystem:
- apiScope = apiScopeSystem
- case android.SdkModule:
- apiScope = apiScopeModuleLib
- case android.SdkTest:
- apiScope = apiScopeTest
- case android.SdkSystemServer:
- apiScope = apiScopeSystemServer
- default:
- apiScope = apiScopePublic
- }
+ apiScope := sdkKindToApiScope(kind)
paths := c.findClosestScopePath(apiScope)
if paths == nil {
@@ -874,6 +862,24 @@
return paths
}
+// sdkKindToApiScope maps from android.SdkKind to apiScope.
+func sdkKindToApiScope(kind android.SdkKind) *apiScope {
+ var apiScope *apiScope
+ switch kind {
+ case android.SdkSystem:
+ apiScope = apiScopeSystem
+ case android.SdkModule:
+ apiScope = apiScopeModuleLib
+ case android.SdkTest:
+ apiScope = apiScopeTest
+ case android.SdkSystemServer:
+ apiScope = apiScopeSystemServer
+ default:
+ apiScope = apiScopePublic
+ }
+ return apiScope
+}
+
// to satisfy SdkLibraryDependency interface
func (c *commonToSdkLibraryAndImport) SdkApiStubDexJar(ctx android.BaseModuleContext, kind android.SdkKind) android.Path {
paths := c.selectScopePaths(ctx, kind)
@@ -884,6 +890,17 @@
return paths.stubsDexJarPath
}
+// to satisfy SdkLibraryDependency interface
+func (c *commonToSdkLibraryAndImport) SdkRemovedTxtFile(ctx android.BaseModuleContext, kind android.SdkKind) android.OptionalPath {
+ apiScope := sdkKindToApiScope(kind)
+ paths := c.findScopePaths(apiScope)
+ if paths == nil {
+ return android.OptionalPath{}
+ }
+
+ return paths.removedApiFilePath
+}
+
func (c *commonToSdkLibraryAndImport) sdkComponentPropertiesForChildLibrary() interface{} {
componentProps := &struct {
SdkLibraryToImplicitlyTrack *string
@@ -964,7 +981,7 @@
var _ SdkLibraryComponentDependency = (*SdkLibrary)(nil)
var _ SdkLibraryComponentDependency = (*SdkLibraryImport)(nil)
-// Provides access to sdk_version related header and implentation jars.
+// Provides access to sdk_version related files, e.g. header and implementation jars.
type SdkLibraryDependency interface {
SdkLibraryComponentDependency
@@ -985,6 +1002,9 @@
// tool which processes dex files.
SdkApiStubDexJar(ctx android.BaseModuleContext, kind android.SdkKind) android.Path
+ // SdkRemovedTxtFile returns the optional path to the removed.txt file for the specified sdk kind.
+ SdkRemovedTxtFile(ctx android.BaseModuleContext, kind android.SdkKind) android.OptionalPath
+
// sharedLibrary returns true if this can be used as a shared library.
sharedLibrary() bool
}
@@ -1629,8 +1649,12 @@
path := path.Join(mctx.ModuleDir(), apiDir, scope.apiFilePrefix+api)
p := android.ExistentPathForSource(mctx, path)
if !p.Valid() {
- mctx.ModuleErrorf("Current api file %#v doesn't exist", path)
- missingCurrentApi = true
+ if mctx.Config().AllowMissingDependencies() {
+ mctx.AddMissingDependencies([]string{path})
+ } else {
+ mctx.ModuleErrorf("Current api file %#v doesn't exist", path)
+ missingCurrentApi = true
+ }
}
}
}
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/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}