diff options
31 files changed, 1285 insertions, 945 deletions
diff --git a/android/bazel.go b/android/bazel.go index ef770bf9c..8c680559e 100644 --- a/android/bazel.go +++ b/android/bazel.go @@ -220,15 +220,7 @@ var ( // Per-module denylist to opt modules out of mixed builds. Such modules will // still be generated via bp2build. mixedBuildsDisabledList = []string{ - "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, 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 - "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) + // Currently empty, though should remain present to facilitate granular bp2build migration. } // Used for quicker lookups diff --git a/android/bazel_handler.go b/android/bazel_handler.go index a1206dc53..f906c8add 100644 --- a/android/bazel_handler.go +++ b/android/bazel_handler.go @@ -351,6 +351,9 @@ func (r *builtinBazelRunner) issueBazelCommand(paths *bazelPaths, runName bazel. "HOME="+paths.homeDir, pwdPrefix(), "BUILD_DIR="+absolutePath(paths.buildDir), + // Make OUT_DIR absolute here so tools/bazel.sh uses the correct + // OUT_DIR at <root>/out, instead of <root>/out/soong/workspace/out. + "OUT_DIR="+absolutePath(paths.outDir()), // Disables local host detection of gcc; toolchain information is defined // explicitly in BUILD files. "BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1") @@ -576,6 +579,11 @@ func (p *bazelPaths) syntheticWorkspaceDir() string { return filepath.Join(p.buildDir, "workspace") } +// Returns the path to the top level out dir ($OUT_DIR). +func (p *bazelPaths) outDir() string { + return filepath.Dir(p.buildDir) +} + // Issues commands to Bazel to receive results for all cquery requests // queued in the BazelContext. func (context *bazelContext) InvokeBazel() error { diff --git a/apex/apex_test.go b/apex/apex_test.go index 4d00944e7..6a7c35c88 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -709,6 +709,79 @@ func TestApexManifest(t *testing.T) { } } +func TestApexManifestMinSdkVersion(t *testing.T) { + ctx := testApex(t, ` + apex_defaults { + name: "my_defaults", + key: "myapex.key", + product_specific: true, + file_contexts: ":my-file-contexts", + updatable: false, + } + apex { + name: "myapex_30", + min_sdk_version: "30", + defaults: ["my_defaults"], + } + + apex { + name: "myapex_current", + min_sdk_version: "current", + defaults: ["my_defaults"], + } + + apex { + name: "myapex_none", + defaults: ["my_defaults"], + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + filegroup { + name: "my-file-contexts", + srcs: ["product_specific_file_contexts"], + } + `, withFiles(map[string][]byte{ + "product_specific_file_contexts": nil, + }), android.FixtureModifyProductVariables( + func(variables android.FixtureProductVariables) { + variables.Unbundled_build = proptools.BoolPtr(true) + variables.Always_use_prebuilt_sdks = proptools.BoolPtr(false) + }), android.FixtureMergeEnv(map[string]string{ + "UNBUNDLED_BUILD_TARGET_SDK_WITH_API_FINGERPRINT": "true", + })) + + testCases := []struct { + module string + minSdkVersion string + }{ + { + module: "myapex_30", + minSdkVersion: "30", + }, + { + module: "myapex_current", + minSdkVersion: "Q.$$(cat out/soong/api_fingerprint.txt)", + }, + { + module: "myapex_none", + minSdkVersion: "Q.$$(cat out/soong/api_fingerprint.txt)", + }, + } + for _, tc := range testCases { + module := ctx.ModuleForTests(tc.module, "android_common_"+tc.module+"_image") + args := module.Rule("apexRule").Args + optFlags := args["opt_flags"] + if !strings.Contains(optFlags, "--min_sdk_version "+tc.minSdkVersion) { + t.Errorf("%s: Expected min_sdk_version=%s, got: %s", tc.module, tc.minSdkVersion, optFlags) + } + } +} + func TestBasicZipApex(t *testing.T) { ctx := testApex(t, ` apex { diff --git a/apex/builder.go b/apex/builder.go index da8841ce7..021e499ed 100644 --- a/apex/builder.go +++ b/apex/builder.go @@ -602,6 +602,11 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { // codename if moduleMinSdkVersion.IsCurrent() || moduleMinSdkVersion.IsNone() { minSdkVersion = ctx.Config().DefaultAppTargetSdk(ctx).String() + + if java.UseApiFingerprint(ctx) { + minSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", java.ApiFingerprintPath(ctx).String()) + implicitInputs = append(implicitInputs, java.ApiFingerprintPath(ctx)) + } } // apex module doesn't have a concept of target_sdk_version, hence for the time // being targetSdkVersion == default targetSdkVersion of the branch. @@ -611,10 +616,6 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { targetSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", java.ApiFingerprintPath(ctx).String()) implicitInputs = append(implicitInputs, java.ApiFingerprintPath(ctx)) } - if java.UseApiFingerprint(ctx) { - minSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", java.ApiFingerprintPath(ctx).String()) - implicitInputs = append(implicitInputs, java.ApiFingerprintPath(ctx)) - } optFlags = append(optFlags, "--target_sdk_version "+targetSdkVersion) optFlags = append(optFlags, "--min_sdk_version "+minSdkVersion) diff --git a/bazel/properties.go b/bazel/properties.go index b9d6ead59..b2d68da52 100644 --- a/bazel/properties.go +++ b/bazel/properties.go @@ -307,19 +307,19 @@ var ( } PlatformTargetMap = map[string]string{ - TARGET_ANDROID_ARM: "//build/bazel/platforms:android_arm", - TARGET_ANDROID_ARM64: "//build/bazel/platforms:android_arm64", - TARGET_ANDROID_X86: "//build/bazel/platforms:android_x86", - TARGET_ANDROID_X86_64: "//build/bazel/platforms:android_x86_64", - TARGET_DARWIN_X86_64: "//build/bazel/platforms:darwin_x86_64", - TARGET_FUCHSIA_ARM64: "//build/bazel/platforms:fuchsia_arm64", - TARGET_FUCHSIA_X86_64: "//build/bazel/platforms:fuchsia_x86_64", - TARGET_LINUX_X86: "//build/bazel/platforms:linux_glibc_x86", - TARGET_LINUX_x86_64: "//build/bazel/platforms:linux_glibc_x86_64", - TARGET_LINUX_BIONIC_ARM64: "//build/bazel/platforms:linux_bionic_arm64", - TARGET_LINUX_BIONIC_X86_64: "//build/bazel/platforms:linux_bionic_x86_64", - TARGET_WINDOWS_X86: "//build/bazel/platforms:windows_x86", - TARGET_WINDOWS_X86_64: "//build/bazel/platforms:windows_x86_64", + TARGET_ANDROID_ARM: "//build/bazel/platforms/os_arch:android_arm", + TARGET_ANDROID_ARM64: "//build/bazel/platforms/os_arch:android_arm64", + TARGET_ANDROID_X86: "//build/bazel/platforms/os_arch:android_x86", + TARGET_ANDROID_X86_64: "//build/bazel/platforms/os_arch:android_x86_64", + TARGET_DARWIN_X86_64: "//build/bazel/platforms/os_arch:darwin_x86_64", + TARGET_FUCHSIA_ARM64: "//build/bazel/platforms/os_arch:fuchsia_arm64", + TARGET_FUCHSIA_X86_64: "//build/bazel/platforms/os_arch:fuchsia_x86_64", + TARGET_LINUX_X86: "//build/bazel/platforms/os_arch:linux_glibc_x86", + TARGET_LINUX_x86_64: "//build/bazel/platforms/os_arch:linux_glibc_x86_64", + TARGET_LINUX_BIONIC_ARM64: "//build/bazel/platforms/os_arch:linux_bionic_arm64", + TARGET_LINUX_BIONIC_X86_64: "//build/bazel/platforms/os_arch:linux_bionic_x86_64", + TARGET_WINDOWS_X86: "//build/bazel/platforms/os_arch:windows_x86", + TARGET_WINDOWS_X86_64: "//build/bazel/platforms/os_arch:windows_x86_64", CONDITIONS_DEFAULT: ConditionsDefaultSelectKey, // The default condition of an os select map. } @@ -993,6 +993,6 @@ func TryVariableSubstitutions(slice []string, productVariable string) ([]string, // TryVariableSubstitution, replace string substitution formatting within s with Starlark // string.format compatible tag for productVariable. func TryVariableSubstitution(s string, productVariable string) (string, bool) { - sub := productVariableSubstitutionPattern.ReplaceAllString(s, "{"+productVariable+"}") + sub := productVariableSubstitutionPattern.ReplaceAllString(s, "$("+productVariable+")") return sub, s != sub } diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go index 49f1f42ba..b87d71330 100644 --- a/bp2build/cc_library_conversion_test.go +++ b/bp2build/cc_library_conversion_test.go @@ -497,7 +497,7 @@ cc_library_static { name: "android_dep_for_shared" } "//build/bazel/platforms/os:android": ["-DANDROID_SHARED"], "//conditions:default": [], }) + select({ - "//build/bazel/platforms:android_arm": ["-DANDROID_ARM_SHARED"], + "//build/bazel/platforms/os_arch:android_arm": ["-DANDROID_ARM_SHARED"], "//conditions:default": [], }), shared_srcs = ["sharedonly.cpp"] + select({ @@ -844,8 +844,8 @@ func TestCcLibraryLabelAttributeGetTargetProperties(t *testing.T) { ], srcs = ["a.cpp"], version_script = select({ - "//build/bazel/platforms:android_arm": "android_arm.map", - "//build/bazel/platforms:linux_bionic_arm64": "linux_bionic_arm64.map", + "//build/bazel/platforms/os_arch:android_arm": "android_arm.map", + "//build/bazel/platforms/os_arch:linux_bionic_arm64": "linux_bionic_arm64.map", "//conditions:default": None, }), )`}, diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go index 770925466..da38adbb6 100644 --- a/bp2build/cc_library_static_conversion_test.go +++ b/bp2build/cc_library_static_conversion_test.go @@ -1282,14 +1282,14 @@ cc_library_static { "//build/bazel/platforms/os:android": ["android_src.c"], "//conditions:default": [], }) + select({ - "//build/bazel/platforms:android_arm": ["android_arm_src.c"], - "//build/bazel/platforms:android_arm64": ["android_arm64_src.c"], - "//build/bazel/platforms:android_x86": ["android_x86_src.c"], - "//build/bazel/platforms:android_x86_64": ["android_x86_64_src.c"], + "//build/bazel/platforms/os_arch:android_arm": ["android_arm_src.c"], + "//build/bazel/platforms/os_arch:android_arm64": ["android_arm64_src.c"], + "//build/bazel/platforms/os_arch:android_x86": ["android_x86_src.c"], + "//build/bazel/platforms/os_arch:android_x86_64": ["android_x86_64_src.c"], "//conditions:default": [], }) + select({ - "//build/bazel/platforms:linux_bionic_arm64": ["linux_bionic_arm64_src.c"], - "//build/bazel/platforms:linux_bionic_x86_64": ["linux_bionic_x86_64_src.c"], + "//build/bazel/platforms/os_arch:linux_bionic_arm64": ["linux_bionic_arm64_src.c"], + "//build/bazel/platforms/os_arch:linux_bionic_x86_64": ["linux_bionic_x86_64_src.c"], "//conditions:default": [], }), )`}, @@ -1412,3 +1412,37 @@ cc_library_static { )`}, }) } + +func TestCcLibraryStaticProductVariableStringReplacement(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: { + platform_sdk_version: { + asflags: ["-DPLATFORM_SDK_VERSION=%d"], + }, + }, +} `, + expectedBazelTargets: []string{`cc_library_static( + name = "foo_static", + asflags = select({ + "//build/bazel/product_variables:platform_sdk_version": ["-DPLATFORM_SDK_VERSION=$(Platform_sdk_version)"], + "//conditions:default": [], + }), + copts = [ + "-I.", + "-I$(BINDIR)/.", + ], + linkstatic = True, + srcs_c = ["common.c"], +)`}, + }) +} diff --git a/bp2build/cc_object_conversion_test.go b/bp2build/cc_object_conversion_test.go index f7e94c28c..57f75eabb 100644 --- a/bp2build/cc_object_conversion_test.go +++ b/bp2build/cc_object_conversion_test.go @@ -210,7 +210,7 @@ func TestCcObjectProductVariable(t *testing.T) { expectedBazelTargets: []string{`cc_object( name = "foo", asflags = select({ - "//build/bazel/product_variables:platform_sdk_version": ["-DPLATFORM_SDK_VERSION={Platform_sdk_version}"], + "//build/bazel/product_variables:platform_sdk_version": ["-DPLATFORM_SDK_VERSION=$(Platform_sdk_version)"], "//conditions:default": [], }), copts = ["-fno-addrsig"], diff --git a/build_test.bash b/build_test.bash index 296a79cd0..b039285ca 100755 --- a/build_test.bash +++ b/build_test.bash @@ -54,7 +54,7 @@ df -h echo echo "Running Bazel smoke test..." -"${TOP}/tools/bazel" --batch --max_idle_secs=1 info +STANDALONE_BAZEL=true "${TOP}/tools/bazel" --batch --max_idle_secs=1 info echo echo "Running Soong test..." diff --git a/cc/bp2build.go b/cc/bp2build.go index 5d024f865..fed993670 100644 --- a/cc/bp2build.go +++ b/cc/bp2build.go @@ -19,6 +19,8 @@ import ( "android/soong/android" "android/soong/bazel" + + "github.com/google/blueprint/proptools" ) // bp2build functions and helpers for converting cc_* modules to Bazel. @@ -266,6 +268,66 @@ func bp2buildParseStaticOrSharedProps(ctx android.TopDownMutatorContext, module return attrs } +// Convenience struct to hold all attributes parsed from prebuilt properties. +type prebuiltAttributes struct { + Src bazel.LabelAttribute +} + +func Bp2BuildParsePrebuiltLibraryProps(ctx android.TopDownMutatorContext, module *Module) prebuiltAttributes { + prebuiltLibraryLinker := module.linker.(*prebuiltLibraryLinker) + prebuiltLinker := prebuiltLibraryLinker.prebuiltLinker + + var srcLabelAttribute bazel.LabelAttribute + + if len(prebuiltLinker.properties.Srcs) > 1 { + ctx.ModuleErrorf("Bp2BuildParsePrebuiltLibraryProps: Expected at most once source file\n") + } + + if len(prebuiltLinker.properties.Srcs) == 1 { + srcLabelAttribute.Value = android.BazelLabelForModuleSrcSingle(ctx, prebuiltLinker.properties.Srcs[0]) + for arch, props := range module.GetArchProperties(ctx, &prebuiltLinkerProperties{}) { + if prebuiltLinkerProperties, ok := props.(*prebuiltLinkerProperties); ok { + if len(prebuiltLinkerProperties.Srcs) > 1 { + ctx.ModuleErrorf("Bp2BuildParsePrebuiltLibraryProps: Expected at most once source file for arch %s\n", arch.Name) + } + if len(prebuiltLinkerProperties.Srcs) == 1 { + srcLabelAttribute.SetValueForArch(arch.Name, android.BazelLabelForModuleSrcSingle(ctx, prebuiltLinkerProperties.Srcs[0])) + } + } + } + } + + for os, targetProperties := range module.GetTargetProperties(ctx, &prebuiltLinkerProperties{}) { + if prebuiltLinkerProperties, ok := targetProperties.Properties.(*prebuiltLinkerProperties); ok { + if len(prebuiltLinkerProperties.Srcs) > 1 { + ctx.ModuleErrorf("Bp2BuildParsePrebuiltLibraryProps: Expected at most once source file for os %s\n", os.Name) + + } + + if len(prebuiltLinkerProperties.Srcs) == 1 { + srcLabelAttribute.SetOsValueForTarget(os.Name, android.BazelLabelForModuleSrcSingle(ctx, prebuiltLinkerProperties.Srcs[0])) + } + } + for arch, archProperties := range targetProperties.ArchProperties { + if prebuiltLinkerProperties, ok := archProperties.(*prebuiltLinkerProperties); ok { + if len(prebuiltLinkerProperties.Srcs) > 1 { + ctx.ModuleErrorf("Bp2BuildParsePrebuiltLibraryProps: Expected at most once source file for os_arch %s_%s\n", os.Name, arch.Name) + + } + + if len(prebuiltLinkerProperties.Srcs) == 1 { + srcLabelAttribute.SetOsArchValueForTarget(os.Name, arch.Name, android.BazelLabelForModuleSrcSingle(ctx, prebuiltLinkerProperties.Srcs[0])) + } + } + + } + } + + return prebuiltAttributes{ + Src: srcLabelAttribute, + } +} + // Convenience struct to hold all attributes parsed from compiler properties. type compilerAttributes struct { // Options for all languages @@ -444,18 +506,25 @@ func bp2BuildParseCompilerProps(ctx android.TopDownMutatorContext, module *Modul } } + productVarPropNameToAttribute := map[string]*bazel.StringListAttribute{ + "Cflags": &copts, + "Asflags": &asFlags, + "CppFlags": &cppFlags, + } 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") + for propName, attr := range productVarPropNameToAttribute { + if props, exists := productVariableProps[propName]; exists { + for _, prop := range props { + flags, ok := prop.Property.([]string) + if !ok { + ctx.ModuleErrorf("Could not convert product variable %s property", proptools.PropertyNameForField(propName)) + } + newFlags, _ := bazel.TryVariableSubstitutions(flags, prop.ProductConfigVariable) + attr.ProductValues = append(attr.ProductValues, bazel.ProductVariableValues{ + ProductVariable: prop.ProductConfigVariable, + Values: newFlags, + }) } - newFlags, _ := bazel.TryVariableSubstitutions(flags, prop.ProductConfigVariable) - copts.ProductValues = append(copts.ProductValues, bazel.ProductVariableValues{ - ProductVariable: prop.ProductConfigVariable, - Values: newFlags, - }) } } @@ -633,11 +702,20 @@ func bp2BuildMakePathsRelativeToModule(ctx android.BazelConversionPathContext, p return relativePaths } -// bp2BuildParseExportedIncludes creates a string list attribute contains the -// exported included directories of a module. func bp2BuildParseExportedIncludes(ctx android.TopDownMutatorContext, module *Module) bazel.StringListAttribute { libraryDecorator := module.linker.(*libraryDecorator) + return bp2BuildParseExportedIncludesHelper(ctx, module, libraryDecorator) +} + +func Bp2BuildParseExportedIncludesForPrebuiltLibrary(ctx android.TopDownMutatorContext, module *Module) bazel.StringListAttribute { + prebuiltLibraryLinker := module.linker.(*prebuiltLibraryLinker) + libraryDecorator := prebuiltLibraryLinker.libraryDecorator + return bp2BuildParseExportedIncludesHelper(ctx, module, libraryDecorator) +} +// bp2BuildParseExportedIncludes creates a string list attribute contains the +// exported included directories of a module. +func bp2BuildParseExportedIncludesHelper(ctx android.TopDownMutatorContext, module *Module, libraryDecorator *libraryDecorator) bazel.StringListAttribute { // Export_system_include_dirs and export_include_dirs are already module dir // relative, so they don't need to be relativized like include_dirs, which // are root-relative. diff --git a/cc/builder.go b/cc/builder.go index 51c8a0bdf..fae9522f2 100644 --- a/cc/builder.go +++ b/cc/builder.go @@ -534,7 +534,7 @@ func transformSourceToObj(ctx android.ModuleContext, subdir string, srcFiles and Implicits: cFlagsDeps, OrderOnly: pathDeps, Args: map[string]string{ - "windresCmd": gccCmd(flags.toolchain, "windres"), + "windresCmd": mingwCmd(flags.toolchain, "windres"), "flags": flags.toolchain.WindresFlags(), }, }) @@ -1069,6 +1069,6 @@ func transformArchiveRepack(ctx android.ModuleContext, inputFile android.Path, }) } -func gccCmd(toolchain config.Toolchain, cmd string) string { +func mingwCmd(toolchain config.Toolchain, cmd string) string { return filepath.Join(toolchain.GccRoot(), "bin", toolchain.GccTriple()+"-"+cmd) } @@ -726,7 +726,6 @@ var ( runtimeDepTag = installDependencyTag{name: "runtime lib"} testPerSrcDepTag = dependencyTag{name: "test_per_src"} stubImplDepTag = dependencyTag{name: "stub_impl"} - llndkStubDepTag = dependencyTag{name: "llndk stub"} ) func IsSharedDepTag(depTag blueprint.DependencyTag) bool { @@ -3238,8 +3237,8 @@ func (c *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Modu return false } } - if depTag == stubImplDepTag || depTag == llndkStubDepTag { - // We don't track beyond LLNDK or from an implementation library to its stubs. + if depTag == stubImplDepTag { + // We don't track from an implementation library to its stubs. return false } if depTag == staticVariantTag { diff --git a/cc/cc_test.go b/cc/cc_test.go index 5acafbe2a..7fc044df3 100644 --- a/cc/cc_test.go +++ b/cc/cc_test.go @@ -2799,12 +2799,8 @@ func TestLlndkLibrary(t *testing.T) { } } expected := []string{ - "android_vendor.29_arm64_armv8-a_shared_1", - "android_vendor.29_arm64_armv8-a_shared_2", "android_vendor.29_arm64_armv8-a_shared_current", "android_vendor.29_arm64_armv8-a_shared", - "android_vendor.29_arm_armv7-a-neon_shared_1", - "android_vendor.29_arm_armv7-a-neon_shared_2", "android_vendor.29_arm_armv7-a-neon_shared_current", "android_vendor.29_arm_armv7-a-neon_shared", } @@ -2813,9 +2809,6 @@ func TestLlndkLibrary(t *testing.T) { params := result.ModuleForTests("libllndk", "android_vendor.29_arm_armv7-a-neon_shared").Description("generate stub") android.AssertSame(t, "use VNDK version for default stubs", "current", params.Args["apiLevel"]) - params = result.ModuleForTests("libllndk", "android_vendor.29_arm_armv7-a-neon_shared_1").Description("generate stub") - android.AssertSame(t, "override apiLevel for versioned stubs", "1", params.Args["apiLevel"]) - checkExportedIncludeDirs := func(module, variant string, expectedDirs ...string) { t.Helper() m := result.ModuleForTests(module, variant).Module() @@ -204,7 +204,7 @@ func genWinMsg(ctx android.ModuleContext, srcFile android.Path, flags builderFla headerFile := android.GenPathWithExt(ctx, "windmc", srcFile, "h") rcFile := android.GenPathWithExt(ctx, "windmc", srcFile, "rc") - windmcCmd := gccCmd(flags.toolchain, "windmc") + windmcCmd := mingwCmd(flags.toolchain, "windmc") ctx.Build(pctx, android.BuildParams{ Rule: windmc, diff --git a/cc/library.go b/cc/library.go index 9fb7a2451..5e70c51e9 100644 --- a/cc/library.go +++ b/cc/library.go @@ -1813,6 +1813,11 @@ func (library *libraryDecorator) stubsVersions(ctx android.BaseMutatorContext) [ return nil } + if library.hasLLNDKStubs() && ctx.Module().(*Module).UseVndk() { + // LLNDK libraries only need a single stubs variant. + return []string{android.FutureApiLevel.String()} + } + // Future API level is implicitly added if there isn't vers := library.Properties.Stubs.Versions if inList(android.FutureApiLevel.String(), vers) { @@ -2154,8 +2159,7 @@ func moduleLibraryInterface(module blueprint.Module) libraryInterface { return nil } -// versionSelector normalizes the versions in the Stubs.Versions property into MutatedProperties.AllStubsVersions, -// and propagates the value from implementation libraries to llndk libraries with the same name. +// versionSelector normalizes the versions in the Stubs.Versions property into MutatedProperties.AllStubsVersions. func versionSelectorMutator(mctx android.BottomUpMutatorContext) { if library := moduleLibraryInterface(mctx.Module()); library != nil && CanBeVersionVariant(mctx.Module().(*Module)) { if library.buildShared() { @@ -2169,15 +2173,6 @@ func versionSelectorMutator(mctx android.BottomUpMutatorContext) { // depend on the implementation library and haven't been mutated yet. library.setAllStubsVersions(versions) } - - if mctx.Module().(*Module).UseVndk() && library.hasLLNDKStubs() { - // Propagate the version to the llndk stubs module. - mctx.VisitDirectDepsWithTag(llndkStubDepTag, func(stubs android.Module) { - if stubsLib := moduleLibraryInterface(stubs); stubsLib != nil { - stubsLib.setAllStubsVersions(library.allStubsVersions()) - } - }) - } } } } diff --git a/cc/object.go b/cc/object.go index cd711617b..39fc43dca 100644 --- a/cc/object.go +++ b/cc/object.go @@ -157,8 +157,6 @@ func ObjectBp2Build(ctx android.TopDownMutatorContext) { // Set arch-specific configurable attributes compilerAttrs := bp2BuildParseCompilerProps(ctx, m) - var asFlags bazel.StringListAttribute - var deps bazel.LabelListAttribute for _, props := range m.linker.linkerProps() { if objectLinkerProps, ok := props.(*ObjectLinkerProperties); ok { @@ -167,24 +165,6 @@ func ObjectBp2Build(ctx android.TopDownMutatorContext) { } } - productVariableProps := android.ProductVariableProperties(ctx) - if props, exists := productVariableProps["Asflags"]; exists { - // TODO(b/183595873): consider deduplicating handling of product variable properties - for _, prop := range props { - flags, ok := prop.Property.([]string) - if !ok { - ctx.ModuleErrorf("Could not convert product variable asflag property") - return - } - 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 - // Don't split cc_object srcs across languages. Doing so would add complexity, // and this isn't typically done for cc_object. srcs := compilerAttrs.srcs @@ -195,7 +175,7 @@ func ObjectBp2Build(ctx android.TopDownMutatorContext) { Srcs: srcs, Deps: deps, Copts: compilerAttrs.copts, - Asflags: asFlags, + Asflags: compilerAttrs.asFlags, } props := bazel.BazelTargetModuleProperties{ diff --git a/cc/snapshot_prebuilt.go b/cc/snapshot_prebuilt.go index a7351a9ef..bf11b11bb 100644 --- a/cc/snapshot_prebuilt.go +++ b/cc/snapshot_prebuilt.go @@ -453,30 +453,49 @@ func (p *baseSnapshotDecorator) snapshotAndroidMkSuffix() string { return p.baseProperties.Androidmk_suffix } -func (p *baseSnapshotDecorator) setSnapshotAndroidMkSuffix(ctx android.ModuleContext) { - coreVariations := append(ctx.Target().Variations(), blueprint.Variation{ +func (p *baseSnapshotDecorator) setSnapshotAndroidMkSuffix(ctx android.ModuleContext, variant string) { + // If there are any 2 or more variations among {core, product, vendor, recovery} + // we have to add the androidmk suffix to avoid duplicate modules with the same + // name. + variations := append(ctx.Target().Variations(), blueprint.Variation{ Mutator: "image", Variation: android.CoreVariation}) - if ctx.OtherModuleFarDependencyVariantExists(coreVariations, ctx.Module().(*Module).BaseModuleName()) { + if ctx.OtherModuleFarDependencyVariantExists(variations, ctx.Module().(*Module).BaseModuleName()) { p.baseProperties.Androidmk_suffix = p.image.moduleNameSuffix() return } - // If there is no matching core variation, there could still be a - // product variation, for example if a module is product specific and - // vendor available. In that case, we also want to add the androidmk - // suffix. - - productVariations := append(ctx.Target().Variations(), blueprint.Variation{ + variations = append(ctx.Target().Variations(), blueprint.Variation{ Mutator: "image", Variation: ProductVariationPrefix + ctx.DeviceConfig().PlatformVndkVersion()}) - if ctx.OtherModuleFarDependencyVariantExists(productVariations, ctx.Module().(*Module).BaseModuleName()) { + if ctx.OtherModuleFarDependencyVariantExists(variations, ctx.Module().(*Module).BaseModuleName()) { p.baseProperties.Androidmk_suffix = p.image.moduleNameSuffix() return } + images := []snapshotImage{vendorSnapshotImageSingleton, recoverySnapshotImageSingleton} + + for _, image := range images { + if p.image == image { + continue + } + variations = append(ctx.Target().Variations(), blueprint.Variation{ + Mutator: "image", + Variation: image.imageVariantName(ctx.DeviceConfig())}) + + if ctx.OtherModuleFarDependencyVariantExists(variations, + ctx.Module().(*Module).BaseModuleName()+ + getSnapshotNameSuffix( + image.moduleNameSuffix()+variant, + p.version(), + ctx.DeviceConfig().Arches()[0].ArchType.String())) { + p.baseProperties.Androidmk_suffix = p.image.moduleNameSuffix() + return + } + } + p.baseProperties.Androidmk_suffix = "" } @@ -566,7 +585,16 @@ func (p *snapshotLibraryDecorator) matchesWithDevice(config android.DeviceConfig // As snapshots are prebuilts, this just returns the prebuilt binary after doing things which are // done by normal library decorator, e.g. exporting flags. func (p *snapshotLibraryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path { - p.setSnapshotAndroidMkSuffix(ctx) + var variant string + if p.shared() { + variant = snapshotSharedSuffix + } else if p.static() { + variant = snapshotStaticSuffix + } else { + variant = snapshotHeaderSuffix + } + + p.setSnapshotAndroidMkSuffix(ctx, variant) if p.header() { return p.libraryDecorator.link(ctx, flags, deps, objs) @@ -784,7 +812,7 @@ func (p *snapshotBinaryDecorator) matchesWithDevice(config android.DeviceConfig) // cc modules' link functions are to link compiled objects into final binaries. // As snapshots are prebuilts, this just returns the prebuilt binary func (p *snapshotBinaryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path { - p.setSnapshotAndroidMkSuffix(ctx) + p.setSnapshotAndroidMkSuffix(ctx, snapshotBinarySuffix) if !p.matchesWithDevice(ctx.DeviceConfig()) { return nil @@ -879,7 +907,7 @@ func (p *snapshotObjectLinker) matchesWithDevice(config android.DeviceConfig) bo // cc modules' link functions are to link compiled objects into final binaries. // As snapshots are prebuilts, this just returns the prebuilt binary func (p *snapshotObjectLinker) link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path { - p.setSnapshotAndroidMkSuffix(ctx) + p.setSnapshotAndroidMkSuffix(ctx, snapshotObjectSuffix) if !p.matchesWithDevice(ctx.DeviceConfig()) { return nil diff --git a/cmd/multiproduct_kati/main.go b/cmd/multiproduct_kati/main.go index e0f8caac2..20f146ae3 100644 --- a/cmd/multiproduct_kati/main.go +++ b/cmd/multiproduct_kati/main.go @@ -433,7 +433,7 @@ func buildProduct(mpctx *mpContext, product string) { config := build.NewConfig(ctx, args...) config.Environment().Set("OUT_DIR", outDir) if !*keepArtifacts { - config.Environment().Set("EMPTY_NINJA_FILE", "true") + config.SetEmptyNinjaFile(true) } build.FindSources(ctx, config, mpctx.Finder) config.Lunch(ctx, product, *buildVariant) diff --git a/java/androidmk.go b/java/androidmk.go index 015454464..04357e066 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -460,6 +460,8 @@ func (a *AndroidTestHelperApp) AndroidMkEntries() []android.AndroidMkEntries { entries := &entriesList[0] entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { testSuiteComponent(entries, a.appTestHelperAppProperties.Test_suites) + // introduce a flag variable to control the generation of the .config file + entries.SetString("LOCAL_DISABLE_TEST_CONFIG", "true") }) return entriesList diff --git a/java/androidmk_test.go b/java/androidmk_test.go index 5eaa77b32..246c0eb07 100644 --- a/java/androidmk_test.go +++ b/java/androidmk_test.go @@ -188,3 +188,21 @@ func TestImportSoongDexJar(t *testing.T) { android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_SOONG_DEX_JAR", result.Config, []string{expectedSoongDexJar}, actualSoongDexJar) } + +func TestAndroidTestHelperApp_LocalDisableTestConfig(t *testing.T) { + ctx, _ := testJava(t, ` + android_test_helper_app { + name: "foo", + srcs: ["a.java"], + } + `) + + mod := ctx.ModuleForTests("foo", "android_common").Module() + entries := android.AndroidMkEntriesForTest(t, ctx, mod)[0] + + expected := []string{"true"} + actual := entries.EntryMap["LOCAL_DISABLE_TEST_CONFIG"] + if !reflect.DeepEqual(expected, actual) { + t.Errorf("Unexpected flag value - expected: %q, actual: %q", expected, actual) + } +} diff --git a/java/droidstubs.go b/java/droidstubs.go index 953105603..17c7a7bf7 100644 --- a/java/droidstubs.go +++ b/java/droidstubs.go @@ -51,7 +51,6 @@ type Droidstubs struct { lastReleasedApiXmlFile android.WritablePath privateApiFile android.WritablePath removedApiFile android.WritablePath - removedDexApiFile android.WritablePath nullabilityWarningsFile android.WritablePath checkCurrentApiTimestamp android.WritablePath @@ -79,9 +78,6 @@ type DroidstubsProperties struct { // the generated removed API filename by Metalava, defaults to <module>_removed.txt Removed_api_filename *string - // the generated removed Dex API filename by Metalava. - Removed_dex_api_filename *string - Check_api struct { Last_released ApiToCheck @@ -274,11 +270,6 @@ func (d *Droidstubs) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuil d.removedApiFilePath = android.PathForModuleSrc(ctx, sourceRemovedApiFile) } - if String(d.properties.Removed_dex_api_filename) != "" { - d.removedDexApiFile = android.PathForModuleOut(ctx, "metalava", String(d.properties.Removed_dex_api_filename)) - cmd.FlagWithOutput("--removed-dex-api ", d.removedDexApiFile) - } - if Bool(d.properties.Write_sdk_values) { d.metadataDir = android.PathForModuleOut(ctx, "metalava", "metadata") cmd.FlagWithArg("--sdk-values ", d.metadataDir.String()) diff --git a/java/java_test.go b/java/java_test.go index 1b8aec286..bd373c177 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -19,7 +19,6 @@ import ( "os" "path/filepath" "reflect" - "regexp" "runtime" "strconv" "strings" @@ -655,306 +654,6 @@ prebuilt_stubs_sources { }) } -func TestJavaSdkLibraryImport(t *testing.T) { - result := prepareForJavaTest.RunTestWithBp(t, ` - java_library { - name: "foo", - srcs: ["a.java"], - libs: ["sdklib"], - sdk_version: "current", - } - - java_library { - name: "foo.system", - srcs: ["a.java"], - libs: ["sdklib"], - sdk_version: "system_current", - } - - java_library { - name: "foo.test", - srcs: ["a.java"], - libs: ["sdklib"], - sdk_version: "test_current", - } - - java_sdk_library_import { - name: "sdklib", - public: { - jars: ["a.jar"], - }, - system: { - jars: ["b.jar"], - }, - test: { - jars: ["c.jar"], - stub_srcs: ["c.java"], - }, - } - `) - - for _, scope := range []string{"", ".system", ".test"} { - fooModule := result.ModuleForTests("foo"+scope, "android_common") - javac := fooModule.Rule("javac") - - sdklibStubsJar := result.ModuleForTests("sdklib.stubs"+scope, "android_common").Rule("combineJar").Output - android.AssertStringDoesContain(t, "foo classpath", javac.Args["classpath"], sdklibStubsJar.String()) - } - - CheckModuleDependencies(t, result.TestContext, "sdklib", "android_common", []string{ - `prebuilt_sdklib.stubs`, - `prebuilt_sdklib.stubs.source.test`, - `prebuilt_sdklib.stubs.system`, - `prebuilt_sdklib.stubs.test`, - }) -} - -func TestJavaSdkLibraryImport_WithSource(t *testing.T) { - result := android.GroupFixturePreparers( - prepareForJavaTest, - PrepareForTestWithJavaSdkLibraryFiles, - FixtureWithLastReleaseApis("sdklib"), - ).RunTestWithBp(t, ` - java_sdk_library { - name: "sdklib", - srcs: ["a.java"], - sdk_version: "none", - system_modules: "none", - public: { - enabled: true, - }, - } - - java_sdk_library_import { - name: "sdklib", - public: { - jars: ["a.jar"], - }, - } - `) - - CheckModuleDependencies(t, result.TestContext, "sdklib", "android_common", []string{ - `dex2oatd`, - `prebuilt_sdklib`, - `sdklib.impl`, - `sdklib.stubs`, - `sdklib.stubs.source`, - `sdklib.xml`, - }) - - CheckModuleDependencies(t, result.TestContext, "prebuilt_sdklib", "android_common", []string{ - `prebuilt_sdklib.stubs`, - `sdklib.impl`, - // This should be prebuilt_sdklib.stubs but is set to sdklib.stubs because the - // dependency is added after prebuilts may have been renamed and so has to use - // the renamed name. - `sdklib.xml`, - }) -} - -func TestJavaSdkLibraryImport_Preferred(t *testing.T) { - result := android.GroupFixturePreparers( - prepareForJavaTest, - PrepareForTestWithJavaSdkLibraryFiles, - FixtureWithLastReleaseApis("sdklib"), - ).RunTestWithBp(t, ` - java_sdk_library { - name: "sdklib", - srcs: ["a.java"], - sdk_version: "none", - system_modules: "none", - public: { - enabled: true, - }, - } - - java_sdk_library_import { - name: "sdklib", - prefer: true, - public: { - jars: ["a.jar"], - }, - } - `) - - CheckModuleDependencies(t, result.TestContext, "sdklib", "android_common", []string{ - `dex2oatd`, - `prebuilt_sdklib`, - `sdklib.impl`, - `sdklib.stubs`, - `sdklib.stubs.source`, - `sdklib.xml`, - }) - - CheckModuleDependencies(t, result.TestContext, "prebuilt_sdklib", "android_common", []string{ - `prebuilt_sdklib.stubs`, - `sdklib.impl`, - `sdklib.xml`, - }) -} - -func TestJavaSdkLibraryEnforce(t *testing.T) { - partitionToBpOption := func(partition string) string { - switch partition { - case "system": - return "" - case "vendor": - return "soc_specific: true," - case "product": - return "product_specific: true," - default: - panic("Invalid partition group name: " + partition) - } - } - - type testConfigInfo struct { - libraryType string - fromPartition string - toPartition string - enforceVendorInterface bool - enforceProductInterface bool - enforceJavaSdkLibraryCheck bool - allowList []string - } - - createPreparer := func(info testConfigInfo) android.FixturePreparer { - bpFileTemplate := ` - java_library { - name: "foo", - srcs: ["foo.java"], - libs: ["bar"], - sdk_version: "current", - %s - } - - %s { - name: "bar", - srcs: ["bar.java"], - sdk_version: "current", - %s - } - ` - - bpFile := fmt.Sprintf(bpFileTemplate, - partitionToBpOption(info.fromPartition), - info.libraryType, - partitionToBpOption(info.toPartition)) - - return android.GroupFixturePreparers( - PrepareForTestWithJavaSdkLibraryFiles, - FixtureWithLastReleaseApis("bar"), - android.FixtureWithRootAndroidBp(bpFile), - android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { - variables.EnforceProductPartitionInterface = proptools.BoolPtr(info.enforceProductInterface) - if info.enforceVendorInterface { - variables.DeviceVndkVersion = proptools.StringPtr("current") - } - variables.EnforceInterPartitionJavaSdkLibrary = proptools.BoolPtr(info.enforceJavaSdkLibraryCheck) - variables.InterPartitionJavaLibraryAllowList = info.allowList - }), - ) - } - - runTest := func(t *testing.T, info testConfigInfo, expectedErrorPattern string) { - t.Run(fmt.Sprintf("%v", info), func(t *testing.T) { - errorHandler := android.FixtureExpectsNoErrors - if expectedErrorPattern != "" { - errorHandler = android.FixtureExpectsAtLeastOneErrorMatchingPattern(expectedErrorPattern) - } - android.GroupFixturePreparers( - prepareForJavaTest, - createPreparer(info), - ). - ExtendWithErrorHandler(errorHandler). - RunTest(t) - }) - } - - errorMessage := "is not allowed across the partitions" - - runTest(t, testConfigInfo{ - libraryType: "java_library", - fromPartition: "product", - toPartition: "system", - enforceVendorInterface: true, - enforceProductInterface: true, - enforceJavaSdkLibraryCheck: false, - }, "") - - runTest(t, testConfigInfo{ - libraryType: "java_library", - fromPartition: "product", - toPartition: "system", - enforceVendorInterface: true, - enforceProductInterface: false, - enforceJavaSdkLibraryCheck: true, - }, "") - - runTest(t, testConfigInfo{ - libraryType: "java_library", - fromPartition: "product", - toPartition: "system", - enforceVendorInterface: true, - enforceProductInterface: true, - enforceJavaSdkLibraryCheck: true, - }, errorMessage) - - runTest(t, testConfigInfo{ - libraryType: "java_library", - fromPartition: "vendor", - toPartition: "system", - enforceVendorInterface: true, - enforceProductInterface: true, - enforceJavaSdkLibraryCheck: true, - }, errorMessage) - - runTest(t, testConfigInfo{ - libraryType: "java_library", - fromPartition: "vendor", - toPartition: "system", - enforceVendorInterface: true, - enforceProductInterface: true, - enforceJavaSdkLibraryCheck: true, - allowList: []string{"bar"}, - }, "") - - runTest(t, testConfigInfo{ - libraryType: "java_library", - fromPartition: "vendor", - toPartition: "product", - enforceVendorInterface: true, - enforceProductInterface: true, - enforceJavaSdkLibraryCheck: true, - }, errorMessage) - - runTest(t, testConfigInfo{ - libraryType: "java_sdk_library", - fromPartition: "product", - toPartition: "system", - enforceVendorInterface: true, - enforceProductInterface: true, - enforceJavaSdkLibraryCheck: true, - }, "") - - runTest(t, testConfigInfo{ - libraryType: "java_sdk_library", - fromPartition: "vendor", - toPartition: "system", - enforceVendorInterface: true, - enforceProductInterface: true, - enforceJavaSdkLibraryCheck: true, - }, "") - - runTest(t, testConfigInfo{ - libraryType: "java_sdk_library", - fromPartition: "vendor", - toPartition: "product", - enforceVendorInterface: true, - enforceProductInterface: true, - enforceJavaSdkLibraryCheck: true, - }, "") -} - func TestDefaults(t *testing.T) { ctx, _ := testJava(t, ` java_defaults { @@ -1411,521 +1110,6 @@ func TestJavaImport(t *testing.T) { }) } -func TestJavaSdkLibrary(t *testing.T) { - result := android.GroupFixturePreparers( - prepareForJavaTest, - PrepareForTestWithJavaSdkLibraryFiles, - FixtureWithPrebuiltApis(map[string][]string{ - "28": {"foo"}, - "29": {"foo"}, - "30": {"bar", "barney", "baz", "betty", "foo", "fred", "quuz", "wilma"}, - }), - ).RunTestWithBp(t, ` - droiddoc_exported_dir { - name: "droiddoc-templates-sdk", - path: ".", - } - java_sdk_library { - name: "foo", - srcs: ["a.java", "b.java"], - api_packages: ["foo"], - } - java_sdk_library { - name: "bar", - srcs: ["a.java", "b.java"], - api_packages: ["bar"], - } - java_library { - name: "baz", - srcs: ["c.java"], - libs: ["foo", "bar.stubs"], - sdk_version: "system_current", - } - java_sdk_library { - name: "barney", - srcs: ["c.java"], - api_only: true, - } - java_sdk_library { - name: "betty", - srcs: ["c.java"], - shared_library: false, - } - java_sdk_library_import { - name: "quuz", - public: { - jars: ["c.jar"], - }, - } - java_sdk_library_import { - name: "fred", - public: { - jars: ["b.jar"], - }, - } - java_sdk_library_import { - name: "wilma", - public: { - jars: ["b.jar"], - }, - shared_library: false, - } - java_library { - name: "qux", - srcs: ["c.java"], - libs: ["baz", "fred", "quuz.stubs", "wilma", "barney", "betty"], - sdk_version: "system_current", - } - java_library { - name: "baz-test", - srcs: ["c.java"], - libs: ["foo"], - sdk_version: "test_current", - } - java_library { - name: "baz-29", - srcs: ["c.java"], - libs: ["foo"], - sdk_version: "system_29", - } - java_library { - name: "baz-module-30", - srcs: ["c.java"], - libs: ["foo"], - sdk_version: "module_30", - } - `) - - // check the existence of the internal modules - result.ModuleForTests("foo", "android_common") - result.ModuleForTests(apiScopePublic.stubsLibraryModuleName("foo"), "android_common") - result.ModuleForTests(apiScopeSystem.stubsLibraryModuleName("foo"), "android_common") - result.ModuleForTests(apiScopeTest.stubsLibraryModuleName("foo"), "android_common") - result.ModuleForTests(apiScopePublic.stubsSourceModuleName("foo"), "android_common") - result.ModuleForTests(apiScopeSystem.stubsSourceModuleName("foo"), "android_common") - result.ModuleForTests(apiScopeTest.stubsSourceModuleName("foo"), "android_common") - result.ModuleForTests("foo"+sdkXmlFileSuffix, "android_common") - result.ModuleForTests("foo.api.public.28", "") - result.ModuleForTests("foo.api.system.28", "") - result.ModuleForTests("foo.api.test.28", "") - - bazJavac := result.ModuleForTests("baz", "android_common").Rule("javac") - // tests if baz is actually linked to the stubs lib - android.AssertStringDoesContain(t, "baz javac classpath", bazJavac.Args["classpath"], "foo.stubs.system.jar") - // ... and not to the impl lib - android.AssertStringDoesNotContain(t, "baz javac classpath", bazJavac.Args["classpath"], "foo.jar") - // test if baz is not linked to the system variant of foo - android.AssertStringDoesNotContain(t, "baz javac classpath", bazJavac.Args["classpath"], "foo.stubs.jar") - - bazTestJavac := result.ModuleForTests("baz-test", "android_common").Rule("javac") - // tests if baz-test is actually linked to the test stubs lib - android.AssertStringDoesContain(t, "baz-test javac classpath", bazTestJavac.Args["classpath"], "foo.stubs.test.jar") - - baz29Javac := result.ModuleForTests("baz-29", "android_common").Rule("javac") - // tests if baz-29 is actually linked to the system 29 stubs lib - android.AssertStringDoesContain(t, "baz-29 javac classpath", baz29Javac.Args["classpath"], "prebuilts/sdk/29/system/foo.jar") - - bazModule30Javac := result.ModuleForTests("baz-module-30", "android_common").Rule("javac") - // tests if "baz-module-30" is actually linked to the module 30 stubs lib - android.AssertStringDoesContain(t, "baz-module-30 javac classpath", bazModule30Javac.Args["classpath"], "prebuilts/sdk/30/module-lib/foo.jar") - - // test if baz has exported SDK lib names foo and bar to qux - qux := result.ModuleForTests("qux", "android_common") - if quxLib, ok := qux.Module().(*Library); ok { - sdkLibs := quxLib.ClassLoaderContexts().UsesLibs() - android.AssertDeepEquals(t, "qux exports", []string{"foo", "bar", "fred", "quuz"}, sdkLibs) - } -} - -func TestJavaSdkLibrary_StubOrImplOnlyLibs(t *testing.T) { - result := android.GroupFixturePreparers( - prepareForJavaTest, - PrepareForTestWithJavaSdkLibraryFiles, - FixtureWithLastReleaseApis("sdklib"), - ).RunTestWithBp(t, ` - java_sdk_library { - name: "sdklib", - srcs: ["a.java"], - libs: ["lib"], - static_libs: ["static-lib"], - impl_only_libs: ["impl-only-lib"], - stub_only_libs: ["stub-only-lib"], - stub_only_static_libs: ["stub-only-static-lib"], - } - java_defaults { - name: "defaults", - srcs: ["a.java"], - sdk_version: "current", - } - java_library { name: "lib", defaults: ["defaults"] } - java_library { name: "static-lib", defaults: ["defaults"] } - java_library { name: "impl-only-lib", defaults: ["defaults"] } - java_library { name: "stub-only-lib", defaults: ["defaults"] } - java_library { name: "stub-only-static-lib", defaults: ["defaults"] } - `) - var expectations = []struct { - lib string - on_impl_classpath bool - on_stub_classpath bool - in_impl_combined bool - in_stub_combined bool - }{ - {lib: "lib", on_impl_classpath: true}, - {lib: "static-lib", in_impl_combined: true}, - {lib: "impl-only-lib", on_impl_classpath: true}, - {lib: "stub-only-lib", on_stub_classpath: true}, - {lib: "stub-only-static-lib", in_stub_combined: true}, - } - verify := func(sdklib, dep string, cp, combined bool) { - sdklibCp := result.ModuleForTests(sdklib, "android_common").Rule("javac").Args["classpath"] - expected := cp || combined // Every combined jar is also on the classpath. - android.AssertStringContainsEquals(t, "bad classpath for "+sdklib, sdklibCp, "/"+dep+".jar", expected) - - combineJarInputs := result.ModuleForTests(sdklib, "android_common").Rule("combineJar").Inputs.Strings() - depPath := filepath.Join("out", "soong", ".intermediates", dep, "android_common", "turbine-combined", dep+".jar") - android.AssertStringListContainsEquals(t, "bad combined inputs for "+sdklib, combineJarInputs, depPath, combined) - } - for _, expectation := range expectations { - verify("sdklib", expectation.lib, expectation.on_impl_classpath, expectation.in_impl_combined) - verify("sdklib.impl", expectation.lib, expectation.on_impl_classpath, expectation.in_impl_combined) - - stubName := apiScopePublic.stubsLibraryModuleName("sdklib") - verify(stubName, expectation.lib, expectation.on_stub_classpath, expectation.in_stub_combined) - } -} - -func TestJavaSdkLibrary_DoNotAccessImplWhenItIsNotBuilt(t *testing.T) { - result := android.GroupFixturePreparers( - prepareForJavaTest, - PrepareForTestWithJavaSdkLibraryFiles, - FixtureWithLastReleaseApis("foo"), - ).RunTestWithBp(t, ` - java_sdk_library { - name: "foo", - srcs: ["a.java"], - api_only: true, - public: { - enabled: true, - }, - } - - java_library { - name: "bar", - srcs: ["b.java"], - libs: ["foo"], - } - `) - - // The bar library should depend on the stubs jar. - barLibrary := result.ModuleForTests("bar", "android_common").Rule("javac") - if expected, actual := `^-classpath .*:out/soong/[^:]*/turbine-combined/foo\.stubs\.jar$`, barLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) { - t.Errorf("expected %q, found %#q", expected, actual) - } -} - -func TestJavaSdkLibrary_UseSourcesFromAnotherSdkLibrary(t *testing.T) { - android.GroupFixturePreparers( - prepareForJavaTest, - PrepareForTestWithJavaSdkLibraryFiles, - FixtureWithLastReleaseApis("foo"), - ).RunTestWithBp(t, ` - java_sdk_library { - name: "foo", - srcs: ["a.java"], - api_packages: ["foo"], - public: { - enabled: true, - }, - } - - java_library { - name: "bar", - srcs: ["b.java", ":foo{.public.stubs.source}"], - } - `) -} - -func TestJavaSdkLibrary_AccessOutputFiles_MissingScope(t *testing.T) { - android.GroupFixturePreparers( - prepareForJavaTest, - PrepareForTestWithJavaSdkLibraryFiles, - FixtureWithLastReleaseApis("foo"), - ). - ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`"foo" does not provide api scope system`)). - RunTestWithBp(t, ` - java_sdk_library { - name: "foo", - srcs: ["a.java"], - api_packages: ["foo"], - public: { - enabled: true, - }, - } - - java_library { - name: "bar", - srcs: ["b.java", ":foo{.system.stubs.source}"], - } - `) -} - -func TestJavaSdkLibrary_Deps(t *testing.T) { - result := android.GroupFixturePreparers( - prepareForJavaTest, - PrepareForTestWithJavaSdkLibraryFiles, - FixtureWithLastReleaseApis("sdklib"), - ).RunTestWithBp(t, ` - java_sdk_library { - name: "sdklib", - srcs: ["a.java"], - sdk_version: "none", - system_modules: "none", - public: { - enabled: true, - }, - } - `) - - CheckModuleDependencies(t, result.TestContext, "sdklib", "android_common", []string{ - `dex2oatd`, - `sdklib.impl`, - `sdklib.stubs`, - `sdklib.stubs.source`, - `sdklib.xml`, - }) -} - -func TestJavaSdkLibraryImport_AccessOutputFiles(t *testing.T) { - prepareForJavaTest.RunTestWithBp(t, ` - java_sdk_library_import { - name: "foo", - public: { - jars: ["a.jar"], - stub_srcs: ["a.java"], - current_api: "api/current.txt", - removed_api: "api/removed.txt", - }, - } - - java_library { - name: "bar", - srcs: [":foo{.public.stubs.source}"], - java_resources: [ - ":foo{.public.api.txt}", - ":foo{.public.removed-api.txt}", - ], - } - `) -} - -func TestJavaSdkLibraryImport_AccessOutputFiles_Invalid(t *testing.T) { - bp := ` - java_sdk_library_import { - name: "foo", - public: { - jars: ["a.jar"], - }, - } - ` - - t.Run("stubs.source", func(t *testing.T) { - prepareForJavaTest. - ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`stubs.source not available for api scope public`)). - RunTestWithBp(t, bp+` - java_library { - name: "bar", - srcs: [":foo{.public.stubs.source}"], - java_resources: [ - ":foo{.public.api.txt}", - ":foo{.public.removed-api.txt}", - ], - } - `) - }) - - t.Run("api.txt", func(t *testing.T) { - prepareForJavaTest. - ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`api.txt not available for api scope public`)). - RunTestWithBp(t, bp+` - java_library { - name: "bar", - srcs: ["a.java"], - java_resources: [ - ":foo{.public.api.txt}", - ], - } - `) - }) - - t.Run("removed-api.txt", func(t *testing.T) { - prepareForJavaTest. - ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`removed-api.txt not available for api scope public`)). - RunTestWithBp(t, bp+` - java_library { - name: "bar", - srcs: ["a.java"], - java_resources: [ - ":foo{.public.removed-api.txt}", - ], - } - `) - }) -} - -func TestJavaSdkLibrary_InvalidScopes(t *testing.T) { - prepareForJavaTest. - ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "foo": enabled api scope "system" depends on disabled scope "public"`)). - RunTestWithBp(t, ` - java_sdk_library { - name: "foo", - srcs: ["a.java", "b.java"], - api_packages: ["foo"], - // Explicitly disable public to test the check that ensures the set of enabled - // scopes is consistent. - public: { - enabled: false, - }, - system: { - enabled: true, - }, - } - `) -} - -func TestJavaSdkLibrary_SdkVersion_ForScope(t *testing.T) { - android.GroupFixturePreparers( - prepareForJavaTest, - PrepareForTestWithJavaSdkLibraryFiles, - FixtureWithLastReleaseApis("foo"), - ).RunTestWithBp(t, ` - java_sdk_library { - name: "foo", - srcs: ["a.java", "b.java"], - api_packages: ["foo"], - system: { - enabled: true, - sdk_version: "module_current", - }, - } - `) -} - -func TestJavaSdkLibrary_ModuleLib(t *testing.T) { - android.GroupFixturePreparers( - prepareForJavaTest, - PrepareForTestWithJavaSdkLibraryFiles, - FixtureWithLastReleaseApis("foo"), - ).RunTestWithBp(t, ` - java_sdk_library { - name: "foo", - srcs: ["a.java", "b.java"], - api_packages: ["foo"], - system: { - enabled: true, - }, - module_lib: { - enabled: true, - }, - } - `) -} - -func TestJavaSdkLibrary_SystemServer(t *testing.T) { - android.GroupFixturePreparers( - prepareForJavaTest, - PrepareForTestWithJavaSdkLibraryFiles, - FixtureWithLastReleaseApis("foo"), - ).RunTestWithBp(t, ` - java_sdk_library { - name: "foo", - srcs: ["a.java", "b.java"], - api_packages: ["foo"], - system: { - enabled: true, - }, - system_server: { - enabled: true, - }, - } - `) -} - -func TestJavaSdkLibrary_MissingScope(t *testing.T) { - prepareForJavaTest. - ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`requires api scope module-lib from foo but it only has \[\] available`)). - RunTestWithBp(t, ` - java_sdk_library { - name: "foo", - srcs: ["a.java"], - public: { - enabled: false, - }, - } - - java_library { - name: "baz", - srcs: ["a.java"], - libs: ["foo"], - sdk_version: "module_current", - } - `) -} - -func TestJavaSdkLibrary_FallbackScope(t *testing.T) { - android.GroupFixturePreparers( - prepareForJavaTest, - PrepareForTestWithJavaSdkLibraryFiles, - FixtureWithLastReleaseApis("foo"), - ).RunTestWithBp(t, ` - java_sdk_library { - name: "foo", - srcs: ["a.java"], - system: { - enabled: true, - }, - } - - java_library { - name: "baz", - srcs: ["a.java"], - libs: ["foo"], - // foo does not have module-lib scope so it should fallback to system - sdk_version: "module_current", - } - `) -} - -func TestJavaSdkLibrary_DefaultToStubs(t *testing.T) { - result := android.GroupFixturePreparers( - prepareForJavaTest, - PrepareForTestWithJavaSdkLibraryFiles, - FixtureWithLastReleaseApis("foo"), - ).RunTestWithBp(t, ` - java_sdk_library { - name: "foo", - srcs: ["a.java"], - system: { - enabled: true, - }, - default_to_stubs: true, - } - - java_library { - name: "baz", - srcs: ["a.java"], - libs: ["foo"], - // does not have sdk_version set, should fallback to module, - // which will then fallback to system because the module scope - // is not enabled. - } - `) - // The baz library should depend on the system stubs jar. - bazLibrary := result.ModuleForTests("baz", "android_common").Rule("javac") - if expected, actual := `^-classpath .*:out/soong/[^:]*/turbine-combined/foo\.stubs.system\.jar$`, bazLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) { - t.Errorf("expected %q, found %#q", expected, actual) - } -} - var compilerFlagsTestCases = []struct { in string out bool diff --git a/java/sdk_library.go b/java/sdk_library.go index 8f36758c8..ecf2b1a03 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -457,6 +457,11 @@ type sdkLibraryProperties struct { // * API incompatibilities baseline filegroup -> <dist-stem>-incompatibilities.api.<scope>.latest Dist_stem *string + // The subdirectory for the artifacts that are copied to the dist directory. If not specified + // then defaults to "android". Should be set to "android" for anything that should be published + // in the public Android SDK. + Dist_group *string + // A compatibility mode that allows historical API-tracking files to not exist. // Do not use. Unsafe_ignore_missing_latest_api bool @@ -1198,12 +1203,10 @@ func (module *SdkLibrary) AndroidMkEntries() []android.AndroidMkEntries { // The dist path of the stub artifacts func (module *SdkLibrary) apiDistPath(apiScope *apiScope) string { - if module.ModuleBase.Owner() != "" { - return path.Join("apistubs", module.ModuleBase.Owner(), apiScope.name) - } else if Bool(module.sdkLibraryProperties.Core_lib) { + if Bool(module.sdkLibraryProperties.Core_lib) { return path.Join("apistubs", "core", apiScope.name) } else { - return path.Join("apistubs", "android", apiScope.name) + return path.Join("apistubs", module.distGroup(), apiScope.name) } } @@ -1228,6 +1231,19 @@ func (module *SdkLibrary) distStem() string { return proptools.StringDefault(module.sdkLibraryProperties.Dist_stem, module.BaseModuleName()) } +// distGroup returns the subdirectory of the dist path of the stub artifacts. +func (module *SdkLibrary) distGroup() string { + if group := proptools.String(module.sdkLibraryProperties.Dist_group); group != "" { + return group + } + // TODO(b/186723288): Remove this once everything uses dist_group. + if owner := module.ModuleBase.Owner(); owner != "" { + return owner + } + // TODO(b/186723288): Make this "unknown". + return "android" +} + func (module *SdkLibrary) latestApiFilegroupName(apiScope *apiScope) string { return ":" + module.distStem() + ".api." + apiScope.name + ".latest" } diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go new file mode 100644 index 000000000..0fe6e72ef --- /dev/null +++ b/java/sdk_library_test.go @@ -0,0 +1,931 @@ +// Copyright 2021 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package java + +import ( + "android/soong/android" + "fmt" + "path/filepath" + "regexp" + "testing" + + "github.com/google/blueprint/proptools" +) + +func TestJavaSdkLibrary(t *testing.T) { + result := android.GroupFixturePreparers( + prepareForJavaTest, + PrepareForTestWithJavaSdkLibraryFiles, + FixtureWithPrebuiltApis(map[string][]string{ + "28": {"foo"}, + "29": {"foo"}, + "30": {"bar", "barney", "baz", "betty", "foo", "fred", "quuz", "wilma"}, + }), + ).RunTestWithBp(t, ` + droiddoc_exported_dir { + name: "droiddoc-templates-sdk", + path: ".", + } + java_sdk_library { + name: "foo", + srcs: ["a.java", "b.java"], + api_packages: ["foo"], + } + java_sdk_library { + name: "bar", + srcs: ["a.java", "b.java"], + api_packages: ["bar"], + } + java_library { + name: "baz", + srcs: ["c.java"], + libs: ["foo", "bar.stubs"], + sdk_version: "system_current", + } + java_sdk_library { + name: "barney", + srcs: ["c.java"], + api_only: true, + } + java_sdk_library { + name: "betty", + srcs: ["c.java"], + shared_library: false, + } + java_sdk_library_import { + name: "quuz", + public: { + jars: ["c.jar"], + }, + } + java_sdk_library_import { + name: "fred", + public: { + jars: ["b.jar"], + }, + } + java_sdk_library_import { + name: "wilma", + public: { + jars: ["b.jar"], + }, + shared_library: false, + } + java_library { + name: "qux", + srcs: ["c.java"], + libs: ["baz", "fred", "quuz.stubs", "wilma", "barney", "betty"], + sdk_version: "system_current", + } + java_library { + name: "baz-test", + srcs: ["c.java"], + libs: ["foo"], + sdk_version: "test_current", + } + java_library { + name: "baz-29", + srcs: ["c.java"], + libs: ["foo"], + sdk_version: "system_29", + } + java_library { + name: "baz-module-30", + srcs: ["c.java"], + libs: ["foo"], + sdk_version: "module_30", + } + `) + + // check the existence of the internal modules + result.ModuleForTests("foo", "android_common") + result.ModuleForTests(apiScopePublic.stubsLibraryModuleName("foo"), "android_common") + result.ModuleForTests(apiScopeSystem.stubsLibraryModuleName("foo"), "android_common") + result.ModuleForTests(apiScopeTest.stubsLibraryModuleName("foo"), "android_common") + result.ModuleForTests(apiScopePublic.stubsSourceModuleName("foo"), "android_common") + result.ModuleForTests(apiScopeSystem.stubsSourceModuleName("foo"), "android_common") + result.ModuleForTests(apiScopeTest.stubsSourceModuleName("foo"), "android_common") + result.ModuleForTests("foo"+sdkXmlFileSuffix, "android_common") + result.ModuleForTests("foo.api.public.28", "") + result.ModuleForTests("foo.api.system.28", "") + result.ModuleForTests("foo.api.test.28", "") + + bazJavac := result.ModuleForTests("baz", "android_common").Rule("javac") + // tests if baz is actually linked to the stubs lib + android.AssertStringDoesContain(t, "baz javac classpath", bazJavac.Args["classpath"], "foo.stubs.system.jar") + // ... and not to the impl lib + android.AssertStringDoesNotContain(t, "baz javac classpath", bazJavac.Args["classpath"], "foo.jar") + // test if baz is not linked to the system variant of foo + android.AssertStringDoesNotContain(t, "baz javac classpath", bazJavac.Args["classpath"], "foo.stubs.jar") + + bazTestJavac := result.ModuleForTests("baz-test", "android_common").Rule("javac") + // tests if baz-test is actually linked to the test stubs lib + android.AssertStringDoesContain(t, "baz-test javac classpath", bazTestJavac.Args["classpath"], "foo.stubs.test.jar") + + baz29Javac := result.ModuleForTests("baz-29", "android_common").Rule("javac") + // tests if baz-29 is actually linked to the system 29 stubs lib + android.AssertStringDoesContain(t, "baz-29 javac classpath", baz29Javac.Args["classpath"], "prebuilts/sdk/29/system/foo.jar") + + bazModule30Javac := result.ModuleForTests("baz-module-30", "android_common").Rule("javac") + // tests if "baz-module-30" is actually linked to the module 30 stubs lib + android.AssertStringDoesContain(t, "baz-module-30 javac classpath", bazModule30Javac.Args["classpath"], "prebuilts/sdk/30/module-lib/foo.jar") + + // test if baz has exported SDK lib names foo and bar to qux + qux := result.ModuleForTests("qux", "android_common") + if quxLib, ok := qux.Module().(*Library); ok { + sdkLibs := quxLib.ClassLoaderContexts().UsesLibs() + android.AssertDeepEquals(t, "qux exports", []string{"foo", "bar", "fred", "quuz"}, sdkLibs) + } +} + +func TestJavaSdkLibrary_StubOrImplOnlyLibs(t *testing.T) { + result := android.GroupFixturePreparers( + prepareForJavaTest, + PrepareForTestWithJavaSdkLibraryFiles, + FixtureWithLastReleaseApis("sdklib"), + ).RunTestWithBp(t, ` + java_sdk_library { + name: "sdklib", + srcs: ["a.java"], + libs: ["lib"], + static_libs: ["static-lib"], + impl_only_libs: ["impl-only-lib"], + stub_only_libs: ["stub-only-lib"], + stub_only_static_libs: ["stub-only-static-lib"], + } + java_defaults { + name: "defaults", + srcs: ["a.java"], + sdk_version: "current", + } + java_library { name: "lib", defaults: ["defaults"] } + java_library { name: "static-lib", defaults: ["defaults"] } + java_library { name: "impl-only-lib", defaults: ["defaults"] } + java_library { name: "stub-only-lib", defaults: ["defaults"] } + java_library { name: "stub-only-static-lib", defaults: ["defaults"] } + `) + var expectations = []struct { + lib string + on_impl_classpath bool + on_stub_classpath bool + in_impl_combined bool + in_stub_combined bool + }{ + {lib: "lib", on_impl_classpath: true}, + {lib: "static-lib", in_impl_combined: true}, + {lib: "impl-only-lib", on_impl_classpath: true}, + {lib: "stub-only-lib", on_stub_classpath: true}, + {lib: "stub-only-static-lib", in_stub_combined: true}, + } + verify := func(sdklib, dep string, cp, combined bool) { + sdklibCp := result.ModuleForTests(sdklib, "android_common").Rule("javac").Args["classpath"] + expected := cp || combined // Every combined jar is also on the classpath. + android.AssertStringContainsEquals(t, "bad classpath for "+sdklib, sdklibCp, "/"+dep+".jar", expected) + + combineJarInputs := result.ModuleForTests(sdklib, "android_common").Rule("combineJar").Inputs.Strings() + depPath := filepath.Join("out", "soong", ".intermediates", dep, "android_common", "turbine-combined", dep+".jar") + android.AssertStringListContainsEquals(t, "bad combined inputs for "+sdklib, combineJarInputs, depPath, combined) + } + for _, expectation := range expectations { + verify("sdklib", expectation.lib, expectation.on_impl_classpath, expectation.in_impl_combined) + verify("sdklib.impl", expectation.lib, expectation.on_impl_classpath, expectation.in_impl_combined) + + stubName := apiScopePublic.stubsLibraryModuleName("sdklib") + verify(stubName, expectation.lib, expectation.on_stub_classpath, expectation.in_stub_combined) + } +} + +func TestJavaSdkLibrary_DoNotAccessImplWhenItIsNotBuilt(t *testing.T) { + result := android.GroupFixturePreparers( + prepareForJavaTest, + PrepareForTestWithJavaSdkLibraryFiles, + FixtureWithLastReleaseApis("foo"), + ).RunTestWithBp(t, ` + java_sdk_library { + name: "foo", + srcs: ["a.java"], + api_only: true, + public: { + enabled: true, + }, + } + + java_library { + name: "bar", + srcs: ["b.java"], + libs: ["foo"], + } + `) + + // The bar library should depend on the stubs jar. + barLibrary := result.ModuleForTests("bar", "android_common").Rule("javac") + if expected, actual := `^-classpath .*:out/soong/[^:]*/turbine-combined/foo\.stubs\.jar$`, barLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) { + t.Errorf("expected %q, found %#q", expected, actual) + } +} + +func TestJavaSdkLibrary_UseSourcesFromAnotherSdkLibrary(t *testing.T) { + android.GroupFixturePreparers( + prepareForJavaTest, + PrepareForTestWithJavaSdkLibraryFiles, + FixtureWithLastReleaseApis("foo"), + ).RunTestWithBp(t, ` + java_sdk_library { + name: "foo", + srcs: ["a.java"], + api_packages: ["foo"], + public: { + enabled: true, + }, + } + + java_library { + name: "bar", + srcs: ["b.java", ":foo{.public.stubs.source}"], + } + `) +} + +func TestJavaSdkLibrary_AccessOutputFiles_MissingScope(t *testing.T) { + android.GroupFixturePreparers( + prepareForJavaTest, + PrepareForTestWithJavaSdkLibraryFiles, + FixtureWithLastReleaseApis("foo"), + ). + ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`"foo" does not provide api scope system`)). + RunTestWithBp(t, ` + java_sdk_library { + name: "foo", + srcs: ["a.java"], + api_packages: ["foo"], + public: { + enabled: true, + }, + } + + java_library { + name: "bar", + srcs: ["b.java", ":foo{.system.stubs.source}"], + } + `) +} + +func TestJavaSdkLibrary_Deps(t *testing.T) { + result := android.GroupFixturePreparers( + prepareForJavaTest, + PrepareForTestWithJavaSdkLibraryFiles, + FixtureWithLastReleaseApis("sdklib"), + ).RunTestWithBp(t, ` + java_sdk_library { + name: "sdklib", + srcs: ["a.java"], + sdk_version: "none", + system_modules: "none", + public: { + enabled: true, + }, + } + `) + + CheckModuleDependencies(t, result.TestContext, "sdklib", "android_common", []string{ + `dex2oatd`, + `sdklib.impl`, + `sdklib.stubs`, + `sdklib.stubs.source`, + `sdklib.xml`, + }) +} + +func TestJavaSdkLibraryImport_AccessOutputFiles(t *testing.T) { + prepareForJavaTest.RunTestWithBp(t, ` + java_sdk_library_import { + name: "foo", + public: { + jars: ["a.jar"], + stub_srcs: ["a.java"], + current_api: "api/current.txt", + removed_api: "api/removed.txt", + }, + } + + java_library { + name: "bar", + srcs: [":foo{.public.stubs.source}"], + java_resources: [ + ":foo{.public.api.txt}", + ":foo{.public.removed-api.txt}", + ], + } + `) +} + +func TestJavaSdkLibraryImport_AccessOutputFiles_Invalid(t *testing.T) { + bp := ` + java_sdk_library_import { + name: "foo", + public: { + jars: ["a.jar"], + }, + } + ` + + t.Run("stubs.source", func(t *testing.T) { + prepareForJavaTest. + ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`stubs.source not available for api scope public`)). + RunTestWithBp(t, bp+` + java_library { + name: "bar", + srcs: [":foo{.public.stubs.source}"], + java_resources: [ + ":foo{.public.api.txt}", + ":foo{.public.removed-api.txt}", + ], + } + `) + }) + + t.Run("api.txt", func(t *testing.T) { + prepareForJavaTest. + ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`api.txt not available for api scope public`)). + RunTestWithBp(t, bp+` + java_library { + name: "bar", + srcs: ["a.java"], + java_resources: [ + ":foo{.public.api.txt}", + ], + } + `) + }) + + t.Run("removed-api.txt", func(t *testing.T) { + prepareForJavaTest. + ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`removed-api.txt not available for api scope public`)). + RunTestWithBp(t, bp+` + java_library { + name: "bar", + srcs: ["a.java"], + java_resources: [ + ":foo{.public.removed-api.txt}", + ], + } + `) + }) +} + +func TestJavaSdkLibrary_InvalidScopes(t *testing.T) { + prepareForJavaTest. + ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "foo": enabled api scope "system" depends on disabled scope "public"`)). + RunTestWithBp(t, ` + java_sdk_library { + name: "foo", + srcs: ["a.java", "b.java"], + api_packages: ["foo"], + // Explicitly disable public to test the check that ensures the set of enabled + // scopes is consistent. + public: { + enabled: false, + }, + system: { + enabled: true, + }, + } + `) +} + +func TestJavaSdkLibrary_SdkVersion_ForScope(t *testing.T) { + android.GroupFixturePreparers( + prepareForJavaTest, + PrepareForTestWithJavaSdkLibraryFiles, + FixtureWithLastReleaseApis("foo"), + ).RunTestWithBp(t, ` + java_sdk_library { + name: "foo", + srcs: ["a.java", "b.java"], + api_packages: ["foo"], + system: { + enabled: true, + sdk_version: "module_current", + }, + } + `) +} + +func TestJavaSdkLibrary_ModuleLib(t *testing.T) { + android.GroupFixturePreparers( + prepareForJavaTest, + PrepareForTestWithJavaSdkLibraryFiles, + FixtureWithLastReleaseApis("foo"), + ).RunTestWithBp(t, ` + java_sdk_library { + name: "foo", + srcs: ["a.java", "b.java"], + api_packages: ["foo"], + system: { + enabled: true, + }, + module_lib: { + enabled: true, + }, + } + `) +} + +func TestJavaSdkLibrary_SystemServer(t *testing.T) { + android.GroupFixturePreparers( + prepareForJavaTest, + PrepareForTestWithJavaSdkLibraryFiles, + FixtureWithLastReleaseApis("foo"), + ).RunTestWithBp(t, ` + java_sdk_library { + name: "foo", + srcs: ["a.java", "b.java"], + api_packages: ["foo"], + system: { + enabled: true, + }, + system_server: { + enabled: true, + }, + } + `) +} + +func TestJavaSdkLibrary_MissingScope(t *testing.T) { + prepareForJavaTest. + ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`requires api scope module-lib from foo but it only has \[\] available`)). + RunTestWithBp(t, ` + java_sdk_library { + name: "foo", + srcs: ["a.java"], + public: { + enabled: false, + }, + } + + java_library { + name: "baz", + srcs: ["a.java"], + libs: ["foo"], + sdk_version: "module_current", + } + `) +} + +func TestJavaSdkLibrary_FallbackScope(t *testing.T) { + android.GroupFixturePreparers( + prepareForJavaTest, + PrepareForTestWithJavaSdkLibraryFiles, + FixtureWithLastReleaseApis("foo"), + ).RunTestWithBp(t, ` + java_sdk_library { + name: "foo", + srcs: ["a.java"], + system: { + enabled: true, + }, + } + + java_library { + name: "baz", + srcs: ["a.java"], + libs: ["foo"], + // foo does not have module-lib scope so it should fallback to system + sdk_version: "module_current", + } + `) +} + +func TestJavaSdkLibrary_DefaultToStubs(t *testing.T) { + result := android.GroupFixturePreparers( + prepareForJavaTest, + PrepareForTestWithJavaSdkLibraryFiles, + FixtureWithLastReleaseApis("foo"), + ).RunTestWithBp(t, ` + java_sdk_library { + name: "foo", + srcs: ["a.java"], + system: { + enabled: true, + }, + default_to_stubs: true, + } + + java_library { + name: "baz", + srcs: ["a.java"], + libs: ["foo"], + // does not have sdk_version set, should fallback to module, + // which will then fallback to system because the module scope + // is not enabled. + } + `) + // The baz library should depend on the system stubs jar. + bazLibrary := result.ModuleForTests("baz", "android_common").Rule("javac") + if expected, actual := `^-classpath .*:out/soong/[^:]*/turbine-combined/foo\.stubs.system\.jar$`, bazLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) { + t.Errorf("expected %q, found %#q", expected, actual) + } +} + +func TestJavaSdkLibraryImport(t *testing.T) { + result := prepareForJavaTest.RunTestWithBp(t, ` + java_library { + name: "foo", + srcs: ["a.java"], + libs: ["sdklib"], + sdk_version: "current", + } + + java_library { + name: "foo.system", + srcs: ["a.java"], + libs: ["sdklib"], + sdk_version: "system_current", + } + + java_library { + name: "foo.test", + srcs: ["a.java"], + libs: ["sdklib"], + sdk_version: "test_current", + } + + java_sdk_library_import { + name: "sdklib", + public: { + jars: ["a.jar"], + }, + system: { + jars: ["b.jar"], + }, + test: { + jars: ["c.jar"], + stub_srcs: ["c.java"], + }, + } + `) + + for _, scope := range []string{"", ".system", ".test"} { + fooModule := result.ModuleForTests("foo"+scope, "android_common") + javac := fooModule.Rule("javac") + + sdklibStubsJar := result.ModuleForTests("sdklib.stubs"+scope, "android_common").Rule("combineJar").Output + android.AssertStringDoesContain(t, "foo classpath", javac.Args["classpath"], sdklibStubsJar.String()) + } + + CheckModuleDependencies(t, result.TestContext, "sdklib", "android_common", []string{ + `prebuilt_sdklib.stubs`, + `prebuilt_sdklib.stubs.source.test`, + `prebuilt_sdklib.stubs.system`, + `prebuilt_sdklib.stubs.test`, + }) +} + +func TestJavaSdkLibraryImport_WithSource(t *testing.T) { + result := android.GroupFixturePreparers( + prepareForJavaTest, + PrepareForTestWithJavaSdkLibraryFiles, + FixtureWithLastReleaseApis("sdklib"), + ).RunTestWithBp(t, ` + java_sdk_library { + name: "sdklib", + srcs: ["a.java"], + sdk_version: "none", + system_modules: "none", + public: { + enabled: true, + }, + } + + java_sdk_library_import { + name: "sdklib", + public: { + jars: ["a.jar"], + }, + } + `) + + CheckModuleDependencies(t, result.TestContext, "sdklib", "android_common", []string{ + `dex2oatd`, + `prebuilt_sdklib`, + `sdklib.impl`, + `sdklib.stubs`, + `sdklib.stubs.source`, + `sdklib.xml`, + }) + + CheckModuleDependencies(t, result.TestContext, "prebuilt_sdklib", "android_common", []string{ + `prebuilt_sdklib.stubs`, + `sdklib.impl`, + // This should be prebuilt_sdklib.stubs but is set to sdklib.stubs because the + // dependency is added after prebuilts may have been renamed and so has to use + // the renamed name. + `sdklib.xml`, + }) +} + +func TestJavaSdkLibraryImport_Preferred(t *testing.T) { + result := android.GroupFixturePreparers( + prepareForJavaTest, + PrepareForTestWithJavaSdkLibraryFiles, + FixtureWithLastReleaseApis("sdklib"), + ).RunTestWithBp(t, ` + java_sdk_library { + name: "sdklib", + srcs: ["a.java"], + sdk_version: "none", + system_modules: "none", + public: { + enabled: true, + }, + } + + java_sdk_library_import { + name: "sdklib", + prefer: true, + public: { + jars: ["a.jar"], + }, + } + `) + + CheckModuleDependencies(t, result.TestContext, "sdklib", "android_common", []string{ + `dex2oatd`, + `prebuilt_sdklib`, + `sdklib.impl`, + `sdklib.stubs`, + `sdklib.stubs.source`, + `sdklib.xml`, + }) + + CheckModuleDependencies(t, result.TestContext, "prebuilt_sdklib", "android_common", []string{ + `prebuilt_sdklib.stubs`, + `sdklib.impl`, + `sdklib.xml`, + }) +} + +func TestJavaSdkLibraryEnforce(t *testing.T) { + partitionToBpOption := func(partition string) string { + switch partition { + case "system": + return "" + case "vendor": + return "soc_specific: true," + case "product": + return "product_specific: true," + default: + panic("Invalid partition group name: " + partition) + } + } + + type testConfigInfo struct { + libraryType string + fromPartition string + toPartition string + enforceVendorInterface bool + enforceProductInterface bool + enforceJavaSdkLibraryCheck bool + allowList []string + } + + createPreparer := func(info testConfigInfo) android.FixturePreparer { + bpFileTemplate := ` + java_library { + name: "foo", + srcs: ["foo.java"], + libs: ["bar"], + sdk_version: "current", + %s + } + + %s { + name: "bar", + srcs: ["bar.java"], + sdk_version: "current", + %s + } + ` + + bpFile := fmt.Sprintf(bpFileTemplate, + partitionToBpOption(info.fromPartition), + info.libraryType, + partitionToBpOption(info.toPartition)) + + return android.GroupFixturePreparers( + PrepareForTestWithJavaSdkLibraryFiles, + FixtureWithLastReleaseApis("bar"), + android.FixtureWithRootAndroidBp(bpFile), + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.EnforceProductPartitionInterface = proptools.BoolPtr(info.enforceProductInterface) + if info.enforceVendorInterface { + variables.DeviceVndkVersion = proptools.StringPtr("current") + } + variables.EnforceInterPartitionJavaSdkLibrary = proptools.BoolPtr(info.enforceJavaSdkLibraryCheck) + variables.InterPartitionJavaLibraryAllowList = info.allowList + }), + ) + } + + runTest := func(t *testing.T, info testConfigInfo, expectedErrorPattern string) { + t.Run(fmt.Sprintf("%v", info), func(t *testing.T) { + errorHandler := android.FixtureExpectsNoErrors + if expectedErrorPattern != "" { + errorHandler = android.FixtureExpectsAtLeastOneErrorMatchingPattern(expectedErrorPattern) + } + android.GroupFixturePreparers( + prepareForJavaTest, + createPreparer(info), + ). + ExtendWithErrorHandler(errorHandler). + RunTest(t) + }) + } + + errorMessage := "is not allowed across the partitions" + + runTest(t, testConfigInfo{ + libraryType: "java_library", + fromPartition: "product", + toPartition: "system", + enforceVendorInterface: true, + enforceProductInterface: true, + enforceJavaSdkLibraryCheck: false, + }, "") + + runTest(t, testConfigInfo{ + libraryType: "java_library", + fromPartition: "product", + toPartition: "system", + enforceVendorInterface: true, + enforceProductInterface: false, + enforceJavaSdkLibraryCheck: true, + }, "") + + runTest(t, testConfigInfo{ + libraryType: "java_library", + fromPartition: "product", + toPartition: "system", + enforceVendorInterface: true, + enforceProductInterface: true, + enforceJavaSdkLibraryCheck: true, + }, errorMessage) + + runTest(t, testConfigInfo{ + libraryType: "java_library", + fromPartition: "vendor", + toPartition: "system", + enforceVendorInterface: true, + enforceProductInterface: true, + enforceJavaSdkLibraryCheck: true, + }, errorMessage) + + runTest(t, testConfigInfo{ + libraryType: "java_library", + fromPartition: "vendor", + toPartition: "system", + enforceVendorInterface: true, + enforceProductInterface: true, + enforceJavaSdkLibraryCheck: true, + allowList: []string{"bar"}, + }, "") + + runTest(t, testConfigInfo{ + libraryType: "java_library", + fromPartition: "vendor", + toPartition: "product", + enforceVendorInterface: true, + enforceProductInterface: true, + enforceJavaSdkLibraryCheck: true, + }, errorMessage) + + runTest(t, testConfigInfo{ + libraryType: "java_sdk_library", + fromPartition: "product", + toPartition: "system", + enforceVendorInterface: true, + enforceProductInterface: true, + enforceJavaSdkLibraryCheck: true, + }, "") + + runTest(t, testConfigInfo{ + libraryType: "java_sdk_library", + fromPartition: "vendor", + toPartition: "system", + enforceVendorInterface: true, + enforceProductInterface: true, + enforceJavaSdkLibraryCheck: true, + }, "") + + runTest(t, testConfigInfo{ + libraryType: "java_sdk_library", + fromPartition: "vendor", + toPartition: "product", + enforceVendorInterface: true, + enforceProductInterface: true, + enforceJavaSdkLibraryCheck: true, + }, "") +} + +func TestJavaSdkLibraryDist(t *testing.T) { + result := android.GroupFixturePreparers( + PrepareForTestWithJavaBuildComponents, + PrepareForTestWithJavaDefaultModules, + PrepareForTestWithJavaSdkLibraryFiles, + ).RunTestWithBp(t, ` + java_sdk_library { + name: "sdklib_no_owner", + unsafe_ignore_missing_latest_api: true, + srcs: ["foo.java"], + } + + java_sdk_library { + name: "sdklib_group_foo", + unsafe_ignore_missing_latest_api: true, + srcs: ["foo.java"], + dist_group: "foo", + } + + java_sdk_library { + name: "sdklib_owner_foo", + unsafe_ignore_missing_latest_api: true, + srcs: ["foo.java"], + owner: "foo", + } + + java_sdk_library { + name: "sdklib_stem_foo", + unsafe_ignore_missing_latest_api: true, + srcs: ["foo.java"], + dist_stem: "foo", + } + + java_sdk_library { + name: "sdklib_core_lib", + unsafe_ignore_missing_latest_api: true, + srcs: ["foo.java"], + core_lib: true, + } + `) + + type testCase struct { + module string + distDir string + distStem string + } + testCases := []testCase{ + { + module: "sdklib_no_owner", + distDir: "apistubs/android/public", + distStem: "sdklib_no_owner.jar", + }, + { + module: "sdklib_group_foo", + distDir: "apistubs/foo/public", + distStem: "sdklib_group_foo.jar", + }, + { + module: "sdklib_owner_foo", + distDir: "apistubs/foo/public", + distStem: "sdklib_owner_foo.jar", + }, + { + module: "sdklib_stem_foo", + distDir: "apistubs/android/public", + distStem: "foo.jar", + }, + { + module: "sdklib_core_lib", + distDir: "apistubs/core/public", + distStem: "sdklib_core_lib.jar", + }, + } + + for _, tt := range testCases { + t.Run(tt.module, func(t *testing.T) { + m := result.ModuleForTests(tt.module+".stubs", "android_common").Module().(*Library) + dists := m.Dists() + if len(dists) != 1 { + t.Fatalf("expected exactly 1 dist entry, got %d", len(dists)) + } + if g, w := String(dists[0].Dir), tt.distDir; g != w { + t.Errorf("expected dist dir %q, got %q", w, g) + } + if g, w := String(dists[0].Dest), tt.distStem; g != w { + t.Errorf("expected dist stem %q, got %q", w, g) + } + }) + } +} diff --git a/python/test.go b/python/test.go index 6713189fd..7413782cb 100644 --- a/python/test.go +++ b/python/test.go @@ -15,6 +15,8 @@ package python import ( + "github.com/google/blueprint/proptools" + "android/soong/android" "android/soong/tradefed" ) @@ -102,6 +104,9 @@ func NewTest(hod android.HostOrDeviceSupported) *Module { binary.pythonInstaller = NewPythonInstaller("nativetest", "nativetest64") test := &testDecorator{binaryDecorator: binary} + if hod == android.HostSupportedNoCross && test.testProperties.Test_options.Unit_test == nil { + test.testProperties.Test_options.Unit_test = proptools.BoolPtr(true) + } module.bootstrapper = test module.installer = test diff --git a/rust/snapshot_utils.go b/rust/snapshot_utils.go index e0ed1f711..943c79098 100644 --- a/rust/snapshot_utils.go +++ b/rust/snapshot_utils.go @@ -20,12 +20,12 @@ import ( func (mod *Module) ExcludeFromVendorSnapshot() bool { // TODO Rust does not yet support snapshotting - return true + return false } func (mod *Module) ExcludeFromRecoverySnapshot() bool { // TODO Rust does not yet support snapshotting - return true + return false } func (mod *Module) IsSnapshotLibrary() bool { diff --git a/scripts/build-mainline-modules.sh b/scripts/build-mainline-modules.sh index 30cb93718..39c8fba48 100755 --- a/scripts/build-mainline-modules.sh +++ b/scripts/build-mainline-modules.sh @@ -68,6 +68,9 @@ lib_dir() { # Make sure this build builds from source, regardless of the default. export SOONG_CONFIG_art_module_source_build=true +# This script does not intend to handle compressed APEX +export OVERRIDE_PRODUCT_COMPRESSED_APEX=false + OUT_DIR=$(source build/envsetup.sh > /dev/null; TARGET_PRODUCT= get_build_var OUT_DIR) DIST_DIR=$(source build/envsetup.sh > /dev/null; TARGET_PRODUCT= get_build_var DIST_DIR) diff --git a/tests/mixed_mode_test.sh b/tests/mixed_mode_test.sh index 80774bf0f..b408fd325 100755 --- a/tests/mixed_mode_test.sh +++ b/tests/mixed_mode_test.sh @@ -14,7 +14,7 @@ function test_bazel_smoke { setup create_mock_bazel - run_bazel info + STANDALONE_BAZEL=true run_bazel info } test_bazel_smoke diff --git a/ui/build/config.go b/ui/build/config.go index f9f638c9a..f1f59895e 100644 --- a/ui/build/config.go +++ b/ui/build/config.go @@ -73,6 +73,9 @@ type configImpl struct { // During Bazel execution, Bazel cannot write outside OUT_DIR. // So if DIST_DIR is set to an external dir (outside of OUT_DIR), we need to rig it temporarily and then migrate files at the end of the build. riggedDistDirForBazel string + + // Set by multiproduct_kati + emptyNinjaFile bool } const srcDirFileCheck = "build/soong/root.bp" @@ -205,9 +208,6 @@ func NewConfig(ctx Context, args ...string) Config { "ANDROID_DEV_SCRIPTS", "ANDROID_EMULATOR_PREBUILTS", "ANDROID_PRE_BUILD_PATHS", - - // Only set in multiproduct_kati after config generation - "EMPTY_NINJA_FILE", ) if ret.UseGoma() || ret.ForceUseGoma() { @@ -1191,3 +1191,11 @@ func (c *configImpl) LogsDir() string { func (c *configImpl) BazelMetricsDir() string { return filepath.Join(c.LogsDir(), "bazel_metrics") } + +func (c *configImpl) SetEmptyNinjaFile(v bool) { + c.emptyNinjaFile = v +} + +func (c *configImpl) EmptyNinjaFile() bool { + return c.emptyNinjaFile +} diff --git a/ui/build/kati.go b/ui/build/kati.go index 06ec64607..dad68fac2 100644 --- a/ui/build/kati.go +++ b/ui/build/kati.go @@ -136,7 +136,7 @@ func runKati(ctx Context, config Config, extraSuffix string, args []string, envF // information out with --empty_ninja_file. // // From https://github.com/google/kati/commit/87b8da7af2c8bea28b1d8ab17679453d859f96e5 - if config.Environment().IsEnvTrue("EMPTY_NINJA_FILE") { + if config.EmptyNinjaFile() { args = append(args, "--empty_ninja_file") } diff --git a/ui/build/soong.go b/ui/build/soong.go index cd645eb41..712841465 100644 --- a/ui/build/soong.go +++ b/ui/build/soong.go @@ -119,6 +119,7 @@ func bootstrapBlueprint(ctx Context, config Config, integratedBp2Build bool) { args.OutFile = shared.JoinPath(config.SoongOutDir(), ".bootstrap/build.ninja") args.GlobFile = globFile args.GeneratingPrimaryBuilder = true + args.EmptyNinjaFile = config.EmptyNinjaFile() args.DelveListen = os.Getenv("SOONG_DELVE") if args.DelveListen != "" { |