diff options
151 files changed, 6243 insertions, 2525 deletions
diff --git a/android/Android.bp b/android/Android.bp index cfa2be38f..da369592a 100644 --- a/android/Android.bp +++ b/android/Android.bp @@ -47,6 +47,7 @@ bootstrap_go_package { "image.go", "license.go", "license_kind.go", + "license_metadata.go", "license_sdk_member.go", "licenses.go", "makefile_goal.go", @@ -113,6 +114,7 @@ bootstrap_go_package { "paths_test.go", "prebuilt_test.go", "rule_builder_test.go", + "sdk_version_test.go", "sdk_test.go", "singleton_module_test.go", "soong_config_modules_test.go", diff --git a/android/androidmk.go b/android/androidmk.go index 0adc2a6eb..4f6e24c18 100644 --- a/android/androidmk.go +++ b/android/androidmk.go @@ -474,6 +474,7 @@ type fillInEntriesContext interface { ModuleDir(module blueprint.Module) string Config() Config ModuleProvider(module blueprint.Module, provider blueprint.ProviderKey) interface{} + ModuleHasProvider(module blueprint.Module, provider blueprint.ProviderKey) bool } func (a *AndroidMkEntries) fillInEntries(ctx fillInEntriesContext, mod blueprint.Module) { @@ -609,6 +610,11 @@ func (a *AndroidMkEntries) fillInEntries(ctx fillInEntriesContext, mod blueprint } } + if ctx.ModuleHasProvider(mod, LicenseMetadataProvider) { + licenseMetadata := ctx.ModuleProvider(mod, LicenseMetadataProvider).(*LicenseMetadataInfo) + a.SetPath("LOCAL_SOONG_LICENSE_METADATA", licenseMetadata.LicenseMetadataPath) + } + extraCtx := &androidMkExtraEntriesContext{ ctx: ctx, mod: mod, @@ -887,6 +893,10 @@ func translateAndroidMkEntriesModule(ctx SingletonContext, w io.Writer, mod blue return nil } +func ShouldSkipAndroidMkProcessing(module Module) bool { + return shouldSkipAndroidMkProcessing(module.base()) +} + func shouldSkipAndroidMkProcessing(module *ModuleBase) bool { if !module.commonProperties.NamespaceExportedToMake { // TODO(jeffrygaston) do we want to validate that there are no modules being diff --git a/android/apex.go b/android/apex.go index 6b4054d44..cf1bcfef4 100644 --- a/android/apex.go +++ b/android/apex.go @@ -878,12 +878,8 @@ var minSdkVersionAllowlist = func(apiMap map[string]int) map[string]ApiLevel { "kotlinx-coroutines-android-nodeps": 30, "kotlinx-coroutines-core": 28, "kotlinx-coroutines-core-nodeps": 30, - "libasyncio": 30, "libbrotli": 30, - "libbuildversion": 30, "libcrypto_static": 30, - "libcrypto_utils": 30, - "libdiagnose_usb": 30, "libeigen": 30, "liblz4": 30, "libmdnssd": 30, @@ -893,7 +889,6 @@ var minSdkVersionAllowlist = func(apiMap map[string]int) map[string]ApiLevel { "libprocpartition": 30, "libprotobuf-java-lite": 30, "libprotoutil": 30, - "libsync": 30, "libtextclassifier_hash_headers": 30, "libtextclassifier_hash_static": 30, "libtflite_kernel_utils": 30, @@ -913,16 +908,18 @@ var minSdkVersionAllowlist = func(apiMap map[string]int) map[string]ApiLevel { // // Return true if the `to` module should be visited, false otherwise. type PayloadDepsCallback func(ctx ModuleContext, from blueprint.Module, to ApexModule, externalDep bool) bool +type WalkPayloadDepsFunc func(ctx ModuleContext, do PayloadDepsCallback) -// UpdatableModule represents updatable APEX/APK -type UpdatableModule interface { +// ModuleWithMinSdkVersionCheck represents a module that implements min_sdk_version checks +type ModuleWithMinSdkVersionCheck interface { Module - WalkPayloadDeps(ctx ModuleContext, do PayloadDepsCallback) + MinSdkVersion(ctx EarlyModuleContext) SdkSpec + CheckMinSdkVersion(ctx ModuleContext) } // CheckMinSdkVersion checks if every dependency of an updatable module sets min_sdk_version // accordingly -func CheckMinSdkVersion(m UpdatableModule, ctx ModuleContext, minSdkVersion ApiLevel) { +func CheckMinSdkVersion(ctx ModuleContext, minSdkVersion ApiLevel, walk WalkPayloadDepsFunc) { // do not enforce min_sdk_version for host if ctx.Host() { return @@ -938,7 +935,7 @@ func CheckMinSdkVersion(m UpdatableModule, ctx ModuleContext, minSdkVersion ApiL return } - m.WalkPayloadDeps(ctx, func(ctx ModuleContext, from blueprint.Module, to ApexModule, externalDep bool) bool { + walk(ctx, func(ctx ModuleContext, from blueprint.Module, to ApexModule, externalDep bool) bool { if externalDep { // external deps are outside the payload boundary, which is "stable" // interface. We don't have to check min_sdk_version for external @@ -948,6 +945,14 @@ func CheckMinSdkVersion(m UpdatableModule, ctx ModuleContext, minSdkVersion ApiL if am, ok := from.(DepIsInSameApex); ok && !am.DepIsInSameApex(ctx, to) { return false } + if m, ok := to.(ModuleWithMinSdkVersionCheck); ok { + // This dependency performs its own min_sdk_version check, just make sure it sets min_sdk_version + // to trigger the check. + if !m.MinSdkVersion(ctx).Specified() { + ctx.OtherModuleErrorf(m, "must set min_sdk_version") + } + return false + } if err := to.ShouldSupportSdkVersion(ctx, minSdkVersion); err != nil { toName := ctx.OtherModuleName(to) if ver, ok := minSdkVersionAllowlist[toName]; !ok || ver.GreaterThan(minSdkVersion) { diff --git a/android/api_levels.go b/android/api_levels.go index c1b3ba2ba..1fbbc1597 100644 --- a/android/api_levels.go +++ b/android/api_levels.go @@ -192,8 +192,8 @@ var LastWithoutModuleLibCoreSystemModules = uncheckedFinalApiLevel(31) // * "30" -> "30" // * "R" -> "30" // * "S" -> "S" -func ReplaceFinalizedCodenames(ctx PathContext, raw string) string { - num, ok := getFinalCodenamesMap(ctx.Config())[raw] +func ReplaceFinalizedCodenames(config Config, raw string) string { + num, ok := getFinalCodenamesMap(config)[raw] if !ok { return raw } @@ -201,7 +201,7 @@ func ReplaceFinalizedCodenames(ctx PathContext, raw string) string { return strconv.Itoa(num) } -// Converts the given string `raw` to an ApiLevel, possibly returning an error. +// ApiLevelFromUser converts the given string `raw` to an ApiLevel, possibly returning an error. // // `raw` must be non-empty. Passing an empty string results in a panic. // @@ -216,6 +216,12 @@ func ReplaceFinalizedCodenames(ctx PathContext, raw string) string { // Inputs that are not "current", known previews, or convertible to an integer // will return an error. func ApiLevelFromUser(ctx PathContext, raw string) (ApiLevel, error) { + return ApiLevelFromUserWithConfig(ctx.Config(), raw) +} + +// ApiLevelFromUserWithConfig implements ApiLevelFromUser, see comments for +// ApiLevelFromUser for more details. +func ApiLevelFromUserWithConfig(config Config, raw string) (ApiLevel, error) { if raw == "" { panic("API level string must be non-empty") } @@ -224,13 +230,13 @@ func ApiLevelFromUser(ctx PathContext, raw string) (ApiLevel, error) { return FutureApiLevel, nil } - for _, preview := range ctx.Config().PreviewApiLevels() { + for _, preview := range config.PreviewApiLevels() { if raw == preview.String() { return preview, nil } } - canonical := ReplaceFinalizedCodenames(ctx, raw) + canonical := ReplaceFinalizedCodenames(config, raw) asInt, err := strconv.Atoi(canonical) if err != nil { return NoneApiLevel, fmt.Errorf("%q could not be parsed as an integer and is not a recognized codename", canonical) diff --git a/android/arch.go b/android/arch.go index 3bf54b711..3cc5e8228 100644 --- a/android/arch.go +++ b/android/arch.go @@ -566,6 +566,8 @@ func GetOsSpecificVariantsOfCommonOSVariant(mctx BaseModuleContext) []Module { return variants } +var DarwinUniversalVariantTag = archDepTag{name: "darwin universal binary"} + // archMutator splits a module into a variant for each Target requested by the module. Target selection // for a module is in three levels, OsClass, multilib, and then Target. // OsClass selection is determined by: @@ -652,7 +654,7 @@ func archMutator(bpctx blueprint.BottomUpMutatorContext) { prefer32 := os == Windows // Determine the multilib selection for this module. - multilib, extraMultilib := decodeMultilib(base, os.Class) + multilib, extraMultilib := decodeMultilib(base, os) // Convert the multilib selection into a list of Targets. targets, err := decodeMultilibTargets(multilib, osTargets, prefer32) @@ -702,6 +704,16 @@ func archMutator(bpctx blueprint.BottomUpMutatorContext) { m.base().commonProperties.SkipInstall = true } } + + // Create a dependency for Darwin Universal binaries from the primary to secondary + // architecture. The module itself will be responsible for calling lipo to merge the outputs. + if os == Darwin { + if multilib == "darwin_universal" && len(modules) == 2 { + mctx.AddInterVariantDependency(DarwinUniversalVariantTag, modules[1], modules[0]) + } else if multilib == "darwin_universal_common_first" && len(modules) == 3 { + mctx.AddInterVariantDependency(DarwinUniversalVariantTag, modules[2], modules[1]) + } + } } // addTargetProperties annotates a variant with the Target is is being compiled for, the list @@ -717,9 +729,9 @@ func addTargetProperties(m Module, target Target, multiTargets []Target, primary // multilib from the factory's call to InitAndroidArchModule if none was set. For modules that // called InitAndroidMultiTargetsArchModule it always returns "common" for multilib, and returns // the actual multilib in extraMultilib. -func decodeMultilib(base *ModuleBase, class OsClass) (multilib, extraMultilib string) { +func decodeMultilib(base *ModuleBase, os OsType) (multilib, extraMultilib string) { // First check the "android.compile_multilib" or "host.compile_multilib" properties. - switch class { + switch os.Class { case Device: multilib = String(base.commonProperties.Target.Android.Compile_multilib) case Host: @@ -737,6 +749,26 @@ func decodeMultilib(base *ModuleBase, class OsClass) (multilib, extraMultilib st } if base.commonProperties.UseTargetVariants { + // Darwin has the concept of "universal binaries" which is implemented in Soong by + // building both x86_64 and arm64 variants, and having select module types know how to + // merge the outputs of their corresponding variants together into a final binary. Most + // module types don't need to understand this logic, as we only build a small portion + // of the tree for Darwin, and only module types writing macho files need to do the + // merging. + // + // This logic is not enabled for: + // "common", as it's not an arch-specific variant + // "32", as Darwin never has a 32-bit variant + // !UseTargetVariants, as the module has opted into handling the arch-specific logic on + // its own. + if os == Darwin && multilib != "common" && multilib != "32" { + if multilib == "common_first" { + multilib = "darwin_universal_common_first" + } else { + multilib = "darwin_universal" + } + } + return multilib, "" } else { // For app modules a single arch variant will be created per OS class which is expected to handle all the @@ -1793,6 +1825,15 @@ func decodeMultilibTargets(multilib string, targets []Target, prefer32 bool) ([] if len(buildTargets) == 0 { buildTargets = filterMultilibTargets(targets, "lib64") } + case "darwin_universal": + buildTargets = filterMultilibTargets(targets, "lib64") + // Reverse the targets so that the first architecture can depend on the second + // architecture module in order to merge the outputs. + reverseSliceInPlace(buildTargets) + case "darwin_universal_common_first": + archTargets := filterMultilibTargets(targets, "lib64") + reverseSliceInPlace(archTargets) + buildTargets = append(getCommonTargets(targets), archTargets...) default: return nil, fmt.Errorf(`compile_multilib must be "both", "first", "32", "64", "prefer32" or "first_prefer32" found %q`, multilib) diff --git a/android/bazel.go b/android/bazel.go index e97acffaf..8c63204b3 100644 --- a/android/bazel.go +++ b/android/bazel.go @@ -15,6 +15,8 @@ package android import ( + "bufio" + "errors" "fmt" "io/ioutil" "path/filepath" @@ -39,6 +41,10 @@ type bazelModuleProperties struct { // To opt-out a module, set bazel_module: { bp2build_available: false } // To defer the default setting for the directory, do not set the value. Bp2build_available *bool + + // CanConvertToBazel is set via InitBazelModule to indicate that a module type can be converted to + // Bazel with Bp2build. + CanConvertToBazel bool `blueprint:"mutated"` } // Properties contains common module properties for Bazel migration purposes. @@ -80,9 +86,10 @@ type Bazelable interface { HasHandcraftedLabel() bool HandcraftedLabel() string GetBazelLabel(ctx BazelConversionPathContext, module blueprint.Module) string - ConvertWithBp2build(ctx BazelConversionContext) bool - convertWithBp2build(ctx BazelConversionContext, module blueprint.Module) bool + ShouldConvertWithBp2build(ctx BazelConversionContext) bool + shouldConvertWithBp2build(ctx BazelConversionContext, module blueprint.Module) bool GetBazelBuildFileContents(c Config, path, name string) (string, error) + ConvertWithBp2build(ctx TopDownMutatorContext) // namespacedVariableProps is a map from a soong config variable namespace // (e.g. acme, android) to a map of interfaces{}, which are really @@ -109,6 +116,7 @@ type BazelModule interface { // properties. func InitBazelModule(module BazelModule) { module.AddProperties(module.bazelProps()) + module.bazelProps().Bazel_module.CanConvertToBazel = true } // bazelProps returns the Bazel properties for the given BazelModuleBase. @@ -147,7 +155,7 @@ func (b *BazelModuleBase) GetBazelLabel(ctx BazelConversionPathContext, module b if b.HasHandcraftedLabel() { return b.HandcraftedLabel() } - if b.ConvertWithBp2build(ctx) { + if b.ShouldConvertWithBp2build(ctx) { return bp2buildModuleLabel(ctx, module) } return "" // no label for unconverted module @@ -200,7 +208,8 @@ var ( "build/bazel/platforms":/* recursive = */ true, "build/bazel/product_variables":/* recursive = */ true, "build/bazel_common_rules":/* recursive = */ true, - "build/make/tools":/* recursive = */ true, + // build/make/tools/signapk BUILD file is generated, so build/make/tools is not recursive. + "build/make/tools":/* recursive = */ false, "build/pesto":/* recursive = */ true, // external/bazelbuild-rules_android/... is needed by mixed builds, otherwise mixed builds analysis fails @@ -226,33 +235,92 @@ var ( // Configure modules in these directories to enable bp2build_available: true or false by default. bp2buildDefaultConfig = Bp2BuildConfig{ - "bionic": Bp2BuildDefaultTrueRecursively, + "art/libdexfile": Bp2BuildDefaultTrueRecursively, + "bionic": Bp2BuildDefaultTrueRecursively, + "bootable/recovery/tools/recovery_l10n": Bp2BuildDefaultTrue, + "build/bazel/examples/soong_config_variables": Bp2BuildDefaultTrueRecursively, "build/bazel/examples/apex/minimal": Bp2BuildDefaultTrueRecursively, + "build/make/tools/signapk": Bp2BuildDefaultTrue, + "build/soong": Bp2BuildDefaultTrue, "build/soong/cc/libbuildversion": Bp2BuildDefaultTrue, // Skip tests subdir + "build/soong/cc/ndkstubgen": Bp2BuildDefaultTrue, + "build/soong/cc/symbolfile": Bp2BuildDefaultTrue, + "cts/common/device-side/nativetesthelper/jni": Bp2BuildDefaultTrueRecursively, + "development/apps/DevelopmentSettings": Bp2BuildDefaultTrue, + "development/apps/Fallback": Bp2BuildDefaultTrue, + "development/apps/WidgetPreview": Bp2BuildDefaultTrue, + "development/samples/BasicGLSurfaceView": Bp2BuildDefaultTrue, + "development/samples/BluetoothChat": Bp2BuildDefaultTrue, + "development/samples/BrokenKeyDerivation": Bp2BuildDefaultTrue, + "development/samples/Compass": Bp2BuildDefaultTrue, + "development/samples/ContactManager": Bp2BuildDefaultTrue, + "development/samples/FixedGridLayout": Bp2BuildDefaultTrue, + "development/samples/HelloEffects": Bp2BuildDefaultTrue, + "development/samples/Home": Bp2BuildDefaultTrue, + "development/samples/HoneycombGallery": Bp2BuildDefaultTrue, + "development/samples/JetBoy": Bp2BuildDefaultTrue, + "development/samples/KeyChainDemo": Bp2BuildDefaultTrue, + "development/samples/LceDemo": Bp2BuildDefaultTrue, + "development/samples/LunarLander": Bp2BuildDefaultTrue, + "development/samples/MultiResolution": Bp2BuildDefaultTrue, + "development/samples/MultiWindow": Bp2BuildDefaultTrue, + "development/samples/NotePad": Bp2BuildDefaultTrue, + "development/samples/Obb": Bp2BuildDefaultTrue, + "development/samples/RSSReader": Bp2BuildDefaultTrue, + "development/samples/ReceiveShareDemo": Bp2BuildDefaultTrue, + "development/samples/SearchableDictionary": Bp2BuildDefaultTrue, + "development/samples/SipDemo": Bp2BuildDefaultTrue, + "development/samples/SkeletonApp": Bp2BuildDefaultTrue, + "development/samples/Snake": Bp2BuildDefaultTrue, + "development/samples/SpellChecker/": Bp2BuildDefaultTrueRecursively, + "development/samples/ThemedNavBarKeyboard": Bp2BuildDefaultTrue, + "development/samples/ToyVpn": Bp2BuildDefaultTrue, + "development/samples/TtsEngine": Bp2BuildDefaultTrue, + "development/samples/USB/AdbTest": Bp2BuildDefaultTrue, + "development/samples/USB/MissileLauncher": Bp2BuildDefaultTrue, + "development/samples/VoiceRecognitionService": Bp2BuildDefaultTrue, + "development/samples/VoicemailProviderDemo": Bp2BuildDefaultTrue, "development/sdk": Bp2BuildDefaultTrueRecursively, "external/arm-optimized-routines": Bp2BuildDefaultTrueRecursively, "external/boringssl": Bp2BuildDefaultTrueRecursively, + "external/bouncycastle": Bp2BuildDefaultTrue, "external/brotli": Bp2BuildDefaultTrue, + "external/conscrypt": Bp2BuildDefaultTrue, "external/fmtlib": Bp2BuildDefaultTrueRecursively, "external/google-benchmark": Bp2BuildDefaultTrueRecursively, - "external/googletest/googletest": Bp2BuildDefaultTrueRecursively, + "external/googletest": Bp2BuildDefaultTrueRecursively, "external/gwp_asan": Bp2BuildDefaultTrueRecursively, "external/jemalloc_new": Bp2BuildDefaultTrueRecursively, "external/jsoncpp": Bp2BuildDefaultTrueRecursively, "external/libcap": Bp2BuildDefaultTrueRecursively, "external/libcxx": Bp2BuildDefaultTrueRecursively, "external/libcxxabi": Bp2BuildDefaultTrueRecursively, + "external/libevent": Bp2BuildDefaultTrueRecursively, "external/lz4/lib": Bp2BuildDefaultTrue, + "external/lzma/C": Bp2BuildDefaultTrueRecursively, "external/mdnsresponder": Bp2BuildDefaultTrueRecursively, "external/minijail": Bp2BuildDefaultTrueRecursively, "external/pcre": Bp2BuildDefaultTrueRecursively, "external/protobuf": Bp2BuildDefaultTrueRecursively, "external/python/six": Bp2BuildDefaultTrueRecursively, + "external/selinux/libsepol": Bp2BuildDefaultTrueRecursively, "external/scudo": Bp2BuildDefaultTrueRecursively, "external/selinux/libselinux": Bp2BuildDefaultTrueRecursively, "external/zlib": Bp2BuildDefaultTrueRecursively, "external/zstd": Bp2BuildDefaultTrueRecursively, + "frameworks/base/media/tests/MediaDump": Bp2BuildDefaultTrue, + "frameworks/base/startop/apps/test": Bp2BuildDefaultTrue, "frameworks/native/libs/adbd_auth": Bp2BuildDefaultTrueRecursively, + "frameworks/native/opengl/tests/gl2_cameraeye": Bp2BuildDefaultTrue, + "frameworks/native/opengl/tests/gl2_java": Bp2BuildDefaultTrue, + "frameworks/native/opengl/tests/testLatency": Bp2BuildDefaultTrue, + "frameworks/native/opengl/tests/testPauseResume": Bp2BuildDefaultTrue, + "frameworks/native/opengl/tests/testViewport": Bp2BuildDefaultTrue, + "frameworks/proto_logging/stats/stats_log_api_gen": Bp2BuildDefaultTrueRecursively, + "libnativehelper": Bp2BuildDefaultTrueRecursively, + "packages/apps/DevCamera": Bp2BuildDefaultTrue, + "packages/apps/HTMLViewer": Bp2BuildDefaultTrue, + "packages/apps/Protips": Bp2BuildDefaultTrue, "packages/modules/adb": Bp2BuildDefaultTrue, "packages/modules/adb/crypto": Bp2BuildDefaultTrueRecursively, "packages/modules/adb/libs": Bp2BuildDefaultTrueRecursively, @@ -260,8 +328,12 @@ var ( "packages/modules/adb/pairing_connection": Bp2BuildDefaultTrueRecursively, "packages/modules/adb/proto": Bp2BuildDefaultTrueRecursively, "packages/modules/adb/tls": Bp2BuildDefaultTrueRecursively, + "packages/providers/MediaProvider/tools/dialogs": Bp2BuildDefaultTrue, + "packages/screensavers/Basic": Bp2BuildDefaultTrue, + "packages/services/Car/tests/SampleRearViewCamera": Bp2BuildDefaultTrue, "prebuilts/clang/host/linux-x86": Bp2BuildDefaultTrueRecursively, "system/apex": Bp2BuildDefaultFalse, // TODO(b/207466993): flaky failures + "system/core/debuggerd": Bp2BuildDefaultTrue, "system/core/diagnose_usb": Bp2BuildDefaultTrueRecursively, "system/core/libasyncio": Bp2BuildDefaultTrue, "system/core/libcrypto_utils": Bp2BuildDefaultTrueRecursively, @@ -270,29 +342,84 @@ var ( "system/core/libprocessgroup": Bp2BuildDefaultTrue, "system/core/libprocessgroup/cgrouprc": Bp2BuildDefaultTrue, "system/core/libprocessgroup/cgrouprc_format": Bp2BuildDefaultTrue, + "system/core/libsystem": Bp2BuildDefaultTrueRecursively, + "system/core/libutils": Bp2BuildDefaultTrueRecursively, + "system/core/libvndksupport": Bp2BuildDefaultTrueRecursively, "system/core/property_service/libpropertyinfoparser": Bp2BuildDefaultTrueRecursively, "system/libbase": Bp2BuildDefaultTrueRecursively, + "system/libprocinfo": Bp2BuildDefaultTrue, "system/libziparchive": Bp2BuildDefaultTrueRecursively, "system/logging/liblog": Bp2BuildDefaultTrueRecursively, "system/sepolicy/apex": Bp2BuildDefaultTrueRecursively, "system/timezone/apex": Bp2BuildDefaultTrueRecursively, "system/timezone/output_data": Bp2BuildDefaultTrueRecursively, + "system/unwinding/libbacktrace": Bp2BuildDefaultTrueRecursively, + "system/unwinding/libunwindstack": Bp2BuildDefaultTrueRecursively, + "tools/apksig": Bp2BuildDefaultTrue, + "tools/platform-compat/java/android/compat": Bp2BuildDefaultTrueRecursively, } // Per-module denylist to always opt modules out of both bp2build and mixed builds. bp2buildModuleDoNotConvertList = []string{ - "libprotobuf-cpp-full", "libprotobuf-cpp-lite", // Unsupported product&vendor suffix. b/204811222 and b/204810610. + "libnativehelper_compat_libc++", // Broken compile: implicit declaration of function 'strerror_r' is invalid in C99 + "art_libdexfile_dex_instruction_list_header", // breaks libart_mterp.armng, header not found + + "libandroid_runtime_lazy", // depends on unconverted modules: libbinder_headers + "libcmd", // depends on unconverted modules: libbinder + + "chkcon", "sefcontext_compile", // depends on unconverted modules: libsepol + + "libsepol", // TODO(b/207408632): Unsupported case of .l sources in cc library rules + + "get_clang_version_test", // depends on unconverted module: get_clang_version + + "libbinder", // TODO(b/188503688): Disabled for some archs, + "libactivitymanager_aidl", // TODO(b/207426160): Depends on activity_manager_procstate_aidl, which is an aidl filegroup. + + "libnativehelper_lazy_mts_jni", // depends on unconverted modules: libgmock_ndk + "libnativehelper_mts_jni", // depends on unconverted modules: libgmock_ndk + "libnativetesthelper_jni", // depends on unconverted modules: libgtest_ndk_c++ + + "statslog-framework-java-gen", "statslog.cpp", "statslog.h", "statslog.rs", "statslog_header.rs", // depends on unconverted modules: stats-log-api-gen + + "stats-log-api-gen", // depends on unconverted modules: libstats_proto_host, libprotobuf-cpp-full - "libc_malloc_debug", // depends on libunwindstack, which depends on unsupported module art_cc_library_statics + "libstatslog", // depends on unconverted modules: statslog.cpp, statslog.h, ... + + "libgmock_main_ndk", "libgmock_ndk", // depends on unconverted module: libgtest_ndk_c++ + + "cmd", // depends on unconverted module packagemanager_aidl-cpp, of unsupported type aidl_interface + "servicedispatcher", // depends on unconverted module android.debug_aidl, of unsupported type aidl_interface + "libutilscallstack", // depends on unconverted module libbacktrace + "libbacktrace", // depends on unconverted module libunwindstack + "libdebuggerd_handler", // depends on unconverted module libdebuggerd_handler_core + "libdebuggerd_handler_core", "libdebuggerd_handler_fallback", // depends on unconverted module libdebuggerd + "unwind_for_offline", // depends on unconverted module libunwindstack_utils + "libdebuggerd", // depends on unconverted modules libdexfile_support, libunwindstack, gwp_asan_crash_handler, libtombstone_proto, libprotobuf-cpp-lite + "libdexfile_static", // depends on libartpalette, libartbase, libdexfile, which are of unsupported type: art_cc_library. + "host_bionic_linker_asm", // depends on extract_linker, a go binary. + "host_bionic_linker_script", // depends on extract_linker, a go binary. + + "pbtombstone", // depends on libprotobuf-cpp-lite, libtombstone_proto + "crash_dump", // depends on unconverted module libprotobuf-cpp-lite + + "libunwindstack_local", "libunwindstack_utils", // depends on unconverted module libunwindstack + "libunwindstack", // depends on libdexfile_support, of unsupported module type art_cc_library_static + "libc_malloc_debug", // depends on unconverted module libunwindstack "libbase_ndk", // http://b/186826477, fails to link libctscamera2_jni for device (required for CtsCameraTestCases) + "lib_linker_config_proto_lite", // contains .proto sources + "libprotobuf-python", // contains .proto sources - "libprotobuf-internal-protos", // we don't handle path property for fileegroups - "libprotobuf-internal-python-srcs", // we don't handle path property for fileegroups + "libprotobuf-internal-protos", // b/210751803, we don't handle path property for filegroups + "libprotobuf-internal-python-srcs", // b/210751803, we don't handle path property for filegroups + "libprotobuf-java-full", // b/210751803, we don't handle path property for filegroups + "libprotobuf-java-util-full", // b/210751803, we don't handle path property for filegroups + "conscrypt", // b/210751803, we don't handle path property for filegroups "libseccomp_policy", // b/201094425: depends on func_to_syscall_nrs, which depends on py_binary, which is unsupported in mixed builds. - "libfdtrack", // depends on libunwindstack, which depends on unsupported module art_cc_library_statics + "libfdtrack", // depends on unconverted module libunwindstack "gwp_asan_crash_handler", // cc_library, ld.lld: error: undefined symbol: memset @@ -303,10 +430,6 @@ var ( "platform_tools_properties", "build_tools_source_properties", - "libminijail", // b/202491296: Uses unsupported c_std property. - "minijail0", // depends on unconverted modules: libminijail - "drop_privs", // depends on unconverted modules: libminijail - // Tests. Handle later. "libbionic_tests_headers_posix", // http://b/186024507, cc_library_static, sched.h, time.h not found "libjemalloc5_integrationtest", @@ -316,36 +439,23 @@ var ( // APEX support "com.android.runtime", // http://b/194746715, apex, depends on 'libc_malloc_debug' - "libadb_crypto", // Depends on libadb_protos - "libadb_crypto_static", // Depends on libadb_protos_static - "libadb_pairing_connection", // Depends on libadb_protos - "libadb_pairing_connection_static", // Depends on libadb_protos_static - "libadb_pairing_server", // Depends on libadb_protos - "libadb_pairing_server_static", // Depends on libadb_protos_static - "libadbd", // Depends on libadbd_core - "libadbd_core", // Depends on libadb_protos - "libadbd_services", // Depends on libadb_protos - - "libadb_protos_static", // b/200601772: Requires cc_library proto support - "libadb_protos", // b/200601772: Requires cc_library proto support - "libapp_processes_protos_lite", // b/200601772: Requires cc_library proto support - "libgtest_ndk_c++", // b/201816222: Requires sdk_version support. "libgtest_main_ndk_c++", // b/201816222: Requires sdk_version support. - "abb", // depends on unconverted modules: libadbd_core, libadbd_services, libcmd, libbinder, libutils, libselinux - "adb", // depends on unconverted modules: bin2c_fastdeployagent, libadb_crypto, libadb_host, libadb_pairing_connection, libadb_protos, libandroidfw, libapp_processes_protos_full, libfastdeploy_host, libmdnssd, libopenscreen-discovery, libopenscreen-platform-impl, libusb, libutils, libziparchive, libzstd, AdbWinApi - "adbd", // depends on unconverted modules: libadb_crypto, libadb_pairing_connection, libadb_protos, libadbd, libadbd_core, libapp_processes_protos_lite, libmdnssd, libzstd, libadbd_services, libcap, libminijail, libselinux - "bionic_tests_zipalign", // depends on unconverted modules: libziparchive, libutils - "linker", // depends on unconverted modules: liblinker_debuggerd_stub, libdebuggerd_handler_fallback, libziparchive, liblinker_main, liblinker_malloc + "abb", // depends on unconverted modules: libcmd, libbinder + "adb", // depends on unconverted modules: AdbWinApi, libadb_host, libandroidfw, libapp_processes_protos_full, libfastdeploy_host, libopenscreen-discovery, libopenscreen-platform-impl, libusb, bin2c_fastdeployagent, AdbWinUsbApi + "linker", // depends on unconverted modules: libdebuggerd_handler_fallback "linker_reloc_bench_main", // depends on unconverted modules: liblinker_reloc_bench_* - "sefcontext_compile", // depends on unconverted modules: libsepol - "versioner", // depends on unconverted modules: libclang_cxx_host, libLLVM_host + "versioner", // depends on unconverted modules: libclang_cxx_host, libLLVM_host, of unsupported type llvm_host_prebuilt_library_shared "linkerconfig", // http://b/202876379 has arch-variant static_executable "mdnsd", // http://b/202876379 has arch-variant static_executable "acvp_modulewrapper", // disabled for android x86/x86_64 + "CarHTMLViewer", // depends on unconverted modules android.car-stubs, car-ui-lib + + "libdexfile", // depends on unconverted modules: dexfile_operator_srcs, libartbase, libartpalette, + "libdexfiled", // depends on unconverted modules: dexfile_operator_srcs, libartbased, libartpalette } // Per-module denylist of cc_library modules to only generate the static @@ -360,8 +470,14 @@ var ( "libbrotli", // http://b/198585397, ld.lld: error: bionic/libc/arch-arm64/generic/bionic/memmove.S:95:(.text+0x10): relocation R_AARCH64_CONDBR19 out of range: -1404176 is not in [-1048576, 1048575]; references __memcpy "minijail_constants_json", // http://b/200899432, bazel-built cc_genrule does not work in mixed build when it is a dependency of another soong module. - "cap_names.h", // TODO(b/204913827) runfiles need to be handled in mixed builds - "libcap", // TODO(b/204913827) runfiles need to be handled in mixed builds + "cap_names.h", // TODO(b/204913827) runfiles need to be handled in mixed builds + "libcap", // TODO(b/204913827) runfiles need to be handled in mixed builds + "libprotobuf-cpp-full", "libprotobuf-cpp-lite", // Unsupported product&vendor suffix. b/204811222 and b/204810610. + + // Depends on libprotobuf-cpp-* + "libadb_pairing_connection", + "libadb_pairing_connection_static", + "libadb_pairing_server", "libadb_pairing_server_static", } // Used for quicker lookups @@ -434,32 +550,21 @@ func convertedToBazel(ctx BazelConversionContext, module blueprint.Module) bool if !ok { return false } - return b.convertWithBp2build(ctx, module) || b.HasHandcraftedLabel() + return b.shouldConvertWithBp2build(ctx, module) || b.HasHandcraftedLabel() } -// ConvertWithBp2build returns whether the given BazelModuleBase should be converted with bp2build. -func (b *BazelModuleBase) ConvertWithBp2build(ctx BazelConversionContext) bool { - return b.convertWithBp2build(ctx, ctx.Module()) +// ShouldConvertWithBp2build returns whether the given BazelModuleBase should be converted with bp2build. +func (b *BazelModuleBase) ShouldConvertWithBp2build(ctx BazelConversionContext) bool { + return b.shouldConvertWithBp2build(ctx, ctx.Module()) } -func (b *BazelModuleBase) convertWithBp2build(ctx BazelConversionContext, module blueprint.Module) bool { +func (b *BazelModuleBase) shouldConvertWithBp2build(ctx BazelConversionContext, module blueprint.Module) bool { if bp2buildModuleDoNotConvert[module.Name()] { return false } - // Ensure that the module type of this module has a bp2build converter. This - // prevents mixed builds from using auto-converted modules just by matching - // the package dir; it also has to have a bp2build mutator as well. - if ctx.Config().bp2buildModuleTypeConfig[ctx.OtherModuleType(module)] == false { - if b, ok := module.(Bazelable); ok && b.BaseModuleType() != "" { - // For modules with custom types from soong_config_module_types, - // check that their _base module type_ has a bp2build mutator. - if ctx.Config().bp2buildModuleTypeConfig[b.BaseModuleType()] == false { - return false - } - } else { - return false - } + if !b.bazelProps().Bazel_module.CanConvertToBazel { + return false } packagePath := ctx.OtherModuleDir(module) @@ -533,3 +638,35 @@ func (b *BazelModuleBase) GetBazelBuildFileContents(c Config, path, name string) } return string(data[:]), nil } + +func registerBp2buildConversionMutator(ctx RegisterMutatorsContext) { + ctx.TopDown("bp2build_conversion", convertWithBp2build).Parallel() +} + +func convertWithBp2build(ctx TopDownMutatorContext) { + bModule, ok := ctx.Module().(Bazelable) + if !ok || !bModule.shouldConvertWithBp2build(ctx, ctx.Module()) { + return + } + + bModule.ConvertWithBp2build(ctx) +} + +// GetMainClassInManifest scans the manifest file specified in filepath and returns +// the value of attribute Main-Class in the manifest file if it exists, or returns error. +// WARNING: this is for bp2build converters of java_* modules only. +func GetMainClassInManifest(c Config, filepath string) (string, error) { + file, err := c.fs.Open(filepath) + if err != nil { + return "", err + } + scanner := bufio.NewScanner(file) + for scanner.Scan() { + line := scanner.Text() + if strings.HasPrefix(line, "Main-Class:") { + return strings.TrimSpace(line[len("Main-Class:"):]), nil + } + } + + return "", errors.New("Main-Class is not found.") +} diff --git a/android/bazel_paths.go b/android/bazel_paths.go index 729c73c8f..62e6156a4 100644 --- a/android/bazel_paths.go +++ b/android/bazel_paths.go @@ -279,6 +279,16 @@ func transformSubpackagePaths(ctx BazelConversionPathContext, paths bazel.LabelL return newPaths } +// Converts root-relative Paths to a list of bazel.Label relative to the module in ctx. +func RootToModuleRelativePaths(ctx BazelConversionPathContext, paths Paths) []bazel.Label { + var newPaths []bazel.Label + for _, path := range PathsWithModuleSrcSubDir(ctx, paths, "") { + s := path.Rel() + newPaths = append(newPaths, bazel.Label{Label: s}) + } + return newPaths +} + // expandSrcsForBazel returns bazel.LabelList with paths rooted from the module's local source // directory and Bazel target labels, excluding those included in the excludes argument (which // should already be expanded to resolve references to Soong-modules). Valid elements of paths @@ -328,12 +338,7 @@ func expandSrcsForBazel(ctx BazelConversionPathContext, paths, expandedExcludes // e.g. turn "math/*.c" in // external/arm-optimized-routines to external/arm-optimized-routines/math/*.c rootRelativeGlobPath := pathForModuleSrc(ctx, p).String() - globbedPaths := GlobFiles(ctx, rootRelativeGlobPath, rootRelativeExpandedExcludes) - globbedPaths = PathsWithModuleSrcSubDir(ctx, globbedPaths, "") - for _, path := range globbedPaths { - s := path.Rel() - expandedPaths = append(expandedPaths, bazel.Label{Label: s}) - } + expandedPaths = RootToModuleRelativePaths(ctx, GlobFiles(ctx, rootRelativeGlobPath, rootRelativeExpandedExcludes)) } else { if !InList(p, expandedExcludes) { expandedPaths = append(expandedPaths, bazel.Label{Label: p}) diff --git a/android/config.go b/android/config.go index 5ee28e735..5d90fd21d 100644 --- a/android/config.go +++ b/android/config.go @@ -157,7 +157,6 @@ type config struct { runningAsBp2Build bool bp2buildPackageConfig Bp2BuildConfig - bp2buildModuleTypeConfig map[string]bool Bp2buildSoongConfigDefinitions soongconfig.Bp2BuildSoongConfigDefinitions // If testAllowNonExistentPaths is true then PathForSource and PathForModuleSrc won't error @@ -324,7 +323,7 @@ func TestConfig(buildDir string, env map[string]string, bp string, fs map[string DeviceName: stringPtr("test_device"), Platform_sdk_version: intPtr(30), Platform_sdk_codename: stringPtr("S"), - Platform_version_active_codenames: []string{"S"}, + Platform_version_active_codenames: []string{"S", "Tiramisu"}, DeviceSystemSdkVersions: []string{"14", "15"}, Platform_systemsdk_versions: []string{"29", "30"}, AAPTConfig: []string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"}, @@ -353,8 +352,6 @@ func TestConfig(buildDir string, env map[string]string, bp string, fs map[string config.mockFileSystem(bp, fs) - config.bp2buildModuleTypeConfig = map[string]bool{} - determineBuildOS(config) return Config{config} @@ -522,7 +519,6 @@ func NewConfig(moduleListFile string, runGoTests bool, outDir, soongOutDir strin config.BazelContext, err = NewBazelContext(config) config.bp2buildPackageConfig = bp2buildDefaultConfig - config.bp2buildModuleTypeConfig = make(map[string]bool) return Config{config}, err } @@ -765,6 +761,16 @@ func (c *config) PreviewApiLevels() []ApiLevel { return levels } +func (c *config) LatestPreviewApiLevel() ApiLevel { + level := NoneApiLevel + for _, l := range c.PreviewApiLevels() { + if l.GreaterThan(level) { + level = l + } + } + return level +} + func (c *config) AllSupportedApiLevels() []ApiLevel { var levels []ApiLevel levels = append(levels, c.FinalApiLevels()...) @@ -856,7 +862,7 @@ func (c *config) UnbundledBuild() bool { // Returns true if building apps that aren't bundled with the platform. // UnbundledBuild() is always true when this is true. func (c *config) UnbundledBuildApps() bool { - return Bool(c.productVariables.Unbundled_build_apps) + return len(c.productVariables.Unbundled_build_apps) > 0 } // Returns true if building image that aren't bundled with the platform. @@ -882,8 +888,13 @@ func (c *config) Eng() bool { return Bool(c.productVariables.Eng) } +// DevicePrimaryArchType returns the ArchType for the first configured device architecture, or +// Common if there are no device architectures. func (c *config) DevicePrimaryArchType() ArchType { - return c.Targets[Android][0].Arch.ArchType + if androidTargets := c.Targets[Android]; len(androidTargets) > 0 { + return androidTargets[0].Arch.ArchType + } + return Common } func (c *config) SanitizeHost() []string { @@ -1184,10 +1195,6 @@ func (c *deviceConfig) DeviceKernelHeaderDirs() []string { return c.config.productVariables.DeviceKernelHeaders } -func (c *deviceConfig) SamplingPGO() bool { - return Bool(c.config.productVariables.SamplingPGO) -} - // JavaCoverageEnabledForPath returns whether Java code coverage is enabled for // path. Coverage is enabled by default when the product variable // JavaCoveragePaths is empty. If JavaCoveragePaths is not empty, coverage is @@ -1470,6 +1477,10 @@ func (c *deviceConfig) BoardSepolicyVers() string { return c.PlatformSepolicyVersion() } +func (c *deviceConfig) BoardPlatVendorPolicy() []string { + return c.config.productVariables.BoardPlatVendorPolicy +} + func (c *deviceConfig) BoardReqdMaskPolicy() []string { return c.config.productVariables.BoardReqdMaskPolicy } diff --git a/android/deapexer.go b/android/deapexer.go index bed657464..265f5312b 100644 --- a/android/deapexer.go +++ b/android/deapexer.go @@ -143,12 +143,16 @@ type RequiresFilesFromPrebuiltApexTag interface { } // FindDeapexerProviderForModule searches through the direct dependencies of the current context -// module for a DeapexerTag dependency and returns its DeapexerInfo. If there is an error then it is -// reported with ctx.ModuleErrorf and nil is returned. +// module for a DeapexerTag dependency and returns its DeapexerInfo. If a single nonambiguous +// deapexer module isn't found then errors are reported with ctx.ModuleErrorf and nil is returned. func FindDeapexerProviderForModule(ctx ModuleContext) *DeapexerInfo { var di *DeapexerInfo ctx.VisitDirectDepsWithTag(DeapexerTag, func(m Module) { p := ctx.OtherModuleProvider(m, DeapexerProvider).(DeapexerInfo) + if di != nil { + ctx.ModuleErrorf("Multiple installable prebuilt APEXes provide ambiguous deapexers: %s and %s", + di.ApexModuleName(), p.ApexModuleName()) + } di = &p }) if di != nil { diff --git a/android/defaults.go b/android/defaults.go index 9046002cc..7b3d38c07 100644 --- a/android/defaults.go +++ b/android/defaults.go @@ -89,10 +89,10 @@ type DefaultableModule interface { var _ Defaultable = (*DefaultableModuleBase)(nil) func InitDefaultableModule(module DefaultableModule) { - if module.(Module).base().module == nil { + if module.base().module == nil { panic("InitAndroidModule must be called before InitDefaultableModule") } - module.setProperties(module.(Module).GetProperties(), module.(Module).base().variableProperties) + module.setProperties(module.GetProperties(), module.base().variableProperties) module.AddProperties(module.defaults()) @@ -173,6 +173,10 @@ func (d *DefaultsModuleBase) productVariableProperties() interface{} { func (d *DefaultsModuleBase) GenerateAndroidBuildActions(ctx ModuleContext) { } +// ConvertWithBp2build to fulfill Bazelable interface; however, at this time defaults module are +// *NOT* converted with bp2build +func (defaultable *DefaultsModuleBase) ConvertWithBp2build(ctx TopDownMutatorContext) {} + func InitDefaultsModule(module DefaultsModule) { commonProperties := &commonProperties{} diff --git a/android/filegroup.go b/android/filegroup.go index a79374d1f..c932ffad2 100644 --- a/android/filegroup.go +++ b/android/filegroup.go @@ -22,7 +22,6 @@ import ( func init() { RegisterModuleType("filegroup", FileGroupFactory) - RegisterBp2BuildMutator("filegroup", FilegroupBp2Build) } var PrepareForTestWithFilegroup = FixtureRegisterWithContext(func(ctx RegistrationContext) { @@ -34,12 +33,8 @@ type bazelFilegroupAttributes struct { Srcs bazel.LabelListAttribute } -func FilegroupBp2Build(ctx TopDownMutatorContext) { - fg, ok := ctx.Module().(*fileGroup) - if !ok || !fg.ConvertWithBp2build(ctx) { - return - } - +// ConvertWithBp2build performs bp2build conversion of filegroup +func (fg *fileGroup) ConvertWithBp2build(ctx TopDownMutatorContext) { srcs := bazel.MakeLabelListAttribute( BazelLabelForModuleSrcExcludes(ctx, fg.properties.Srcs, fg.properties.Exclude_srcs)) diff --git a/android/license_metadata.go b/android/license_metadata.go new file mode 100644 index 000000000..3bc53d6a4 --- /dev/null +++ b/android/license_metadata.go @@ -0,0 +1,231 @@ +// Copyright 2021 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package android + +import ( + "fmt" + "sort" + "strings" + + "github.com/google/blueprint" + "github.com/google/blueprint/proptools" +) + +var ( + _ = pctx.HostBinToolVariable("licenseMetadataCmd", "build_license_metadata") + + licenseMetadataRule = pctx.AndroidStaticRule("licenseMetadataRule", blueprint.RuleParams{ + Command: "${licenseMetadataCmd} -o $out @${out}.rsp", + CommandDeps: []string{"${licenseMetadataCmd}"}, + Rspfile: "${out}.rsp", + RspfileContent: "${args}", + }, "args") +) + +func buildLicenseMetadata(ctx ModuleContext) { + base := ctx.Module().base() + + if !base.Enabled() { + return + } + + if exemptFromRequiredApplicableLicensesProperty(ctx.Module()) { + return + } + + var allDepMetadataFiles Paths + var allDepMetadataArgs []string + var allDepOutputFiles Paths + + ctx.VisitDirectDepsBlueprint(func(bpdep blueprint.Module) { + dep, _ := bpdep.(Module) + if dep == nil { + return + } + if !dep.Enabled() { + return + } + + if ctx.OtherModuleHasProvider(dep, LicenseMetadataProvider) { + info := ctx.OtherModuleProvider(dep, LicenseMetadataProvider).(*LicenseMetadataInfo) + allDepMetadataFiles = append(allDepMetadataFiles, info.LicenseMetadataPath) + + depAnnotations := licenseAnnotationsFromTag(ctx.OtherModuleDependencyTag(dep)) + + allDepMetadataArgs = append(allDepMetadataArgs, info.LicenseMetadataPath.String()+depAnnotations) + + if depInstallFiles := dep.base().installFiles; len(depInstallFiles) > 0 { + allDepOutputFiles = append(allDepOutputFiles, depInstallFiles.Paths()...) + } else if depOutputFiles, err := outputFilesForModule(ctx, dep, ""); err == nil { + depOutputFiles = PathsIfNonNil(depOutputFiles...) + allDepOutputFiles = append(allDepOutputFiles, depOutputFiles...) + } + } + }) + + allDepMetadataFiles = SortedUniquePaths(allDepMetadataFiles) + sort.Strings(allDepMetadataArgs) + allDepOutputFiles = SortedUniquePaths(allDepOutputFiles) + + var orderOnlyDeps Paths + var args []string + + if t := ctx.ModuleType(); t != "" { + args = append(args, + "-mt "+proptools.NinjaAndShellEscape(t)) + } + + args = append(args, + "-r "+proptools.NinjaAndShellEscape(ctx.ModuleDir()), + "-mc UNKNOWN") + + if p := base.commonProperties.Effective_package_name; p != nil { + args = append(args, + "-p "+proptools.NinjaAndShellEscape(*p)) + } + + args = append(args, + JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(base.commonProperties.Effective_license_kinds), "-k ")) + + args = append(args, + JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(base.commonProperties.Effective_license_conditions), "-c ")) + + args = append(args, + JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(base.commonProperties.Effective_license_text.Strings()), "-n ")) + + args = append(args, + JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(allDepMetadataArgs), "-d ")) + orderOnlyDeps = append(orderOnlyDeps, allDepMetadataFiles...) + + args = append(args, + JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(allDepOutputFiles.Strings()), "-s ")) + + // Install map + args = append(args, + JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(base.licenseInstallMap), "-m ")) + + // Built files + var outputFiles Paths + if outputFileProducer, ok := ctx.Module().(OutputFileProducer); ok { + outputFiles, _ = outputFileProducer.OutputFiles("") + outputFiles = PathsIfNonNil(outputFiles...) + } + + if len(outputFiles) > 0 { + args = append(args, + JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(outputFiles.Strings()), "-t ")) + } else { + args = append(args, fmt.Sprintf("-t //%s:%s", ctx.ModuleDir(), ctx.ModuleName())) + } + + // Installed files + args = append(args, + JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(base.installFiles.Strings()), "-i ")) + + isContainer := isContainerFromFileExtensions(base.installFiles, outputFiles) + if isContainer { + args = append(args, "--is_container") + } + + licenseMetadataFile := PathForModuleOut(ctx, "meta_lic") + + ctx.Build(pctx, BuildParams{ + Rule: licenseMetadataRule, + Output: licenseMetadataFile, + OrderOnly: orderOnlyDeps, + Description: "license metadata", + Args: map[string]string{ + "args": strings.Join(args, " "), + }, + }) + + ctx.SetProvider(LicenseMetadataProvider, &LicenseMetadataInfo{ + LicenseMetadataPath: licenseMetadataFile, + }) +} + +func isContainerFromFileExtensions(installPaths InstallPaths, builtPaths Paths) bool { + var paths Paths + if len(installPaths) > 0 { + paths = installPaths.Paths() + } else { + paths = builtPaths + } + + for _, path := range paths { + switch path.Ext() { + case ".zip", ".tar", ".tgz", ".tar.gz", ".img", ".srcszip", ".apex": + return true + } + } + + return false +} + +// LicenseMetadataProvider is used to propagate license metadata paths between modules. +var LicenseMetadataProvider = blueprint.NewProvider(&LicenseMetadataInfo{}) + +// LicenseMetadataInfo stores the license metadata path for a module. +type LicenseMetadataInfo struct { + LicenseMetadataPath Path +} + +// licenseAnnotationsFromTag returns the LicenseAnnotations for a tag (if any) converted into +// a string, or an empty string if there are none. +func licenseAnnotationsFromTag(tag blueprint.DependencyTag) string { + if annoTag, ok := tag.(LicenseAnnotationsDependencyTag); ok { + annos := annoTag.LicenseAnnotations() + if len(annos) > 0 { + annoStrings := make([]string, len(annos)) + for i, s := range annos { + annoStrings[i] = string(s) + } + return ":" + strings.Join(annoStrings, ",") + } + } + return "" +} + +// LicenseAnnotationsDependencyTag is implemented by dependency tags in order to provide a +// list of license dependency annotations. +type LicenseAnnotationsDependencyTag interface { + LicenseAnnotations() []LicenseAnnotation +} + +// LicenseAnnotation is an enum of annotations that can be applied to dependencies for propagating +// license information. +type LicenseAnnotation string + +const ( + // LicenseAnnotationSharedDependency should be returned by LicenseAnnotations implementations + // of dependency tags when the usage of the dependency is dynamic, for example a shared library + // linkage for native modules or as a classpath library for java modules. + LicenseAnnotationSharedDependency LicenseAnnotation = "dynamic" + + // LicenseAnnotationToolchain should be returned by LicenseAnnotations implementations of + // dependency tags when the dependency is used as a toolchain. + // + // Dependency tags that need to always return LicenseAnnotationToolchain + // can embed LicenseAnnotationToolchainDependencyTag to implement LicenseAnnotations. + LicenseAnnotationToolchain LicenseAnnotation = "toolchain" +) + +// LicenseAnnotationToolchainDependencyTag can be embedded in a dependency tag to implement +// LicenseAnnotations that always returns LicenseAnnotationToolchain. +type LicenseAnnotationToolchainDependencyTag struct{} + +func (LicenseAnnotationToolchainDependencyTag) LicenseAnnotations() []LicenseAnnotation { + return []LicenseAnnotation{LicenseAnnotationToolchain} +} diff --git a/android/module.go b/android/module.go index 4a388b562..189781a83 100644 --- a/android/module.go +++ b/android/module.go @@ -419,7 +419,6 @@ type ModuleContext interface { PackageFile(installPath InstallPath, name string, srcPath Path) PackagingSpec CheckbuildFile(srcPath Path) - TidyFile(srcPath WritablePath) InstallInData() bool InstallInTestcases() bool @@ -1200,7 +1199,6 @@ type ModuleBase struct { installFiles InstallPaths installFilesDepSet *installPathsDepSet checkbuildFiles Paths - tidyFiles WritablePaths packagingSpecs []PackagingSpec packagingSpecsDepSet *packagingSpecsDepSet noticeFiles Paths @@ -1216,7 +1214,6 @@ type ModuleBase struct { // Only set on the final variant of each module installTarget WritablePath checkbuildTarget WritablePath - tidyTarget WritablePath blueprintDir string hooks hooks @@ -1230,6 +1227,10 @@ type ModuleBase struct { initRcPaths Paths vintfFragmentsPaths Paths + + // set of dependency module:location mappings used to populate the license metadata for + // apex containers. + licenseInstallMap []string } // A struct containing all relevant information about a Bazel target converted via bp2build. @@ -1289,7 +1290,7 @@ func (b *baseModuleContext) AddUnconvertedBp2buildDep(dep string) { // GetUnconvertedBp2buildDeps returns the list of module names of this module's direct dependencies that // were not converted to Bazel. func (m *ModuleBase) GetUnconvertedBp2buildDeps() []string { - return m.commonProperties.UnconvertedBp2buildDeps + return FirstUniqueStrings(m.commonProperties.UnconvertedBp2buildDeps) } func (m *ModuleBase) AddJSONData(d *map[string]interface{}) { @@ -1300,6 +1301,8 @@ func (m *ModuleBase) ComponentDepsMutator(BottomUpMutatorContext) {} func (m *ModuleBase) DepsMutator(BottomUpMutatorContext) {} +// AddProperties "registers" the provided props +// each value in props MUST be a pointer to a struct func (m *ModuleBase) AddProperties(props ...interface{}) { m.registerProps = append(m.registerProps, props...) } @@ -1702,7 +1705,7 @@ func (m *ModuleBase) InstallInRoot() bool { } func (m *ModuleBase) InstallBypassMake() bool { - return false + return true } func (m *ModuleBase) InstallForceOS() (*OsType, *ArchType) { @@ -1774,20 +1777,24 @@ func (m *ModuleBase) VintfFragments() Paths { return append(Paths{}, m.vintfFragmentsPaths...) } +// SetLicenseInstallMap stores the set of dependency module:location mappings for files in an +// apex container for use when generation the license metadata file. +func (m *ModuleBase) SetLicenseInstallMap(installMap []string) { + m.licenseInstallMap = append(m.licenseInstallMap, installMap...) +} + func (m *ModuleBase) generateModuleTarget(ctx ModuleContext) { var allInstalledFiles InstallPaths var allCheckbuildFiles Paths - var allTidyFiles WritablePaths ctx.VisitAllModuleVariants(func(module Module) { a := module.base() allInstalledFiles = append(allInstalledFiles, a.installFiles...) - // A module's -{checkbuild,tidy} phony targets should + // A module's -checkbuild phony targets should // not be created if the module is not exported to make. // Those could depend on the build target and fail to compile // for the current build target. if !ctx.Config().KatiEnabled() || !shouldSkipAndroidMkProcessing(a) { allCheckbuildFiles = append(allCheckbuildFiles, a.checkbuildFiles...) - allTidyFiles = append(allTidyFiles, a.tidyFiles...) } }) @@ -1812,13 +1819,6 @@ func (m *ModuleBase) generateModuleTarget(ctx ModuleContext) { deps = append(deps, m.checkbuildTarget) } - if len(allTidyFiles) > 0 { - name := namespacePrefix + ctx.ModuleName() + "-tidy" - ctx.Phony(name, allTidyFiles.Paths()...) - m.tidyTarget = PathForPhony(ctx, name) - deps = append(deps, m.tidyTarget) - } - if len(deps) > 0 { suffix := "" if ctx.Config().KatiEnabled() { @@ -2027,7 +2027,6 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) m.installFiles = append(m.installFiles, ctx.installFiles...) m.checkbuildFiles = append(m.checkbuildFiles, ctx.checkbuildFiles...) - m.tidyFiles = append(m.tidyFiles, ctx.tidyFiles...) m.packagingSpecs = append(m.packagingSpecs, ctx.packagingSpecs...) m.katiInstalls = append(m.katiInstalls, ctx.katiInstalls...) m.katiSymlinks = append(m.katiSymlinks, ctx.katiSymlinks...) @@ -2049,6 +2048,8 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) m.installFilesDepSet = newInstallPathsDepSet(m.installFiles, dependencyInstallFiles) m.packagingSpecsDepSet = newPackagingSpecsDepSet(m.packagingSpecs, dependencyPackagingSpecs) + buildLicenseMetadata(ctx) + m.buildParams = ctx.buildParams m.ruleParams = ctx.ruleParams m.variables = ctx.variables @@ -2225,7 +2226,6 @@ type moduleContext struct { packagingSpecs []PackagingSpec installFiles InstallPaths checkbuildFiles Paths - tidyFiles WritablePaths module Module phonies map[string]Paths @@ -3063,10 +3063,6 @@ func (m *moduleContext) CheckbuildFile(srcPath Path) { m.checkbuildFiles = append(m.checkbuildFiles, srcPath) } -func (m *moduleContext) TidyFile(srcPath WritablePath) { - m.tidyFiles = append(m.tidyFiles, srcPath) -} - func (m *moduleContext) blueprintModuleContext() blueprint.ModuleContext { return m.bp } @@ -3325,9 +3321,10 @@ func parentDir(dir string) string { type buildTargetSingleton struct{} -func addAncestors(ctx SingletonContext, dirMap map[string]Paths, mmName func(string) string) []string { +func AddAncestors(ctx SingletonContext, dirMap map[string]Paths, mmName func(string) string) ([]string, []string) { // Ensure ancestor directories are in dirMap // Make directories build their direct subdirectories + // Returns a slice of all directories and a slice of top-level directories. dirs := SortedStringKeys(dirMap) for _, dir := range dirs { dir := parentDir(dir) @@ -3340,34 +3337,31 @@ func addAncestors(ctx SingletonContext, dirMap map[string]Paths, mmName func(str } } dirs = SortedStringKeys(dirMap) + var topDirs []string for _, dir := range dirs { p := parentDir(dir) if p != "." && p != "/" { dirMap[p] = append(dirMap[p], PathForPhony(ctx, mmName(dir))) + } else if dir != "." && dir != "/" && dir != "" { + topDirs = append(topDirs, dir) } } - return SortedStringKeys(dirMap) + return SortedStringKeys(dirMap), topDirs } func (c *buildTargetSingleton) GenerateBuildActions(ctx SingletonContext) { var checkbuildDeps Paths - var tidyDeps Paths mmTarget := func(dir string) string { return "MODULES-IN-" + strings.Replace(filepath.Clean(dir), "/", "-", -1) } - mmTidyTarget := func(dir string) string { - return "tidy-" + strings.Replace(filepath.Clean(dir), "/", "-", -1) - } modulesInDir := make(map[string]Paths) - tidyModulesInDir := make(map[string]Paths) ctx.VisitAllModules(func(module Module) { blueprintDir := module.base().blueprintDir installTarget := module.base().installTarget checkbuildTarget := module.base().checkbuildTarget - tidyTarget := module.base().tidyTarget if checkbuildTarget != nil { checkbuildDeps = append(checkbuildDeps, checkbuildTarget) @@ -3377,16 +3371,6 @@ func (c *buildTargetSingleton) GenerateBuildActions(ctx SingletonContext) { if installTarget != nil { modulesInDir[blueprintDir] = append(modulesInDir[blueprintDir], installTarget) } - - if tidyTarget != nil { - tidyDeps = append(tidyDeps, tidyTarget) - // tidyTarget is in modulesInDir so it will be built with "mm". - modulesInDir[blueprintDir] = append(modulesInDir[blueprintDir], tidyTarget) - // tidyModulesInDir contains tidyTarget but not checkbuildTarget - // or installTarget, so tidy targets in a directory can be built - // without other checkbuild or install targets. - tidyModulesInDir[blueprintDir] = append(tidyModulesInDir[blueprintDir], tidyTarget) - } }) suffix := "" @@ -3397,24 +3381,12 @@ func (c *buildTargetSingleton) GenerateBuildActions(ctx SingletonContext) { // Create a top-level checkbuild target that depends on all modules ctx.Phony("checkbuild"+suffix, checkbuildDeps...) - // Create a top-level tidy target that depends on all modules - ctx.Phony("tidy"+suffix, tidyDeps...) - - dirs := addAncestors(ctx, tidyModulesInDir, mmTidyTarget) - - // Kati does not generate tidy-* phony targets yet. - // Create a tidy-<directory> target that depends on all subdirectories - // and modules in the directory. - for _, dir := range dirs { - ctx.Phony(mmTidyTarget(dir), tidyModulesInDir[dir]...) - } - // Make will generate the MODULES-IN-* targets if ctx.Config().KatiEnabled() { return } - dirs = addAncestors(ctx, modulesInDir, mmTarget) + dirs, _ := AddAncestors(ctx, modulesInDir, mmTarget) // Create a MODULES-IN-<directory> target that depends on all modules in a directory, and // depends on the MODULES-IN-* targets of all of its subdirectories that contain Android.bp diff --git a/android/mutator.go b/android/mutator.go index 461cb17d8..dbd8c04db 100644 --- a/android/mutator.go +++ b/android/mutator.go @@ -16,7 +16,6 @@ package android import ( "reflect" - "sync" "android/soong/bazel" @@ -34,12 +33,12 @@ import ( // continue on to GenerateAndroidBuildActions // RegisterMutatorsForBazelConversion is a alternate registration pipeline for bp2build. Exported for testing. -func RegisterMutatorsForBazelConversion(ctx *Context, preArchMutators, bp2buildMutators []RegisterMutatorFunc) { +func RegisterMutatorsForBazelConversion(ctx *Context, preArchMutators []RegisterMutatorFunc) { mctx := ®isterMutatorsContext{ bazelConversionMode: true, } - bp2buildPreArchMutators = append([]RegisterMutatorFunc{ + bp2buildMutators := append([]RegisterMutatorFunc{ RegisterNamespaceMutator, RegisterDefaultsPreArchMutators, // TODO(b/165114590): this is required to resolve deps that are only prebuilts, but we should @@ -47,10 +46,7 @@ func RegisterMutatorsForBazelConversion(ctx *Context, preArchMutators, bp2buildM RegisterPrebuiltsPreArchMutators, }, preArchMutators...) - - for _, f := range bp2buildPreArchMutators { - f(mctx) - } + bp2buildMutators = append(bp2buildMutators, registerBp2buildConversionMutator) // Register bp2build mutators for _, f := range bp2buildMutators { @@ -216,24 +212,12 @@ func FinalDepsMutators(f RegisterMutatorFunc) { } var bp2buildPreArchMutators = []RegisterMutatorFunc{} -var bp2buildMutators = map[string]RegisterMutatorFunc{} -// See http://b/192523357 -var bp2buildLock sync.Mutex +// A minimal context for Bp2build conversion +type Bp2buildMutatorContext interface { + BazelConversionPathContext -// RegisterBp2BuildMutator registers specially crafted mutators for -// converting Blueprint/Android modules into special modules that can -// be code-generated into Bazel BUILD targets. -// -// TODO(b/178068862): bring this into TestContext. -func RegisterBp2BuildMutator(moduleType string, m func(TopDownMutatorContext)) { - f := func(ctx RegisterMutatorsContext) { - ctx.TopDown(moduleType, m) - } - // Use a lock to avoid a concurrent map write if RegisterBp2BuildMutator is called in parallel - bp2buildLock.Lock() - defer bp2buildLock.Unlock() - bp2buildMutators[moduleType] = f + CreateBazelTargetModule(bazel.BazelTargetModuleProperties, CommonAttributes, interface{}) } // PreArchBp2BuildMutators adds mutators to be register for converting Android Blueprint modules @@ -529,28 +513,6 @@ func (t *topDownMutatorContext) CreateBazelTargetModule( mod.base().addBp2buildInfo(info) } -func (t *topDownMutatorContext) appendPrependHelper(props []interface{}, - extendFn func([]interface{}, interface{}, proptools.ExtendPropertyFilterFunc) error) { - for _, p := range props { - err := extendFn(t.Module().base().customizableProperties, p, nil) - if err != nil { - if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok { - t.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error()) - } else { - panic(err) - } - } - } -} - -func (t *topDownMutatorContext) AppendProperties(props ...interface{}) { - t.appendPrependHelper(props, proptools.AppendMatchingProperties) -} - -func (t *topDownMutatorContext) PrependProperties(props ...interface{}) { - t.appendPrependHelper(props, proptools.PrependMatchingProperties) -} - // android.topDownMutatorContext either has to embed blueprint.TopDownMutatorContext, in which case every method that // has an overridden version in android.BaseModuleContext has to be manually forwarded to BaseModuleContext to avoid // ambiguous method errors, or it has to store a blueprint.TopDownMutatorContext non-embedded, in which case every diff --git a/android/neverallow.go b/android/neverallow.go index b36bf045a..034861958 100644 --- a/android/neverallow.go +++ b/android/neverallow.go @@ -252,7 +252,7 @@ func neverallowMutator(ctx BottomUpMutatorContext) { continue } - if !n.appliesToProperties(properties) { + if !n.appliesToProperties(ctx, properties) { continue } @@ -272,8 +272,12 @@ func neverallowMutator(ctx BottomUpMutatorContext) { } } +type ValueMatcherContext interface { + Config() Config +} + type ValueMatcher interface { - Test(string) bool + Test(ValueMatcherContext, string) bool String() string } @@ -281,7 +285,7 @@ type equalMatcher struct { expected string } -func (m *equalMatcher) Test(value string) bool { +func (m *equalMatcher) Test(ctx ValueMatcherContext, value string) bool { return m.expected == value } @@ -292,7 +296,7 @@ func (m *equalMatcher) String() string { type anyMatcher struct { } -func (m *anyMatcher) Test(value string) bool { +func (m *anyMatcher) Test(ctx ValueMatcherContext, value string) bool { return true } @@ -306,7 +310,7 @@ type startsWithMatcher struct { prefix string } -func (m *startsWithMatcher) Test(value string) bool { +func (m *startsWithMatcher) Test(ctx ValueMatcherContext, value string) bool { return strings.HasPrefix(value, m.prefix) } @@ -318,7 +322,7 @@ type regexMatcher struct { re *regexp.Regexp } -func (m *regexMatcher) Test(value string) bool { +func (m *regexMatcher) Test(ctx ValueMatcherContext, value string) bool { return m.re.MatchString(value) } @@ -330,7 +334,7 @@ type notInListMatcher struct { allowed []string } -func (m *notInListMatcher) Test(value string) bool { +func (m *notInListMatcher) Test(ctx ValueMatcherContext, value string) bool { return !InList(value, m.allowed) } @@ -340,7 +344,7 @@ func (m *notInListMatcher) String() string { type isSetMatcher struct{} -func (m *isSetMatcher) Test(value string) bool { +func (m *isSetMatcher) Test(ctx ValueMatcherContext, value string) bool { return value != "" } @@ -350,6 +354,19 @@ func (m *isSetMatcher) String() string { var isSetMatcherInstance = &isSetMatcher{} +type sdkVersionMatcher struct { + condition func(ctx ValueMatcherContext, spec SdkSpec) bool + description string +} + +func (m *sdkVersionMatcher) Test(ctx ValueMatcherContext, value string) bool { + return m.condition(ctx, SdkSpecFromWithConfig(ctx.Config(), value)) +} + +func (m *sdkVersionMatcher) String() string { + return ".sdk-version(" + m.description + ")" +} + type ruleProperty struct { fields []string // e.x.: Vndk.Enabled matcher ValueMatcher @@ -563,9 +580,10 @@ func (r *rule) appliesToModuleType(moduleType string) bool { return (len(r.moduleTypes) == 0 || InList(moduleType, r.moduleTypes)) && !InList(moduleType, r.unlessModuleTypes) } -func (r *rule) appliesToProperties(properties []interface{}) bool { - includeProps := hasAllProperties(properties, r.props) - excludeProps := hasAnyProperty(properties, r.unlessProps) +func (r *rule) appliesToProperties(ctx ValueMatcherContext, + properties []interface{}) bool { + includeProps := hasAllProperties(ctx, properties, r.props) + excludeProps := hasAnyProperty(ctx, properties, r.unlessProps) return includeProps && !excludeProps } @@ -585,6 +603,16 @@ func NotInList(allowed []string) ValueMatcher { return ¬InListMatcher{allowed} } +func LessThanSdkVersion(sdk string) ValueMatcher { + return &sdkVersionMatcher{ + condition: func(ctx ValueMatcherContext, spec SdkSpec) bool { + return spec.ApiLevel.LessThan( + SdkSpecFromWithConfig(ctx.Config(), sdk).ApiLevel) + }, + description: "lessThan=" + sdk, + } +} + // assorted utils func cleanPaths(paths []string) []string { @@ -603,25 +631,28 @@ func fieldNamesForProperties(propertyNames string) []string { return names } -func hasAnyProperty(properties []interface{}, props []ruleProperty) bool { +func hasAnyProperty(ctx ValueMatcherContext, properties []interface{}, + props []ruleProperty) bool { for _, v := range props { - if hasProperty(properties, v) { + if hasProperty(ctx, properties, v) { return true } } return false } -func hasAllProperties(properties []interface{}, props []ruleProperty) bool { +func hasAllProperties(ctx ValueMatcherContext, properties []interface{}, + props []ruleProperty) bool { for _, v := range props { - if !hasProperty(properties, v) { + if !hasProperty(ctx, properties, v) { return false } } return true } -func hasProperty(properties []interface{}, prop ruleProperty) bool { +func hasProperty(ctx ValueMatcherContext, properties []interface{}, + prop ruleProperty) bool { for _, propertyStruct := range properties { propertiesValue := reflect.ValueOf(propertyStruct).Elem() for _, v := range prop.fields { @@ -635,7 +666,7 @@ func hasProperty(properties []interface{}, prop ruleProperty) bool { } check := func(value string) bool { - return prop.matcher.Test(value) + return prop.matcher.Test(ctx, value) } if matchValue(propertiesValue, check) { diff --git a/android/neverallow_test.go b/android/neverallow_test.go index edda2444b..18a870501 100644 --- a/android/neverallow_test.go +++ b/android/neverallow_test.go @@ -296,6 +296,48 @@ var neverallowTests = []struct { "Only boot images and seapp contexts may be imported as a makefile goal.", }, }, + { + name: "min_sdk too low", + fs: map[string][]byte{ + "Android.bp": []byte(` + java_library { + name: "min_sdk_too_low", + min_sdk_version: "30", + }`), + }, + rules: []Rule{ + NeverAllow().WithMatcher("min_sdk_version", LessThanSdkVersion("31")), + }, + expectedErrors: []string{ + "module \"min_sdk_too_low\": violates neverallow", + }, + }, + { + name: "min_sdk high enough", + fs: map[string][]byte{ + "Android.bp": []byte(` + java_library { + name: "min_sdk_high_enough", + min_sdk_version: "31", + }`), + }, + rules: []Rule{ + NeverAllow().WithMatcher("min_sdk_version", LessThanSdkVersion("31")), + }, + }, + { + name: "current min_sdk high enough", + fs: map[string][]byte{ + "Android.bp": []byte(` + java_library { + name: "current_min_sdk_high_enough", + min_sdk_version: "current", + }`), + }, + rules: []Rule{ + NeverAllow().WithMatcher("min_sdk_version", LessThanSdkVersion("31")), + }, + }, } var prepareForNeverAllowTest = GroupFixturePreparers( @@ -379,9 +421,10 @@ func (p *mockCcLibraryModule) GenerateAndroidBuildActions(ModuleContext) { } type mockJavaLibraryProperties struct { - Libs []string - Sdk_version *string - Uncompress_dex *bool + Libs []string + Min_sdk_version *string + Sdk_version *string + Uncompress_dex *bool } type mockJavaLibraryModule struct { diff --git a/android/package_ctx.go b/android/package_ctx.go index c19debbb4..f354db83f 100644 --- a/android/package_ctx.go +++ b/android/package_ctx.go @@ -19,6 +19,7 @@ import ( "strings" "github.com/google/blueprint" + "github.com/google/blueprint/proptools" "android/soong/remoteexec" ) @@ -173,7 +174,7 @@ func (p PackageContext) SourcePathVariableWithEnvOverride(name, path, env string // package-scoped variable's initialization. func (p PackageContext) HostBinToolVariable(name, path string) blueprint.Variable { return p.VariableFunc(name, func(ctx PackageVarContext) string { - return ctx.Config().HostToolPath(ctx, path).String() + return proptools.NinjaAndShellEscape(ctx.Config().HostToolPath(ctx, path).String()) }) } @@ -183,7 +184,7 @@ func (p PackageContext) HostBinToolVariable(name, path string) blueprint.Variabl // package-scoped variable's initialization. func (p PackageContext) HostJNIToolVariable(name, path string) blueprint.Variable { return p.VariableFunc(name, func(ctx PackageVarContext) string { - return ctx.Config().HostJNIToolPath(ctx, path).String() + return proptools.NinjaAndShellEscape(ctx.Config().HostJNIToolPath(ctx, path).String()) }) } @@ -193,7 +194,7 @@ func (p PackageContext) HostJNIToolVariable(name, path string) blueprint.Variabl // part of a package-scoped variable's initialization. func (p PackageContext) HostJavaToolVariable(name, path string) blueprint.Variable { return p.VariableFunc(name, func(ctx PackageVarContext) string { - return ctx.Config().HostJavaToolPath(ctx, path).String() + return proptools.NinjaAndShellEscape(ctx.Config().HostJavaToolPath(ctx, path).String()) }) } diff --git a/android/prebuilt.go b/android/prebuilt.go index e18989271..b0a4f434f 100644 --- a/android/prebuilt.go +++ b/android/prebuilt.go @@ -97,7 +97,10 @@ type ConfigVarProperties struct { type Prebuilt struct { properties PrebuiltProperties - srcsSupplier PrebuiltSrcsSupplier + // nil if the prebuilt has no srcs property at all. See InitPrebuiltModuleWithoutSrcs. + srcsSupplier PrebuiltSrcsSupplier + + // "-" if the prebuilt has no srcs property at all. See InitPrebuiltModuleWithoutSrcs. srcsPropertyName string } @@ -177,6 +180,23 @@ func (p *Prebuilt) UsePrebuilt() bool { // Return the src value or nil if it is not available. type PrebuiltSrcsSupplier func(ctx BaseModuleContext, prebuilt Module) []string +func initPrebuiltModuleCommon(module PrebuiltInterface) *Prebuilt { + p := module.Prebuilt() + module.AddProperties(&p.properties) + module.base().customizableProperties = module.GetProperties() + return p +} + +// Initialize the module as a prebuilt module that has no dedicated property that lists its +// sources. SingleSourcePathFromSupplier should not be called for this module. +// +// This is the case e.g. for header modules, which provides the headers in source form +// regardless whether they are prebuilt or not. +func InitPrebuiltModuleWithoutSrcs(module PrebuiltInterface) { + p := initPrebuiltModuleCommon(module) + p.srcsPropertyName = "-" +} + // Initialize the module as a prebuilt module that uses the provided supplier to access the // prebuilt sources of the module. // @@ -190,10 +210,6 @@ type PrebuiltSrcsSupplier func(ctx BaseModuleContext, prebuilt Module) []string // The provided property name is used to provide helpful error messages in the event that // a problem arises, e.g. calling SingleSourcePath() when more than one source is provided. func InitPrebuiltModuleWithSrcSupplier(module PrebuiltInterface, srcsSupplier PrebuiltSrcsSupplier, srcsPropertyName string) { - p := module.Prebuilt() - module.AddProperties(&p.properties) - module.base().customizableProperties = module.GetProperties() - if srcsSupplier == nil { panic(fmt.Errorf("srcsSupplier must not be nil")) } @@ -201,6 +217,7 @@ func InitPrebuiltModuleWithSrcSupplier(module PrebuiltInterface, srcsSupplier Pr panic(fmt.Errorf("srcsPropertyName must not be empty")) } + p := initPrebuiltModuleCommon(module) p.srcsSupplier = srcsSupplier p.srcsPropertyName = srcsPropertyName } @@ -336,7 +353,7 @@ func PrebuiltSourceDepsMutator(ctx BottomUpMutatorContext) { func PrebuiltSelectModuleMutator(ctx TopDownMutatorContext) { m := ctx.Module() if p := GetEmbeddedPrebuilt(m); p != nil { - if p.srcsSupplier == nil { + if p.srcsSupplier == nil && p.srcsPropertyName == "" { panic(fmt.Errorf("prebuilt module did not have InitPrebuiltModule called on it")) } if !p.properties.SourceExists { diff --git a/android/proto.go b/android/proto.go index 0be7893c8..64d4d057c 100644 --- a/android/proto.go +++ b/android/proto.go @@ -15,12 +15,17 @@ package android import ( + "android/soong/bazel" "strings" "github.com/google/blueprint" "github.com/google/blueprint/proptools" ) +const ( + canonicalPathFromRootDefault = true +) + // TODO(ccross): protos are often used to communicate between multiple modules. If the only // way to convert a proto to source is to reference it as a source file, and external modules cannot // reference source files in other modules, then every module that owns a proto file will need to @@ -90,7 +95,7 @@ func GetProtoFlags(ctx ModuleContext, p *ProtoProperties) ProtoFlags { Flags: flags, Deps: deps, OutTypeFlag: protoOutFlag, - CanonicalPathFromRoot: proptools.BoolDefault(p.Proto.Canonical_path_from_root, true), + CanonicalPathFromRoot: proptools.BoolDefault(p.Proto.Canonical_path_from_root, canonicalPathFromRootDefault), Dir: PathForModuleGen(ctx, "proto"), SubDir: PathForModuleGen(ctx, "proto", ctx.ModuleDir()), } @@ -146,3 +151,57 @@ func ProtoRule(rule *RuleBuilder, protoFile Path, flags ProtoFlags, deps Paths, rule.Command(). BuiltTool("dep_fixer").Flag(depFile.String()) } + +// Bp2buildProtoInfo contains information necessary to pass on to language specific conversion. +type Bp2buildProtoInfo struct { + Type *string + Name string +} + +type protoAttrs struct { + Srcs bazel.LabelListAttribute + Strip_import_prefix *string +} + +// Bp2buildProtoProperties converts proto properties, creating a proto_library and returning the +// information necessary for language-specific handling. +func Bp2buildProtoProperties(ctx Bp2buildMutatorContext, module Module, srcs bazel.LabelListAttribute) (Bp2buildProtoInfo, bool) { + var info Bp2buildProtoInfo + if srcs.IsEmpty() { + return info, false + } + m := module.base() + + info.Name = m.Name() + "_proto" + attrs := protoAttrs{ + Srcs: srcs, + } + + for axis, configToProps := range m.GetArchVariantProperties(ctx, &ProtoProperties{}) { + for _, rawProps := range configToProps { + var props *ProtoProperties + var ok bool + if props, ok = rawProps.(*ProtoProperties); !ok { + ctx.ModuleErrorf("Could not cast ProtoProperties to expected type") + } + if axis == bazel.NoConfigAxis { + info.Type = props.Proto.Type + + if proptools.BoolDefault(props.Proto.Canonical_path_from_root, canonicalPathFromRootDefault) { + // an empty string indicates to strips the package path + path := "" + attrs.Strip_import_prefix = &path + } + } else if props.Proto.Type != info.Type && props.Proto.Type != nil { + ctx.ModuleErrorf("Cannot handle arch-variant types for protos at this time.") + } + } + } + + ctx.CreateBazelTargetModule( + bazel.BazelTargetModuleProperties{Rule_class: "proto_library"}, + CommonAttributes{Name: info.Name}, + &attrs) + + return info, true +} diff --git a/android/register.go b/android/register.go index 424439806..1ac44402d 100644 --- a/android/register.go +++ b/android/register.go @@ -178,13 +178,7 @@ func (ctx *Context) RegisterForBazelConversion() { t.register(ctx) } - bp2buildMutatorList := []RegisterMutatorFunc{} - for t, f := range bp2buildMutators { - ctx.config.bp2buildModuleTypeConfig[t] = true - bp2buildMutatorList = append(bp2buildMutatorList, f) - } - - RegisterMutatorsForBazelConversion(ctx, bp2buildPreArchMutators, bp2buildMutatorList) + RegisterMutatorsForBazelConversion(ctx, bp2buildPreArchMutators) } // Register the pipeline of singletons, module types, and mutators for @@ -196,15 +190,6 @@ func (ctx *Context) Register() { t.register(ctx) } - if ctx.config.BazelContext.BazelEnabled() { - // Hydrate the configuration of bp2build-enabled module types. This is - // required as a signal to identify which modules should be deferred to - // Bazel in mixed builds, if it is enabled. - for t, _ := range bp2buildMutators { - ctx.config.bp2buildModuleTypeConfig[t] = true - } - } - mutators := collateGloballyRegisteredMutators() mutators.registerAll(ctx) diff --git a/android/sdk_version.go b/android/sdk_version.go index 1813e7e14..2004c9290 100644 --- a/android/sdk_version.go +++ b/android/sdk_version.go @@ -117,7 +117,7 @@ func (s SdkSpec) Stable() bool { return false } -// PrebuiltSdkAvailableForUnbundledBuilt tells whether this SdkSpec can have a prebuilt SDK +// PrebuiltSdkAvailableForUnbundledBuild tells whether this SdkSpec can have a prebuilt SDK // that can be used for unbundled builds. func (s SdkSpec) PrebuiltSdkAvailableForUnbundledBuild() bool { // "", "none", and "core_platform" are not available for unbundled build @@ -212,6 +212,10 @@ var ( ) func SdkSpecFrom(ctx EarlyModuleContext, str string) SdkSpec { + return SdkSpecFromWithConfig(ctx.Config(), str) +} + +func SdkSpecFromWithConfig(config Config, str string) SdkSpec { switch str { // special cases first case "": @@ -252,7 +256,7 @@ func SdkSpecFrom(ctx EarlyModuleContext, str string) SdkSpec { return SdkSpec{SdkInvalid, NoneApiLevel, str} } - apiLevel, err := ApiLevelFromUser(ctx, versionString) + apiLevel, err := ApiLevelFromUserWithConfig(config, versionString) if err != nil { return SdkSpec{SdkInvalid, apiLevel, str} } diff --git a/android/sdk_version_test.go b/android/sdk_version_test.go new file mode 100644 index 000000000..ec81782f0 --- /dev/null +++ b/android/sdk_version_test.go @@ -0,0 +1,89 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package android + +import ( + "testing" +) + +func TestSdkSpecFrom(t *testing.T) { + testCases := []struct { + input string + expected string + }{ + { + input: "", + expected: "private_current", + }, + { + input: "none", + expected: "none_(no version)", + }, + { + input: "core_platform", + expected: "core_platform_current", + }, + { + input: "_", + expected: "invalid_(no version)", + }, + { + input: "_31", + expected: "invalid_(no version)", + }, + { + input: "system_R", + expected: "system_30", + }, + { + input: "test_31", + expected: "test_31", + }, + { + input: "module_current", + expected: "module-lib_current", + }, + { + input: "31", + expected: "public_31", + }, + { + input: "S", + expected: "public_31", + }, + { + input: "current", + expected: "public_current", + }, + { + input: "Tiramisu", + expected: "public_Tiramisu", + }, + } + + config := NullConfig("", "") + + config.productVariables = productVariables{ + Platform_sdk_version: intPtr(31), + Platform_sdk_codename: stringPtr("Tiramisu"), + Platform_version_active_codenames: []string{"Tiramisu"}, + } + + for _, tc := range testCases { + if got := SdkSpecFromWithConfig(config, tc.input).String(); tc.expected != got { + t.Errorf("Expected %v, got %v", tc.expected, got) + } + } +} diff --git a/android/testing.go b/android/testing.go index 6290d4317..8daf6b783 100644 --- a/android/testing.go +++ b/android/testing.go @@ -208,16 +208,6 @@ func (ctx *TestContext) RegisterBp2BuildConfig(config Bp2BuildConfig) { ctx.config.bp2buildPackageConfig = config } -// RegisterBp2BuildMutator registers a BazelTargetModule mutator for converting a module -// type to the equivalent Bazel target. -func (ctx *TestContext) RegisterBp2BuildMutator(moduleType string, m func(TopDownMutatorContext)) { - f := func(ctx RegisterMutatorsContext) { - ctx.TopDown(moduleType, m) - } - ctx.config.bp2buildModuleTypeConfig[moduleType] = true - ctx.bp2buildMutators = append(ctx.bp2buildMutators, f) -} - // PreArchBp2BuildMutators adds mutators to be register for converting Android Blueprint modules // into Bazel BUILD targets that should run prior to deps and conversion. func (ctx *TestContext) PreArchBp2BuildMutators(f RegisterMutatorFunc) { @@ -459,7 +449,7 @@ func (ctx *TestContext) Register() { // RegisterForBazelConversion prepares a test context for bp2build conversion. func (ctx *TestContext) RegisterForBazelConversion() { ctx.SetRunningAsBp2build() - RegisterMutatorsForBazelConversion(ctx.Context, ctx.bp2buildPreArch, ctx.bp2buildMutators) + RegisterMutatorsForBazelConversion(ctx.Context, ctx.bp2buildPreArch) } func (ctx *TestContext) ParseFileList(rootDir string, filePaths []string) (deps []string, errs []error) { diff --git a/android/variable.go b/android/variable.go index fe828d3e3..a70681088 100644 --- a/android/variable.go +++ b/android/variable.go @@ -15,13 +15,14 @@ package android import ( - "android/soong/android/soongconfig" - "android/soong/bazel" "fmt" "reflect" "runtime" "strings" + "android/soong/android/soongconfig" + "android/soong/bazel" + "github.com/google/blueprint/proptools" ) @@ -245,30 +246,30 @@ type productVariables struct { AppsDefaultVersionName *string `json:",omitempty"` - Allow_missing_dependencies *bool `json:",omitempty"` - Unbundled_build *bool `json:",omitempty"` - Unbundled_build_apps *bool `json:",omitempty"` - Unbundled_build_image *bool `json:",omitempty"` - Always_use_prebuilt_sdks *bool `json:",omitempty"` - Skip_boot_jars_check *bool `json:",omitempty"` - Malloc_not_svelte *bool `json:",omitempty"` - Malloc_zero_contents *bool `json:",omitempty"` - Malloc_pattern_fill_contents *bool `json:",omitempty"` - Safestack *bool `json:",omitempty"` - HostStaticBinaries *bool `json:",omitempty"` - Binder32bit *bool `json:",omitempty"` - UseGoma *bool `json:",omitempty"` - UseRBE *bool `json:",omitempty"` - UseRBEJAVAC *bool `json:",omitempty"` - UseRBER8 *bool `json:",omitempty"` - UseRBED8 *bool `json:",omitempty"` - Debuggable *bool `json:",omitempty"` - Eng *bool `json:",omitempty"` - Treble_linker_namespaces *bool `json:",omitempty"` - Enforce_vintf_manifest *bool `json:",omitempty"` - Uml *bool `json:",omitempty"` - Arc *bool `json:",omitempty"` - MinimizeJavaDebugInfo *bool `json:",omitempty"` + Allow_missing_dependencies *bool `json:",omitempty"` + Unbundled_build *bool `json:",omitempty"` + Unbundled_build_apps []string `json:",omitempty"` + Unbundled_build_image *bool `json:",omitempty"` + Always_use_prebuilt_sdks *bool `json:",omitempty"` + Skip_boot_jars_check *bool `json:",omitempty"` + Malloc_not_svelte *bool `json:",omitempty"` + Malloc_zero_contents *bool `json:",omitempty"` + Malloc_pattern_fill_contents *bool `json:",omitempty"` + Safestack *bool `json:",omitempty"` + HostStaticBinaries *bool `json:",omitempty"` + Binder32bit *bool `json:",omitempty"` + UseGoma *bool `json:",omitempty"` + UseRBE *bool `json:",omitempty"` + UseRBEJAVAC *bool `json:",omitempty"` + UseRBER8 *bool `json:",omitempty"` + UseRBED8 *bool `json:",omitempty"` + Debuggable *bool `json:",omitempty"` + Eng *bool `json:",omitempty"` + Treble_linker_namespaces *bool `json:",omitempty"` + Enforce_vintf_manifest *bool `json:",omitempty"` + Uml *bool `json:",omitempty"` + Arc *bool `json:",omitempty"` + MinimizeJavaDebugInfo *bool `json:",omitempty"` Check_elf_files *bool `json:",omitempty"` @@ -298,8 +299,6 @@ type productVariables struct { ClangTidy *bool `json:",omitempty"` TidyChecks *string `json:",omitempty"` - SamplingPGO *bool `json:",omitempty"` - JavaCoveragePaths []string `json:",omitempty"` JavaCoverageExcludePaths []string `json:",omitempty"` @@ -348,6 +347,7 @@ type productVariables struct { BoardVendorSepolicyDirs []string `json:",omitempty"` BoardOdmSepolicyDirs []string `json:",omitempty"` BoardReqdMaskPolicy []string `json:",omitempty"` + BoardPlatVendorPolicy []string `json:",omitempty"` SystemExtPublicSepolicyDirs []string `json:",omitempty"` SystemExtPrivateSepolicyDirs []string `json:",omitempty"` BoardSepolicyM4Defs []string `json:",omitempty"` diff --git a/androidmk/androidmk/androidmk_test.go b/androidmk/androidmk/androidmk_test.go index ca40aaa93..a2d6992e6 100644 --- a/androidmk/androidmk/androidmk_test.go +++ b/androidmk/androidmk/androidmk_test.go @@ -1537,9 +1537,11 @@ android_app { }, { desc: "LOCAL_LICENSE_KINDS, LOCAL_LICENSE_CONDITIONS, LOCAL_NOTICE_FILE", - // TODO(b/205615944): When valid "android_license_files" exists, the test requires an Android.mk - // file (and an Android.bp file is required as well if the license files locates outside the current - // directory). So plan to use a mock file system to mock the Android.mk and Android.bp files. + // When "android_license_files" is valid, the test requires an Android.mk file + // outside the current (and an Android.bp file is required as well if the license + // files locates directory), thus a mock file system is needed. The integration + // test cases for these scenarios have been added in + // $(ANDROID_BUILD_TOP)/build/soong/tests/androidmk_test.sh. in: ` include $(CLEAR_VARS) LOCAL_MODULE := foo diff --git a/apex/androidmk.go b/apex/androidmk.go index 7764b6b8d..f001fa265 100644 --- a/apex/androidmk.go +++ b/apex/androidmk.go @@ -309,19 +309,17 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, apexName, mo return moduleNames } -func (a *apexBundle) writeRequiredModules(w io.Writer, apexBundleName string) { +func (a *apexBundle) writeRequiredModules(w io.Writer) { var required []string var targetRequired []string var hostRequired []string required = append(required, a.RequiredModuleNames()...) targetRequired = append(targetRequired, a.TargetRequiredModuleNames()...) hostRequired = append(hostRequired, a.HostRequiredModuleNames()...) - installMapSet := make(map[string]bool) // set of dependency module:location mappings for _, fi := range a.filesInfo { required = append(required, fi.requiredModuleNames...) targetRequired = append(targetRequired, fi.targetRequiredModuleNames...) hostRequired = append(hostRequired, fi.hostRequiredModuleNames...) - installMapSet[a.fullModuleName(apexBundleName, &fi)+":"+fi.installDir+"/"+fi.builtFile.Base()] = true } if len(required) > 0 { @@ -333,11 +331,6 @@ func (a *apexBundle) writeRequiredModules(w io.Writer, apexBundleName string) { if len(hostRequired) > 0 { fmt.Fprintln(w, "LOCAL_HOST_REQUIRED_MODULES +=", strings.Join(hostRequired, " ")) } - if len(installMapSet) > 0 { - var installs []string - installs = append(installs, android.SortedStringKeys(installMapSet)...) - fmt.Fprintln(w, "LOCAL_LICENSE_INSTALL_MAP +=", strings.Join(installs, " ")) - } } func (a *apexBundle) androidMkForType() android.AndroidMkData { @@ -359,7 +352,7 @@ func (a *apexBundle) androidMkForType() android.AndroidMkData { if len(moduleNames) > 0 { fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", strings.Join(moduleNames, " ")) } - a.writeRequiredModules(w, name) + a.writeRequiredModules(w) fmt.Fprintln(w, "include $(BUILD_PHONY_PACKAGE)") } else { @@ -401,7 +394,7 @@ func (a *apexBundle) androidMkForType() android.AndroidMkData { if len(a.requiredDeps) > 0 { fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES +=", strings.Join(a.requiredDeps, " ")) } - a.writeRequiredModules(w, name) + a.writeRequiredModules(w) if a.mergedNotices.Merged.Valid() { fmt.Fprintln(w, "LOCAL_NOTICE_FILE :=", a.mergedNotices.Merged.Path().String()) diff --git a/apex/apex.go b/apex/apex.go index c1a4b40bb..b7faa5b98 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -54,8 +54,6 @@ func registerApexBuildComponents(ctx android.RegistrationContext) { ctx.PreArchMutators(registerPreArchMutators) ctx.PreDepsMutators(RegisterPreDepsMutators) ctx.PostDepsMutators(RegisterPostDepsMutators) - - android.RegisterBp2BuildMutator("apex", ApexBundleBp2Build) } func registerPreArchMutators(ctx android.RegisterMutatorsContext) { @@ -98,6 +96,14 @@ type apexBundleProperties struct { // /system/sepolicy/apex/<module_name>_file_contexts. File_contexts *string `android:"path"` + // Path to the canned fs config file for customizing file's uid/gid/mod/capabilities. The + // format is /<path_or_glob> <uid> <gid> <mode> [capabilities=0x<cap>], where path_or_glob is a + // path or glob pattern for a file or set of files, uid/gid are numerial values of user ID + // and group ID, mode is octal value for the file mode, and cap is hexadecimal value for the + // capability. If this property is not set, or a file is missing in the file, default config + // is used. + Canned_fs_config *string `android:"path"` + ApexNativeDependencies Multilib apexMultilibProperties @@ -111,6 +117,9 @@ type apexBundleProperties struct { // List of java libraries that are embedded inside this APEX bundle. Java_libs []string + // List of sh binaries that are embedded inside this APEX bundle. + Sh_binaries []string + // List of platform_compat_config files that are embedded inside this APEX bundle. Compat_configs []string @@ -127,6 +136,13 @@ type apexBundleProperties struct { // symlinking to the system libs. Default is true. Updatable *bool + // Marks that this APEX is designed to be updatable in the future, although it's not + // updatable yet. This is used to mimic some of the build behaviors that are applied only to + // updatable APEXes. Currently, this disables the size optimization, so that the size of + // APEX will not increase when the APEX is actually marked as truly updatable. Default is + // false. + Future_updatable *bool + // Whether this APEX can use platform APIs or not. Can be set to true only when `updatable: // false`. Default is false. Platform_apis *bool @@ -618,6 +634,7 @@ var ( sharedLibTag = dependencyTag{name: "sharedLib", payload: true} testForTag = dependencyTag{name: "test for"} testTag = dependencyTag{name: "test", payload: true} + shBinaryTag = dependencyTag{name: "shBinary", payload: true} ) // TODO(jiyong): shorten this function signature @@ -762,6 +779,10 @@ func (a *apexBundle) DepsMutator(ctx android.BottomUpMutatorContext) { for _, d := range depsList { addDependenciesForNativeModules(ctx, d, target, imageVariation) } + ctx.AddFarVariationDependencies([]blueprint.Variation{ + {Mutator: "os", Variation: target.OsVariation()}, + {Mutator: "arch", Variation: target.ArchVariation()}, + }, shBinaryTag, a.properties.Sh_binaries...) } // Common-arch dependencies come next @@ -1298,6 +1319,10 @@ func (a *apexBundle) Updatable() bool { return proptools.BoolDefault(a.properties.Updatable, true) } +func (a *apexBundle) FutureUpdatable() bool { + return proptools.BoolDefault(a.properties.Future_updatable, false) +} + func (a *apexBundle) UsePlatformApis() bool { return proptools.BoolDefault(a.properties.Platform_apis, false) } @@ -1482,6 +1507,9 @@ func apexFileForGoBinary(ctx android.BaseModuleContext, depName string, gb boots func apexFileForShBinary(ctx android.BaseModuleContext, sh *sh.ShBinary) apexFile { dirInApex := filepath.Join("bin", sh.SubDir()) + if sh.Target().NativeBridge == android.NativeBridgeEnabled { + dirInApex = filepath.Join(dirInApex, sh.Target().NativeBridgeRelativePath) + } fileToCopy := sh.OutputFile() af := newApexFile(ctx, fileToCopy, sh.BaseModuleName(), dirInApex, shBinary, sh) af.symlinks = sh.Symlinks() @@ -1659,7 +1687,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { // 1) do some validity checks such as apex_available, min_sdk_version, etc. a.checkApexAvailability(ctx) a.checkUpdatable(ctx) - a.checkMinSdkVersion(ctx) + a.CheckMinSdkVersion(ctx) a.checkStaticLinkingToStubLibraries(ctx) a.checkStaticExecutables(ctx) if len(a.properties.Tests) > 0 && !a.testApex { @@ -1710,6 +1738,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { return true // track transitive dependencies } else if r, ok := child.(*rust.Module); ok { fi := apexFileForRustLibrary(ctx, r) + fi.isJniLib = isJniLib filesInfo = append(filesInfo, fi) } else { propertyName := "native_shared_libs" @@ -1722,8 +1751,6 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { if cc, ok := child.(*cc.Module); ok { filesInfo = append(filesInfo, apexFileForExecutable(ctx, cc)) return true // track transitive dependencies - } else if sh, ok := child.(*sh.ShBinary); ok { - filesInfo = append(filesInfo, apexFileForShBinary(ctx, sh)) } else if py, ok := child.(*python.Module); ok && py.HostToolPath().Valid() { filesInfo = append(filesInfo, apexFileForPyBinary(ctx, py)) } else if gb, ok := child.(bootstrap.GoBinaryTool); ok && a.Host() { @@ -1732,7 +1759,13 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { filesInfo = append(filesInfo, apexFileForRustExecutable(ctx, rust)) return true // track transitive dependencies } else { - ctx.PropertyErrorf("binaries", "%q is neither cc_binary, rust_binary, (embedded) py_binary, (host) blueprint_go_binary, (host) bootstrap_go_binary, nor sh_binary", depName) + ctx.PropertyErrorf("binaries", "%q is neither cc_binary, rust_binary, (embedded) py_binary, (host) blueprint_go_binary, nor (host) bootstrap_go_binary", depName) + } + case shBinaryTag: + if sh, ok := child.(*sh.ShBinary); ok { + filesInfo = append(filesInfo, apexFileForShBinary(ctx, sh)) + } else { + ctx.PropertyErrorf("sh_binaries", "%q is not a sh_binary module", depName) } case bcpfTag: { @@ -1988,6 +2021,8 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { } } else if _, ok := depTag.(android.CopyDirectlyInAnyApexTag); ok { // nothing + } else if depTag == android.DarwinUniversalVariantTag { + // nothing } else if am.CanHaveApexVariants() && am.IsInstallableToApex() { ctx.ModuleErrorf("unexpected tag %s for indirect dependency %q", android.PrettyPrintTag(depTag), depName) } @@ -2089,10 +2124,11 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { } forced := ctx.Config().ForceApexSymlinkOptimization() + updatable := a.Updatable() || a.FutureUpdatable() // We don't need the optimization for updatable APEXes, as it might give false signal // to the system health when the APEXes are still bundled (b/149805758). - if !forced && a.Updatable() && a.properties.ApexType == imageApex { + if !forced && updatable && a.properties.ApexType == imageApex { a.linkToSystemLib = false } @@ -2158,6 +2194,40 @@ func apexBootclasspathFragmentFiles(ctx android.ModuleContext, module blueprint. filesToAdd = append(filesToAdd, *af) } + if pathInApex := bootclasspathFragmentInfo.ProfileInstallPathInApex(); pathInApex != "" { + pathOnHost := bootclasspathFragmentInfo.ProfilePathOnHost() + tempPath := android.PathForModuleOut(ctx, "boot_image_profile", pathInApex) + + if pathOnHost != nil { + // We need to copy the profile to a temporary path with the right filename because the apexer + // will take the filename as is. + ctx.Build(pctx, android.BuildParams{ + Rule: android.Cp, + Input: pathOnHost, + Output: tempPath, + }) + } else { + // At this point, the boot image profile cannot be generated. It is probably because the boot + // image profile source file does not exist on the branch, or it is not available for the + // current build target. + // However, we cannot enforce the boot image profile to be generated because some build + // targets (such as module SDK) do not need it. It is only needed when the APEX is being + // built. Therefore, we create an error rule so that an error will occur at the ninja phase + // only if the APEX is being built. + ctx.Build(pctx, android.BuildParams{ + Rule: android.ErrorRule, + Output: tempPath, + Args: map[string]string{ + "error": "Boot image profile cannot be generated", + }, + }) + } + + androidMkModuleName := filepath.Base(pathInApex) + af := newApexFile(ctx, tempPath, androidMkModuleName, filepath.Dir(pathInApex), etc, nil) + filesToAdd = append(filesToAdd, af) + } + return filesToAdd } @@ -2284,18 +2354,28 @@ func overrideApexFactory() android.Module { // // TODO(jiyong): move these checks to a separate go file. +var _ android.ModuleWithMinSdkVersionCheck = (*apexBundle)(nil) + // Entures that min_sdk_version of the included modules are equal or less than the min_sdk_version // of this apexBundle. -func (a *apexBundle) checkMinSdkVersion(ctx android.ModuleContext) { +func (a *apexBundle) CheckMinSdkVersion(ctx android.ModuleContext) { if a.testApex || a.vndkApex { return } // apexBundle::minSdkVersion reports its own errors. minSdkVersion := a.minSdkVersion(ctx) - android.CheckMinSdkVersion(a, ctx, minSdkVersion) + android.CheckMinSdkVersion(ctx, minSdkVersion, a.WalkPayloadDeps) } -func (a *apexBundle) minSdkVersion(ctx android.BaseModuleContext) android.ApiLevel { +func (a *apexBundle) MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { + return android.SdkSpec{ + Kind: android.SdkNone, + ApiLevel: a.minSdkVersion(ctx), + Raw: String(a.properties.Min_sdk_version), + } +} + +func (a *apexBundle) minSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel { ver := proptools.String(a.properties.Min_sdk_version) if ver == "" { return android.NoneApiLevel @@ -2361,6 +2441,12 @@ func (a *apexBundle) checkUpdatable(ctx android.ModuleContext) { if a.UsePlatformApis() { ctx.PropertyErrorf("updatable", "updatable APEXes can't use platform APIs") } + if a.SocSpecific() || a.DeviceSpecific() { + ctx.PropertyErrorf("updatable", "vendor APEXes are not updatable") + } + if a.FutureUpdatable() { + ctx.PropertyErrorf("future_updatable", "Already updatable. Remove `future_updatable: true:`") + } a.checkJavaStableSdkVersion(ctx) a.checkClasspathFragments(ctx) } @@ -3120,15 +3206,16 @@ func createApexPermittedPackagesRules(modules_packages map[string][]string) []an BootclasspathJar(). With("apex_available", module_name). WithMatcher("permitted_packages", android.NotInList(module_packages)). + WithMatcher("min_sdk_version", android.LessThanSdkVersion("Tiramisu")). Because("jars that are part of the " + module_name + " module may only allow these packages: " + strings.Join(module_packages, ",") + - ". Please jarjar or move code around.") + " with min_sdk < T. Please jarjar or move code around.") rules = append(rules, permittedPackagesRule) } return rules } -// DO NOT EDIT! These are the package prefixes that are exempted from being AOT'ed by ART. +// DO NOT EDIT! These are the package prefixes that are exempted from being AOT'ed by ART on Q/R/S. // Adding code to the bootclasspath in new packages will cause issues on module update. func qModulesPackages() map[string][]string { return map[string][]string{ @@ -3142,7 +3229,7 @@ func qModulesPackages() map[string][]string { } } -// DO NOT EDIT! These are the package prefixes that are exempted from being AOT'ed by ART. +// DO NOT EDIT! These are the package prefixes that are exempted from being AOT'ed by ART on R/S. // Adding code to the bootclasspath in new packages will cause issues on module update. func rModulesPackages() map[string][]string { return map[string][]string{ @@ -3185,80 +3272,70 @@ type bazelApexBundleAttributes struct { File_contexts bazel.LabelAttribute Key bazel.LabelAttribute Certificate bazel.LabelAttribute - Min_sdk_version string + Min_sdk_version *string Updatable bazel.BoolAttribute Installable bazel.BoolAttribute Native_shared_libs bazel.LabelListAttribute - Binaries bazel.StringListAttribute + Binaries bazel.LabelListAttribute Prebuilts bazel.LabelListAttribute } -func ApexBundleBp2Build(ctx android.TopDownMutatorContext) { - module, ok := ctx.Module().(*apexBundle) - if !ok { - // Not an APEX bundle - return - } - if !module.ConvertWithBp2build(ctx) { - return - } +// ConvertWithBp2build performs bp2build conversion of an apex +func (a *apexBundle) ConvertWithBp2build(ctx android.TopDownMutatorContext) { + // We do not convert apex_test modules at this time if ctx.ModuleType() != "apex" { return } - apexBundleBp2BuildInternal(ctx, module) -} - -func apexBundleBp2BuildInternal(ctx android.TopDownMutatorContext, module *apexBundle) { var manifestLabelAttribute bazel.LabelAttribute - if module.properties.Manifest != nil { - manifestLabelAttribute.SetValue(android.BazelLabelForModuleSrcSingle(ctx, *module.properties.Manifest)) + if a.properties.Manifest != nil { + manifestLabelAttribute.SetValue(android.BazelLabelForModuleSrcSingle(ctx, *a.properties.Manifest)) } var androidManifestLabelAttribute bazel.LabelAttribute - if module.properties.AndroidManifest != nil { - androidManifestLabelAttribute.SetValue(android.BazelLabelForModuleSrcSingle(ctx, *module.properties.AndroidManifest)) + if a.properties.AndroidManifest != nil { + androidManifestLabelAttribute.SetValue(android.BazelLabelForModuleSrcSingle(ctx, *a.properties.AndroidManifest)) } var fileContextsLabelAttribute bazel.LabelAttribute - if module.properties.File_contexts != nil { - fileContextsLabelAttribute.SetValue(android.BazelLabelForModuleDepSingle(ctx, *module.properties.File_contexts)) + if a.properties.File_contexts != nil { + fileContextsLabelAttribute.SetValue(android.BazelLabelForModuleDepSingle(ctx, *a.properties.File_contexts)) } - var minSdkVersion string - if module.properties.Min_sdk_version != nil { - minSdkVersion = *module.properties.Min_sdk_version + var minSdkVersion *string + if a.properties.Min_sdk_version != nil { + minSdkVersion = a.properties.Min_sdk_version } var keyLabelAttribute bazel.LabelAttribute - if module.overridableProperties.Key != nil { - keyLabelAttribute.SetValue(android.BazelLabelForModuleDepSingle(ctx, *module.overridableProperties.Key)) + if a.overridableProperties.Key != nil { + keyLabelAttribute.SetValue(android.BazelLabelForModuleDepSingle(ctx, *a.overridableProperties.Key)) } var certificateLabelAttribute bazel.LabelAttribute - if module.overridableProperties.Certificate != nil { - certificateLabelAttribute.SetValue(android.BazelLabelForModuleDepSingle(ctx, *module.overridableProperties.Certificate)) + if a.overridableProperties.Certificate != nil { + certificateLabelAttribute.SetValue(android.BazelLabelForModuleDepSingle(ctx, *a.overridableProperties.Certificate)) } - nativeSharedLibs := module.properties.ApexNativeDependencies.Native_shared_libs + nativeSharedLibs := a.properties.ApexNativeDependencies.Native_shared_libs nativeSharedLibsLabelList := android.BazelLabelForModuleDeps(ctx, nativeSharedLibs) nativeSharedLibsLabelListAttribute := bazel.MakeLabelListAttribute(nativeSharedLibsLabelList) - prebuilts := module.overridableProperties.Prebuilts + prebuilts := a.overridableProperties.Prebuilts prebuiltsLabelList := android.BazelLabelForModuleDeps(ctx, prebuilts) prebuiltsLabelListAttribute := bazel.MakeLabelListAttribute(prebuiltsLabelList) - binaries := module.properties.ApexNativeDependencies.Binaries - binariesStringListAttribute := bazel.MakeStringListAttribute(binaries) + binaries := android.BazelLabelForModuleDeps(ctx, a.properties.ApexNativeDependencies.Binaries) + binariesLabelListAttribute := bazel.MakeLabelListAttribute(binaries) var updatableAttribute bazel.BoolAttribute - if module.properties.Updatable != nil { - updatableAttribute.Value = module.properties.Updatable + if a.properties.Updatable != nil { + updatableAttribute.Value = a.properties.Updatable } var installableAttribute bazel.BoolAttribute - if module.properties.Installable != nil { - installableAttribute.Value = module.properties.Installable + if a.properties.Installable != nil { + installableAttribute.Value = a.properties.Installable } attrs := &bazelApexBundleAttributes{ @@ -3271,7 +3348,7 @@ func apexBundleBp2BuildInternal(ctx android.TopDownMutatorContext, module *apexB Updatable: updatableAttribute, Installable: installableAttribute, Native_shared_libs: nativeSharedLibsLabelListAttribute, - Binaries: binariesStringListAttribute, + Binaries: binariesLabelListAttribute, Prebuilts: prebuiltsLabelListAttribute, } @@ -3280,5 +3357,5 @@ func apexBundleBp2BuildInternal(ctx android.TopDownMutatorContext, module *apexB Bzl_load_location: "//build/bazel/rules:apex.bzl", } - ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name()}, attrs) + ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: a.Name()}, attrs) } diff --git a/apex/apex_test.go b/apex/apex_test.go index 59ea206f4..a749ea161 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -215,7 +215,9 @@ var prepareForApexTest = android.GroupFixturePreparers( variables.CertificateOverrides = []string{"myapex_keytest:myapex.certificate.override"} variables.Platform_sdk_codename = proptools.StringPtr("Q") variables.Platform_sdk_final = proptools.BoolPtr(false) - variables.Platform_version_active_codenames = []string{"Q"} + // "Tiramisu" needs to be in the next line for compatibility with soong code, + // not because of these tests specifically (it's not used by the tests) + variables.Platform_version_active_codenames = []string{"Q", "Tiramisu"} variables.Platform_vndk_version = proptools.StringPtr("29") }), ) @@ -2579,22 +2581,21 @@ func TestFilesInSubDir(t *testing.T) { `) generateFsRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("generateFsConfig") - dirs := strings.Split(generateFsRule.Args["exec_paths"], " ") + cmd := generateFsRule.RuleParams.Command // Ensure that the subdirectories are all listed - ensureListContains(t, dirs, "etc") - ensureListContains(t, dirs, "etc/foo") - ensureListContains(t, dirs, "etc/foo/bar") - ensureListContains(t, dirs, "lib64") - ensureListContains(t, dirs, "lib64/foo") - ensureListContains(t, dirs, "lib64/foo/bar") - ensureListContains(t, dirs, "lib") - ensureListContains(t, dirs, "lib/foo") - ensureListContains(t, dirs, "lib/foo/bar") - - ensureListContains(t, dirs, "bin") - ensureListContains(t, dirs, "bin/foo") - ensureListContains(t, dirs, "bin/foo/bar") + ensureContains(t, cmd, "/etc ") + ensureContains(t, cmd, "/etc/foo ") + ensureContains(t, cmd, "/etc/foo/bar ") + ensureContains(t, cmd, "/lib64 ") + ensureContains(t, cmd, "/lib64/foo ") + ensureContains(t, cmd, "/lib64/foo/bar ") + ensureContains(t, cmd, "/lib ") + ensureContains(t, cmd, "/lib/foo ") + ensureContains(t, cmd, "/lib/foo/bar ") + ensureContains(t, cmd, "/bin ") + ensureContains(t, cmd, "/bin/foo ") + ensureContains(t, cmd, "/bin/foo/bar ") } func TestFilesInSubDirWhenNativeBridgeEnabled(t *testing.T) { @@ -4248,7 +4249,7 @@ func TestApexWithShBinary(t *testing.T) { apex { name: "myapex", key: "myapex.key", - binaries: ["myscript"], + sh_binaries: ["myscript"], updatable: false, } @@ -6204,7 +6205,7 @@ func TestJavaSDKLibrary(t *testing.T) { }) // Permission XML should point to the activated path of impl jar of java_sdk_library sdkLibrary := ctx.ModuleForTests("foo.xml", "android_common_myapex").Rule("java_sdk_xml") - ensureContains(t, sdkLibrary.RuleParams.Command, `<library name=\"foo\" file=\"/apex/myapex/javalib/foo.jar\"`) + ensureMatches(t, sdkLibrary.RuleParams.Command, `<library\\n\s+name=\\\"foo\\\"\\n\s+file=\\\"/apex/myapex/javalib/foo.jar\\\"`) } func TestJavaSDKLibrary_WithinApex(t *testing.T) { @@ -7035,6 +7036,7 @@ func testDexpreoptWithApexes(t *testing.T, bp, errmsg string, preparer android.F `, insert)) } }), + dexpreopt.FixtureSetBootImageProfiles("art/build/boot/boot-image-profile.txt"), ). ExtendWithErrorHandler(errorHandler). RunTestWithBp(t, bp) @@ -7042,6 +7044,75 @@ func testDexpreoptWithApexes(t *testing.T, bp, errmsg string, preparer android.F return result.TestContext } +func TestDuplicateDeapexeresFromPrebuiltApexes(t *testing.T) { + preparers := android.GroupFixturePreparers( + java.PrepareForTestWithJavaDefaultModules, + PrepareForTestWithApexBuildComponents, + ). + ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern( + "Multiple installable prebuilt APEXes provide ambiguous deapexers: com.android.myapex and com.mycompany.android.myapex")) + + bpBase := ` + apex_set { + name: "com.android.myapex", + installable: true, + exported_bootclasspath_fragments: ["my-bootclasspath-fragment"], + set: "myapex.apks", + } + + apex_set { + name: "com.mycompany.android.myapex", + apex_name: "com.android.myapex", + installable: true, + exported_bootclasspath_fragments: ["my-bootclasspath-fragment"], + set: "company-myapex.apks", + } + + prebuilt_bootclasspath_fragment { + name: "my-bootclasspath-fragment", + apex_available: ["com.android.myapex"], + %s + } + ` + + t.Run("java_import", func(t *testing.T) { + _ = preparers.RunTestWithBp(t, fmt.Sprintf(bpBase, `contents: ["libfoo"]`)+` + java_import { + name: "libfoo", + jars: ["libfoo.jar"], + apex_available: ["com.android.myapex"], + } + `) + }) + + t.Run("java_sdk_library_import", func(t *testing.T) { + _ = preparers.RunTestWithBp(t, fmt.Sprintf(bpBase, `contents: ["libfoo"]`)+` + java_sdk_library_import { + name: "libfoo", + public: { + jars: ["libbar.jar"], + }, + apex_available: ["com.android.myapex"], + } + `) + }) + + t.Run("prebuilt_bootclasspath_fragment", func(t *testing.T) { + _ = preparers.RunTestWithBp(t, fmt.Sprintf(bpBase, ` + image_name: "art", + contents: ["libfoo"], + `)+` + java_sdk_library_import { + name: "libfoo", + public: { + jars: ["libbar.jar"], + }, + apex_available: ["com.android.myapex"], + } + `) + }) +} + func TestUpdatable_should_set_min_sdk_version(t *testing.T) { testApexError(t, `"myapex" .*: updatable: updatable APEXes should set min_sdk_version`, ` apex { @@ -7073,6 +7144,23 @@ func TestUpdatableDefault_should_set_min_sdk_version(t *testing.T) { `) } +func TestUpdatable_cannot_be_vendor_apex(t *testing.T) { + testApexError(t, `"myapex" .*: updatable: vendor APEXes are not updatable`, ` + apex { + name: "myapex", + key: "myapex.key", + updatable: true, + soc_specific: true, + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + `) +} + func TestUpdatable_should_not_set_generate_classpaths_proto(t *testing.T) { testApexError(t, `"mysystemserverclasspathfragment" .* it must not set generate_classpaths_proto to false`, ` apex { @@ -7339,6 +7427,7 @@ func TestApexPermittedPackagesRules(t *testing.T) { apex_available: ["myapex"], sdk_version: "none", system_modules: "none", + min_sdk_version: "30", } java_library { name: "nonbcp_lib2", @@ -7347,9 +7436,11 @@ func TestApexPermittedPackagesRules(t *testing.T) { permitted_packages: ["a.b"], sdk_version: "none", system_modules: "none", + min_sdk_version: "30", } apex { name: "myapex", + min_sdk_version: "30", key: "myapex.key", java_libs: ["bcp_lib1", "nonbcp_lib2"], updatable: false, @@ -7362,8 +7453,45 @@ func TestApexPermittedPackagesRules(t *testing.T) { }, }, { - name: "Bootclasspath apex jar not satisfying allowed module packages.", - expectedError: `module "bcp_lib2" .* which is restricted because jars that are part of the myapex module may only allow these packages: foo.bar. Please jarjar or move code around.`, + name: "Bootclasspath apex jar not satisfying allowed module packages on Q.", + expectedError: `module "bcp_lib2" .* which is restricted because jars that are part of the myapex module may only allow these packages: foo.bar with min_sdk < T. Please jarjar or move code around.`, + bp: ` + java_library { + name: "bcp_lib1", + srcs: ["lib1/src/*.java"], + apex_available: ["myapex"], + permitted_packages: ["foo.bar"], + sdk_version: "none", + system_modules: "none", + min_sdk_version: "29", + } + java_library { + name: "bcp_lib2", + srcs: ["lib2/src/*.java"], + apex_available: ["myapex"], + permitted_packages: ["foo.bar", "bar.baz"], + sdk_version: "none", + system_modules: "none", + min_sdk_version: "29", + } + apex { + name: "myapex", + min_sdk_version: "29", + key: "myapex.key", + java_libs: ["bcp_lib1", "bcp_lib2"], + updatable: false, + } + `, + bootJars: []string{"bcp_lib1", "bcp_lib2"}, + modulesPackages: map[string][]string{ + "myapex": []string{ + "foo.bar", + }, + }, + }, + { + name: "Bootclasspath apex jar not satisfying allowed module packages on R.", + expectedError: `module "bcp_lib2" .* which is restricted because jars that are part of the myapex module may only allow these packages: foo.bar with min_sdk < T. Please jarjar or move code around.`, bp: ` java_library { name: "bcp_lib1", @@ -7372,6 +7500,7 @@ func TestApexPermittedPackagesRules(t *testing.T) { permitted_packages: ["foo.bar"], sdk_version: "none", system_modules: "none", + min_sdk_version: "30", } java_library { name: "bcp_lib2", @@ -7380,9 +7509,48 @@ func TestApexPermittedPackagesRules(t *testing.T) { permitted_packages: ["foo.bar", "bar.baz"], sdk_version: "none", system_modules: "none", + min_sdk_version: "30", } apex { name: "myapex", + min_sdk_version: "30", + key: "myapex.key", + java_libs: ["bcp_lib1", "bcp_lib2"], + updatable: false, + } + `, + bootJars: []string{"bcp_lib1", "bcp_lib2"}, + modulesPackages: map[string][]string{ + "myapex": []string{ + "foo.bar", + }, + }, + }, + { + name: "Bootclasspath apex jar >= T not satisfying Q/R/S allowed module packages.", + expectedError: "", + bp: ` + java_library { + name: "bcp_lib1", + srcs: ["lib1/src/*.java"], + apex_available: ["myapex"], + permitted_packages: ["foo.bar"], + sdk_version: "none", + system_modules: "none", + min_sdk_version: "current", + } + java_library { + name: "bcp_lib2", + srcs: ["lib2/src/*.java"], + apex_available: ["myapex"], + permitted_packages: ["foo.bar", "bar.baz"], + sdk_version: "none", + system_modules: "none", + min_sdk_version: "current", + } + apex { + name: "myapex", + min_sdk_version: "current", key: "myapex.key", java_libs: ["bcp_lib1", "bcp_lib2"], updatable: false, @@ -8390,6 +8558,184 @@ func TestAndroidMk_RequiredModules(t *testing.T) { ensureContains(t, androidMk, "LOCAL_REQUIRED_MODULES += otherapex") } +func TestSdkLibraryCanHaveHigherMinSdkVersion(t *testing.T) { + preparer := android.GroupFixturePreparers( + PrepareForTestWithApexBuildComponents, + prepareForTestWithMyapex, + java.PrepareForTestWithJavaSdkLibraryFiles, + java.PrepareForTestWithJavaDefaultModules, + android.PrepareForTestWithAndroidBuildComponents, + dexpreopt.FixtureSetApexBootJars("myapex:mybootclasspathlib"), + dexpreopt.FixtureSetApexSystemServerJars("myapex:mysystemserverclasspathlib"), + ) + + // Test java_sdk_library in bootclasspath_fragment may define higher min_sdk_version than the apex + t.Run("bootclasspath_fragment jar has higher min_sdk_version than apex", func(t *testing.T) { + preparer.RunTestWithBp(t, ` + apex { + name: "myapex", + key: "myapex.key", + bootclasspath_fragments: ["mybootclasspathfragment"], + min_sdk_version: "30", + updatable: false, + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + bootclasspath_fragment { + name: "mybootclasspathfragment", + contents: ["mybootclasspathlib"], + apex_available: ["myapex"], + } + + java_sdk_library { + name: "mybootclasspathlib", + srcs: ["mybootclasspathlib.java"], + apex_available: ["myapex"], + compile_dex: true, + unsafe_ignore_missing_latest_api: true, + min_sdk_version: "31", + static_libs: ["util"], + } + + java_library { + name: "util", + srcs: ["a.java"], + apex_available: ["myapex"], + min_sdk_version: "31", + static_libs: ["another_util"], + } + + java_library { + name: "another_util", + srcs: ["a.java"], + min_sdk_version: "31", + apex_available: ["myapex"], + } + `) + }) + + // Test java_sdk_library in systemserverclasspath_fragment may define higher min_sdk_version than the apex + t.Run("systemserverclasspath_fragment jar has higher min_sdk_version than apex", func(t *testing.T) { + preparer.RunTestWithBp(t, ` + apex { + name: "myapex", + key: "myapex.key", + systemserverclasspath_fragments: ["mysystemserverclasspathfragment"], + min_sdk_version: "30", + updatable: false, + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + systemserverclasspath_fragment { + name: "mysystemserverclasspathfragment", + contents: ["mysystemserverclasspathlib"], + apex_available: ["myapex"], + } + + java_sdk_library { + name: "mysystemserverclasspathlib", + srcs: ["mysystemserverclasspathlib.java"], + apex_available: ["myapex"], + compile_dex: true, + min_sdk_version: "32", + unsafe_ignore_missing_latest_api: true, + static_libs: ["util"], + } + + java_library { + name: "util", + srcs: ["a.java"], + apex_available: ["myapex"], + min_sdk_version: "31", + static_libs: ["another_util"], + } + + java_library { + name: "another_util", + srcs: ["a.java"], + min_sdk_version: "31", + apex_available: ["myapex"], + } + `) + }) + + t.Run("bootclasspath_fragment jar must set min_sdk_version", func(t *testing.T) { + preparer.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "mybootclasspathlib".*must set min_sdk_version`)). + RunTestWithBp(t, ` + apex { + name: "myapex", + key: "myapex.key", + bootclasspath_fragments: ["mybootclasspathfragment"], + min_sdk_version: "30", + updatable: false, + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + bootclasspath_fragment { + name: "mybootclasspathfragment", + contents: ["mybootclasspathlib"], + apex_available: ["myapex"], + } + + java_sdk_library { + name: "mybootclasspathlib", + srcs: ["mybootclasspathlib.java"], + apex_available: ["myapex"], + compile_dex: true, + unsafe_ignore_missing_latest_api: true, + } + `) + }) + + t.Run("systemserverclasspath_fragment jar must set min_sdk_version", func(t *testing.T) { + preparer.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "mysystemserverclasspathlib".*must set min_sdk_version`)). + RunTestWithBp(t, ` + apex { + name: "myapex", + key: "myapex.key", + systemserverclasspath_fragments: ["mysystemserverclasspathfragment"], + min_sdk_version: "30", + updatable: false, + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + systemserverclasspath_fragment { + name: "mysystemserverclasspathfragment", + contents: ["mysystemserverclasspathlib"], + apex_available: ["myapex"], + } + + java_sdk_library { + name: "mysystemserverclasspathlib", + srcs: ["mysystemserverclasspathlib.java"], + apex_available: ["myapex"], + compile_dex: true, + unsafe_ignore_missing_latest_api: true, + } + `) + }) +} + func TestMain(m *testing.M) { os.Exit(m.Run()) } diff --git a/apex/bootclasspath_fragment_test.go b/apex/bootclasspath_fragment_test.go index cb7d3d113..7ecf9b20f 100644 --- a/apex/bootclasspath_fragment_test.go +++ b/apex/bootclasspath_fragment_test.go @@ -21,6 +21,7 @@ import ( "testing" "android/soong/android" + "android/soong/dexpreopt" "android/soong/java" "github.com/google/blueprint/proptools" @@ -35,11 +36,14 @@ var prepareForTestWithBootclasspathFragment = android.GroupFixturePreparers( ) // Some additional files needed for the art apex. -var prepareForTestWithArtApex = android.FixtureMergeMockFs(android.MockFS{ - "com.android.art.avbpubkey": nil, - "com.android.art.pem": nil, - "system/sepolicy/apex/com.android.art-file_contexts": nil, -}) +var prepareForTestWithArtApex = android.GroupFixturePreparers( + android.FixtureMergeMockFs(android.MockFS{ + "com.android.art.avbpubkey": nil, + "com.android.art.pem": nil, + "system/sepolicy/apex/com.android.art-file_contexts": nil, + }), + dexpreopt.FixtureSetBootImageProfiles("art/build/boot/boot-image-profile.txt"), +) func TestBootclasspathFragments(t *testing.T) { result := android.GroupFixturePreparers( @@ -408,6 +412,7 @@ func TestBootclasspathFragmentInArtApex(t *testing.T) { ).RunTest(t) ensureExactContents(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{ + "etc/boot-image.prof", "etc/classpaths/bootclasspath.pb", "javalib/arm/boot.art", "javalib/arm/boot.oat", @@ -451,6 +456,7 @@ func TestBootclasspathFragmentInArtApex(t *testing.T) { ).RunTest(t) ensureExactContents(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{ + "etc/boot-image.prof", "etc/classpaths/bootclasspath.pb", "javalib/arm/boot.art", "javalib/arm/boot.oat", @@ -542,7 +548,7 @@ func TestBootclasspathFragmentInArtApex(t *testing.T) { } func TestBootclasspathFragmentInPrebuiltArtApex(t *testing.T) { - result := android.GroupFixturePreparers( + preparers := android.GroupFixturePreparers( prepareForTestWithBootclasspathFragment, prepareForTestWithArtApex, @@ -553,7 +559,9 @@ func TestBootclasspathFragmentInPrebuiltArtApex(t *testing.T) { // Configure some libraries in the art bootclasspath_fragment. java.FixtureConfigureBootJars("com.android.art:foo", "com.android.art:bar"), - ).RunTestWithBp(t, ` + ) + + bp := ` prebuilt_apex { name: "com.android.art", arch: { @@ -599,22 +607,45 @@ func TestBootclasspathFragmentInPrebuiltArtApex(t *testing.T) { all_flags: "mybootclasspathfragment/all-flags.csv", }, } - `) - java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art", []string{ - `com.android.art.apex.selector`, - `prebuilt_mybootclasspathfragment`, - }) + // A prebuilt apex with the same apex_name that shouldn't interfere when it isn't enabled. + prebuilt_apex { + name: "com.mycompany.android.art", + apex_name: "com.android.art", + %s + src: "com.mycompany.android.art.apex", + exported_bootclasspath_fragments: ["mybootclasspathfragment"], + } + ` + + t.Run("disabled alternative APEX", func(t *testing.T) { + result := preparers.RunTestWithBp(t, fmt.Sprintf(bp, "enabled: false,")) - java.CheckModuleDependencies(t, result.TestContext, "mybootclasspathfragment", "android_common_com.android.art", []string{ - `com.android.art.deapexer`, - `dex2oatd`, - `prebuilt_bar`, - `prebuilt_foo`, + java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art", []string{ + `com.android.art.apex.selector`, + `prebuilt_mybootclasspathfragment`, + }) + + java.CheckModuleDependencies(t, result.TestContext, "mybootclasspathfragment", "android_common_com.android.art", []string{ + `com.android.art.deapexer`, + `dex2oatd`, + `prebuilt_bar`, + `prebuilt_foo`, + }) + + module := result.ModuleForTests("mybootclasspathfragment", "android_common_com.android.art") + checkCopiesToPredefinedLocationForArt(t, result.Config, module, "bar", "foo") + + // Check that the right deapexer module was chosen for a boot image. + param := module.Output("out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art") + android.AssertStringDoesContain(t, "didn't find the expected deapexer in the input path", param.Input.String(), "/com.android.art.deapexer") }) - module := result.ModuleForTests("mybootclasspathfragment", "android_common_com.android.art") - checkCopiesToPredefinedLocationForArt(t, result.Config, module, "bar", "foo") + t.Run("enabled alternative APEX", func(t *testing.T) { + preparers.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern( + "Multiple installable prebuilt APEXes provide ambiguous deapexers: com.android.art and com.mycompany.android.art")). + RunTestWithBp(t, fmt.Sprintf(bp, "")) + }) } // checkCopiesToPredefinedLocationForArt checks that the supplied modules are copied to the diff --git a/apex/builder.go b/apex/builder.go index 0880e2bab..ea25537ca 100644 --- a/apex/builder.go +++ b/apex/builder.go @@ -72,19 +72,6 @@ func init() { } var ( - // Create a canned fs config file where all files and directories are - // by default set to (uid/gid/mode) = (1000/1000/0644) - // TODO(b/113082813) make this configurable using config.fs syntax - generateFsConfig = pctx.StaticRule("generateFsConfig", blueprint.RuleParams{ - Command: `( set -e; echo '/ 1000 1000 0755' ` + - `&& for i in ${ro_paths}; do echo "/$$i 1000 1000 0644"; done ` + - `&& for i in ${exec_paths}; do echo "/$$i 0 2000 0755"; done ` + - `&& ( tr ' ' '\n' <${out}.apklist | for i in ${apk_paths}; do read apk; echo "/$$i 0 2000 0755"; zipinfo -1 $$apk | sed "s:\(.*\):/$$i/\1 1000 1000 0644:"; done ) ) > ${out}`, - Description: "fs_config ${out}", - Rspfile: "$out.apklist", - RspfileContent: "$in", - }, "ro_paths", "exec_paths", "apk_paths") - apexManifestRule = pctx.StaticRule("apexManifestRule", blueprint.RuleParams{ Command: `rm -f $out && ${jsonmodify} $in ` + `-a provideNativeLibs ${provideNativeLibs} ` + @@ -434,7 +421,10 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { // Avoid creating duplicate build rules for multi-installed APEXes. if proptools.BoolDefault(a.properties.Multi_install_skip_symbol_files, false) { installSymbolFiles = false + } + // set of dependency module:location mappings + installMapSet := make(map[string]bool) // TODO(jiyong): use the RuleBuilder var copyCommands []string @@ -442,7 +432,6 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { pathWhenActivated := android.PathForModuleInPartitionInstall(ctx, "apex", apexName) for _, fi := range a.filesInfo { destPath := imageDir.Join(ctx, fi.path()).String() - var installedPath android.InstallPath // Prepare the destination path destPathDir := filepath.Dir(destPath) if fi.class == appSet { @@ -450,6 +439,8 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { } copyCommands = append(copyCommands, "mkdir -p "+destPathDir) + installMapPath := fi.builtFile + // Copy the built file to the directory. But if the symlink optimization is turned // on, place a symlink to the corresponding file in /system partition instead. if a.linkToSystemLib && fi.transitiveDep && fi.availableToPlatform() { @@ -457,6 +448,7 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { pathOnDevice := filepath.Join("/system", fi.path()) copyCommands = append(copyCommands, "ln -sfn "+pathOnDevice+" "+destPath) } else { + var installedPath android.InstallPath if fi.class == appSet { copyCommands = append(copyCommands, fmt.Sprintf("unzip -qDD -d %s %s", destPathDir, @@ -475,17 +467,19 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { if installSymbolFiles { implicitInputs = append(implicitInputs, installedPath) } - } - // Create additional symlinks pointing the file inside the APEX (if any). Note that - // this is independent from the symlink optimization. - for _, symlinkPath := range fi.symlinkPaths() { - symlinkDest := imageDir.Join(ctx, symlinkPath).String() - copyCommands = append(copyCommands, "ln -sfn "+filepath.Base(destPath)+" "+symlinkDest) - if installSymbolFiles { - installedSymlink := ctx.InstallSymlink(pathWhenActivated.Join(ctx, filepath.Dir(symlinkPath)), filepath.Base(symlinkPath), installedPath) - implicitInputs = append(implicitInputs, installedSymlink) + // Create additional symlinks pointing the file inside the APEX (if any). Note that + // this is independent from the symlink optimization. + for _, symlinkPath := range fi.symlinkPaths() { + symlinkDest := imageDir.Join(ctx, symlinkPath).String() + copyCommands = append(copyCommands, "ln -sfn "+filepath.Base(destPath)+" "+symlinkDest) + if installSymbolFiles { + installedSymlink := ctx.InstallSymlink(pathWhenActivated.Join(ctx, filepath.Dir(symlinkPath)), filepath.Base(symlinkPath), installedPath) + implicitInputs = append(implicitInputs, installedSymlink) + } } + + installMapPath = installedPath } // Copy the test files (if any) @@ -502,6 +496,8 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { copyCommands = append(copyCommands, "cp -f "+d.SrcPath.String()+" "+dataDest) implicitInputs = append(implicitInputs, d.SrcPath) } + + installMapSet[installMapPath.String()+":"+fi.installDir+"/"+fi.builtFile.Base()] = true } implicitInputs = append(implicitInputs, a.manifestPbOut) if installSymbolFiles { @@ -510,6 +506,12 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { implicitInputs = append(implicitInputs, installedManifest, installedKey) } + if len(installMapSet) > 0 { + var installs []string + installs = append(installs, android.SortedStringKeys(installMapSet)...) + a.SetLicenseInstallMap(installs) + } + //////////////////////////////////////////////////////////////////////////////////////////// // Step 1.a: Write the list of files in this APEX to a txt file and compare it against // the allowed list given via the allowed_files property. Build fails when the two lists @@ -568,55 +570,11 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { // Figure out if need to compress apex. compressionEnabled := ctx.Config().CompressedApex() && proptools.BoolDefault(a.properties.Compressible, false) && !a.testApex && !ctx.Config().UnbundledBuildApps() if apexType == imageApex { + //////////////////////////////////////////////////////////////////////////////////// // Step 2: create canned_fs_config which encodes filemode,uid,gid of each files // in this APEX. The file will be used by apexer in later steps. - // TODO(jiyong): make this as a function - // TODO(jiyong): use the RuleBuilder - var readOnlyPaths = []string{"apex_manifest.json", "apex_manifest.pb"} - var executablePaths []string // this also includes dirs - var extractedAppSetPaths android.Paths - var extractedAppSetDirs []string - for _, f := range a.filesInfo { - pathInApex := f.path() - if f.installDir == "bin" || strings.HasPrefix(f.installDir, "bin/") { - executablePaths = append(executablePaths, pathInApex) - for _, d := range f.dataPaths { - readOnlyPaths = append(readOnlyPaths, filepath.Join(f.installDir, d.RelativeInstallPath, d.SrcPath.Rel())) - } - for _, s := range f.symlinks { - executablePaths = append(executablePaths, filepath.Join(f.installDir, s)) - } - } else if f.class == appSet { - extractedAppSetPaths = append(extractedAppSetPaths, f.builtFile) - extractedAppSetDirs = append(extractedAppSetDirs, f.installDir) - } else { - readOnlyPaths = append(readOnlyPaths, pathInApex) - } - dir := f.installDir - for !android.InList(dir, executablePaths) && dir != "" { - executablePaths = append(executablePaths, dir) - dir, _ = filepath.Split(dir) // move up to the parent - if len(dir) > 0 { - // remove trailing slash - dir = dir[:len(dir)-1] - } - } - } - sort.Strings(readOnlyPaths) - sort.Strings(executablePaths) - cannedFsConfig := android.PathForModuleOut(ctx, "canned_fs_config") - ctx.Build(pctx, android.BuildParams{ - Rule: generateFsConfig, - Output: cannedFsConfig, - Description: "generate fs config", - Inputs: extractedAppSetPaths, - Args: map[string]string{ - "ro_paths": strings.Join(readOnlyPaths, " "), - "exec_paths": strings.Join(executablePaths, " "), - "apk_paths": strings.Join(extractedAppSetDirs, " "), - }, - }) + cannedFsConfig := a.buildCannedFsConfig(ctx) implicitInputs = append(implicitInputs, cannedFsConfig) //////////////////////////////////////////////////////////////////////////////////// @@ -1057,3 +1015,65 @@ func (a *apexBundle) buildLintReports(ctx android.ModuleContext) { a.lintReports = java.BuildModuleLintReportZips(ctx, depSetsBuilder.Build()) } + +func (a *apexBundle) buildCannedFsConfig(ctx android.ModuleContext) android.OutputPath { + var readOnlyPaths = []string{"apex_manifest.json", "apex_manifest.pb"} + var executablePaths []string // this also includes dirs + var appSetDirs []string + appSetFiles := make(map[string]android.Path) + for _, f := range a.filesInfo { + pathInApex := f.path() + if f.installDir == "bin" || strings.HasPrefix(f.installDir, "bin/") { + executablePaths = append(executablePaths, pathInApex) + for _, d := range f.dataPaths { + readOnlyPaths = append(readOnlyPaths, filepath.Join(f.installDir, d.RelativeInstallPath, d.SrcPath.Rel())) + } + for _, s := range f.symlinks { + executablePaths = append(executablePaths, filepath.Join(f.installDir, s)) + } + } else if f.class == appSet { + appSetDirs = append(appSetDirs, f.installDir) + appSetFiles[f.installDir] = f.builtFile + } else { + readOnlyPaths = append(readOnlyPaths, pathInApex) + } + dir := f.installDir + for !android.InList(dir, executablePaths) && dir != "" { + executablePaths = append(executablePaths, dir) + dir, _ = filepath.Split(dir) // move up to the parent + if len(dir) > 0 { + // remove trailing slash + dir = dir[:len(dir)-1] + } + } + } + sort.Strings(readOnlyPaths) + sort.Strings(executablePaths) + sort.Strings(appSetDirs) + + cannedFsConfig := android.PathForModuleOut(ctx, "canned_fs_config") + builder := android.NewRuleBuilder(pctx, ctx) + cmd := builder.Command() + cmd.Text("(") + cmd.Text("echo '/ 1000 1000 0755';") + for _, p := range readOnlyPaths { + cmd.Textf("echo '/%s 1000 1000 0644';", p) + } + for _, p := range executablePaths { + cmd.Textf("echo '/%s 0 2000 0755';", p) + } + for _, dir := range appSetDirs { + cmd.Textf("echo '/%s 0 2000 0755';", dir) + file := appSetFiles[dir] + cmd.Text("zipinfo -1").Input(file).Textf(`| sed "s:\(.*\):/%s/\1 1000 1000 0644:";`, dir) + } + // Custom fs_config is "appended" to the last so that entries from the file are preferred + // over default ones set above. + if a.properties.Canned_fs_config != nil { + cmd.Text("cat").Input(android.PathForModuleSrc(ctx, *a.properties.Canned_fs_config)) + } + cmd.Text(")").FlagWithOutput("> ", cannedFsConfig) + builder.Build("generateFsConfig", fmt.Sprintf("Generating canned fs config for %s", a.BaseModuleName())) + + return cannedFsConfig.OutputPath +} diff --git a/apex/key.go b/apex/key.go index 259060f3b..829410ed2 100644 --- a/apex/key.go +++ b/apex/key.go @@ -34,8 +34,6 @@ func init() { func registerApexKeyBuildComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("apex_key", ApexKeyFactory) ctx.RegisterSingletonType("apex_keys_text", apexKeysTextFactory) - - android.RegisterBp2BuildMutator("apex_key", ApexKeyBp2Build) } type apexKey struct { @@ -209,20 +207,9 @@ type bazelApexKeyAttributes struct { Private_key bazel.LabelAttribute } -func ApexKeyBp2Build(ctx android.TopDownMutatorContext) { - module, ok := ctx.Module().(*apexKey) - if !ok { - // Not an APEX key - return - } - if !module.ConvertWithBp2build(ctx) { - return - } - if ctx.ModuleType() != "apex_key" { - return - } - - apexKeyBp2BuildInternal(ctx, module) +// ConvertWithBp2build performs conversion apexKey for bp2build +func (m *apexKey) ConvertWithBp2build(ctx android.TopDownMutatorContext) { + apexKeyBp2BuildInternal(ctx, m) } func apexKeyBp2BuildInternal(ctx android.TopDownMutatorContext, module *apexKey) { diff --git a/apex/prebuilt.go b/apex/prebuilt.go index 84bdcddf7..254c90ec0 100644 --- a/apex/prebuilt.go +++ b/apex/prebuilt.go @@ -965,7 +965,7 @@ func (a *ApexSet) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.installDir = android.PathForModuleInstall(ctx, "apex") if a.installable() { - ctx.InstallFile(a.installDir, a.installFilename, a.outputApex) + a.installedFile = ctx.InstallFile(a.installDir, a.installFilename, a.outputApex) } // in case that apex_set replaces source apex (using prefer: prop) diff --git a/apex/systemserver_classpath_fragment_test.go b/apex/systemserver_classpath_fragment_test.go index 412fa0e37..d03766448 100644 --- a/apex/systemserver_classpath_fragment_test.go +++ b/apex/systemserver_classpath_fragment_test.go @@ -231,3 +231,95 @@ func TestPrebuiltSystemserverclasspathFragmentContents(t *testing.T) { `prebuilt_foo`, }) } + +func TestSystemserverclasspathFragmentStandaloneContents(t *testing.T) { + result := android.GroupFixturePreparers( + prepareForTestWithSystemserverclasspathFragment, + prepareForTestWithMyapex, + dexpreopt.FixtureSetApexStandaloneSystemServerJars("myapex:foo"), + ).RunTestWithBp(t, ` + apex { + name: "myapex", + key: "myapex.key", + systemserverclasspath_fragments: [ + "mysystemserverclasspathfragment", + ], + updatable: false, + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + java_library { + name: "foo", + srcs: ["b.java"], + installable: true, + apex_available: [ + "myapex", + ], + } + + systemserverclasspath_fragment { + name: "mysystemserverclasspathfragment", + standalone_contents: [ + "foo", + ], + apex_available: [ + "myapex", + ], + } + `) + + ensureExactContents(t, result.TestContext, "myapex", "android_common_myapex_image", []string{ + "etc/classpaths/systemserverclasspath.pb", + "javalib/foo.jar", + }) +} + +func TestPrebuiltStandaloneSystemserverclasspathFragmentContents(t *testing.T) { + result := android.GroupFixturePreparers( + prepareForTestWithSystemserverclasspathFragment, + prepareForTestWithMyapex, + dexpreopt.FixtureSetApexStandaloneSystemServerJars("myapex:foo"), + ).RunTestWithBp(t, ` + prebuilt_apex { + name: "myapex", + arch: { + arm64: { + src: "myapex-arm64.apex", + }, + arm: { + src: "myapex-arm.apex", + }, + }, + exported_systemserverclasspath_fragments: ["mysystemserverclasspathfragment"], + } + + java_import { + name: "foo", + jars: ["foo.jar"], + apex_available: [ + "myapex", + ], + } + + prebuilt_systemserverclasspath_fragment { + name: "mysystemserverclasspathfragment", + prefer: true, + standalone_contents: [ + "foo", + ], + apex_available: [ + "myapex", + ], + } + `) + + java.CheckModuleDependencies(t, result.TestContext, "mysystemserverclasspathfragment", "android_common_myapex", []string{ + `myapex.deapexer`, + `prebuilt_foo`, + }) +} diff --git a/apex/vndk.go b/apex/vndk.go index cf525a874..ef3e5e1c5 100644 --- a/apex/vndk.go +++ b/apex/vndk.go @@ -140,21 +140,5 @@ func makeCompatSymlinks(name string, ctx android.ModuleContext, primaryApex bool addSymlink("/apex/com.android.i18n/etc/icu", dir, "icu") } - // TODO(b/124106384): Clean up compat symlinks for ART binaries. - if name == "com.android.art" { - dir := android.PathForModuleInPartitionInstall(ctx, "system", "bin") - addSymlink("/apex/com.android.art/bin/dalvikvm", dir, "dalvikvm") - dex2oat := "dex2oat32" - if ctx.Config().Android64() { - dex2oat = "dex2oat64" - } - addSymlink("/apex/com.android.art/bin/"+dex2oat, dir, "dex2oat") - } else if name == "com.android.art" || strings.HasPrefix(name, "com.android.art.") { - dir := android.PathForModuleInPartitionInstall(ctx, "system", "bin") - symlinks = append(symlinks, - dir.Join(ctx, "dalvikvm"), - dir.Join(ctx, "dex2oat")) - } - return symlinks } diff --git a/bazel/cquery/request_type.go b/bazel/cquery/request_type.go index 0bd71c63a..41f98862c 100644 --- a/bazel/cquery/request_type.go +++ b/bazel/cquery/request_type.go @@ -17,6 +17,7 @@ type CcInfo struct { CcStaticLibraryFiles []string Includes []string SystemIncludes []string + Headers []string // Archives owned by the current target (not by its dependencies). These will // be a subset of OutputFiles. (or static libraries, this will be equal to OutputFiles, // but general cc_library will also have dynamic libraries in output files). @@ -105,6 +106,7 @@ cc_info = providers(target)["CcInfo"] includes = cc_info.compilation_context.includes.to_list() system_includes = cc_info.compilation_context.system_includes.to_list() +headers = [f.path for f in cc_info.compilation_context.headers.to_list()] ccObjectFiles = [] staticLibraries = [] @@ -145,6 +147,7 @@ returns = [ ccObjectFiles, includes, system_includes, + headers, rootStaticArchives, rootDynamicLibraries, [toc_file] @@ -161,7 +164,7 @@ func (g getCcInfoType) ParseResult(rawString string) (CcInfo, error) { var ccObjects []string splitString := strings.Split(rawString, "|") - if expectedLen := 8; len(splitString) != expectedLen { + if expectedLen := 9; len(splitString) != expectedLen { return CcInfo{}, fmt.Errorf("Expected %d items, got %q", expectedLen, splitString) } outputFilesString := splitString[0] @@ -172,15 +175,17 @@ func (g getCcInfoType) ParseResult(rawString string) (CcInfo, error) { ccObjects = splitOrEmpty(ccObjectsString, ", ") includes := splitOrEmpty(splitString[3], ", ") systemIncludes := splitOrEmpty(splitString[4], ", ") - rootStaticArchives := splitOrEmpty(splitString[5], ", ") - rootDynamicLibraries := splitOrEmpty(splitString[6], ", ") - tocFile := splitString[7] // NOTE: Will be the empty string if there wasn't + headers := splitOrEmpty(splitString[5], ", ") + rootStaticArchives := splitOrEmpty(splitString[6], ", ") + rootDynamicLibraries := splitOrEmpty(splitString[7], ", ") + tocFile := splitString[8] // NOTE: Will be the empty string if there wasn't return CcInfo{ OutputFiles: outputFiles, CcObjectFiles: ccObjects, CcStaticLibraryFiles: ccStaticLibraries, Includes: includes, SystemIncludes: systemIncludes, + Headers: headers, RootStaticArchives: rootStaticArchives, RootDynamicLibraries: rootDynamicLibraries, TocFile: tocFile, diff --git a/bazel/cquery/request_type_test.go b/bazel/cquery/request_type_test.go index 34d083226..d3bcb45f4 100644 --- a/bazel/cquery/request_type_test.go +++ b/bazel/cquery/request_type_test.go @@ -71,13 +71,14 @@ func TestGetCcInfoParseResults(t *testing.T) { }{ { description: "no result", - input: "|||||||", + input: "||||||||", expectedOutput: CcInfo{ OutputFiles: []string{}, CcObjectFiles: []string{}, CcStaticLibraryFiles: []string{}, Includes: []string{}, SystemIncludes: []string{}, + Headers: []string{}, RootStaticArchives: []string{}, RootDynamicLibraries: []string{}, TocFile: "", @@ -85,13 +86,14 @@ func TestGetCcInfoParseResults(t *testing.T) { }, { description: "only output", - input: "test|||||||", + input: "test||||||||", expectedOutput: CcInfo{ OutputFiles: []string{"test"}, CcObjectFiles: []string{}, CcStaticLibraryFiles: []string{}, Includes: []string{}, SystemIncludes: []string{}, + Headers: []string{}, RootStaticArchives: []string{}, RootDynamicLibraries: []string{}, TocFile: "", @@ -99,13 +101,14 @@ func TestGetCcInfoParseResults(t *testing.T) { }, { description: "all items set", - input: "out1, out2|static_lib1, static_lib2|object1, object2|., dir/subdir|system/dir, system/other/dir|rootstaticarchive1|rootdynamiclibrary1|lib.so.toc", + input: "out1, out2|static_lib1, static_lib2|object1, object2|., dir/subdir|system/dir, system/other/dir|dir/subdir/hdr.h|rootstaticarchive1|rootdynamiclibrary1|lib.so.toc", expectedOutput: CcInfo{ OutputFiles: []string{"out1", "out2"}, CcObjectFiles: []string{"object1", "object2"}, CcStaticLibraryFiles: []string{"static_lib1", "static_lib2"}, Includes: []string{".", "dir/subdir"}, SystemIncludes: []string{"system/dir", "system/other/dir"}, + Headers: []string{"dir/subdir/hdr.h"}, RootStaticArchives: []string{"rootstaticarchive1"}, RootDynamicLibraries: []string{"rootdynamiclibrary1"}, TocFile: "lib.so.toc", @@ -115,13 +118,13 @@ func TestGetCcInfoParseResults(t *testing.T) { description: "too few result splits", input: "|", expectedOutput: CcInfo{}, - expectedErrorMessage: fmt.Sprintf("Expected %d items, got %q", 8, []string{"", ""}), + expectedErrorMessage: fmt.Sprintf("Expected %d items, got %q", 9, []string{"", ""}), }, { description: "too many result splits", - input: strings.Repeat("|", 8), + input: strings.Repeat("|", 50), expectedOutput: CcInfo{}, - expectedErrorMessage: fmt.Sprintf("Expected %d items, got %q", 8, make([]string, 9)), + expectedErrorMessage: fmt.Sprintf("Expected %d items, got %q", 9, make([]string, 51)), }, } for _, tc := range testCases { diff --git a/bazel/properties.go b/bazel/properties.go index b370bbfb2..76be0581b 100644 --- a/bazel/properties.go +++ b/bazel/properties.go @@ -107,6 +107,14 @@ func (ll *LabelList) uniqueParentDirectories() []string { return dirs } +// Add inserts the label Label at the end of the LabelList. +func (ll *LabelList) Add(label *Label) { + if label == nil { + return + } + ll.Includes = append(ll.Includes, *label) +} + // Append appends the fields of other labelList to the corresponding fields of ll. func (ll *LabelList) Append(other LabelList) { if len(ll.Includes) > 0 || len(other.Includes) > 0 { @@ -366,9 +374,23 @@ func (ba *BoolAttribute) SortedConfigurationAxes() []ConfigurationAxis { // labelListSelectValues supports config-specific label_list typed Bazel attribute values. type labelListSelectValues map[string]LabelList -func (ll labelListSelectValues) appendSelects(other labelListSelectValues) { +func (ll labelListSelectValues) addSelects(label labelSelectValues) { + for k, v := range label { + if label == nil { + continue + } + l := ll[k] + (&l).Add(v) + ll[k] = l + } +} + +func (ll labelListSelectValues) appendSelects(other labelListSelectValues, forceSpecifyEmptyList bool) { for k, v := range other { l := ll[k] + if forceSpecifyEmptyList && l.IsNil() && !v.IsNil() { + l.Includes = []Label{} + } (&l).Append(v) ll[k] = l } @@ -424,17 +446,22 @@ func (cll configurableLabelLists) setValueForAxis(axis ConfigurationAxis, config cll[axis][config] = list } -func (cll configurableLabelLists) Append(other configurableLabelLists) { +func (cll configurableLabelLists) Append(other configurableLabelLists, forceSpecifyEmptyList bool) { for axis, otherSelects := range other { selects := cll[axis] if selects == nil { selects = make(labelListSelectValues, len(otherSelects)) } - selects.appendSelects(otherSelects) + selects.appendSelects(otherSelects, forceSpecifyEmptyList) cll[axis] = selects } } +func (lla *LabelListAttribute) Clone() *LabelListAttribute { + result := &LabelListAttribute{ForceSpecifyEmptyList: lla.ForceSpecifyEmptyList} + return result.Append(*lla) +} + // MakeLabelListAttribute initializes a LabelListAttribute with the non-arch specific value. func MakeLabelListAttribute(value LabelList) LabelListAttribute { return LabelListAttribute{ @@ -488,16 +515,37 @@ func (lla *LabelListAttribute) SortedConfigurationAxes() []ConfigurationAxis { } // Append all values, including os and arch specific ones, from another -// LabelListAttribute to this LabelListAttribute. -func (lla *LabelListAttribute) Append(other LabelListAttribute) { - if lla.ForceSpecifyEmptyList && !other.Value.IsNil() { +// LabelListAttribute to this LabelListAttribute. Returns this LabelListAttribute. +func (lla *LabelListAttribute) Append(other LabelListAttribute) *LabelListAttribute { + forceSpecifyEmptyList := lla.ForceSpecifyEmptyList || other.ForceSpecifyEmptyList + if forceSpecifyEmptyList && lla.Value.IsNil() && !other.Value.IsNil() { lla.Value.Includes = []Label{} } lla.Value.Append(other.Value) if lla.ConfigurableValues == nil { lla.ConfigurableValues = make(configurableLabelLists) } - lla.ConfigurableValues.Append(other.ConfigurableValues) + lla.ConfigurableValues.Append(other.ConfigurableValues, forceSpecifyEmptyList) + return lla +} + +// Add inserts the labels for each axis of LabelAttribute at the end of corresponding axis's +// LabelList within the LabelListAttribute +func (lla *LabelListAttribute) Add(label *LabelAttribute) { + if label == nil { + return + } + + lla.Value.Add(label.Value) + if lla.ConfigurableValues == nil && label.ConfigurableValues != nil { + lla.ConfigurableValues = make(configurableLabelLists) + } + for axis, _ := range label.ConfigurableValues { + if _, exists := lla.ConfigurableValues[axis]; !exists { + lla.ConfigurableValues[axis] = make(labelListSelectValues) + } + lla.ConfigurableValues[axis].addSelects(label.ConfigurableValues[axis]) + } } // HasConfigurableValues returns true if the attribute contains axis-specific label list values. @@ -566,7 +614,7 @@ type OtherModuleContext interface { // LabelMapper is a function that takes a OtherModuleContext and returns a (potentially changed) // label and whether it was changed. -type LabelMapper func(OtherModuleContext, string) (string, bool) +type LabelMapper func(OtherModuleContext, Label) (string, bool) // LabelPartition contains descriptions of a partition for labels type LabelPartition struct { @@ -588,7 +636,7 @@ type LabelPartitions map[string]LabelPartition // not. func (lf LabelPartition) filter(ctx OtherModuleContext, label Label) *Label { if lf.LabelMapper != nil { - if newLabel, changed := lf.LabelMapper(ctx, label.Label); changed { + if newLabel, changed := lf.LabelMapper(ctx, label); changed { return &Label{newLabel, label.OriginalModuleName} } } @@ -757,12 +805,18 @@ func (sla StringListAttribute) HasConfigurableValues() bool { // Append appends all values, including os and arch specific ones, from another // StringListAttribute to this StringListAttribute -func (sla *StringListAttribute) Append(other StringListAttribute) { +func (sla *StringListAttribute) Append(other StringListAttribute) *StringListAttribute { sla.Value = append(sla.Value, other.Value...) if sla.ConfigurableValues == nil { sla.ConfigurableValues = make(configurableStringLists) } sla.ConfigurableValues.Append(other.ConfigurableValues) + return sla +} + +func (sla *StringListAttribute) Clone() *StringListAttribute { + result := &StringListAttribute{} + return result.Append(*sla) } // SetSelectValue set a value for a bazel select for the given axis, config and value. diff --git a/bazel/properties_test.go b/bazel/properties_test.go index 7a7d6f3b8..c7f977678 100644 --- a/bazel/properties_test.go +++ b/bazel/properties_test.go @@ -313,16 +313,16 @@ func TestResolveExcludes(t *testing.T) { // labelAddSuffixForTypeMapper returns a LabelMapper that adds suffix to label name for modules of // typ func labelAddSuffixForTypeMapper(suffix, typ string) LabelMapper { - return func(omc OtherModuleContext, label string) (string, bool) { - m, ok := omc.ModuleFromName(label) + return func(omc OtherModuleContext, label Label) (string, bool) { + m, ok := omc.ModuleFromName(label.Label) if !ok { - return label, false + return label.Label, false } mTyp := omc.OtherModuleType(m) if typ == mTyp { - return label + suffix, true + return label.Label + suffix, true } - return label, false + return label.Label, false } } diff --git a/bp2build/Android.bp b/bp2build/Android.bp index 9b66354b1..ae0fb11a5 100644 --- a/bp2build/Android.bp +++ b/bp2build/Android.bp @@ -19,6 +19,7 @@ bootstrap_go_package { deps: [ "soong-android", "soong-android-soongconfig", + "soong-shared", "soong-apex", "soong-bazel", "soong-cc", @@ -27,18 +28,21 @@ bootstrap_go_package { "soong-genrule", "soong-python", "soong-sh", + "soong-ui-metrics", ], testSrcs: [ "android_app_certificate_conversion_test.go", + "android_app_conversion_test.go", "apex_conversion_test.go", "apex_key_conversion_test.go", "build_conversion_test.go", "bzl_conversion_test.go", + "cc_binary_conversion_test.go", "cc_genrule_conversion_test.go", "cc_library_conversion_test.go", "cc_library_headers_conversion_test.go", - "cc_library_static_conversion_test.go", "cc_library_shared_conversion_test.go", + "cc_library_static_conversion_test.go", "cc_object_conversion_test.go", "conversion_test.go", "filegroup_conversion_test.go", @@ -48,6 +52,7 @@ bootstrap_go_package { "python_binary_conversion_test.go", "python_library_conversion_test.go", "sh_conversion_test.go", + "soong_config_module_type_conversion_test.go", "testing.go", ], pluginFor: [ diff --git a/bp2build/android_app_certificate_conversion_test.go b/bp2build/android_app_certificate_conversion_test.go index 6a53b00da..035a3529e 100644 --- a/bp2build/android_app_certificate_conversion_test.go +++ b/bp2build/android_app_certificate_conversion_test.go @@ -31,11 +31,10 @@ func registerAndroidAppCertificateModuleTypes(ctx android.RegistrationContext) { func TestAndroidAppCertificateSimple(t *testing.T) { runAndroidAppCertificateTestCase(t, bp2buildTestCase{ - description: "Android app certificate - simple example", - moduleTypeUnderTest: "android_app_certificate", - moduleTypeUnderTestFactory: java.AndroidAppCertificateFactory, - moduleTypeUnderTestBp2BuildMutator: java.AndroidAppCertificateBp2Build, - filesystem: map[string]string{}, + description: "Android app certificate - simple example", + moduleTypeUnderTest: "android_app_certificate", + moduleTypeUnderTestFactory: java.AndroidAppCertificateFactory, + filesystem: map[string]string{}, blueprint: ` android_app_certificate { name: "com.android.apogee.cert", diff --git a/bp2build/android_app_conversion_test.go b/bp2build/android_app_conversion_test.go new file mode 100644 index 000000000..153817b08 --- /dev/null +++ b/bp2build/android_app_conversion_test.go @@ -0,0 +1,90 @@ +// Copyright 2021 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package bp2build + +import ( + "android/soong/android" + "android/soong/java" + + "testing" +) + +func runAndroidAppTestCase(t *testing.T, tc bp2buildTestCase) { + t.Helper() + runBp2BuildTestCase(t, registerAndroidAppModuleTypes, tc) +} + +func registerAndroidAppModuleTypes(ctx android.RegistrationContext) { +} + +func TestMinimalAndroidApp(t *testing.T) { + runAndroidAppTestCase(t, bp2buildTestCase{ + description: "Android app - simple example", + moduleTypeUnderTest: "android_app", + moduleTypeUnderTestFactory: java.AndroidAppFactory, + filesystem: map[string]string{ + "app.java": "", + "res/res.png": "", + "AndroidManifest.xml": "", + }, + blueprint: ` +android_app { + name: "TestApp", + srcs: ["app.java"], + sdk_version: "current", +} +`, + expectedBazelTargets: []string{ + makeBazelTarget("android_binary", "TestApp", attrNameToString{ + "srcs": `["app.java"]`, + "manifest": `"AndroidManifest.xml"`, + "resource_files": `["res/res.png"]`, + }), + }}) +} + +func TestAndroidAppAllSupportedFields(t *testing.T) { + runAndroidAppTestCase(t, bp2buildTestCase{ + description: "Android app - all supported fields", + moduleTypeUnderTest: "android_app", + moduleTypeUnderTestFactory: java.AndroidAppFactory, + filesystem: map[string]string{ + "app.java": "", + "resa/res.png": "", + "resb/res.png": "", + "manifest/AndroidManifest.xml": "", + }, + blueprint: ` +android_app { + name: "TestApp", + srcs: ["app.java"], + sdk_version: "current", + package_name: "com.google", + resource_dirs: ["resa", "resb"], + manifest: "manifest/AndroidManifest.xml", +} +`, + expectedBazelTargets: []string{ + makeBazelTarget("android_binary", "TestApp", attrNameToString{ + "srcs": `["app.java"]`, + "manifest": `"manifest/AndroidManifest.xml"`, + "resource_files": `[ + "resa/res.png", + "resb/res.png", + ]`, + "custom_package": `"com.google"`, + }), + }}) +} diff --git a/bp2build/apex_conversion_test.go b/bp2build/apex_conversion_test.go index 1a23db700..a3825e663 100644 --- a/bp2build/apex_conversion_test.go +++ b/bp2build/apex_conversion_test.go @@ -19,6 +19,7 @@ import ( "android/soong/apex" "android/soong/cc" "android/soong/java" + "android/soong/sh" "testing" ) @@ -32,6 +33,8 @@ func registerApexModuleTypes(ctx android.RegistrationContext) { // CC module types needed as they can be APEX dependencies cc.RegisterCCBuildComponents(ctx) + ctx.RegisterModuleType("sh_binary", sh.ShBinaryFactory) + ctx.RegisterModuleType("cc_binary", cc.BinaryFactory) ctx.RegisterModuleType("cc_library", cc.LibraryFactory) ctx.RegisterModuleType("apex_key", apex.ApexKeyFactory) ctx.RegisterModuleType("android_app_certificate", java.AndroidAppCertificateFactory) @@ -40,60 +43,62 @@ func registerApexModuleTypes(ctx android.RegistrationContext) { func TestApexBundleSimple(t *testing.T) { runApexTestCase(t, bp2buildTestCase{ - description: "apex - simple example", - moduleTypeUnderTest: "apex", - moduleTypeUnderTestFactory: apex.BundleFactory, - moduleTypeUnderTestBp2BuildMutator: apex.ApexBundleBp2Build, - filesystem: map[string]string{}, + description: "apex - example with all props", + moduleTypeUnderTest: "apex", + moduleTypeUnderTestFactory: apex.BundleFactory, + filesystem: map[string]string{}, blueprint: ` apex_key { - name: "com.android.apogee.key", - public_key: "com.android.apogee.avbpubkey", - private_key: "com.android.apogee.pem", + name: "com.android.apogee.key", + public_key: "com.android.apogee.avbpubkey", + private_key: "com.android.apogee.pem", bazel_module: { bp2build_available: false }, } android_app_certificate { - name: "com.android.apogee.certificate", - certificate: "com.android.apogee", - bazel_module: { bp2build_available: false }, + name: "com.android.apogee.certificate", + certificate: "com.android.apogee", + bazel_module: { bp2build_available: false }, } cc_library { - name: "native_shared_lib_1", + name: "native_shared_lib_1", bazel_module: { bp2build_available: false }, } cc_library { - name: "native_shared_lib_2", + name: "native_shared_lib_2", bazel_module: { bp2build_available: false }, } // TODO(b/194878861): Add bp2build support for prebuilt_etc cc_library { - name: "pretend_prebuilt_1", - bazel_module: { bp2build_available: false }, + name: "pretend_prebuilt_1", + bazel_module: { bp2build_available: false }, } // TODO(b/194878861): Add bp2build support for prebuilt_etc cc_library { - name: "pretend_prebuilt_2", - bazel_module: { bp2build_available: false }, + name: "pretend_prebuilt_2", + bazel_module: { bp2build_available: false }, } filegroup { name: "com.android.apogee-file_contexts", - srcs: [ - "com.android.apogee-file_contexts", - ], - bazel_module: { bp2build_available: false }, + srcs: [ + "com.android.apogee-file_contexts", + ], + bazel_module: { bp2build_available: false }, } +cc_binary { name: "cc_binary_1", bazel_module: { bp2build_available: false } } +sh_binary { name: "sh_binary_2", bazel_module: { bp2build_available: false } } + apex { name: "com.android.apogee", manifest: "apogee_manifest.json", androidManifest: "ApogeeAndroidManifest.xml", - file_contexts: "com.android.apogee-file_contexts", + file_contexts: "com.android.apogee-file_contexts", min_sdk_version: "29", key: "com.android.apogee.key", certificate: "com.android.apogee.certificate", @@ -104,8 +109,8 @@ apex { "native_shared_lib_2", ], binaries: [ - "binary_1", - "binary_2", + "cc_binary_1", + "sh_binary_2", ], prebuilts: [ "pretend_prebuilt_1", @@ -117,8 +122,8 @@ apex { makeBazelTarget("apex", "com.android.apogee", attrNameToString{ "android_manifest": `"ApogeeAndroidManifest.xml"`, "binaries": `[ - "binary_1", - "binary_2", + ":cc_binary_1", + ":sh_binary_2", ]`, "certificate": `":com.android.apogee.certificate"`, "file_contexts": `":com.android.apogee-file_contexts"`, @@ -141,11 +146,10 @@ apex { func TestApexBundleDefaultPropertyValues(t *testing.T) { runApexTestCase(t, bp2buildTestCase{ - description: "apex - default property values", - moduleTypeUnderTest: "apex", - moduleTypeUnderTestFactory: apex.BundleFactory, - moduleTypeUnderTestBp2BuildMutator: apex.ApexBundleBp2Build, - filesystem: map[string]string{}, + description: "apex - default property values", + moduleTypeUnderTest: "apex", + moduleTypeUnderTestFactory: apex.BundleFactory, + filesystem: map[string]string{}, blueprint: ` apex { name: "com.android.apogee", @@ -160,11 +164,10 @@ apex { func TestApexBundleHasBazelModuleProps(t *testing.T) { runApexTestCase(t, bp2buildTestCase{ - description: "apex - has bazel module props", - moduleTypeUnderTest: "apex", - moduleTypeUnderTestFactory: apex.BundleFactory, - moduleTypeUnderTestBp2BuildMutator: apex.ApexBundleBp2Build, - filesystem: map[string]string{}, + description: "apex - has bazel module props", + moduleTypeUnderTest: "apex", + moduleTypeUnderTestFactory: apex.BundleFactory, + filesystem: map[string]string{}, blueprint: ` apex { name: "apogee", diff --git a/bp2build/apex_key_conversion_test.go b/bp2build/apex_key_conversion_test.go index 17f79a6b0..1d949901c 100644 --- a/bp2build/apex_key_conversion_test.go +++ b/bp2build/apex_key_conversion_test.go @@ -31,11 +31,10 @@ func registerApexKeyModuleTypes(ctx android.RegistrationContext) { func TestApexKeySimple(t *testing.T) { runApexKeyTestCase(t, bp2buildTestCase{ - description: "apex key - simple example", - moduleTypeUnderTest: "apex_key", - moduleTypeUnderTestFactory: apex.ApexKeyFactory, - moduleTypeUnderTestBp2BuildMutator: apex.ApexKeyBp2Build, - filesystem: map[string]string{}, + description: "apex key - simple example", + moduleTypeUnderTest: "apex_key", + moduleTypeUnderTestFactory: apex.ApexKeyFactory, + filesystem: map[string]string{}, blueprint: ` apex_key { name: "com.android.apogee.key", diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go index 10ee58294..54b59af3a 100644 --- a/bp2build/build_conversion.go +++ b/bp2build/build_conversion.go @@ -259,7 +259,7 @@ func GenerateBazelTargets(ctx *CodegenContext, generateFilegroups bool) (convers // Simple metrics tracking for bp2build metrics := CodegenMetrics{ - ruleClassCount: make(map[string]int), + ruleClassCount: make(map[string]uint64), } dirs := make(map[string]bool) @@ -698,9 +698,9 @@ func isZero(value reflect.Value) bool { } else { return true } - // Always print bools, if you want a bool attribute to be able to take the default value, use a - // bool pointer instead - case reflect.Bool: + // Always print bool/strings, if you want a bool/string attribute to be able to take the default value, use a + // pointer instead + case reflect.Bool, reflect.String: return false default: if !value.IsValid() { diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go index 983604b93..1440b6fce 100644 --- a/bp2build/build_conversion_test.go +++ b/bp2build/build_conversion_test.go @@ -41,6 +41,7 @@ func TestGenerateSoongModuleTargets(t *testing.T) { soong_module_deps = [ ], bool_prop = False, + string_prop = "", )`, }, { @@ -58,6 +59,7 @@ func TestGenerateSoongModuleTargets(t *testing.T) { soong_module_deps = [ ], bool_prop = True, + string_prop = "", )`, }, { @@ -76,6 +78,7 @@ func TestGenerateSoongModuleTargets(t *testing.T) { ], bool_prop = False, owner = "a_string_with\"quotes\"_and_\\backslashes\\\\", + string_prop = "", )`, }, { @@ -94,6 +97,7 @@ func TestGenerateSoongModuleTargets(t *testing.T) { ], bool_prop = False, required = ["bar"], + string_prop = "", )`, }, { @@ -111,6 +115,7 @@ func TestGenerateSoongModuleTargets(t *testing.T) { soong_module_deps = [ ], bool_prop = False, + string_prop = "", target_required = [ "qux", "bazqux", @@ -147,6 +152,7 @@ func TestGenerateSoongModuleTargets(t *testing.T) { "tag": ".bar", "targets": ["goal_bar"], }], + string_prop = "", )`, }, { @@ -179,6 +185,7 @@ func TestGenerateSoongModuleTargets(t *testing.T) { }], owner = "custom_owner", required = ["bar"], + string_prop = "", target_required = [ "qux", "bazqux", @@ -223,11 +230,24 @@ func TestGenerateSoongModuleTargets(t *testing.T) { func TestGenerateBazelTargetModules(t *testing.T) { testCases := []bp2buildTestCase{ { - description: "string props", + description: "string ptr props", blueprint: `custom { name: "foo", + string_ptr_prop: "", + bazel_module: { bp2build_available: true }, +}`, + expectedBazelTargets: []string{ + makeBazelTarget("custom", "foo", attrNameToString{ + "string_ptr_prop": `""`, + }), + }, + }, + { + description: "string props", + blueprint: `custom { + name: "foo", string_list_prop: ["a", "b"], - string_prop: "a", + string_ptr_prop: "a", bazel_module: { bp2build_available: true }, }`, expectedBazelTargets: []string{ @@ -236,7 +256,7 @@ func TestGenerateBazelTargetModules(t *testing.T) { "a", "b", ]`, - "string_prop": `"a"`, + "string_ptr_prop": `"a"`, }), }, }, @@ -245,7 +265,7 @@ func TestGenerateBazelTargetModules(t *testing.T) { blueprint: `custom { name: "foo", string_list_prop: ["\t", "\n"], - string_prop: "a\t\n\r", + string_ptr_prop: "a\t\n\r", bazel_module: { bp2build_available: true }, }`, expectedBazelTargets: []string{ @@ -254,7 +274,7 @@ func TestGenerateBazelTargetModules(t *testing.T) { "\t", "\n", ]`, - "string_prop": `"a\t\n\r"`, + "string_ptr_prop": `"a\t\n\r"`, }), }, }, @@ -450,7 +470,7 @@ custom { android.FailIfErrored(t, err) if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount { - t.Errorf("Expected %d bazel target, got %d", expectedCount, actualCount) + t.Errorf("Expected %d bazel target (%s),\ngot %d (%s)", expectedCount, testCase.expectedBazelTargets, actualCount, bazelTargets) } else { for i, expectedBazelTarget := range testCase.expectedBazelTargets { actualBazelTarget := bazelTargets[i] @@ -576,6 +596,7 @@ func TestGenerateBazelTargetModules_OneToMany_LoadedFromStarlark(t *testing.T) { { bp: `custom { name: "bar", + one_to_many_prop: true, bazel_module: { bp2build_available: true }, }`, expectedBazelTarget: `my_library( @@ -600,7 +621,6 @@ load("//build/bazel/rules:rules.bzl", "my_library")`, config := android.TestConfig(buildDir, nil, testCase.bp, nil) ctx := android.NewTestContext(config) ctx.RegisterModuleType("custom", customModuleFactory) - ctx.RegisterBp2BuildMutator("custom", customBp2BuildMutatorFromStarlark) ctx.RegisterForBazelConversion() _, errs := ctx.ParseFileList(dir, []string{"Android.bp"}) @@ -638,10 +658,9 @@ load("//build/bazel/rules:rules.bzl", "my_library")`, func TestModuleTypeBp2Build(t *testing.T) { testCases := []bp2buildTestCase{ { - description: "filegroup with does not specify srcs", - moduleTypeUnderTest: "filegroup", - moduleTypeUnderTestFactory: android.FileGroupFactory, - moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build, + description: "filegroup with does not specify srcs", + moduleTypeUnderTest: "filegroup", + moduleTypeUnderTestFactory: android.FileGroupFactory, blueprint: `filegroup { name: "fg_foo", bazel_module: { bp2build_available: true }, @@ -651,10 +670,9 @@ func TestModuleTypeBp2Build(t *testing.T) { }, }, { - description: "filegroup with no srcs", - moduleTypeUnderTest: "filegroup", - moduleTypeUnderTestFactory: android.FileGroupFactory, - moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build, + description: "filegroup with no srcs", + moduleTypeUnderTest: "filegroup", + moduleTypeUnderTestFactory: android.FileGroupFactory, blueprint: `filegroup { name: "fg_foo", srcs: [], @@ -665,10 +683,9 @@ func TestModuleTypeBp2Build(t *testing.T) { }, }, { - description: "filegroup with srcs", - moduleTypeUnderTest: "filegroup", - moduleTypeUnderTestFactory: android.FileGroupFactory, - moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build, + description: "filegroup with srcs", + moduleTypeUnderTest: "filegroup", + moduleTypeUnderTestFactory: android.FileGroupFactory, blueprint: `filegroup { name: "fg_foo", srcs: ["a", "b"], @@ -684,10 +701,9 @@ func TestModuleTypeBp2Build(t *testing.T) { }, }, { - description: "filegroup with excludes srcs", - moduleTypeUnderTest: "filegroup", - moduleTypeUnderTestFactory: android.FileGroupFactory, - moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build, + description: "filegroup with excludes srcs", + moduleTypeUnderTest: "filegroup", + moduleTypeUnderTestFactory: android.FileGroupFactory, blueprint: `filegroup { name: "fg_foo", srcs: ["a", "b"], @@ -701,10 +717,9 @@ func TestModuleTypeBp2Build(t *testing.T) { }, }, { - description: "filegroup with glob", - moduleTypeUnderTest: "filegroup", - moduleTypeUnderTestFactory: android.FileGroupFactory, - moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build, + description: "filegroup with glob", + moduleTypeUnderTest: "filegroup", + moduleTypeUnderTestFactory: android.FileGroupFactory, blueprint: `filegroup { name: "fg_foo", srcs: ["**/*.txt"], @@ -727,12 +742,10 @@ func TestModuleTypeBp2Build(t *testing.T) { }, }, { - description: "filegroup with glob in subdir", - moduleTypeUnderTest: "filegroup", - moduleTypeUnderTestFactory: android.FileGroupFactory, - moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build, - blueprint: ``, - dir: "other", + description: "filegroup with glob in subdir", + moduleTypeUnderTest: "filegroup", + moduleTypeUnderTestFactory: android.FileGroupFactory, + dir: "other", filesystem: map[string]string{ "other/Android.bp": `filegroup { name: "fg_foo", @@ -755,10 +768,9 @@ func TestModuleTypeBp2Build(t *testing.T) { }, }, { - description: "depends_on_other_dir_module", - moduleTypeUnderTest: "filegroup", - moduleTypeUnderTestFactory: android.FileGroupFactory, - moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build, + description: "depends_on_other_dir_module", + moduleTypeUnderTest: "filegroup", + moduleTypeUnderTestFactory: android.FileGroupFactory, blueprint: `filegroup { name: "fg_foo", srcs: [ @@ -784,26 +796,25 @@ func TestModuleTypeBp2Build(t *testing.T) { }, }, { - description: "depends_on_other_unconverted_module_error", - moduleTypeUnderTest: "filegroup", - moduleTypeUnderTestFactory: android.FileGroupFactory, - moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build, - unconvertedDepsMode: errorModulesUnconvertedDeps, - filesystem: map[string]string{ - "other/Android.bp": `filegroup { - name: "foo", - srcs: ["a", "b"], -}`, - }, + description: "depends_on_other_unconverted_module_error", + moduleTypeUnderTest: "filegroup", + moduleTypeUnderTestFactory: android.FileGroupFactory, + unconvertedDepsMode: errorModulesUnconvertedDeps, blueprint: `filegroup { - name: "fg_foo", + name: "foobar", srcs: [ ":foo", "c", ], bazel_module: { bp2build_available: true }, }`, - expectedErr: fmt.Errorf(`"fg_foo" depends on unconverted modules: foo`), + expectedErr: fmt.Errorf(`"foobar" depends on unconverted modules: foo`), + filesystem: map[string]string{ + "other/Android.bp": `filegroup { + name: "foo", + srcs: ["a", "b"], +}`, + }, }, } @@ -818,18 +829,16 @@ type bp2buildMutator = func(android.TopDownMutatorContext) func TestAllowlistingBp2buildTargetsExplicitly(t *testing.T) { testCases := []struct { - moduleTypeUnderTest string - moduleTypeUnderTestFactory android.ModuleFactory - moduleTypeUnderTestBp2BuildMutator bp2buildMutator - bp string - expectedCount int - description string + moduleTypeUnderTest string + moduleTypeUnderTestFactory android.ModuleFactory + bp string + expectedCount int + description string }{ { - description: "explicitly unavailable", - moduleTypeUnderTest: "filegroup", - moduleTypeUnderTestFactory: android.FileGroupFactory, - moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build, + description: "explicitly unavailable", + moduleTypeUnderTest: "filegroup", + moduleTypeUnderTestFactory: android.FileGroupFactory, bp: `filegroup { name: "foo", srcs: ["a", "b"], @@ -838,10 +847,9 @@ func TestAllowlistingBp2buildTargetsExplicitly(t *testing.T) { expectedCount: 0, }, { - description: "implicitly unavailable", - moduleTypeUnderTest: "filegroup", - moduleTypeUnderTestFactory: android.FileGroupFactory, - moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build, + description: "implicitly unavailable", + moduleTypeUnderTest: "filegroup", + moduleTypeUnderTestFactory: android.FileGroupFactory, bp: `filegroup { name: "foo", srcs: ["a", "b"], @@ -849,10 +857,9 @@ func TestAllowlistingBp2buildTargetsExplicitly(t *testing.T) { expectedCount: 0, }, { - description: "explicitly available", - moduleTypeUnderTest: "filegroup", - moduleTypeUnderTestFactory: android.FileGroupFactory, - moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build, + description: "explicitly available", + moduleTypeUnderTest: "filegroup", + moduleTypeUnderTestFactory: android.FileGroupFactory, bp: `filegroup { name: "foo", srcs: ["a", "b"], @@ -861,12 +868,12 @@ func TestAllowlistingBp2buildTargetsExplicitly(t *testing.T) { expectedCount: 1, }, { - description: "generates more than 1 target if needed", - moduleTypeUnderTest: "custom", - moduleTypeUnderTestFactory: customModuleFactory, - moduleTypeUnderTestBp2BuildMutator: customBp2BuildMutatorFromStarlark, + description: "generates more than 1 target if needed", + moduleTypeUnderTest: "custom", + moduleTypeUnderTestFactory: customModuleFactory, bp: `custom { name: "foo", + one_to_many_prop: true, bazel_module: { bp2build_available: true }, }`, expectedCount: 3, @@ -879,7 +886,6 @@ func TestAllowlistingBp2buildTargetsExplicitly(t *testing.T) { config := android.TestConfig(buildDir, nil, testCase.bp, nil) ctx := android.NewTestContext(config) ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory) - ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator) ctx.RegisterForBazelConversion() _, errs := ctx.ParseFileList(dir, []string{"Android.bp"}) @@ -899,20 +905,18 @@ func TestAllowlistingBp2buildTargetsExplicitly(t *testing.T) { func TestAllowlistingBp2buildTargetsWithConfig(t *testing.T) { testCases := []struct { - moduleTypeUnderTest string - moduleTypeUnderTestFactory android.ModuleFactory - moduleTypeUnderTestBp2BuildMutator bp2buildMutator - expectedCount map[string]int - description string - bp2buildConfig android.Bp2BuildConfig - checkDir string - fs map[string]string + moduleTypeUnderTest string + moduleTypeUnderTestFactory android.ModuleFactory + expectedCount map[string]int + description string + bp2buildConfig android.Bp2BuildConfig + checkDir string + fs map[string]string }{ { - description: "test bp2build config package and subpackages config", - moduleTypeUnderTest: "filegroup", - moduleTypeUnderTestFactory: android.FileGroupFactory, - moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build, + description: "test bp2build config package and subpackages config", + moduleTypeUnderTest: "filegroup", + moduleTypeUnderTestFactory: android.FileGroupFactory, expectedCount: map[string]int{ "migrated": 1, "migrated/but_not_really": 0, @@ -934,10 +938,9 @@ func TestAllowlistingBp2buildTargetsWithConfig(t *testing.T) { }, }, { - description: "test bp2build config opt-in and opt-out", - moduleTypeUnderTest: "filegroup", - moduleTypeUnderTestFactory: android.FileGroupFactory, - moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build, + description: "test bp2build config opt-in and opt-out", + moduleTypeUnderTest: "filegroup", + moduleTypeUnderTestFactory: android.FileGroupFactory, expectedCount: map[string]int{ "package-opt-in": 2, "package-opt-in/subpackage": 0, @@ -988,7 +991,6 @@ filegroup { name: "opt-out-h", bazel_module: { bp2build_available: false } } config := android.TestConfig(buildDir, nil, "", fs) ctx := android.NewTestContext(config) ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory) - ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator) ctx.RegisterBp2BuildConfig(testCase.bp2buildConfig) ctx.RegisterForBazelConversion() @@ -1019,10 +1021,9 @@ filegroup { name: "opt-out-h", bazel_module: { bp2build_available: false } } func TestCombineBuildFilesBp2buildTargets(t *testing.T) { testCases := []bp2buildTestCase{ { - description: "filegroup bazel_module.label", - moduleTypeUnderTest: "filegroup", - moduleTypeUnderTestFactory: android.FileGroupFactory, - moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build, + description: "filegroup bazel_module.label", + moduleTypeUnderTest: "filegroup", + moduleTypeUnderTestFactory: android.FileGroupFactory, blueprint: `filegroup { name: "fg_foo", bazel_module: { label: "//other:fg_foo" }, @@ -1035,19 +1036,18 @@ func TestCombineBuildFilesBp2buildTargets(t *testing.T) { }, }, { - description: "multiple bazel_module.label same BUILD", - moduleTypeUnderTest: "filegroup", - moduleTypeUnderTestFactory: android.FileGroupFactory, - moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build, + description: "multiple bazel_module.label same BUILD", + moduleTypeUnderTest: "filegroup", + moduleTypeUnderTestFactory: android.FileGroupFactory, blueprint: `filegroup { - name: "fg_foo", - bazel_module: { label: "//other:fg_foo" }, - } + name: "fg_foo", + bazel_module: { label: "//other:fg_foo" }, + } - filegroup { - name: "foo", - bazel_module: { label: "//other:foo" }, - }`, + filegroup { + name: "foo", + bazel_module: { label: "//other:foo" }, + }`, expectedBazelTargets: []string{ `// BUILD file`, }, @@ -1056,25 +1056,24 @@ func TestCombineBuildFilesBp2buildTargets(t *testing.T) { }, }, { - description: "filegroup bazel_module.label and bp2build in subdir", - moduleTypeUnderTest: "filegroup", - moduleTypeUnderTestFactory: android.FileGroupFactory, - moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build, - dir: "other", - blueprint: ``, + description: "filegroup bazel_module.label and bp2build in subdir", + moduleTypeUnderTest: "filegroup", + moduleTypeUnderTestFactory: android.FileGroupFactory, + dir: "other", + blueprint: ``, filesystem: map[string]string{ "other/Android.bp": `filegroup { - name: "fg_foo", - bazel_module: { - bp2build_available: true, - }, - } - filegroup { - name: "fg_bar", - bazel_module: { - label: "//other:fg_bar" - }, - }`, + name: "fg_foo", + bazel_module: { + bp2build_available: true, + }, + } + filegroup { + name: "fg_bar", + bazel_module: { + label: "//other:fg_bar" + }, + }`, "other/BUILD.bazel": `// definition for fg_bar`, }, expectedBazelTargets: []string{ @@ -1083,26 +1082,26 @@ func TestCombineBuildFilesBp2buildTargets(t *testing.T) { }, }, { - description: "filegroup bazel_module.label and filegroup bp2build", - moduleTypeUnderTest: "filegroup", - moduleTypeUnderTestFactory: android.FileGroupFactory, - moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build, + description: "filegroup bazel_module.label and filegroup bp2build", + moduleTypeUnderTest: "filegroup", + moduleTypeUnderTestFactory: android.FileGroupFactory, + filesystem: map[string]string{ "other/BUILD.bazel": `// BUILD file`, }, blueprint: `filegroup { - name: "fg_foo", - bazel_module: { - label: "//other:fg_foo", - }, - } + name: "fg_foo", + bazel_module: { + label: "//other:fg_foo", + }, + } - filegroup { - name: "fg_bar", - bazel_module: { - bp2build_available: true, - }, - }`, + filegroup { + name: "fg_bar", + bazel_module: { + bp2build_available: true, + }, + }`, expectedBazelTargets: []string{ makeBazelTarget("filegroup", "fg_bar", map[string]string{}), `// BUILD file`, @@ -1126,7 +1125,6 @@ func TestCombineBuildFilesBp2buildTargets(t *testing.T) { config := android.TestConfig(buildDir, nil, testCase.blueprint, fs) ctx := android.NewTestContext(config) ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory) - ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator) ctx.RegisterForBazelConversion() _, errs := ctx.ParseFileList(dir, toParse) @@ -1172,10 +1170,9 @@ func TestCombineBuildFilesBp2buildTargets(t *testing.T) { func TestGlobExcludeSrcs(t *testing.T) { testCases := []bp2buildTestCase{ { - description: "filegroup top level exclude_srcs", - moduleTypeUnderTest: "filegroup", - moduleTypeUnderTestFactory: android.FileGroupFactory, - moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build, + description: "filegroup top level exclude_srcs", + moduleTypeUnderTest: "filegroup", + moduleTypeUnderTestFactory: android.FileGroupFactory, blueprint: `filegroup { name: "fg_foo", srcs: ["**/*.txt"], @@ -1202,12 +1199,11 @@ func TestGlobExcludeSrcs(t *testing.T) { }, }, { - description: "filegroup in subdir exclude_srcs", - moduleTypeUnderTest: "filegroup", - moduleTypeUnderTestFactory: android.FileGroupFactory, - moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build, - blueprint: "", - dir: "dir", + description: "filegroup in subdir exclude_srcs", + moduleTypeUnderTest: "filegroup", + moduleTypeUnderTestFactory: android.FileGroupFactory, + blueprint: "", + dir: "dir", filesystem: map[string]string{ "dir/Android.bp": `filegroup { name: "fg_foo", @@ -1244,10 +1240,9 @@ func TestGlobExcludeSrcs(t *testing.T) { func TestCommonBp2BuildModuleAttrs(t *testing.T) { testCases := []bp2buildTestCase{ { - description: "Required into data test", - moduleTypeUnderTest: "filegroup", - moduleTypeUnderTestFactory: android.FileGroupFactory, - moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build, + description: "Required into data test", + moduleTypeUnderTest: "filegroup", + moduleTypeUnderTestFactory: android.FileGroupFactory, blueprint: simpleModuleDoNotConvertBp2build("filegroup", "reqd") + ` filegroup { name: "fg_foo", @@ -1261,21 +1256,20 @@ filegroup { }, }, { - description: "Required via arch into data test", - moduleTypeUnderTest: "python_library", - moduleTypeUnderTestFactory: python.PythonLibraryFactory, - moduleTypeUnderTestBp2BuildMutator: python.PythonLibraryBp2Build, + description: "Required via arch into data test", + moduleTypeUnderTest: "python_library", + moduleTypeUnderTestFactory: python.PythonLibraryFactory, blueprint: simpleModuleDoNotConvertBp2build("python_library", "reqdx86") + simpleModuleDoNotConvertBp2build("python_library", "reqdarm") + ` python_library { name: "fg_foo", arch: { - arm: { - required: ["reqdarm"], - }, - x86: { - required: ["reqdx86"], - }, + arm: { + required: ["reqdarm"], + }, + x86: { + required: ["reqdx86"], + }, }, bazel_module: { bp2build_available: true }, }`, @@ -1291,10 +1285,9 @@ python_library { }, }, { - description: "Required appended to data test", - moduleTypeUnderTest: "python_library", - moduleTypeUnderTestFactory: python.PythonLibraryFactory, - moduleTypeUnderTestBp2BuildMutator: python.PythonLibraryBp2Build, + description: "Required appended to data test", + moduleTypeUnderTest: "python_library", + moduleTypeUnderTestFactory: python.PythonLibraryFactory, filesystem: map[string]string{ "data.bin": "", "src.py": "", @@ -1317,10 +1310,9 @@ python_library { }, }, { - description: "All props-to-attrs at once together test", - moduleTypeUnderTest: "filegroup", - moduleTypeUnderTestFactory: android.FileGroupFactory, - moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build, + description: "All props-to-attrs at once together test", + moduleTypeUnderTest: "filegroup", + moduleTypeUnderTestFactory: android.FileGroupFactory, blueprint: simpleModuleDoNotConvertBp2build("filegroup", "reqd") + ` filegroup { name: "fg_foo", diff --git a/bp2build/bzl_conversion_test.go b/bp2build/bzl_conversion_test.go index 1e78c0ecd..f3345a6ae 100644 --- a/bp2build/bzl_conversion_test.go +++ b/bp2build/bzl_conversion_test.go @@ -100,6 +100,7 @@ custom = rule( # nested_props_ptr start # "nested_prop": attr.string(), # nested_props_ptr end + "one_to_many_prop": attr.bool(), "other_embedded_prop": attr.string(), "string_list_prop": attr.string_list(), "string_prop": attr.string(), @@ -128,6 +129,7 @@ custom_defaults = rule( # nested_props_ptr start # "nested_prop": attr.string(), # nested_props_ptr end + "one_to_many_prop": attr.bool(), "other_embedded_prop": attr.string(), "string_list_prop": attr.string_list(), "string_prop": attr.string(), @@ -156,6 +158,7 @@ custom_test_ = rule( # nested_props_ptr start # "nested_prop": attr.string(), # nested_props_ptr end + "one_to_many_prop": attr.bool(), "other_embedded_prop": attr.string(), "string_list_prop": attr.string_list(), "string_prop": attr.string(), diff --git a/bp2build/cc_binary_conversion_test.go b/bp2build/cc_binary_conversion_test.go index f9abcba6f..a156480d2 100644 --- a/bp2build/cc_binary_conversion_test.go +++ b/bp2build/cc_binary_conversion_test.go @@ -24,8 +24,7 @@ import ( ) const ( - ccBinaryTypePlaceHolder = "{rule_name}" - compatibleWithPlaceHolder = "{target_compatible_with}" + ccBinaryTypePlaceHolder = "{rule_name}" ) type testBazelTarget struct { @@ -69,14 +68,14 @@ func runCcBinaryTestCase(t *testing.T, tc ccBinaryBp2buildTestCase) { t.Helper() moduleTypeUnderTest := "cc_binary" testCase := bp2buildTestCase{ - expectedBazelTargets: generateBazelTargetsForTest(tc.targets), - moduleTypeUnderTest: moduleTypeUnderTest, - moduleTypeUnderTestFactory: cc.BinaryFactory, - moduleTypeUnderTestBp2BuildMutator: cc.BinaryBp2build, - description: fmt.Sprintf("%s %s", moduleTypeUnderTest, tc.description), - blueprint: binaryReplacer.Replace(tc.blueprint), + expectedBazelTargets: generateBazelTargetsForTest(tc.targets), + moduleTypeUnderTest: moduleTypeUnderTest, + moduleTypeUnderTestFactory: cc.BinaryFactory, + description: fmt.Sprintf("%s %s", moduleTypeUnderTest, tc.description), + blueprint: binaryReplacer.Replace(tc.blueprint), } t.Run(testCase.description, func(t *testing.T) { + t.Helper() runBp2BuildTestCase(t, registerCcBinaryModuleTypes, testCase) }) } @@ -84,22 +83,24 @@ func runCcBinaryTestCase(t *testing.T, tc ccBinaryBp2buildTestCase) { func runCcHostBinaryTestCase(t *testing.T, tc ccBinaryBp2buildTestCase) { t.Helper() testCase := tc - for i, t := range testCase.targets { - t.attrs["target_compatible_with"] = `select({ + for i, tar := range testCase.targets { + if tar.typ != "cc_binary" { + continue + } + tar.attrs["target_compatible_with"] = `select({ "//build/bazel/platforms/os:android": ["@platforms//:incompatible"], "//conditions:default": [], })` - testCase.targets[i] = t + testCase.targets[i] = tar } moduleTypeUnderTest := "cc_binary_host" t.Run(testCase.description, func(t *testing.T) { runBp2BuildTestCase(t, registerCcBinaryModuleTypes, bp2buildTestCase{ - expectedBazelTargets: generateBazelTargetsForTest(testCase.targets), - moduleTypeUnderTest: moduleTypeUnderTest, - moduleTypeUnderTestFactory: cc.BinaryHostFactory, - moduleTypeUnderTestBp2BuildMutator: cc.BinaryHostBp2build, - description: fmt.Sprintf("%s %s", moduleTypeUnderTest, tc.description), - blueprint: hostBinaryReplacer.Replace(testCase.blueprint), + expectedBazelTargets: generateBazelTargetsForTest(testCase.targets), + moduleTypeUnderTest: moduleTypeUnderTest, + moduleTypeUnderTestFactory: cc.BinaryHostFactory, + description: fmt.Sprintf("%s %s", moduleTypeUnderTest, tc.description), + blueprint: hostBinaryReplacer.Replace(testCase.blueprint), }) }) } @@ -256,11 +257,13 @@ func TestCcBinaryDoNotDistinguishBetweenDepsAndImplementationDeps(t *testing.T) genrule { name: "generated_hdr", cmd: "nothing to see here", + bazel_module: { bp2build_available: false }, } genrule { name: "export_generated_hdr", cmd: "nothing to see here", + bazel_module: { bp2build_available: false }, } {rule_name} { @@ -301,6 +304,7 @@ genrule { ":not_explicitly_exported_whole_static_dep", ":whole_static_dep", ]`, + "local_includes": `["."]`, }, }, }, @@ -448,3 +452,51 @@ func TestCcBinaryPropertiesToFeatures(t *testing.T) { }) } } + +func TestCcBinarySharedProto(t *testing.T) { + runCcBinaryTests(t, ccBinaryBp2buildTestCase{ + blueprint: soongCcProtoLibraries + `{rule_name} { + name: "foo", + srcs: ["foo.proto"], + proto: { + canonical_path_from_root: false, + }, + include_build_directory: false, +}`, + targets: []testBazelTarget{ + {"proto_library", "foo_proto", attrNameToString{ + "srcs": `["foo.proto"]`, + }}, {"cc_lite_proto_library", "foo_cc_proto_lite", attrNameToString{ + "deps": `[":foo_proto"]`, + }}, {"cc_binary", "foo", attrNameToString{ + "dynamic_deps": `[":libprotobuf-cpp-lite"]`, + "whole_archive_deps": `[":foo_cc_proto_lite"]`, + }}, + }, + }) +} + +func TestCcBinaryStaticProto(t *testing.T) { + runCcBinaryTests(t, ccBinaryBp2buildTestCase{ + blueprint: soongCcProtoLibraries + `{rule_name} { + name: "foo", + srcs: ["foo.proto"], + static_executable: true, + proto: { + canonical_path_from_root: false, + }, + include_build_directory: false, +}`, + targets: []testBazelTarget{ + {"proto_library", "foo_proto", attrNameToString{ + "srcs": `["foo.proto"]`, + }}, {"cc_lite_proto_library", "foo_cc_proto_lite", attrNameToString{ + "deps": `[":foo_proto"]`, + }}, {"cc_binary", "foo", attrNameToString{ + "deps": `[":libprotobuf-cpp-lite"]`, + "whole_archive_deps": `[":foo_cc_proto_lite"]`, + "linkshared": `False`, + }}, + }, + }) +} diff --git a/bp2build/cc_genrule_conversion_test.go b/bp2build/cc_genrule_conversion_test.go index b3624ddb0..440b462b9 100644 --- a/bp2build/cc_genrule_conversion_test.go +++ b/bp2build/cc_genrule_conversion_test.go @@ -19,7 +19,6 @@ import ( "android/soong/android" "android/soong/cc" - "android/soong/genrule" ) var otherCcGenruleBp = map[string]string{ @@ -41,7 +40,6 @@ func runCcGenruleTestCase(t *testing.T, tc bp2buildTestCase) { t.Helper() (&tc).moduleTypeUnderTest = "cc_genrule" (&tc).moduleTypeUnderTestFactory = cc.GenRuleFactory - (&tc).moduleTypeUnderTestBp2BuildMutator = genrule.CcGenruleBp2Build runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc) } diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go index a3d902a9d..b4eb28f00 100644 --- a/bp2build/cc_library_conversion_test.go +++ b/bp2build/cc_library_conversion_test.go @@ -39,6 +39,19 @@ toolchain_library { native_bridge_supported: true, src: "", }` + + soongCcProtoLibraries = ` +cc_library { + name: "libprotobuf-cpp-lite", + bazel_module: { bp2build_available: false }, +} + +cc_library { + name: "libprotobuf-cpp-full", + bazel_module: { bp2build_available: false }, +}` + + soongCcProtoPreamble = soongCcLibraryPreamble + soongCcProtoLibraries ) func runCcLibraryTestCase(t *testing.T, tc bp2buildTestCase) { @@ -57,10 +70,9 @@ func registerCcLibraryModuleTypes(ctx android.RegistrationContext) { func TestCcLibrarySimple(t *testing.T) { runCcLibraryTestCase(t, bp2buildTestCase{ - description: "cc_library - simple example", - moduleTypeUnderTest: "cc_library", - moduleTypeUnderTestFactory: cc.LibraryFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, + description: "cc_library - simple example", + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, filesystem: map[string]string{ "android.cpp": "", "bionic.cpp": "", @@ -117,17 +129,16 @@ cc_library { include_build_directory: false, } `, - expectedBazelTargets: []string{ - makeBazelTarget("cc_library", "foo-lib", attrNameToString{ - "copts": `["-Wall"]`, - "export_includes": `["foo-dir"]`, - "implementation_deps": `[":some-headers"]`, - "linkopts": `["-Wl,--exclude-libs=bar.a"] + select({ + expectedBazelTargets: makeCcLibraryTargets("foo-lib", attrNameToString{ + "copts": `["-Wall"]`, + "export_includes": `["foo-dir"]`, + "implementation_deps": `[":some-headers"]`, + "linkopts": `["-Wl,--exclude-libs=bar.a"] + select({ "//build/bazel/platforms/arch:x86": ["-Wl,--exclude-libs=baz.a"], "//build/bazel/platforms/arch:x86_64": ["-Wl,--exclude-libs=qux.a"], "//conditions:default": [], })`, - "srcs": `["impl.cpp"] + select({ + "srcs": `["impl.cpp"] + select({ "//build/bazel/platforms/arch:x86": ["x86.cpp"], "//build/bazel/platforms/arch:x86_64": ["x86_64.cpp"], "//conditions:default": [], @@ -141,17 +152,15 @@ cc_library { "//build/bazel/platforms/os:linux_bionic": ["bionic.cpp"], "//conditions:default": [], })`, - }), - }, + }), }) } func TestCcLibraryTrimmedLdAndroid(t *testing.T) { runCcLibraryTestCase(t, bp2buildTestCase{ - description: "cc_library - trimmed example of //bionic/linker:ld-android", - moduleTypeUnderTest: "cc_library", - moduleTypeUnderTestFactory: cc.LibraryFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, + description: "cc_library - trimmed example of //bionic/linker:ld-android", + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, filesystem: map[string]string{ "ld-android.cpp": "", "linked_list.h": "", @@ -159,8 +168,8 @@ func TestCcLibraryTrimmedLdAndroid(t *testing.T) { "linker_block_allocator.h": "", "linker_cfi.h": "", }, - blueprint: soongCcLibraryPreamble + ` -cc_library_headers { name: "libc_headers" } + blueprint: soongCcLibraryPreamble + + simpleModuleDoNotConvertBp2build("cc_library_headers", "libc_headers") + ` cc_library { name: "fake-ld-android", srcs: ["ld_android.cpp"], @@ -190,17 +199,16 @@ cc_library { include_build_directory: false, } `, - expectedBazelTargets: []string{ - makeBazelTarget("cc_library", "fake-ld-android", attrNameToString{ - "srcs": `["ld_android.cpp"]`, - "copts": `[ + expectedBazelTargets: makeCcLibraryTargets("fake-ld-android", attrNameToString{ + "srcs": `["ld_android.cpp"]`, + "copts": `[ "-Wall", "-Wextra", "-Wunused", "-Werror", ]`, - "implementation_deps": `[":libc_headers"]`, - "linkopts": `[ + "implementation_deps": `[":libc_headers"]`, + "linkopts": `[ "-Wl,--exclude-libs=libgcc.a", "-Wl,--exclude-libs=libgcc_stripped.a", "-Wl,--exclude-libs=libclang_rt.builtins-arm-android.a", @@ -212,18 +220,16 @@ cc_library { "//build/bazel/platforms/arch:x86_64": ["-Wl,--exclude-libs=libgcc_eh.a"], "//conditions:default": [], })`, - }), - }, + }), }) } func TestCcLibraryExcludeSrcs(t *testing.T) { runCcLibraryTestCase(t, bp2buildTestCase{ - description: "cc_library exclude_srcs - trimmed example of //external/arm-optimized-routines:libarm-optimized-routines-math", - moduleTypeUnderTest: "cc_library", - moduleTypeUnderTestFactory: cc.LibraryFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, - dir: "external", + description: "cc_library exclude_srcs - trimmed example of //external/arm-optimized-routines:libarm-optimized-routines-math", + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, + dir: "external", filesystem: map[string]string{ "external/math/cosf.c": "", "external/math/erf.c": "", @@ -258,25 +264,22 @@ cc_library { `, }, blueprint: soongCcLibraryPreamble, - expectedBazelTargets: []string{ - makeBazelTarget("cc_library", "fake-libarm-optimized-routines-math", attrNameToString{ - "copts": `select({ + expectedBazelTargets: makeCcLibraryTargets("fake-libarm-optimized-routines-math", attrNameToString{ + "copts": `select({ "//build/bazel/platforms/arch:arm64": ["-DHAVE_FAST_FMA=1"], "//conditions:default": [], })`, - "local_includes": `["."]`, - "srcs_c": `["math/cosf.c"]`, - }), - }, + "local_includes": `["."]`, + "srcs_c": `["math/cosf.c"]`, + }), }) } func TestCcLibrarySharedStaticProps(t *testing.T) { runCcLibraryTestCase(t, bp2buildTestCase{ - description: "cc_library shared/static props", - moduleTypeUnderTest: "cc_library", - moduleTypeUnderTestFactory: cc.LibraryFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, + description: "cc_library shared/static props", + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, filesystem: map[string]string{ "both.cpp": "", "sharedonly.cpp": "", @@ -353,26 +356,48 @@ cc_library { } `, expectedBazelTargets: []string{ - makeBazelTarget("cc_library", "a", attrNameToString{ - "copts": `["bothflag"]`, - "implementation_deps": `[":static_dep_for_both"]`, - "implementation_dynamic_deps": `[":shared_dep_for_both"]`, - "shared": `{ - "copts": ["sharedflag"], - "implementation_deps": [":static_dep_for_shared"], - "implementation_dynamic_deps": [":shared_dep_for_shared"], - "srcs": ["sharedonly.cpp"], - "whole_archive_deps": [":whole_static_lib_for_shared"], - }`, - "srcs": `["both.cpp"]`, - "static": `{ - "copts": ["staticflag"], - "implementation_deps": [":static_dep_for_static"], - "implementation_dynamic_deps": [":shared_dep_for_static"], - "srcs": ["staticonly.cpp"], - "whole_archive_deps": [":whole_static_lib_for_static"], - }`, - "whole_archive_deps": `[":whole_static_lib_for_both"]`, + makeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", attrNameToString{ + "copts": `[ + "bothflag", + "staticflag", + ]`, + "implementation_deps": `[ + ":static_dep_for_both", + ":static_dep_for_static", + ]`, + "implementation_dynamic_deps": `[ + ":shared_dep_for_both", + ":shared_dep_for_static", + ]`, + "srcs": `[ + "both.cpp", + "staticonly.cpp", + ]`, + "whole_archive_deps": `[ + ":whole_static_lib_for_both", + ":whole_static_lib_for_static", + ]`}), + makeBazelTarget("cc_library_shared", "a", attrNameToString{ + "copts": `[ + "bothflag", + "sharedflag", + ]`, + "implementation_deps": `[ + ":static_dep_for_both", + ":static_dep_for_shared", + ]`, + "implementation_dynamic_deps": `[ + ":shared_dep_for_both", + ":shared_dep_for_shared", + ]`, + "srcs": `[ + "both.cpp", + "sharedonly.cpp", + ]`, + "whole_archive_deps": `[ + ":whole_static_lib_for_both", + ":whole_static_lib_for_shared", + ]`, }), }, }) @@ -380,10 +405,9 @@ cc_library { func TestCcLibraryDeps(t *testing.T) { runCcLibraryTestCase(t, bp2buildTestCase{ - description: "cc_library shared/static props", - moduleTypeUnderTest: "cc_library", - moduleTypeUnderTestFactory: cc.LibraryFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, + description: "cc_library shared/static props", + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, filesystem: map[string]string{ "both.cpp": "", "sharedonly.cpp": "", @@ -438,52 +462,79 @@ cc_library { simpleModuleDoNotConvertBp2build("cc_library", "shared_dep_for_both") + simpleModuleDoNotConvertBp2build("cc_library", "implementation_shared_dep_for_both"), expectedBazelTargets: []string{ - makeBazelTarget("cc_library", "a", attrNameToString{ - "copts": `["bothflag"]`, - "deps": `[":static_dep_for_both"]`, - "dynamic_deps": `[":shared_dep_for_both"]`, - "implementation_deps": `[":implementation_static_dep_for_both"]`, - "implementation_dynamic_deps": `[":implementation_shared_dep_for_both"]`, - "shared": `{ - "copts": ["sharedflag"], - "deps": [":static_dep_for_shared"], - "dynamic_deps": [":shared_dep_for_shared"], - "implementation_deps": [":implementation_static_dep_for_shared"], - "implementation_dynamic_deps": [":implementation_shared_dep_for_shared"], - "srcs": ["sharedonly.cpp"], - "whole_archive_deps": [ - ":not_explicitly_exported_whole_static_dep_for_shared", - ":whole_static_dep_for_shared", - ], - }`, - "srcs": `["both.cpp"]`, - "static": `{ - "copts": ["staticflag"], - "deps": [":static_dep_for_static"], - "dynamic_deps": [":shared_dep_for_static"], - "implementation_deps": [":implementation_static_dep_for_static"], - "implementation_dynamic_deps": [":implementation_shared_dep_for_static"], - "srcs": ["staticonly.cpp"], - "whole_archive_deps": [ - ":not_explicitly_exported_whole_static_dep_for_static", - ":whole_static_dep_for_static", - ], - }`, + makeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", attrNameToString{ + "copts": `[ + "bothflag", + "staticflag", + ]`, + "deps": `[ + ":static_dep_for_both", + ":static_dep_for_static", + ]`, + "dynamic_deps": `[ + ":shared_dep_for_both", + ":shared_dep_for_static", + ]`, + "implementation_deps": `[ + ":implementation_static_dep_for_both", + ":implementation_static_dep_for_static", + ]`, + "implementation_dynamic_deps": `[ + ":implementation_shared_dep_for_both", + ":implementation_shared_dep_for_static", + ]`, + "srcs": `[ + "both.cpp", + "staticonly.cpp", + ]`, "whole_archive_deps": `[ ":not_explicitly_exported_whole_static_dep_for_both", ":whole_static_dep_for_both", + ":not_explicitly_exported_whole_static_dep_for_static", + ":whole_static_dep_for_static", ]`, }), - }, - }) + makeBazelTarget("cc_library_shared", "a", attrNameToString{ + "copts": `[ + "bothflag", + "sharedflag", + ]`, + "deps": `[ + ":static_dep_for_both", + ":static_dep_for_shared", + ]`, + "dynamic_deps": `[ + ":shared_dep_for_both", + ":shared_dep_for_shared", + ]`, + "implementation_deps": `[ + ":implementation_static_dep_for_both", + ":implementation_static_dep_for_shared", + ]`, + "implementation_dynamic_deps": `[ + ":implementation_shared_dep_for_both", + ":implementation_shared_dep_for_shared", + ]`, + "srcs": `[ + "both.cpp", + "sharedonly.cpp", + ]`, + "whole_archive_deps": `[ + ":not_explicitly_exported_whole_static_dep_for_both", + ":whole_static_dep_for_both", + ":not_explicitly_exported_whole_static_dep_for_shared", + ":whole_static_dep_for_shared", + ]`, + })}, + }, + ) } func TestCcLibraryWholeStaticLibsAlwaysLink(t *testing.T) { runCcLibraryTestCase(t, bp2buildTestCase{ - moduleTypeUnderTest: "cc_library", - moduleTypeUnderTestFactory: cc.LibraryFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, - dir: "foo/bar", + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, + dir: "foo/bar", filesystem: map[string]string{ "foo/bar/Android.bp": ` cc_library { @@ -508,26 +559,29 @@ cc_prebuilt_library_static { name: "whole_static_lib_for_both" } }, blueprint: soongCcLibraryPreamble, expectedBazelTargets: []string{ - makeBazelTarget("cc_library", "a", attrNameToString{ - "shared": `{ - "whole_archive_deps": [":whole_static_lib_for_shared_alwayslink"], - }`, - "static": `{ - "whole_archive_deps": [":whole_static_lib_for_static_alwayslink"], - }`, - "whole_archive_deps": `[":whole_static_lib_for_both_alwayslink"]`, + makeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", attrNameToString{ + "whole_archive_deps": `[ + ":whole_static_lib_for_both_alwayslink", + ":whole_static_lib_for_static_alwayslink", + ]`, + }), + makeBazelTarget("cc_library_shared", "a", attrNameToString{ + "whole_archive_deps": `[ + ":whole_static_lib_for_both_alwayslink", + ":whole_static_lib_for_shared_alwayslink", + ]`, }), }, - }) + }, + ) } func TestCcLibrarySharedStaticPropsInArch(t *testing.T) { runCcLibraryTestCase(t, bp2buildTestCase{ - description: "cc_library shared/static props in arch", - moduleTypeUnderTest: "cc_library", - moduleTypeUnderTestFactory: cc.LibraryFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, - dir: "foo/bar", + description: "cc_library shared/static props in arch", + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, + dir: "foo/bar", filesystem: map[string]string{ "foo/bar/arm.cpp": "", "foo/bar/x86.cpp": "", @@ -599,71 +653,85 @@ cc_library_static { name: "android_dep_for_shared" } }, blueprint: soongCcLibraryPreamble, expectedBazelTargets: []string{ - makeBazelTarget("cc_library", "a", attrNameToString{ - "copts": `["bothflag"]`, - "implementation_deps": `[":static_dep_for_both"]`, - "local_includes": `["."]`, - "shared": `{ - "copts": ["sharedflag"] + select({ - "//build/bazel/platforms/arch:arm": ["-DARM_SHARED"], - "//conditions:default": [], - }) + select({ - "//build/bazel/platforms/os:android": ["-DANDROID_SHARED"], - "//conditions:default": [], - }) + select({ - "//build/bazel/platforms/os_arch:android_arm": ["-DANDROID_ARM_SHARED"], - "//conditions:default": [], - }), - "implementation_deps": [":static_dep_for_shared"] + select({ - "//build/bazel/platforms/arch:arm": [":arm_static_dep_for_shared"], - "//conditions:default": [], - }) + select({ - "//build/bazel/platforms/os:android": [":android_dep_for_shared"], - "//conditions:default": [], - }), - "implementation_dynamic_deps": select({ - "//build/bazel/platforms/arch:arm": [":arm_shared_dep_for_shared"], - "//conditions:default": [], - }), - "srcs": ["sharedonly.cpp"] + select({ - "//build/bazel/platforms/arch:arm": ["arm_shared.cpp"], - "//conditions:default": [], - }) + select({ - "//build/bazel/platforms/os:android": ["android_shared.cpp"], - "//conditions:default": [], - }), - "whole_archive_deps": select({ - "//build/bazel/platforms/arch:arm": [":arm_whole_static_dep_for_shared"], - "//conditions:default": [], - }), - }`, - "srcs": `["both.cpp"]`, - "static": `{ - "copts": ["staticflag"] + select({ - "//build/bazel/platforms/arch:x86": ["-DX86_STATIC"], - "//conditions:default": [], - }), - "implementation_deps": [":static_dep_for_static"] + select({ - "//build/bazel/platforms/arch:x86": [":x86_dep_for_static"], - "//conditions:default": [], - }), - "srcs": ["staticonly.cpp"] + select({ - "//build/bazel/platforms/arch:x86": ["x86_static.cpp"], - "//conditions:default": [], - }), - }`, + makeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", attrNameToString{ + "copts": `[ + "bothflag", + "staticflag", + ] + select({ + "//build/bazel/platforms/arch:x86": ["-DX86_STATIC"], + "//conditions:default": [], + })`, + "implementation_deps": `[ + ":static_dep_for_both", + ":static_dep_for_static", + ] + select({ + "//build/bazel/platforms/arch:x86": [":x86_dep_for_static"], + "//conditions:default": [], + })`, + "local_includes": `["."]`, + "srcs": `[ + "both.cpp", + "staticonly.cpp", + ] + select({ + "//build/bazel/platforms/arch:x86": ["x86_static.cpp"], + "//conditions:default": [], + })`, + }), + makeBazelTarget("cc_library_shared", "a", attrNameToString{ + "copts": `[ + "bothflag", + "sharedflag", + ] + select({ + "//build/bazel/platforms/arch:arm": ["-DARM_SHARED"], + "//conditions:default": [], + }) + select({ + "//build/bazel/platforms/os:android": ["-DANDROID_SHARED"], + "//conditions:default": [], + }) + select({ + "//build/bazel/platforms/os_arch:android_arm": ["-DANDROID_ARM_SHARED"], + "//conditions:default": [], + })`, + "implementation_deps": `[ + ":static_dep_for_both", + ":static_dep_for_shared", + ] + select({ + "//build/bazel/platforms/arch:arm": [":arm_static_dep_for_shared"], + "//conditions:default": [], + }) + select({ + "//build/bazel/platforms/os:android": [":android_dep_for_shared"], + "//conditions:default": [], + })`, + "implementation_dynamic_deps": `select({ + "//build/bazel/platforms/arch:arm": [":arm_shared_dep_for_shared"], + "//conditions:default": [], + })`, + "local_includes": `["."]`, + "srcs": `[ + "both.cpp", + "sharedonly.cpp", + ] + select({ + "//build/bazel/platforms/arch:arm": ["arm_shared.cpp"], + "//conditions:default": [], + }) + select({ + "//build/bazel/platforms/os:android": ["android_shared.cpp"], + "//conditions:default": [], + })`, + "whole_archive_deps": `select({ + "//build/bazel/platforms/arch:arm": [":arm_whole_static_dep_for_shared"], + "//conditions:default": [], + })`, }), }, - }) + }, + ) } func TestCcLibrarySharedStaticPropsWithMixedSources(t *testing.T) { runCcLibraryTestCase(t, bp2buildTestCase{ - description: "cc_library shared/static props with c/cpp/s mixed sources", - moduleTypeUnderTest: "cc_library", - moduleTypeUnderTestFactory: cc.LibraryFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, - dir: "foo/bar", + description: "cc_library shared/static props with c/cpp/s mixed sources", + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, + dir: "foo/bar", filesystem: map[string]string{ "foo/bar/both_source.cpp": "", "foo/bar/both_source.cc": "", @@ -738,66 +806,64 @@ filegroup { }, blueprint: soongCcLibraryPreamble, expectedBazelTargets: []string{ - makeBazelTarget("cc_library", "a", attrNameToString{ + makeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", attrNameToString{ "local_includes": `["."]`, - "shared": `{ - "srcs": [ - "shared_source.cpp", - "shared_source.cc", - ":shared_filegroup_cpp_srcs", - ], - "srcs_as": [ - "shared_source.s", - "shared_source.S", - ":shared_filegroup_as_srcs", - ], - "srcs_c": [ - "shared_source.c", - ":shared_filegroup_c_srcs", - ], - }`, "srcs": `[ "both_source.cpp", "both_source.cc", ":both_filegroup_cpp_srcs", + "static_source.cpp", + "static_source.cc", + ":static_filegroup_cpp_srcs", ]`, "srcs_as": `[ "both_source.s", "both_source.S", ":both_filegroup_as_srcs", + "static_source.s", + "static_source.S", + ":static_filegroup_as_srcs", ]`, "srcs_c": `[ "both_source.c", ":both_filegroup_c_srcs", + "static_source.c", + ":static_filegroup_c_srcs", ]`, - "static": `{ - "srcs": [ - "static_source.cpp", - "static_source.cc", - ":static_filegroup_cpp_srcs", - ], - "srcs_as": [ - "static_source.s", - "static_source.S", - ":static_filegroup_as_srcs", - ], - "srcs_c": [ - "static_source.c", - ":static_filegroup_c_srcs", - ], - }`, }), - }, - }) + makeBazelTarget("cc_library_shared", "a", attrNameToString{ + "local_includes": `["."]`, + "srcs": `[ + "both_source.cpp", + "both_source.cc", + ":both_filegroup_cpp_srcs", + "shared_source.cpp", + "shared_source.cc", + ":shared_filegroup_cpp_srcs", + ]`, + "srcs_as": `[ + "both_source.s", + "both_source.S", + ":both_filegroup_as_srcs", + "shared_source.s", + "shared_source.S", + ":shared_filegroup_as_srcs", + ]`, + "srcs_c": `[ + "both_source.c", + ":both_filegroup_c_srcs", + "shared_source.c", + ":shared_filegroup_c_srcs", + ]`, + })}}) } func TestCcLibraryNonConfiguredVersionScript(t *testing.T) { runCcLibraryTestCase(t, bp2buildTestCase{ - description: "cc_library non-configured version script", - moduleTypeUnderTest: "cc_library", - moduleTypeUnderTestFactory: cc.LibraryFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, - dir: "foo/bar", + description: "cc_library non-configured version script", + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, + dir: "foo/bar", filesystem: map[string]string{ "foo/bar/Android.bp": ` cc_library { @@ -810,23 +876,21 @@ cc_library { `, }, blueprint: soongCcLibraryPreamble, - expectedBazelTargets: []string{ - makeBazelTarget("cc_library", "a", attrNameToString{ - "additional_linker_inputs": `["v.map"]`, - "linkopts": `["-Wl,--version-script,$(location v.map)"]`, - "srcs": `["a.cpp"]`, - }), - }, - }) + expectedBazelTargets: makeCcLibraryTargets("a", attrNameToString{ + "additional_linker_inputs": `["v.map"]`, + "linkopts": `["-Wl,--version-script,$(location v.map)"]`, + "srcs": `["a.cpp"]`, + }), + }, + ) } func TestCcLibraryConfiguredVersionScript(t *testing.T) { runCcLibraryTestCase(t, bp2buildTestCase{ - description: "cc_library configured version script", - moduleTypeUnderTest: "cc_library", - moduleTypeUnderTestFactory: cc.LibraryFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, - dir: "foo/bar", + description: "cc_library configured version script", + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, + dir: "foo/bar", filesystem: map[string]string{ "foo/bar/Android.bp": ` cc_library { @@ -847,30 +911,28 @@ cc_library { `, }, blueprint: soongCcLibraryPreamble, - expectedBazelTargets: []string{ - makeBazelTarget("cc_library", "a", attrNameToString{ - "additional_linker_inputs": `select({ + expectedBazelTargets: makeCcLibraryTargets("a", attrNameToString{ + "additional_linker_inputs": `select({ "//build/bazel/platforms/arch:arm": ["arm.map"], "//build/bazel/platforms/arch:arm64": ["arm64.map"], "//conditions:default": [], })`, - "linkopts": `select({ + "linkopts": `select({ "//build/bazel/platforms/arch:arm": ["-Wl,--version-script,$(location arm.map)"], "//build/bazel/platforms/arch:arm64": ["-Wl,--version-script,$(location arm64.map)"], "//conditions:default": [], })`, - "srcs": `["a.cpp"]`, - }), - }, - }) + "srcs": `["a.cpp"]`, + }), + }, + ) } func TestCcLibrarySharedLibs(t *testing.T) { runCcLibraryTestCase(t, bp2buildTestCase{ - description: "cc_library shared_libs", - moduleTypeUnderTest: "cc_library", - moduleTypeUnderTestFactory: cc.LibraryFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, + description: "cc_library shared_libs", + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, blueprint: soongCcLibraryPreamble + ` cc_library { name: "mylib", @@ -883,20 +945,47 @@ cc_library { include_build_directory: false, } `, - expectedBazelTargets: []string{ - makeBazelTarget("cc_library", "a", attrNameToString{ - "implementation_dynamic_deps": `[":mylib"]`, - }), - }, - }) + expectedBazelTargets: makeCcLibraryTargets("a", attrNameToString{ + "implementation_dynamic_deps": `[":mylib"]`, + }), + }, + ) } func TestCcLibraryFeatures(t *testing.T) { + expected_targets := []string{} + expected_targets = append(expected_targets, makeCcLibraryTargets("a", attrNameToString{ + "features": `[ + "disable_pack_relocations", + "-no_undefined_symbols", + ]`, + "srcs": `["a.cpp"]`, + })...) + expected_targets = append(expected_targets, makeCcLibraryTargets("b", attrNameToString{ + "features": `select({ + "//build/bazel/platforms/arch:x86_64": [ + "disable_pack_relocations", + "-no_undefined_symbols", + ], + "//conditions:default": [], + })`, + "srcs": `["b.cpp"]`, + })...) + expected_targets = append(expected_targets, makeCcLibraryTargets("c", attrNameToString{ + "features": `select({ + "//build/bazel/platforms/os:darwin": [ + "disable_pack_relocations", + "-no_undefined_symbols", + ], + "//conditions:default": [], + })`, + "srcs": `["c.cpp"]`, + })...) + runCcLibraryTestCase(t, bp2buildTestCase{ - description: "cc_library pack_relocations test", - moduleTypeUnderTest: "cc_library", - moduleTypeUnderTestFactory: cc.LibraryFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, + description: "cc_library pack_relocations test", + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, blueprint: soongCcLibraryPreamble + ` cc_library { name: "a", @@ -929,42 +1018,15 @@ cc_library { }, include_build_directory: false, }`, - expectedBazelTargets: []string{ - makeBazelTarget("cc_library", "a", attrNameToString{ - "features": `[ - "disable_pack_relocations", - "-no_undefined_symbols", - ]`, - "srcs": `["a.cpp"]`, - }), makeBazelTarget("cc_library", "b", attrNameToString{ - "features": `select({ - "//build/bazel/platforms/arch:x86_64": [ - "disable_pack_relocations", - "-no_undefined_symbols", - ], - "//conditions:default": [], - })`, - "srcs": `["b.cpp"]`, - }), makeBazelTarget("cc_library", "c", attrNameToString{ - "features": `select({ - "//build/bazel/platforms/os:darwin": [ - "disable_pack_relocations", - "-no_undefined_symbols", - ], - "//conditions:default": [], - })`, - "srcs": `["c.cpp"]`, - }), - }, + expectedBazelTargets: expected_targets, }) } func TestCcLibrarySpacesInCopts(t *testing.T) { runCcLibraryTestCase(t, bp2buildTestCase{ - description: "cc_library spaces in copts", - moduleTypeUnderTest: "cc_library", - moduleTypeUnderTestFactory: cc.LibraryFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, + description: "cc_library spaces in copts", + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, blueprint: soongCcLibraryPreamble + ` cc_library { name: "a", @@ -972,23 +1034,21 @@ cc_library { include_build_directory: false, } `, - expectedBazelTargets: []string{ - makeBazelTarget("cc_library", "a", attrNameToString{ - "copts": `[ + expectedBazelTargets: makeCcLibraryTargets("a", attrNameToString{ + "copts": `[ "-include", "header.h", ]`, - }), - }, - }) + }), + }, + ) } func TestCcLibraryCppFlagsGoesIntoCopts(t *testing.T) { runCcLibraryTestCase(t, bp2buildTestCase{ - description: "cc_library cppflags usage", - moduleTypeUnderTest: "cc_library", - moduleTypeUnderTestFactory: cc.LibraryFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, + description: "cc_library cppflags usage", + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, blueprint: soongCcLibraryPreamble + `cc_library { name: "a", srcs: ["a.cpp"], @@ -1010,10 +1070,9 @@ func TestCcLibraryCppFlagsGoesIntoCopts(t *testing.T) { include_build_directory: false, } `, - expectedBazelTargets: []string{ - makeBazelTarget("cc_library", "a", attrNameToString{ - "copts": `["-Wall"]`, - "cppflags": `[ + expectedBazelTargets: makeCcLibraryTargets("a", attrNameToString{ + "copts": `["-Wall"]`, + "cppflags": `[ "-fsigned-char", "-pedantic", ] + select({ @@ -1023,18 +1082,17 @@ func TestCcLibraryCppFlagsGoesIntoCopts(t *testing.T) { "//build/bazel/platforms/os:android": ["-DANDROID=1"], "//conditions:default": [], })`, - "srcs": `["a.cpp"]`, - }), - }, - }) + "srcs": `["a.cpp"]`, + }), + }, + ) } func TestCcLibraryExcludeLibs(t *testing.T) { runCcLibraryTestCase(t, bp2buildTestCase{ - moduleTypeUnderTest: "cc_library", - moduleTypeUnderTestFactory: cc.LibraryFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, - filesystem: map[string]string{}, + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, + filesystem: map[string]string{}, blueprint: soongCcLibraryStaticPreamble + ` cc_library { name: "foo_static", @@ -1109,41 +1167,39 @@ cc_library { bazel_module: { bp2build_available: false }, } `, - expectedBazelTargets: []string{ - makeBazelTarget("cc_library", "foo_static", attrNameToString{ - "implementation_deps": `select({ + expectedBazelTargets: makeCcLibraryTargets("foo_static", attrNameToString{ + "implementation_deps": `select({ "//build/bazel/platforms/arch:arm": [], "//conditions:default": [":arm_static_lib_excludes_bp2build_cc_library_static"], }) + select({ "//build/bazel/product_variables:malloc_not_svelte": [], "//conditions:default": [":malloc_not_svelte_static_lib_excludes_bp2build_cc_library_static"], })`, - "implementation_dynamic_deps": `select({ + "implementation_dynamic_deps": `select({ "//build/bazel/platforms/arch:arm": [], "//conditions:default": [":arm_shared_lib_excludes"], }) + select({ "//build/bazel/product_variables:malloc_not_svelte": [":malloc_not_svelte_shared_lib"], "//conditions:default": [], })`, - "srcs_c": `["common.c"]`, - "whole_archive_deps": `select({ + "srcs_c": `["common.c"]`, + "whole_archive_deps": `select({ "//build/bazel/platforms/arch:arm": [], "//conditions:default": [":arm_whole_static_lib_excludes_bp2build_cc_library_static"], }) + select({ "//build/bazel/product_variables:malloc_not_svelte": [":malloc_not_svelte_whole_static_lib_bp2build_cc_library_static"], "//conditions:default": [":malloc_not_svelte_whole_static_lib_excludes_bp2build_cc_library_static"], })`, - }), - }, - }) + }), + }, + ) } func TestCCLibraryNoCrtTrue(t *testing.T) { runCcLibraryTestCase(t, bp2buildTestCase{ - description: "cc_library - nocrt: true emits attribute", - moduleTypeUnderTest: "cc_library", - moduleTypeUnderTestFactory: cc.LibraryFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, + description: "cc_library - nocrt: true emits attribute", + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, filesystem: map[string]string{ "impl.cpp": "", }, @@ -1155,21 +1211,19 @@ cc_library { include_build_directory: false, } `, - expectedBazelTargets: []string{ - makeBazelTarget("cc_library", "foo-lib", attrNameToString{ - "link_crt": `False`, - "srcs": `["impl.cpp"]`, - }), - }, - }) + expectedBazelTargets: makeCcLibraryTargets("foo-lib", attrNameToString{ + "link_crt": `False`, + "srcs": `["impl.cpp"]`, + }), + }, + ) } func TestCCLibraryNoCrtFalse(t *testing.T) { runCcLibraryTestCase(t, bp2buildTestCase{ - description: "cc_library - nocrt: false - does not emit attribute", - moduleTypeUnderTest: "cc_library", - moduleTypeUnderTestFactory: cc.LibraryFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, + description: "cc_library - nocrt: false - does not emit attribute", + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, filesystem: map[string]string{ "impl.cpp": "", }, @@ -1181,20 +1235,17 @@ cc_library { include_build_directory: false, } `, - expectedBazelTargets: []string{ - makeBazelTarget("cc_library", "foo-lib", attrNameToString{ - "srcs": `["impl.cpp"]`, - }), - }, + expectedBazelTargets: makeCcLibraryTargets("foo-lib", attrNameToString{ + "srcs": `["impl.cpp"]`, + }), }) } func TestCCLibraryNoCrtArchVariant(t *testing.T) { runCcLibraryTestCase(t, bp2buildTestCase{ - description: "cc_library - nocrt in select", - moduleTypeUnderTest: "cc_library", - moduleTypeUnderTestFactory: cc.LibraryFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, + description: "cc_library - nocrt in select", + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, filesystem: map[string]string{ "impl.cpp": "", }, @@ -1219,15 +1270,12 @@ cc_library { func TestCCLibraryNoLibCrtTrue(t *testing.T) { runCcLibraryTestCase(t, bp2buildTestCase{ - description: "cc_library - simple example", - moduleTypeUnderTest: "cc_library", - moduleTypeUnderTestFactory: cc.LibraryFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, filesystem: map[string]string{ "impl.cpp": "", }, blueprint: soongCcLibraryPreamble + ` -cc_library_headers { name: "some-headers" } cc_library { name: "foo-lib", srcs: ["impl.cpp"], @@ -1235,24 +1283,45 @@ cc_library { include_build_directory: false, } `, - expectedBazelTargets: []string{ - makeBazelTarget("cc_library", "foo-lib", attrNameToString{ - "srcs": `["impl.cpp"]`, - "use_libcrt": `False`, - }), - }}) + expectedBazelTargets: makeCcLibraryTargets("foo-lib", attrNameToString{ + "srcs": `["impl.cpp"]`, + "use_libcrt": `False`, + }), + }) +} + +func makeCcLibraryTargets(name string, attrs attrNameToString) []string { + STATIC_ONLY_ATTRS := map[string]bool{} + SHARED_ONLY_ATTRS := map[string]bool{ + "link_crt": true, + "additional_linker_inputs": true, + "linkopts": true, + "strip": true, + } + sharedAttrs := attrNameToString{} + staticAttrs := attrNameToString{} + for key, val := range attrs { + if _, staticOnly := STATIC_ONLY_ATTRS[key]; !staticOnly { + sharedAttrs[key] = val + } + if _, sharedOnly := SHARED_ONLY_ATTRS[key]; !sharedOnly { + staticAttrs[key] = val + } + } + sharedTarget := makeBazelTarget("cc_library_shared", name, sharedAttrs) + staticTarget := makeBazelTarget("cc_library_static", name+"_bp2build_cc_library_static", staticAttrs) + + return []string{staticTarget, sharedTarget} } func TestCCLibraryNoLibCrtFalse(t *testing.T) { runCcLibraryTestCase(t, bp2buildTestCase{ - moduleTypeUnderTest: "cc_library", - moduleTypeUnderTestFactory: cc.LibraryFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, filesystem: map[string]string{ "impl.cpp": "", }, blueprint: soongCcLibraryPreamble + ` -cc_library_headers { name: "some-headers" } cc_library { name: "foo-lib", srcs: ["impl.cpp"], @@ -1260,19 +1329,17 @@ cc_library { include_build_directory: false, } `, - expectedBazelTargets: []string{ - makeBazelTarget("cc_library", "foo-lib", attrNameToString{ - "srcs": `["impl.cpp"]`, - "use_libcrt": `True`, - }), - }}) + expectedBazelTargets: makeCcLibraryTargets("foo-lib", attrNameToString{ + "srcs": `["impl.cpp"]`, + "use_libcrt": `True`, + }), + }) } func TestCCLibraryNoLibCrtArchVariant(t *testing.T) { runCcLibraryTestCase(t, bp2buildTestCase{ - moduleTypeUnderTest: "cc_library", - moduleTypeUnderTestFactory: cc.LibraryFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, filesystem: map[string]string{ "impl.cpp": "", }, @@ -1291,24 +1358,50 @@ cc_library { include_build_directory: false, } `, - expectedBazelTargets: []string{ - makeBazelTarget("cc_library", "foo-lib", attrNameToString{ - "srcs": `["impl.cpp"]`, - "use_libcrt": `select({ + expectedBazelTargets: makeCcLibraryTargets("foo-lib", attrNameToString{ + "srcs": `["impl.cpp"]`, + "use_libcrt": `select({ "//build/bazel/platforms/arch:arm": False, "//build/bazel/platforms/arch:x86": False, "//conditions:default": None, })`, - }), - }}) + }), + }) } func TestCcLibraryStrip(t *testing.T) { + expectedTargets := []string{} + expectedTargets = append(expectedTargets, makeCcLibraryTargets("all", attrNameToString{ + "strip": `{ + "all": True, + }`, + })...) + expectedTargets = append(expectedTargets, makeCcLibraryTargets("keep_symbols", attrNameToString{ + "strip": `{ + "keep_symbols": True, + }`, + })...) + expectedTargets = append(expectedTargets, makeCcLibraryTargets("keep_symbols_and_debug_frame", attrNameToString{ + "strip": `{ + "keep_symbols_and_debug_frame": True, + }`, + })...) + expectedTargets = append(expectedTargets, makeCcLibraryTargets("keep_symbols_list", attrNameToString{ + "strip": `{ + "keep_symbols_list": ["symbol"], + }`, + })...) + expectedTargets = append(expectedTargets, makeCcLibraryTargets("none", attrNameToString{ + "strip": `{ + "none": True, + }`, + })...) + expectedTargets = append(expectedTargets, makeCcLibraryTargets("nothing", attrNameToString{})...) + runCcLibraryTestCase(t, bp2buildTestCase{ - description: "cc_library strip args", - moduleTypeUnderTest: "cc_library", - moduleTypeUnderTestFactory: cc.LibraryFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, + description: "cc_library strip args", + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, blueprint: soongCcLibraryPreamble + ` cc_library { name: "nothing", @@ -1350,38 +1443,15 @@ cc_library { include_build_directory: false, } `, - expectedBazelTargets: []string{ - makeBazelTarget("cc_library", "all", attrNameToString{ - "strip": `{ - "all": True, - }`, - }), makeBazelTarget("cc_library", "keep_symbols", attrNameToString{ - "strip": `{ - "keep_symbols": True, - }`, - }), makeBazelTarget("cc_library", "keep_symbols_and_debug_frame", attrNameToString{ - "strip": `{ - "keep_symbols_and_debug_frame": True, - }`, - }), makeBazelTarget("cc_library", "keep_symbols_list", attrNameToString{ - "strip": `{ - "keep_symbols_list": ["symbol"], - }`, - }), makeBazelTarget("cc_library", "none", attrNameToString{ - "strip": `{ - "none": True, - }`, - }), makeBazelTarget("cc_library", "nothing", attrNameToString{}), - }, + expectedBazelTargets: expectedTargets, }) } func TestCcLibraryStripWithArch(t *testing.T) { runCcLibraryTestCase(t, bp2buildTestCase{ - description: "cc_library strip args", - moduleTypeUnderTest: "cc_library", - moduleTypeUnderTestFactory: cc.LibraryFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, + description: "cc_library strip args", + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, blueprint: soongCcLibraryPreamble + ` cc_library { name: "multi-arch", @@ -1407,9 +1477,8 @@ cc_library { include_build_directory: false, } `, - expectedBazelTargets: []string{ - makeBazelTarget("cc_library", "multi-arch", attrNameToString{ - "strip": `{ + expectedBazelTargets: makeCcLibraryTargets("multi-arch", attrNameToString{ + "strip": `{ "keep_symbols": select({ "//build/bazel/platforms/arch:arm64": True, "//conditions:default": None, @@ -1426,17 +1495,16 @@ cc_library { "//conditions:default": [], }), }`, - }), - }, - }) + }), + }, + ) } func TestCcLibrary_SystemSharedLibsRootEmpty(t *testing.T) { runCcLibraryTestCase(t, bp2buildTestCase{ - description: "cc_library system_shared_libs empty at root", - moduleTypeUnderTest: "cc_library", - moduleTypeUnderTestFactory: cc.LibraryFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, + description: "cc_library system_shared_libs empty at root", + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, blueprint: soongCcLibraryPreamble + ` cc_library { name: "root_empty", @@ -1444,20 +1512,18 @@ cc_library { include_build_directory: false, } `, - expectedBazelTargets: []string{ - makeBazelTarget("cc_library", "root_empty", attrNameToString{ - "system_dynamic_deps": `[]`, - }), - }, - }) + expectedBazelTargets: makeCcLibraryTargets("root_empty", attrNameToString{ + "system_dynamic_deps": `[]`, + }), + }, + ) } func TestCcLibrary_SystemSharedLibsStaticEmpty(t *testing.T) { runCcLibraryTestCase(t, bp2buildTestCase{ - description: "cc_library system_shared_libs empty for static variant", - moduleTypeUnderTest: "cc_library", - moduleTypeUnderTestFactory: cc.LibraryFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, + description: "cc_library system_shared_libs empty for static variant", + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, blueprint: soongCcLibraryPreamble + ` cc_library { name: "static_empty", @@ -1468,21 +1534,19 @@ cc_library { } `, expectedBazelTargets: []string{ - makeBazelTarget("cc_library", "static_empty", attrNameToString{ - "static": `{ - "system_dynamic_deps": [], - }`, + makeBazelTarget("cc_library_static", "static_empty_bp2build_cc_library_static", attrNameToString{ + "system_dynamic_deps": "[]", }), + makeBazelTarget("cc_library_shared", "static_empty", attrNameToString{}), }, }) } func TestCcLibrary_SystemSharedLibsSharedEmpty(t *testing.T) { runCcLibraryTestCase(t, bp2buildTestCase{ - description: "cc_library system_shared_libs empty for shared variant", - moduleTypeUnderTest: "cc_library", - moduleTypeUnderTestFactory: cc.LibraryFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, + description: "cc_library system_shared_libs empty for shared variant", + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, blueprint: soongCcLibraryPreamble + ` cc_library { name: "shared_empty", @@ -1493,10 +1557,9 @@ cc_library { } `, expectedBazelTargets: []string{ - makeBazelTarget("cc_library", "shared_empty", attrNameToString{ - "shared": `{ - "system_dynamic_deps": [], - }`, + makeBazelTarget("cc_library_static", "shared_empty_bp2build_cc_library_static", attrNameToString{}), + makeBazelTarget("cc_library_shared", "shared_empty", attrNameToString{ + "system_dynamic_deps": "[]", }), }, }) @@ -1504,10 +1567,9 @@ cc_library { func TestCcLibrary_SystemSharedLibsSharedBionicEmpty(t *testing.T) { runCcLibraryTestCase(t, bp2buildTestCase{ - description: "cc_library system_shared_libs empty for shared, bionic variant", - moduleTypeUnderTest: "cc_library", - moduleTypeUnderTestFactory: cc.LibraryFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, + description: "cc_library system_shared_libs empty for shared, bionic variant", + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, blueprint: soongCcLibraryPreamble + ` cc_library { name: "shared_empty", @@ -1522,10 +1584,9 @@ cc_library { } `, expectedBazelTargets: []string{ - makeBazelTarget("cc_library", "shared_empty", attrNameToString{ - "shared": `{ - "system_dynamic_deps": [], - }`, + makeBazelTarget("cc_library_static", "shared_empty_bp2build_cc_library_static", attrNameToString{}), + makeBazelTarget("cc_library_shared", "shared_empty", attrNameToString{ + "system_dynamic_deps": "[]", }), }, }) @@ -1537,10 +1598,9 @@ func TestCcLibrary_SystemSharedLibsLinuxBionicEmpty(t *testing.T) { // only for linux_bionic, but `android` had `["libc", "libdl", "libm"]. // b/195791252 tracks the fix. runCcLibraryTestCase(t, bp2buildTestCase{ - description: "cc_library system_shared_libs empty for linux_bionic variant", - moduleTypeUnderTest: "cc_library", - moduleTypeUnderTestFactory: cc.LibraryFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, + description: "cc_library system_shared_libs empty for linux_bionic variant", + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, blueprint: soongCcLibraryPreamble + ` cc_library { name: "target_linux_bionic_empty", @@ -1552,20 +1612,18 @@ cc_library { include_build_directory: false, } `, - expectedBazelTargets: []string{ - makeBazelTarget("cc_library", "target_linux_bionic_empty", attrNameToString{ - "system_dynamic_deps": `[]`, - }), - }, - }) + expectedBazelTargets: makeCcLibraryTargets("target_linux_bionic_empty", attrNameToString{ + "system_dynamic_deps": `[]`, + }), + }, + ) } func TestCcLibrary_SystemSharedLibsBionicEmpty(t *testing.T) { runCcLibraryTestCase(t, bp2buildTestCase{ - description: "cc_library system_shared_libs empty for bionic variant", - moduleTypeUnderTest: "cc_library", - moduleTypeUnderTestFactory: cc.LibraryFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, + description: "cc_library system_shared_libs empty for bionic variant", + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, blueprint: soongCcLibraryPreamble + ` cc_library { name: "target_bionic_empty", @@ -1577,20 +1635,18 @@ cc_library { include_build_directory: false, } `, - expectedBazelTargets: []string{ - makeBazelTarget("cc_library", "target_bionic_empty", attrNameToString{ - "system_dynamic_deps": `[]`, - }), - }, - }) + expectedBazelTargets: makeCcLibraryTargets("target_bionic_empty", attrNameToString{ + "system_dynamic_deps": `[]`, + }), + }, + ) } func TestCcLibrary_SystemSharedLibsSharedAndRoot(t *testing.T) { runCcLibraryTestCase(t, bp2buildTestCase{ - description: "cc_library system_shared_libs set for shared and root", - moduleTypeUnderTest: "cc_library", - moduleTypeUnderTestFactory: cc.LibraryFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, + description: "cc_library system_shared_libs set for shared and root", + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, blueprint: soongCcLibraryPreamble + ` cc_library { name: "libc", @@ -1611,25 +1667,26 @@ cc_library { } `, expectedBazelTargets: []string{ - makeBazelTarget("cc_library", "foo", attrNameToString{ - "shared": `{ - "system_dynamic_deps": [":libm"], - }`, + makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", attrNameToString{ "system_dynamic_deps": `[":libc"]`, }), + makeBazelTarget("cc_library_shared", "foo", attrNameToString{ + "system_dynamic_deps": `[ + ":libc", + ":libm", + ]`, + }), }, }) } func TestCcLibraryOsSelects(t *testing.T) { runCcLibraryTestCase(t, bp2buildTestCase{ - description: "cc_library - selects for all os targets", - moduleTypeUnderTest: "cc_library", - moduleTypeUnderTestFactory: cc.LibraryFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, - filesystem: map[string]string{}, + description: "cc_library - selects for all os targets", + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, + filesystem: map[string]string{}, blueprint: soongCcLibraryPreamble + ` -cc_library_headers { name: "some-headers" } cc_library { name: "foo-lib", srcs: ["base.cpp"], @@ -1659,9 +1716,8 @@ cc_library { include_build_directory: false, } `, - expectedBazelTargets: []string{ - makeBazelTarget("cc_library", "foo-lib", attrNameToString{ - "srcs": `["base.cpp"] + select({ + expectedBazelTargets: makeCcLibraryTargets("foo-lib", attrNameToString{ + "srcs": `["base.cpp"] + select({ "//build/bazel/platforms/os:android": [ "linux.cpp", "bionic.cpp", @@ -1683,16 +1739,18 @@ cc_library { "//build/bazel/platforms/os:windows": ["windows.cpp"], "//conditions:default": [], })`, - }), - }, - }) + }), + }, + ) } func TestCcLibraryCppStdWithGnuExtensions_ConvertsToFeatureAttr(t *testing.T) { type testCase struct { cpp_std string + c_std string gnu_extensions string bazel_cpp_std string + bazel_c_std string } testCases := []testCase{ @@ -1702,45 +1760,58 @@ func TestCcLibraryCppStdWithGnuExtensions_ConvertsToFeatureAttr(t *testing.T) { // not set, only emit if gnu_extensions is disabled. the default (gnu+17 // is set in the toolchain.) {cpp_std: "", gnu_extensions: "", bazel_cpp_std: ""}, - {cpp_std: "", gnu_extensions: "false", bazel_cpp_std: "c++17"}, + {cpp_std: "", gnu_extensions: "false", bazel_cpp_std: "c++17", bazel_c_std: "c99"}, {cpp_std: "", gnu_extensions: "true", bazel_cpp_std: ""}, // experimental defaults to gnu++2a {cpp_std: "experimental", gnu_extensions: "", bazel_cpp_std: "gnu++2a"}, - {cpp_std: "experimental", gnu_extensions: "false", bazel_cpp_std: "c++2a"}, + {cpp_std: "experimental", gnu_extensions: "false", bazel_cpp_std: "c++2a", bazel_c_std: "c99"}, {cpp_std: "experimental", gnu_extensions: "true", bazel_cpp_std: "gnu++2a"}, // Explicitly setting a c++ std does not use replace gnu++ std even if // gnu_extensions is true. // "c++11", {cpp_std: "c++11", gnu_extensions: "", bazel_cpp_std: "c++11"}, - {cpp_std: "c++11", gnu_extensions: "false", bazel_cpp_std: "c++11"}, + {cpp_std: "c++11", gnu_extensions: "false", bazel_cpp_std: "c++11", bazel_c_std: "c99"}, {cpp_std: "c++11", gnu_extensions: "true", bazel_cpp_std: "c++11"}, // "c++17", {cpp_std: "c++17", gnu_extensions: "", bazel_cpp_std: "c++17"}, - {cpp_std: "c++17", gnu_extensions: "false", bazel_cpp_std: "c++17"}, + {cpp_std: "c++17", gnu_extensions: "false", bazel_cpp_std: "c++17", bazel_c_std: "c99"}, {cpp_std: "c++17", gnu_extensions: "true", bazel_cpp_std: "c++17"}, // "c++2a", {cpp_std: "c++2a", gnu_extensions: "", bazel_cpp_std: "c++2a"}, - {cpp_std: "c++2a", gnu_extensions: "false", bazel_cpp_std: "c++2a"}, + {cpp_std: "c++2a", gnu_extensions: "false", bazel_cpp_std: "c++2a", bazel_c_std: "c99"}, {cpp_std: "c++2a", gnu_extensions: "true", bazel_cpp_std: "c++2a"}, // "c++98", {cpp_std: "c++98", gnu_extensions: "", bazel_cpp_std: "c++98"}, - {cpp_std: "c++98", gnu_extensions: "false", bazel_cpp_std: "c++98"}, + {cpp_std: "c++98", gnu_extensions: "false", bazel_cpp_std: "c++98", bazel_c_std: "c99"}, {cpp_std: "c++98", gnu_extensions: "true", bazel_cpp_std: "c++98"}, // gnu++ is replaced with c++ if gnu_extensions is explicitly false. // "gnu++11", {cpp_std: "gnu++11", gnu_extensions: "", bazel_cpp_std: "gnu++11"}, - {cpp_std: "gnu++11", gnu_extensions: "false", bazel_cpp_std: "c++11"}, + {cpp_std: "gnu++11", gnu_extensions: "false", bazel_cpp_std: "c++11", bazel_c_std: "c99"}, {cpp_std: "gnu++11", gnu_extensions: "true", bazel_cpp_std: "gnu++11"}, // "gnu++17", {cpp_std: "gnu++17", gnu_extensions: "", bazel_cpp_std: "gnu++17"}, - {cpp_std: "gnu++17", gnu_extensions: "false", bazel_cpp_std: "c++17"}, + {cpp_std: "gnu++17", gnu_extensions: "false", bazel_cpp_std: "c++17", bazel_c_std: "c99"}, {cpp_std: "gnu++17", gnu_extensions: "true", bazel_cpp_std: "gnu++17"}, + + // some c_std test cases + {c_std: "experimental", gnu_extensions: "", bazel_c_std: "gnu11"}, + {c_std: "experimental", gnu_extensions: "false", bazel_cpp_std: "c++17", bazel_c_std: "c11"}, + {c_std: "experimental", gnu_extensions: "true", bazel_c_std: "gnu11"}, + {c_std: "gnu11", cpp_std: "gnu++17", gnu_extensions: "", bazel_cpp_std: "gnu++17", bazel_c_std: "gnu11"}, + {c_std: "gnu11", cpp_std: "gnu++17", gnu_extensions: "false", bazel_cpp_std: "c++17", bazel_c_std: "c11"}, + {c_std: "gnu11", cpp_std: "gnu++17", gnu_extensions: "true", bazel_cpp_std: "gnu++17", bazel_c_std: "gnu11"}, } - for _, tc := range testCases { + for i, tc := range testCases { + name_prefix := fmt.Sprintf("a_%v", i) cppStdProp := "" if tc.cpp_std != "" { cppStdProp = fmt.Sprintf(" cpp_std: \"%s\",", tc.cpp_std) } + cStdProp := "" + if tc.c_std != "" { + cStdProp = fmt.Sprintf(" c_std: \"%s\",", tc.c_std) + } gnuExtensionsProp := "" if tc.gnu_extensions != "" { gnuExtensionsProp = fmt.Sprintf(" gnu_extensions: %s,", tc.gnu_extensions) @@ -1749,62 +1820,224 @@ func TestCcLibraryCppStdWithGnuExtensions_ConvertsToFeatureAttr(t *testing.T) { if tc.bazel_cpp_std != "" { attrs["cpp_std"] = fmt.Sprintf(`"%s"`, tc.bazel_cpp_std) } + if tc.bazel_c_std != "" { + attrs["c_std"] = fmt.Sprintf(`"%s"`, tc.bazel_c_std) + } runCcLibraryTestCase(t, bp2buildTestCase{ description: fmt.Sprintf( "cc_library with cpp_std: %s and gnu_extensions: %s", tc.cpp_std, tc.gnu_extensions), - moduleTypeUnderTest: "cc_library", - moduleTypeUnderTestFactory: cc.LibraryFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, blueprint: soongCcLibraryPreamble + fmt.Sprintf(` cc_library { - name: "a", + name: "%s_full", %s // cpp_std: *string +%s // c_std: *string %s // gnu_extensions: *bool include_build_directory: false, } -`, cppStdProp, gnuExtensionsProp), - expectedBazelTargets: []string{ - makeBazelTarget("cc_library", "a", attrs), - }, +`, name_prefix, cppStdProp, cStdProp, gnuExtensionsProp), + expectedBazelTargets: makeCcLibraryTargets(name_prefix+"_full", attrs), }) runCcLibraryStaticTestCase(t, bp2buildTestCase{ description: fmt.Sprintf( "cc_library_static with cpp_std: %s and gnu_extensions: %s", tc.cpp_std, tc.gnu_extensions), - moduleTypeUnderTest: "cc_library_static", - moduleTypeUnderTestFactory: cc.LibraryStaticFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build, + moduleTypeUnderTest: "cc_library_static", + moduleTypeUnderTestFactory: cc.LibraryStaticFactory, blueprint: soongCcLibraryPreamble + fmt.Sprintf(` cc_library_static { - name: "a", + name: "%s_static", %s // cpp_std: *string +%s // c_std: *string %s // gnu_extensions: *bool include_build_directory: false, } -`, cppStdProp, gnuExtensionsProp), +`, name_prefix, cppStdProp, cStdProp, gnuExtensionsProp), expectedBazelTargets: []string{ - makeBazelTarget("cc_library_static", "a", attrs), + makeBazelTarget("cc_library_static", name_prefix+"_static", attrs), }, }) runCcLibrarySharedTestCase(t, bp2buildTestCase{ description: fmt.Sprintf( "cc_library_shared with cpp_std: %s and gnu_extensions: %s", tc.cpp_std, tc.gnu_extensions), - moduleTypeUnderTest: "cc_library_shared", - moduleTypeUnderTestFactory: cc.LibrarySharedFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibrarySharedBp2Build, + moduleTypeUnderTest: "cc_library_shared", + moduleTypeUnderTestFactory: cc.LibrarySharedFactory, blueprint: soongCcLibraryPreamble + fmt.Sprintf(` cc_library_shared { - name: "a", + name: "%s_shared", %s // cpp_std: *string +%s // c_std: *string %s // gnu_extensions: *bool include_build_directory: false, } -`, cppStdProp, gnuExtensionsProp), +`, name_prefix, cppStdProp, cStdProp, gnuExtensionsProp), expectedBazelTargets: []string{ - makeBazelTarget("cc_library_shared", "a", attrs), + makeBazelTarget("cc_library_shared", name_prefix+"_shared", attrs), }, }) } } + +func TestCcLibraryProtoSimple(t *testing.T) { + runCcLibraryTestCase(t, bp2buildTestCase{ + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, + blueprint: soongCcProtoPreamble + `cc_library { + name: "foo", + srcs: ["foo.proto"], + include_build_directory: false, +}`, + expectedBazelTargets: []string{ + makeBazelTarget("proto_library", "foo_proto", attrNameToString{ + "srcs": `["foo.proto"]`, + "strip_import_prefix": `""`, + }), makeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", attrNameToString{ + "deps": `[":foo_proto"]`, + }), makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", attrNameToString{ + "implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`, + "deps": `[":libprotobuf-cpp-lite"]`, + }), makeBazelTarget("cc_library_shared", "foo", attrNameToString{ + "dynamic_deps": `[":libprotobuf-cpp-lite"]`, + }), + }, + }) +} + +func TestCcLibraryProtoNoCanonicalPathFromRoot(t *testing.T) { + runCcLibraryTestCase(t, bp2buildTestCase{ + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, + blueprint: soongCcProtoPreamble + `cc_library { + name: "foo", + srcs: ["foo.proto"], + proto: { canonical_path_from_root: false}, + include_build_directory: false, +}`, + expectedBazelTargets: []string{ + makeBazelTarget("proto_library", "foo_proto", attrNameToString{ + "srcs": `["foo.proto"]`, + }), makeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", attrNameToString{ + "deps": `[":foo_proto"]`, + }), makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", attrNameToString{ + "implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`, + "deps": `[":libprotobuf-cpp-lite"]`, + }), makeBazelTarget("cc_library_shared", "foo", attrNameToString{ + "dynamic_deps": `[":libprotobuf-cpp-lite"]`, + }), + }, + }) +} + +func TestCcLibraryProtoExplicitCanonicalPathFromRoot(t *testing.T) { + runCcLibraryTestCase(t, bp2buildTestCase{ + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, + blueprint: soongCcProtoPreamble + `cc_library { + name: "foo", + srcs: ["foo.proto"], + proto: { canonical_path_from_root: true}, + include_build_directory: false, +}`, + expectedBazelTargets: []string{ + makeBazelTarget("proto_library", "foo_proto", attrNameToString{ + "srcs": `["foo.proto"]`, + "strip_import_prefix": `""`, + }), makeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", attrNameToString{ + "deps": `[":foo_proto"]`, + }), makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", attrNameToString{ + "implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`, + "deps": `[":libprotobuf-cpp-lite"]`, + }), makeBazelTarget("cc_library_shared", "foo", attrNameToString{ + "dynamic_deps": `[":libprotobuf-cpp-lite"]`, + }), + }, + }) +} + +func TestCcLibraryProtoFull(t *testing.T) { + runCcLibraryTestCase(t, bp2buildTestCase{ + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, + blueprint: soongCcProtoPreamble + `cc_library { + name: "foo", + srcs: ["foo.proto"], + proto: { + canonical_path_from_root: false, + type: "full", + }, + include_build_directory: false, +}`, + expectedBazelTargets: []string{ + makeBazelTarget("proto_library", "foo_proto", attrNameToString{ + "srcs": `["foo.proto"]`, + }), makeBazelTarget("cc_proto_library", "foo_cc_proto", attrNameToString{ + "deps": `[":foo_proto"]`, + }), makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", attrNameToString{ + "implementation_whole_archive_deps": `[":foo_cc_proto"]`, + "deps": `[":libprotobuf-cpp-full"]`, + }), makeBazelTarget("cc_library_shared", "foo", attrNameToString{ + "dynamic_deps": `[":libprotobuf-cpp-full"]`, + }), + }, + }) +} + +func TestCcLibraryProtoLite(t *testing.T) { + runCcLibraryTestCase(t, bp2buildTestCase{ + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, + blueprint: soongCcProtoPreamble + `cc_library { + name: "foo", + srcs: ["foo.proto"], + proto: { + canonical_path_from_root: false, + type: "lite", + }, + include_build_directory: false, +}`, + expectedBazelTargets: []string{ + makeBazelTarget("proto_library", "foo_proto", attrNameToString{ + "srcs": `["foo.proto"]`, + }), makeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", attrNameToString{ + "deps": `[":foo_proto"]`, + }), makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", attrNameToString{ + "implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`, + "deps": `[":libprotobuf-cpp-lite"]`, + }), makeBazelTarget("cc_library_shared", "foo", attrNameToString{ + "dynamic_deps": `[":libprotobuf-cpp-lite"]`, + }), + }, + }) +} + +func TestCcLibraryProtoExportHeaders(t *testing.T) { + runCcLibraryTestCase(t, bp2buildTestCase{ + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, + blueprint: soongCcProtoPreamble + `cc_library { + name: "foo", + srcs: ["foo.proto"], + proto: { + canonical_path_from_root: false, + export_proto_headers: true, + }, + include_build_directory: false, +}`, + expectedBazelTargets: []string{ + makeBazelTarget("proto_library", "foo_proto", attrNameToString{ + "srcs": `["foo.proto"]`, + }), makeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", attrNameToString{ + "deps": `[":foo_proto"]`, + }), makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", attrNameToString{ + "deps": `[":libprotobuf-cpp-lite"]`, + "whole_archive_deps": `[":foo_cc_proto_lite"]`, + }), makeBazelTarget("cc_library_shared", "foo", attrNameToString{ + "dynamic_deps": `[":libprotobuf-cpp-lite"]`, + "whole_archive_deps": `[":foo_cc_proto_lite"]`, + }), + }, + }) +} diff --git a/bp2build/cc_library_headers_conversion_test.go b/bp2build/cc_library_headers_conversion_test.go index 76fdab2f4..594c05009 100644 --- a/bp2build/cc_library_headers_conversion_test.go +++ b/bp2build/cc_library_headers_conversion_test.go @@ -78,10 +78,9 @@ func runCcLibraryHeadersTestCase(t *testing.T, tc bp2buildTestCase) { func TestCcLibraryHeadersSimple(t *testing.T) { runCcLibraryHeadersTestCase(t, bp2buildTestCase{ - description: "cc_library_headers test", - moduleTypeUnderTest: "cc_library_headers", - moduleTypeUnderTestFactory: cc.LibraryHeaderFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryHeadersBp2Build, + description: "cc_library_headers test", + moduleTypeUnderTest: "cc_library_headers", + moduleTypeUnderTestFactory: cc.LibraryHeaderFactory, filesystem: map[string]string{ "lib-1/lib1a.h": "", "lib-1/lib1b.h": "", @@ -150,11 +149,10 @@ cc_library_headers { func TestCcLibraryHeadersOsSpecificHeader(t *testing.T) { runCcLibraryHeadersTestCase(t, bp2buildTestCase{ - description: "cc_library_headers test with os-specific header_libs props", - moduleTypeUnderTest: "cc_library_headers", - moduleTypeUnderTestFactory: cc.LibraryHeaderFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryHeadersBp2Build, - filesystem: map[string]string{}, + description: "cc_library_headers test with os-specific header_libs props", + moduleTypeUnderTest: "cc_library_headers", + moduleTypeUnderTestFactory: cc.LibraryHeaderFactory, + filesystem: map[string]string{}, blueprint: soongCcLibraryPreamble + ` cc_library_headers { name: "android-lib", @@ -209,11 +207,10 @@ cc_library_headers { func TestCcLibraryHeadersOsSpecficHeaderLibsExportHeaderLibHeaders(t *testing.T) { runCcLibraryHeadersTestCase(t, bp2buildTestCase{ - description: "cc_library_headers test with os-specific header_libs and export_header_lib_headers props", - moduleTypeUnderTest: "cc_library_headers", - moduleTypeUnderTestFactory: cc.LibraryHeaderFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryHeadersBp2Build, - filesystem: map[string]string{}, + description: "cc_library_headers test with os-specific header_libs and export_header_lib_headers props", + moduleTypeUnderTest: "cc_library_headers", + moduleTypeUnderTestFactory: cc.LibraryHeaderFactory, + filesystem: map[string]string{}, blueprint: soongCcLibraryPreamble + ` cc_library_headers { name: "android-lib", @@ -250,11 +247,10 @@ 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, - filesystem: map[string]string{}, + description: "cc_library_headers test with arch-specific and target-specific export_system_include_dirs props", + moduleTypeUnderTest: "cc_library_headers", + moduleTypeUnderTestFactory: cc.LibraryHeaderFactory, + filesystem: map[string]string{}, blueprint: soongCcLibraryPreamble + `cc_library_headers { name: "foo_headers", export_system_include_dirs: [ @@ -310,10 +306,9 @@ func TestCcLibraryHeadersArchAndTargetExportSystemIncludes(t *testing.T) { func TestCcLibraryHeadersNoCrtIgnored(t *testing.T) { runCcLibraryHeadersTestCase(t, bp2buildTestCase{ - description: "cc_library_headers test", - moduleTypeUnderTest: "cc_library_headers", - moduleTypeUnderTestFactory: cc.LibraryHeaderFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryHeadersBp2Build, + description: "cc_library_headers test", + moduleTypeUnderTest: "cc_library_headers", + moduleTypeUnderTestFactory: cc.LibraryHeaderFactory, filesystem: map[string]string{ "lib-1/lib1a.h": "", "lib-1/lib1b.h": "", diff --git a/bp2build/cc_library_shared_conversion_test.go b/bp2build/cc_library_shared_conversion_test.go index 4ec95c3a3..97a600a99 100644 --- a/bp2build/cc_library_shared_conversion_test.go +++ b/bp2build/cc_library_shared_conversion_test.go @@ -33,13 +33,13 @@ func registerCcLibrarySharedModuleTypes(ctx android.RegistrationContext) { ctx.RegisterModuleType("toolchain_library", cc.ToolchainLibraryFactory) ctx.RegisterModuleType("cc_library_headers", cc.LibraryHeaderFactory) ctx.RegisterModuleType("cc_library_static", cc.LibraryStaticFactory) + ctx.RegisterModuleType("cc_library", cc.LibraryFactory) } func runCcLibrarySharedTestCase(t *testing.T, tc bp2buildTestCase) { t.Helper() (&tc).moduleTypeUnderTest = "cc_library_shared" (&tc).moduleTypeUnderTestFactory = cc.LibrarySharedFactory - (&tc).moduleTypeUnderTestBp2BuildMutator = cc.CcLibrarySharedBp2Build runBp2BuildTestCase(t, registerCcLibrarySharedModuleTypes, tc) } @@ -425,3 +425,42 @@ cc_library_shared { expectedErr: fmt.Errorf("Android.bp:16:1: module \"foo_shared\": nocrt is not supported for arch variants"), }) } + +func TestCcLibrarySharedProto(t *testing.T) { + runCcLibrarySharedTestCase(t, bp2buildTestCase{ + blueprint: soongCcProtoPreamble + `cc_library_shared { + name: "foo", + srcs: ["foo.proto"], + proto: { + canonical_path_from_root: false, + export_proto_headers: true, + }, + include_build_directory: false, +}`, + expectedBazelTargets: []string{ + makeBazelTarget("proto_library", "foo_proto", attrNameToString{ + "srcs": `["foo.proto"]`, + }), makeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", attrNameToString{ + "deps": `[":foo_proto"]`, + }), makeBazelTarget("cc_library_shared", "foo", attrNameToString{ + "dynamic_deps": `[":libprotobuf-cpp-lite"]`, + "whole_archive_deps": `[":foo_cc_proto_lite"]`, + }), + }, + }) +} + +func TestCcLibrarySharedUseVersionLib(t *testing.T) { + runCcLibrarySharedTestCase(t, bp2buildTestCase{ + blueprint: soongCcProtoPreamble + `cc_library_shared { + name: "foo", + use_version_lib: true, + include_build_directory: false, +}`, + expectedBazelTargets: []string{ + makeBazelTarget("cc_library_shared", "foo", attrNameToString{ + "use_version_lib": "True", + }), + }, + }) +} diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go index 2f760d236..e2e55ddee 100644 --- a/bp2build/cc_library_static_conversion_test.go +++ b/bp2build/cc_library_static_conversion_test.go @@ -82,7 +82,6 @@ func runCcLibraryStaticTestCase(t *testing.T, tc bp2buildTestCase) { (&tc).moduleTypeUnderTest = "cc_library_static" (&tc).moduleTypeUnderTestFactory = cc.LibraryStaticFactory - (&tc).moduleTypeUnderTestBp2BuildMutator = cc.CcLibraryStaticBp2Build runBp2BuildTestCase(t, registerCcLibraryStaticModuleTypes, tc) } @@ -954,11 +953,13 @@ func TestCcLibraryStaticGeneratedHeadersAllPartitions(t *testing.T) { genrule { name: "generated_hdr", cmd: "nothing to see here", + bazel_module: { bp2build_available: false }, } genrule { name: "export_generated_hdr", cmd: "nothing to see here", + bazel_module: { bp2build_available: false }, } cc_library_static { @@ -970,7 +971,9 @@ cc_library_static { }`, expectedBazelTargets: []string{ makeBazelTarget("cc_library_static", "foo_static", attrNameToString{ - "hdrs": `[":export_generated_hdr"]`, + "export_includes": `["."]`, + "local_includes": `["."]`, + "hdrs": `[":export_generated_hdr"]`, "srcs": `[ "cpp_src.cpp", ":generated_hdr", @@ -996,66 +999,38 @@ func TestCcLibraryStaticArchSrcsExcludeSrcsGeneratedFiles(t *testing.T) { "for-x86.cpp": "", "not-for-x86.cpp": "", "not-for-everything.cpp": "", - "dep/Android.bp": ` -genrule { - name: "generated_src_other_pkg", - cmd: "nothing to see here", -} - -genrule { - name: "generated_hdr_other_pkg", - cmd: "nothing to see here", -} - -genrule { - name: "generated_hdr_other_pkg_x86", - cmd: "nothing to see here", -} - -genrule { - name: "generated_hdr_other_pkg_android", - cmd: "nothing to see here", -}`, + "dep/Android.bp": simpleModuleDoNotConvertBp2build("genrule", "generated_src_other_pkg") + + simpleModuleDoNotConvertBp2build("genrule", "generated_hdr_other_pkg") + + simpleModuleDoNotConvertBp2build("genrule", "generated_src_other_pkg_x86") + + simpleModuleDoNotConvertBp2build("genrule", "generated_hdr_other_pkg_x86") + + simpleModuleDoNotConvertBp2build("genrule", "generated_hdr_other_pkg_android"), }, - blueprint: soongCcLibraryStaticPreamble + ` -genrule { - name: "generated_src", - cmd: "nothing to see here", -} - -genrule { - name: "generated_src_not_x86", - cmd: "nothing to see here", -} - -genrule { - name: "generated_src_android", - cmd: "nothing to see here", -} - -genrule { - name: "generated_hdr", - cmd: "nothing to see here", -} - + blueprint: soongCcLibraryStaticPreamble + + simpleModuleDoNotConvertBp2build("genrule", "generated_src") + + simpleModuleDoNotConvertBp2build("genrule", "generated_src_not_x86") + + simpleModuleDoNotConvertBp2build("genrule", "generated_src_android") + + simpleModuleDoNotConvertBp2build("genrule", "generated_hdr") + ` cc_library_static { name: "foo_static", srcs: ["common.cpp", "not-for-*.cpp"], exclude_srcs: ["not-for-everything.cpp"], generated_sources: ["generated_src", "generated_src_other_pkg", "generated_src_not_x86"], generated_headers: ["generated_hdr", "generated_hdr_other_pkg"], + export_generated_headers: ["generated_hdr_other_pkg"], arch: { x86: { srcs: ["for-x86.cpp"], exclude_srcs: ["not-for-x86.cpp"], generated_headers: ["generated_hdr_other_pkg_x86"], exclude_generated_sources: ["generated_src_not_x86"], + export_generated_headers: ["generated_hdr_other_pkg_x86"], }, }, target: { android: { generated_sources: ["generated_src_android"], generated_headers: ["generated_hdr_other_pkg_android"], + export_generated_headers: ["generated_hdr_other_pkg_android"], }, }, @@ -1069,23 +1044,25 @@ cc_library_static { ":generated_src", "//dep:generated_src_other_pkg", ":generated_hdr", - "//dep:generated_hdr_other_pkg", ] + select({ - "//build/bazel/platforms/arch:x86": [ - "for-x86.cpp", - "//dep:generated_hdr_other_pkg_x86", - ], + "//build/bazel/platforms/arch:x86": ["for-x86.cpp"], "//conditions:default": [ "not-for-x86.cpp", ":generated_src_not_x86", ], }) + select({ - "//build/bazel/platforms/os:android": [ - ":generated_src_android", - "//dep:generated_hdr_other_pkg_android", - ], + "//build/bazel/platforms/os:android": [":generated_src_android"], "//conditions:default": [], })`, + "hdrs": `["//dep:generated_hdr_other_pkg"] + select({ + "//build/bazel/platforms/arch:x86": ["//dep:generated_hdr_other_pkg_x86"], + "//conditions:default": [], + }) + select({ + "//build/bazel/platforms/os:android": ["//dep:generated_hdr_other_pkg_android"], + "//conditions:default": [], + })`, + "local_includes": `["."]`, + "export_absolute_includes": `["dep"]`, }), }, }) @@ -1366,9 +1343,8 @@ cc_library_static { func TestStaticLibrary_SystemSharedLibsBionic(t *testing.T) { runCcLibraryStaticTestCase(t, bp2buildTestCase{ description: "cc_library_static system_shared_libs set for bionic variant", - blueprint: soongCcLibraryStaticPreamble + ` -cc_library{name: "libc"} - + blueprint: soongCcLibraryStaticPreamble + + simpleModuleDoNotConvertBp2build("cc_library", "libc") + ` cc_library_static { name: "target_bionic", target: { @@ -1394,10 +1370,9 @@ cc_library_static { func TestStaticLibrary_SystemSharedLibsLinuxRootAndLinuxBionic(t *testing.T) { runCcLibraryStaticTestCase(t, bp2buildTestCase{ description: "cc_library_static system_shared_libs set for root and linux_bionic variant", - blueprint: soongCcLibraryStaticPreamble + ` -cc_library{name: "libc"} -cc_library{name: "libm"} - + blueprint: soongCcLibraryStaticPreamble + + simpleModuleDoNotConvertBp2build("cc_library", "libc") + + simpleModuleDoNotConvertBp2build("cc_library", "libm") + ` cc_library_static { name: "target_linux_bionic", system_shared_libs: ["libc"], @@ -1419,3 +1394,42 @@ cc_library_static { }, }) } + +func TestCcLibraryStaticProto(t *testing.T) { + runCcLibraryStaticTestCase(t, bp2buildTestCase{ + blueprint: soongCcProtoPreamble + `cc_library_static { + name: "foo", + srcs: ["foo.proto"], + proto: { + canonical_path_from_root: false, + export_proto_headers: true, + }, + include_build_directory: false, +}`, + expectedBazelTargets: []string{ + makeBazelTarget("proto_library", "foo_proto", attrNameToString{ + "srcs": `["foo.proto"]`, + }), makeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", attrNameToString{ + "deps": `[":foo_proto"]`, + }), makeBazelTarget("cc_library_static", "foo", attrNameToString{ + "deps": `[":libprotobuf-cpp-lite"]`, + "whole_archive_deps": `[":foo_cc_proto_lite"]`, + }), + }, + }) +} + +func TestCcLibraryStaticUseVersionLib(t *testing.T) { + runCcLibraryStaticTestCase(t, bp2buildTestCase{ + blueprint: soongCcProtoPreamble + `cc_library_static { + name: "foo", + use_version_lib: true, + include_build_directory: false, +}`, + expectedBazelTargets: []string{ + makeBazelTarget("cc_library_static", "foo", attrNameToString{ + "use_version_lib": "True", + }), + }, + }) +} diff --git a/bp2build/cc_object_conversion_test.go b/bp2build/cc_object_conversion_test.go index 5ab9129e7..0a6c3175d 100644 --- a/bp2build/cc_object_conversion_test.go +++ b/bp2build/cc_object_conversion_test.go @@ -30,7 +30,6 @@ func runCcObjectTestCase(t *testing.T, tc bp2buildTestCase) { t.Helper() (&tc).moduleTypeUnderTest = "cc_object" (&tc).moduleTypeUnderTestFactory = cc.ObjectFactory - (&tc).moduleTypeUnderTestBp2BuildMutator = cc.ObjectBp2Build runBp2BuildTestCase(t, registerCcObjectModuleTypes, tc) } diff --git a/bp2build/cc_prebuilt_library_shared_test.go b/bp2build/cc_prebuilt_library_shared_test.go index bac3908da..ef2fddc5b 100644 --- a/bp2build/cc_prebuilt_library_shared_test.go +++ b/bp2build/cc_prebuilt_library_shared_test.go @@ -9,10 +9,9 @@ import ( func TestSharedPrebuiltLibrary(t *testing.T) { runBp2BuildTestCaseSimple(t, bp2buildTestCase{ - description: "prebuilt library shared simple", - moduleTypeUnderTest: "cc_prebuilt_library_shared", - moduleTypeUnderTestFactory: cc.PrebuiltSharedLibraryFactory, - moduleTypeUnderTestBp2BuildMutator: cc.PrebuiltLibrarySharedBp2Build, + description: "prebuilt library shared simple", + moduleTypeUnderTest: "cc_prebuilt_library_shared", + moduleTypeUnderTestFactory: cc.PrebuiltSharedLibraryFactory, filesystem: map[string]string{ "libf.so": "", }, @@ -33,10 +32,9 @@ cc_prebuilt_library_shared { func TestSharedPrebuiltLibraryWithArchVariance(t *testing.T) { runBp2BuildTestCaseSimple(t, bp2buildTestCase{ - description: "prebuilt library shared with arch variance", - moduleTypeUnderTest: "cc_prebuilt_library_shared", - moduleTypeUnderTestFactory: cc.PrebuiltSharedLibraryFactory, - moduleTypeUnderTestBp2BuildMutator: cc.PrebuiltLibrarySharedBp2Build, + description: "prebuilt library shared with arch variance", + moduleTypeUnderTest: "cc_prebuilt_library_shared", + moduleTypeUnderTestFactory: cc.PrebuiltSharedLibraryFactory, filesystem: map[string]string{ "libf.so": "", "libg.so": "", diff --git a/bp2build/filegroup_conversion_test.go b/bp2build/filegroup_conversion_test.go index 9f4add2ff..b43cf5374 100644 --- a/bp2build/filegroup_conversion_test.go +++ b/bp2build/filegroup_conversion_test.go @@ -25,7 +25,6 @@ func runFilegroupTestCase(t *testing.T, tc bp2buildTestCase) { t.Helper() (&tc).moduleTypeUnderTest = "filegroup" (&tc).moduleTypeUnderTestFactory = android.FileGroupFactory - (&tc).moduleTypeUnderTestBp2BuildMutator = android.FilegroupBp2Build runBp2BuildTestCase(t, registerFilegroupModuleTypes, tc) } diff --git a/bp2build/genrule_conversion_test.go b/bp2build/genrule_conversion_test.go index 597666694..fd631a53b 100644 --- a/bp2build/genrule_conversion_test.go +++ b/bp2build/genrule_conversion_test.go @@ -28,7 +28,6 @@ func runGenruleTestCase(t *testing.T, tc bp2buildTestCase) { t.Helper() (&tc).moduleTypeUnderTest = "genrule" (&tc).moduleTypeUnderTestFactory = genrule.GenRuleFactory - (&tc).moduleTypeUnderTestBp2BuildMutator = genrule.GenruleBp2Build runBp2BuildTestCase(t, registerGenruleModuleTypes, tc) } diff --git a/bp2build/java_binary_host_conversion_test.go b/bp2build/java_binary_host_conversion_test.go new file mode 100644 index 000000000..96b895876 --- /dev/null +++ b/bp2build/java_binary_host_conversion_test.go @@ -0,0 +1,63 @@ +// Copyright 2021 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package bp2build + +import ( + "testing" + + "android/soong/android" + "android/soong/cc" + "android/soong/java" +) + +func runJavaBinaryHostTestCase(t *testing.T, tc bp2buildTestCase) { + t.Helper() + (&tc).moduleTypeUnderTest = "java_binary_host" + (&tc).moduleTypeUnderTestFactory = java.BinaryHostFactory + runBp2BuildTestCase(t, func(ctx android.RegistrationContext) { + ctx.RegisterModuleType("cc_library_host_shared", cc.LibraryHostSharedFactory) + }, tc) +} + +var fs = map[string]string{ + "test.mf": "Main-Class: com.android.test.MainClass", + "other/Android.bp": `cc_library_host_shared { + name: "jni-lib-1", + stl: "none", +}`, +} + +func TestJavaBinaryHost(t *testing.T) { + runJavaBinaryHostTestCase(t, bp2buildTestCase{ + description: "java_binary_host with srcs, exclude_srcs, jni_libs and manifest.", + filesystem: fs, + blueprint: `java_binary_host { + name: "java-binary-host-1", + srcs: ["a.java", "b.java"], + exclude_srcs: ["b.java"], + manifest: "test.mf", + jni_libs: ["jni-lib-1"], + bazel_module: { bp2build_available: true }, +}`, + expectedBazelTargets: []string{ + makeBazelTarget("java_binary", "java-binary-host-1", attrNameToString{ + "srcs": `["a.java"]`, + "main_class": `"com.android.test.MainClass"`, + "deps": `["//other:jni-lib-1"]`, + "jvm_flags": `["-Djava.library.path=$${RUNPATH}other"]`, + }), + }, + }) +} diff --git a/bp2build/java_library_conversion_test.go b/bp2build/java_library_conversion_test.go new file mode 100644 index 000000000..5c65ec230 --- /dev/null +++ b/bp2build/java_library_conversion_test.go @@ -0,0 +1,57 @@ +// Copyright 2021 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package bp2build + +import ( + "testing" + + "android/soong/android" + "android/soong/java" +) + +func runJavaLibraryTestCase(t *testing.T, tc bp2buildTestCase) { + t.Helper() + (&tc).moduleTypeUnderTest = "java_library" + (&tc).moduleTypeUnderTestFactory = java.LibraryFactory + runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc) +} + +func TestJavaLibrary(t *testing.T) { + runJavaLibraryTestCase(t, bp2buildTestCase{ + description: "java_library with srcs, exclude_srcs and libs", + blueprint: `java_library { + name: "java-lib-1", + srcs: ["a.java", "b.java"], + exclude_srcs: ["b.java"], + libs: ["java-lib-2"], + bazel_module: { bp2build_available: true }, +} + +java_library { + name: "java-lib-2", + srcs: ["b.java"], + bazel_module: { bp2build_available: true }, +}`, + expectedBazelTargets: []string{ + makeBazelTarget("java_library", "java-lib-1", attrNameToString{ + "srcs": `["a.java"]`, + "deps": `[":java-lib-2"]`, + }), + makeBazelTarget("java_library", "java-lib-2", attrNameToString{ + "srcs": `["b.java"]`, + }), + }, + }) +} diff --git a/bp2build/java_library_host_conversion_test.go b/bp2build/java_library_host_conversion_test.go new file mode 100644 index 000000000..6ac82dbd2 --- /dev/null +++ b/bp2build/java_library_host_conversion_test.go @@ -0,0 +1,57 @@ +// Copyright 2021 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package bp2build + +import ( + "testing" + + "android/soong/android" + "android/soong/java" +) + +func runJavaLibraryHostTestCase(t *testing.T, tc bp2buildTestCase) { + t.Helper() + (&tc).moduleTypeUnderTest = "java_library_host" + (&tc).moduleTypeUnderTestFactory = java.LibraryHostFactory + runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc) +} + +func TestJavaLibraryHost(t *testing.T) { + runJavaLibraryHostTestCase(t, bp2buildTestCase{ + description: "java_library_host with srcs, exclude_srcs and libs", + blueprint: `java_library_host { + name: "java-lib-host-1", + srcs: ["a.java", "b.java"], + exclude_srcs: ["b.java"], + libs: ["java-lib-host-2"], + bazel_module: { bp2build_available: true }, +} + +java_library_host { + name: "java-lib-host-2", + srcs: ["c.java"], + bazel_module: { bp2build_available: true }, +}`, + expectedBazelTargets: []string{ + makeBazelTarget("java_library", "java-lib-host-1", attrNameToString{ + "srcs": `["a.java"]`, + "deps": `[":java-lib-host-2"]`, + }), + makeBazelTarget("java_library", "java-lib-host-2", attrNameToString{ + "srcs": `["c.java"]`, + }), + }, + }) +} diff --git a/bp2build/metrics.go b/bp2build/metrics.go index 1cc4143c5..68ac54435 100644 --- a/bp2build/metrics.go +++ b/bp2build/metrics.go @@ -1,41 +1,61 @@ package bp2build import ( - "android/soong/android" "fmt" + "os" + "path/filepath" "strings" + + "android/soong/android" + "android/soong/shared" + "android/soong/ui/metrics/bp2build_metrics_proto" ) // Simple metrics struct to collect information about a Blueprint to BUILD // conversion process. type CodegenMetrics struct { // Total number of Soong modules converted to generated targets - generatedModuleCount int + generatedModuleCount uint64 // Total number of Soong modules converted to handcrafted targets - handCraftedModuleCount int + handCraftedModuleCount uint64 // Total number of unconverted Soong modules - unconvertedModuleCount int + unconvertedModuleCount uint64 // Counts of generated Bazel targets per Bazel rule class - ruleClassCount map[string]int + ruleClassCount map[string]uint64 + // List of modules with unconverted deps + // NOTE: NOT in the .proto moduleWithUnconvertedDepsMsgs []string + // List of converted modules convertedModules []string } +// Serialize returns the protoized version of CodegenMetrics: bp2build_metrics_proto.Bp2BuildMetrics +func (metrics *CodegenMetrics) Serialize() bp2build_metrics_proto.Bp2BuildMetrics { + return bp2build_metrics_proto.Bp2BuildMetrics{ + GeneratedModuleCount: metrics.generatedModuleCount, + HandCraftedModuleCount: metrics.handCraftedModuleCount, + UnconvertedModuleCount: metrics.unconvertedModuleCount, + RuleClassCount: metrics.ruleClassCount, + ConvertedModules: metrics.convertedModules, + } +} + // Print the codegen metrics to stdout. func (metrics *CodegenMetrics) Print() { - generatedTargetCount := 0 + generatedTargetCount := uint64(0) for _, ruleClass := range android.SortedStringKeys(metrics.ruleClassCount) { count := metrics.ruleClassCount[ruleClass] fmt.Printf("[bp2build] %s: %d targets\n", ruleClass, count) generatedTargetCount += count } fmt.Printf( - "[bp2build] Generated %d total BUILD targets and included %d handcrafted BUILD targets from %d Android.bp modules.\n With %d modules with unconverted deps \n\t%s", + "[bp2build] Converted %d Android.bp modules to %d total generated BUILD targets. Included %d handcrafted BUILD targets. There are %d total Android.bp modules.\n%d converted modules have unconverted deps: \n\t%s", + metrics.generatedModuleCount, generatedTargetCount, metrics.handCraftedModuleCount, metrics.TotalModuleCount(), @@ -43,6 +63,40 @@ func (metrics *CodegenMetrics) Print() { strings.Join(metrics.moduleWithUnconvertedDepsMsgs, "\n\t")) } +const bp2buildMetricsFilename = "bp2build_metrics.pb" + +// fail prints $PWD to stderr, followed by the given printf string and args (vals), +// then the given alert, and then exits with 1 for failure +func fail(err error, alertFmt string, vals ...interface{}) { + cwd, wderr := os.Getwd() + if wderr != nil { + cwd = "FAILED TO GET $PWD: " + wderr.Error() + } + fmt.Fprintf(os.Stderr, "\nIn "+cwd+":\n"+alertFmt+"\n"+err.Error()+"\n", vals...) + os.Exit(1) +} + +// Write the bp2build-protoized codegen metrics into the given directory +func (metrics *CodegenMetrics) Write(dir string) { + if _, err := os.Stat(dir); os.IsNotExist(err) { + // The metrics dir doesn't already exist, so create it (and parents) + if err := os.MkdirAll(dir, 0755); err != nil { // rx for all; w for user + fail(err, "Failed to `mkdir -p` %s", dir) + } + } else if err != nil { + fail(err, "Failed to `stat` %s", dir) + } + metricsFile := filepath.Join(dir, bp2buildMetricsFilename) + if err := metrics.dump(metricsFile); err != nil { + fail(err, "Error outputting %s", metricsFile) + } + if _, err := os.Stat(metricsFile); err != nil { + fail(err, "MISSING BP2BUILD METRICS OUTPUT: Failed to `stat` %s", metricsFile) + } else { + fmt.Printf("\nWrote bp2build metrics to: %s\n", metricsFile) + } +} + func (metrics *CodegenMetrics) IncrementRuleClassCount(ruleClass string) { metrics.ruleClassCount[ruleClass] += 1 } @@ -51,12 +105,18 @@ func (metrics *CodegenMetrics) IncrementUnconvertedCount() { metrics.unconvertedModuleCount += 1 } -func (metrics *CodegenMetrics) TotalModuleCount() int { +func (metrics *CodegenMetrics) TotalModuleCount() uint64 { return metrics.handCraftedModuleCount + metrics.generatedModuleCount + metrics.unconvertedModuleCount } +// Dump serializes the metrics to the given filename +func (metrics *CodegenMetrics) dump(filename string) (err error) { + ser := metrics.Serialize() + return shared.Save(&ser, filename) +} + type ConversionType int const ( diff --git a/bp2build/performance_test.go b/bp2build/performance_test.go index 32839522a..c4bbae262 100644 --- a/bp2build/performance_test.go +++ b/bp2build/performance_test.go @@ -29,6 +29,10 @@ import ( "testing" ) +const ( + performance_test_dir = "." +) + func genCustomModule(i int, convert bool) string { var conversionString string if convert { @@ -76,34 +80,83 @@ func genCustomModuleBp(pctConverted float64) string { return strings.Join(bp, "\n\n") } +type testConfig struct { + config android.Config + ctx *android.TestContext + codegenCtx *CodegenContext +} + +func (tc testConfig) parse() []error { + _, errs := tc.ctx.ParseFileList(performance_test_dir, []string{"Android.bp"}) + return errs +} + +func (tc testConfig) resolveDependencies() []error { + _, errs := tc.ctx.ResolveDependencies(tc.config) + return errs +} + +func (tc testConfig) convert() { + generateBazelTargetsForDir(tc.codegenCtx, performance_test_dir) +} + +func setup(builddir string, tcSize float64) testConfig { + config := android.TestConfig(buildDir, nil, genCustomModuleBp(tcSize), nil) + ctx := android.NewTestContext(config) + + registerCustomModuleForBp2buildConversion(ctx) + codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build) + return testConfig{ + config, + ctx, + codegenCtx, + } +} + var pctToConvert = []float64{0.0, 0.01, 0.05, 0.10, 0.25, 0.5, 0.75, 1.0} +// This is not intended to test performance, but to verify performance infra continues to work +func TestConvertManyModulesFull(t *testing.T) { + for _, tcSize := range pctToConvert { + + t.Run(fmt.Sprintf("pctConverted %f", tcSize), func(t *testing.T) { + testConfig := setup(buildDir, tcSize) + + errs := testConfig.parse() + if len(errs) > 0 { + t.Fatalf("Unexpected errors: %s", errs) + } + + errs = testConfig.resolveDependencies() + if len(errs) > 0 { + t.Fatalf("Unexpected errors: %s", errs) + } + + testConfig.convert() + }) + } +} + func BenchmarkManyModulesFull(b *testing.B) { - dir := "." for _, tcSize := range pctToConvert { b.Run(fmt.Sprintf("pctConverted %f", tcSize), func(b *testing.B) { for n := 0; n < b.N; n++ { b.StopTimer() - // setup we don't want to measure - config := android.TestConfig(buildDir, nil, genCustomModuleBp(tcSize), nil) - ctx := android.NewTestContext(config) - - registerCustomModuleForBp2buildConversion(ctx) - codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build) + testConfig := setup(buildDir, tcSize) b.StartTimer() - _, errs := ctx.ParseFileList(dir, []string{"Android.bp"}) + errs := testConfig.parse() if len(errs) > 0 { b.Fatalf("Unexpected errors: %s", errs) } - _, errs = ctx.ResolveDependencies(config) + errs = testConfig.resolveDependencies() if len(errs) > 0 { b.Fatalf("Unexpected errors: %s", errs) } - generateBazelTargetsForDir(codegenCtx, dir) + testConfig.convert() b.StopTimer() } }) @@ -111,63 +164,53 @@ func BenchmarkManyModulesFull(b *testing.B) { } func BenchmarkManyModulesResolveDependencies(b *testing.B) { - dir := "." for _, tcSize := range pctToConvert { b.Run(fmt.Sprintf("pctConverted %f", tcSize), func(b *testing.B) { for n := 0; n < b.N; n++ { b.StopTimer() // setup we don't want to measure - config := android.TestConfig(buildDir, nil, genCustomModuleBp(tcSize), nil) - ctx := android.NewTestContext(config) - - registerCustomModuleForBp2buildConversion(ctx) - codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build) + testConfig := setup(buildDir, tcSize) - _, errs := ctx.ParseFileList(dir, []string{"Android.bp"}) + errs := testConfig.parse() if len(errs) > 0 { b.Fatalf("Unexpected errors: %s", errs) } b.StartTimer() - _, errs = ctx.ResolveDependencies(config) + errs = testConfig.resolveDependencies() b.StopTimer() if len(errs) > 0 { b.Fatalf("Unexpected errors: %s", errs) } - generateBazelTargetsForDir(codegenCtx, dir) + testConfig.convert() } }) } } func BenchmarkManyModulesGenerateBazelTargetsForDir(b *testing.B) { - dir := "." for _, tcSize := range pctToConvert { b.Run(fmt.Sprintf("pctConverted %f", tcSize), func(b *testing.B) { for n := 0; n < b.N; n++ { b.StopTimer() // setup we don't want to measure - config := android.TestConfig(buildDir, nil, genCustomModuleBp(tcSize), nil) - ctx := android.NewTestContext(config) - - registerCustomModuleForBp2buildConversion(ctx) - codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build) + testConfig := setup(buildDir, tcSize) - _, errs := ctx.ParseFileList(dir, []string{"Android.bp"}) + errs := testConfig.parse() if len(errs) > 0 { b.Fatalf("Unexpected errors: %s", errs) } - _, errs = ctx.ResolveDependencies(config) + errs = testConfig.resolveDependencies() if len(errs) > 0 { b.Fatalf("Unexpected errors: %s", errs) } b.StartTimer() - generateBazelTargetsForDir(codegenCtx, dir) + testConfig.convert() b.StopTimer() } }) diff --git a/bp2build/prebuilt_etc_conversion_test.go b/bp2build/prebuilt_etc_conversion_test.go index 118930994..506589389 100644 --- a/bp2build/prebuilt_etc_conversion_test.go +++ b/bp2build/prebuilt_etc_conversion_test.go @@ -25,7 +25,6 @@ func runPrebuiltEtcTestCase(t *testing.T, tc bp2buildTestCase) { t.Helper() (&tc).moduleTypeUnderTest = "prebuilt_etc" (&tc).moduleTypeUnderTestFactory = etc.PrebuiltEtcFactory - (&tc).moduleTypeUnderTestBp2BuildMutator = etc.PrebuiltEtcBp2Build runBp2BuildTestCase(t, registerPrebuiltEtcModuleTypes, tc) } diff --git a/bp2build/python_binary_conversion_test.go b/bp2build/python_binary_conversion_test.go index 01b6aa268..40c8ba1e9 100644 --- a/bp2build/python_binary_conversion_test.go +++ b/bp2build/python_binary_conversion_test.go @@ -17,10 +17,9 @@ func runBp2BuildTestCaseWithPythonLibraries(t *testing.T, tc bp2buildTestCase) { func TestPythonBinaryHostSimple(t *testing.T) { runBp2BuildTestCaseWithPythonLibraries(t, bp2buildTestCase{ - description: "simple python_binary_host converts to a native py_binary", - moduleTypeUnderTest: "python_binary_host", - moduleTypeUnderTestFactory: python.PythonBinaryHostFactory, - moduleTypeUnderTestBp2BuildMutator: python.PythonBinaryBp2Build, + description: "simple python_binary_host converts to a native py_binary", + moduleTypeUnderTest: "python_binary_host", + moduleTypeUnderTestFactory: python.PythonBinaryHostFactory, filesystem: map[string]string{ "a.py": "", "b/c.py": "", @@ -40,7 +39,7 @@ func TestPythonBinaryHostSimple(t *testing.T) { python_library_host { name: "bar", srcs: ["b/e.py"], - bazel_module: { bp2build_available: true }, + bazel_module: { bp2build_available: false }, }`, expectedBazelTargets: []string{ makeBazelTarget("py_binary", "foo", attrNameToString{ @@ -59,10 +58,9 @@ func TestPythonBinaryHostSimple(t *testing.T) { func TestPythonBinaryHostPy2(t *testing.T) { runBp2BuildTestCaseSimple(t, bp2buildTestCase{ - description: "py2 python_binary_host", - moduleTypeUnderTest: "python_binary_host", - moduleTypeUnderTestFactory: python.PythonBinaryHostFactory, - moduleTypeUnderTestBp2BuildMutator: python.PythonBinaryBp2Build, + description: "py2 python_binary_host", + moduleTypeUnderTest: "python_binary_host", + moduleTypeUnderTestFactory: python.PythonBinaryHostFactory, blueprint: `python_binary_host { name: "foo", srcs: ["a.py"], @@ -89,10 +87,9 @@ func TestPythonBinaryHostPy2(t *testing.T) { func TestPythonBinaryHostPy3(t *testing.T) { runBp2BuildTestCaseSimple(t, bp2buildTestCase{ - description: "py3 python_binary_host", - moduleTypeUnderTest: "python_binary_host", - moduleTypeUnderTestFactory: python.PythonBinaryHostFactory, - moduleTypeUnderTestBp2BuildMutator: python.PythonBinaryBp2Build, + description: "py3 python_binary_host", + moduleTypeUnderTest: "python_binary_host", + moduleTypeUnderTestFactory: python.PythonBinaryHostFactory, blueprint: `python_binary_host { name: "foo", srcs: ["a.py"], @@ -119,10 +116,9 @@ func TestPythonBinaryHostPy3(t *testing.T) { func TestPythonBinaryHostArchVariance(t *testing.T) { runBp2BuildTestCaseSimple(t, bp2buildTestCase{ - description: "test arch variants", - moduleTypeUnderTest: "python_binary_host", - moduleTypeUnderTestFactory: python.PythonBinaryHostFactory, - moduleTypeUnderTestBp2BuildMutator: python.PythonBinaryBp2Build, + description: "test arch variants", + moduleTypeUnderTest: "python_binary_host", + moduleTypeUnderTestFactory: python.PythonBinaryHostFactory, filesystem: map[string]string{ "dir/arm.py": "", "dir/x86.py": "", diff --git a/bp2build/python_library_conversion_test.go b/bp2build/python_library_conversion_test.go index e3345921e..6b261052c 100644 --- a/bp2build/python_library_conversion_test.go +++ b/bp2build/python_library_conversion_test.go @@ -18,7 +18,6 @@ func runPythonLibraryTestCase(t *testing.T, tc bp2buildTestCase) { testCase.blueprint = fmt.Sprintf(testCase.blueprint, "python_library") testCase.moduleTypeUnderTest = "python_library" testCase.moduleTypeUnderTestFactory = python.PythonLibraryFactory - testCase.moduleTypeUnderTestBp2BuildMutator = python.PythonLibraryBp2Build runBp2BuildTestCaseSimple(t, testCase) } @@ -29,7 +28,6 @@ func runPythonLibraryHostTestCase(t *testing.T, tc bp2buildTestCase) { testCase.blueprint = fmt.Sprintf(testCase.blueprint, "python_library_host") testCase.moduleTypeUnderTest = "python_library_host" testCase.moduleTypeUnderTestFactory = python.PythonLibraryHostFactory - testCase.moduleTypeUnderTestBp2BuildMutator = python.PythonLibraryHostBp2Build runBp2BuildTestCase(t, func(ctx android.RegistrationContext) { ctx.RegisterModuleType("python_library", python.PythonLibraryFactory) }, diff --git a/bp2build/sh_conversion_test.go b/bp2build/sh_conversion_test.go index 1ca4a0e85..f6d2a2066 100644 --- a/bp2build/sh_conversion_test.go +++ b/bp2build/sh_conversion_test.go @@ -55,18 +55,21 @@ func runShBinaryTestCase(t *testing.T, tc bp2buildTestCase) { func TestShBinarySimple(t *testing.T) { runShBinaryTestCase(t, bp2buildTestCase{ - description: "sh_binary test", - moduleTypeUnderTest: "sh_binary", - moduleTypeUnderTestFactory: sh.ShBinaryFactory, - moduleTypeUnderTestBp2BuildMutator: sh.ShBinaryBp2Build, + description: "sh_binary test", + moduleTypeUnderTest: "sh_binary", + moduleTypeUnderTestFactory: sh.ShBinaryFactory, blueprint: `sh_binary { name: "foo", src: "foo.sh", + filename: "foo.exe", + sub_dir: "sub", bazel_module: { bp2build_available: true }, }`, expectedBazelTargets: []string{ makeBazelTarget("sh_binary", "foo", attrNameToString{ - "srcs": `["foo.sh"]`, + "srcs": `["foo.sh"]`, + "filename": `"foo.exe"`, + "sub_dir": `"sub"`, })}, }) } diff --git a/bp2build/soong_config_module_type_conversion_test.go b/bp2build/soong_config_module_type_conversion_test.go index d21db0459..f1489aab9 100644 --- a/bp2build/soong_config_module_type_conversion_test.go +++ b/bp2build/soong_config_module_type_conversion_test.go @@ -61,11 +61,10 @@ custom_cc_library_static { ` runSoongConfigModuleTypeTest(t, bp2buildTestCase{ - description: "soong config variables - soong_config_module_type is supported in bp2build", - moduleTypeUnderTest: "cc_library_static", - moduleTypeUnderTestFactory: cc.LibraryStaticFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build, - blueprint: bp, + description: "soong config variables - soong_config_module_type is supported in bp2build", + moduleTypeUnderTest: "cc_library_static", + moduleTypeUnderTestFactory: cc.LibraryStaticFactory, + blueprint: bp, expectedBazelTargets: []string{`cc_library_static( name = "foo", copts = select({ @@ -107,10 +106,9 @@ custom_cc_library_static { ` runSoongConfigModuleTypeTest(t, bp2buildTestCase{ - description: "soong config variables - soong_config_module_type_import is supported in bp2build", - moduleTypeUnderTest: "cc_library_static", - moduleTypeUnderTestFactory: cc.LibraryStaticFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build, + description: "soong config variables - soong_config_module_type_import is supported in bp2build", + moduleTypeUnderTest: "cc_library_static", + moduleTypeUnderTestFactory: cc.LibraryStaticFactory, filesystem: map[string]string{ "foo/bar/SoongConfig.bp": configBp, }, @@ -161,11 +159,10 @@ custom_cc_library_static { ` runSoongConfigModuleTypeTest(t, bp2buildTestCase{ - description: "soong config variables - generates selects for string vars", - moduleTypeUnderTest: "cc_library_static", - moduleTypeUnderTestFactory: cc.LibraryStaticFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build, - blueprint: bp, + description: "soong config variables - generates selects for string vars", + moduleTypeUnderTest: "cc_library_static", + moduleTypeUnderTestFactory: cc.LibraryStaticFactory, + blueprint: bp, expectedBazelTargets: []string{`cc_library_static( name = "foo", copts = select({ @@ -232,11 +229,10 @@ custom_cc_library_static { }` runSoongConfigModuleTypeTest(t, bp2buildTestCase{ - description: "soong config variables - generates selects for multiple variable types", - moduleTypeUnderTest: "cc_library_static", - moduleTypeUnderTestFactory: cc.LibraryStaticFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build, - blueprint: bp, + description: "soong config variables - generates selects for multiple variable types", + moduleTypeUnderTest: "cc_library_static", + moduleTypeUnderTestFactory: cc.LibraryStaticFactory, + blueprint: bp, expectedBazelTargets: []string{`cc_library_static( name = "foo", copts = select({ @@ -298,11 +294,10 @@ cc_library_static { name: "soc_default_static_dep", bazel_module: { bp2build_ava ` runSoongConfigModuleTypeTest(t, bp2buildTestCase{ - description: "soong config variables - generates selects for label list attributes", - moduleTypeUnderTest: "cc_library_static", - moduleTypeUnderTestFactory: cc.LibraryStaticFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build, - blueprint: bp, + description: "soong config variables - generates selects for label list attributes", + moduleTypeUnderTest: "cc_library_static", + moduleTypeUnderTestFactory: cc.LibraryStaticFactory, + blueprint: bp, filesystem: map[string]string{ "foo/bar/Android.bp": otherDeps, }, @@ -365,11 +360,10 @@ cc_library_static { ` runSoongConfigModuleTypeTest(t, bp2buildTestCase{ - description: "soong config variables - defaults with a single namespace", - moduleTypeUnderTest: "cc_library_static", - moduleTypeUnderTestFactory: cc.LibraryStaticFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build, - blueprint: bp, + description: "soong config variables - defaults with a single namespace", + moduleTypeUnderTest: "cc_library_static", + moduleTypeUnderTestFactory: cc.LibraryStaticFactory, + blueprint: bp, expectedBazelTargets: []string{`cc_library_static( name = "lib", copts = select({ @@ -445,11 +439,10 @@ cc_library_static { ` runSoongConfigModuleTypeTest(t, bp2buildTestCase{ - description: "soong config variables - multiple defaults with a single namespace", - moduleTypeUnderTest: "cc_library_static", - moduleTypeUnderTestFactory: cc.LibraryStaticFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build, - blueprint: bp, + description: "soong config variables - multiple defaults with a single namespace", + moduleTypeUnderTest: "cc_library_static", + moduleTypeUnderTestFactory: cc.LibraryStaticFactory, + blueprint: bp, expectedBazelTargets: []string{`cc_library_static( name = "lib", asflags = select({ @@ -561,11 +554,10 @@ cc_library_static { ` runSoongConfigModuleTypeTest(t, bp2buildTestCase{ - description: "soong config variables - defaults with multiple namespaces", - moduleTypeUnderTest: "cc_library_static", - moduleTypeUnderTestFactory: cc.LibraryStaticFactory, - moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build, - blueprint: bp, + description: "soong config variables - defaults with multiple namespaces", + moduleTypeUnderTest: "cc_library_static", + moduleTypeUnderTestFactory: cc.LibraryStaticFactory, + blueprint: bp, expectedBazelTargets: []string{`cc_library_static( name = "lib", copts = select({ @@ -652,11 +644,10 @@ cc_library { name: "lib_default", bazel_module: { bp2build_available: false } } ` runSoongConfigModuleTypeTest(t, bp2buildTestCase{ - description: "soong config variables - generates selects for library_linking_strategy", - moduleTypeUnderTest: "cc_binary", - moduleTypeUnderTestFactory: cc.BinaryFactory, - moduleTypeUnderTestBp2BuildMutator: cc.BinaryBp2build, - blueprint: bp, + description: "soong config variables - generates selects for library_linking_strategy", + moduleTypeUnderTest: "cc_binary", + moduleTypeUnderTestFactory: cc.BinaryFactory, + blueprint: bp, filesystem: map[string]string{ "foo/bar/Android.bp": otherDeps, }, @@ -733,11 +724,10 @@ cc_library { name: "lib_b", bazel_module: { bp2build_available: false } } ` runSoongConfigModuleTypeTest(t, bp2buildTestCase{ - description: "soong config variables - generates selects for library_linking_strategy", - moduleTypeUnderTest: "cc_binary", - moduleTypeUnderTestFactory: cc.BinaryFactory, - moduleTypeUnderTestBp2BuildMutator: cc.BinaryBp2build, - blueprint: bp, + description: "soong config variables - generates selects for library_linking_strategy", + moduleTypeUnderTest: "cc_binary", + moduleTypeUnderTestFactory: cc.BinaryFactory, + blueprint: bp, filesystem: map[string]string{ "foo/bar/Android.bp": otherDeps, }, @@ -821,11 +811,10 @@ cc_library { name: "lib_default", bazel_module: { bp2build_available: false } } ` runSoongConfigModuleTypeTest(t, bp2buildTestCase{ - description: "soong config variables - generates selects for library_linking_strategy", - moduleTypeUnderTest: "cc_binary", - moduleTypeUnderTestFactory: cc.BinaryFactory, - moduleTypeUnderTestBp2BuildMutator: cc.BinaryBp2build, - blueprint: bp, + description: "soong config variables - generates selects for library_linking_strategy", + moduleTypeUnderTest: "cc_binary", + moduleTypeUnderTestFactory: cc.BinaryFactory, + blueprint: bp, filesystem: map[string]string{ "foo/bar/Android.bp": otherDeps, }, diff --git a/bp2build/testing.go b/bp2build/testing.go index daa9c22db..15cf48689 100644 --- a/bp2build/testing.go +++ b/bp2build/testing.go @@ -74,16 +74,15 @@ func runBp2BuildTestCaseSimple(t *testing.T, tc bp2buildTestCase) { } type bp2buildTestCase struct { - description string - moduleTypeUnderTest string - moduleTypeUnderTestFactory android.ModuleFactory - moduleTypeUnderTestBp2BuildMutator func(android.TopDownMutatorContext) - blueprint string - expectedBazelTargets []string - filesystem map[string]string - dir string - expectedErr error - unconvertedDepsMode unconvertedDepsMode + description string + moduleTypeUnderTest string + moduleTypeUnderTestFactory android.ModuleFactory + blueprint string + expectedBazelTargets []string + filesystem map[string]string + dir string + expectedErr error + unconvertedDepsMode unconvertedDepsMode } func runBp2BuildTestCase(t *testing.T, registerModuleTypes func(ctx android.RegistrationContext), tc bp2buildTestCase) { @@ -105,7 +104,6 @@ func runBp2BuildTestCase(t *testing.T, registerModuleTypes func(ctx android.Regi registerModuleTypes(ctx) ctx.RegisterModuleType(tc.moduleTypeUnderTest, tc.moduleTypeUnderTestFactory) ctx.RegisterBp2BuildConfig(bp2buildConfig) - ctx.RegisterBp2BuildMutator(tc.moduleTypeUnderTest, tc.moduleTypeUnderTestBp2BuildMutator) ctx.RegisterForBazelConversion() _, parseErrs := ctx.ParseFileList(dir, toParse) @@ -149,15 +147,15 @@ func runBp2BuildTestCase(t *testing.T, registerModuleTypes func(ctx android.Regi } type nestedProps struct { - Nested_prop string + Nested_prop *string } type EmbeddedProps struct { - Embedded_prop string + Embedded_prop *string } type OtherEmbeddedProps struct { - Other_embedded_prop string + Other_embedded_prop *string } type customProps struct { @@ -178,6 +176,9 @@ type customProps struct { Arch_paths []string `android:"path,arch_variant"` Arch_paths_exclude []string `android:"path,arch_variant"` + + // Prop used to indicate this conversion should be 1 module -> multiple targets + One_to_many_prop *bool } type customModule struct { @@ -262,86 +263,80 @@ func customDefaultsModuleFactory() android.Module { } type EmbeddedAttr struct { - Embedded_attr string + Embedded_attr *string } type OtherEmbeddedAttr struct { - Other_embedded_attr string + Other_embedded_attr *string } type customBazelModuleAttributes struct { EmbeddedAttr *OtherEmbeddedAttr - String_prop string + String_ptr_prop *string String_list_prop []string Arch_paths bazel.LabelListAttribute } -func customBp2BuildMutator(ctx android.TopDownMutatorContext) { - if m, ok := ctx.Module().(*customModule); ok { - if !m.ConvertWithBp2build(ctx) { - return - } +func (m *customModule) ConvertWithBp2build(ctx android.TopDownMutatorContext) { + paths := bazel.LabelListAttribute{} - paths := bazel.LabelListAttribute{} + if p := m.props.One_to_many_prop; p != nil && *p { + customBp2buildOneToMany(ctx, m) + return + } - for axis, configToProps := range m.GetArchVariantProperties(ctx, &customProps{}) { - for config, props := range configToProps { - if archProps, ok := props.(*customProps); ok && archProps.Arch_paths != nil { - paths.SetSelectValue(axis, config, android.BazelLabelForModuleSrcExcludes(ctx, archProps.Arch_paths, archProps.Arch_paths_exclude)) - } + for axis, configToProps := range m.GetArchVariantProperties(ctx, &customProps{}) { + for config, props := range configToProps { + if archProps, ok := props.(*customProps); ok && archProps.Arch_paths != nil { + paths.SetSelectValue(axis, config, android.BazelLabelForModuleSrcExcludes(ctx, archProps.Arch_paths, archProps.Arch_paths_exclude)) } } + } - paths.ResolveExcludes() - - attrs := &customBazelModuleAttributes{ - String_prop: m.props.String_prop, - String_list_prop: m.props.String_list_prop, - Arch_paths: paths, - } - attrs.Embedded_attr = m.props.Embedded_prop - if m.props.OtherEmbeddedProps != nil { - attrs.OtherEmbeddedAttr = &OtherEmbeddedAttr{Other_embedded_attr: m.props.OtherEmbeddedProps.Other_embedded_prop} - } + paths.ResolveExcludes() - props := bazel.BazelTargetModuleProperties{ - Rule_class: "custom", - } + attrs := &customBazelModuleAttributes{ + String_ptr_prop: m.props.String_ptr_prop, + String_list_prop: m.props.String_list_prop, + Arch_paths: paths, + } + attrs.Embedded_attr = m.props.Embedded_prop + if m.props.OtherEmbeddedProps != nil { + attrs.OtherEmbeddedAttr = &OtherEmbeddedAttr{Other_embedded_attr: m.props.OtherEmbeddedProps.Other_embedded_prop} + } - ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs) + props := bazel.BazelTargetModuleProperties{ + Rule_class: "custom", } + + ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs) } // A bp2build mutator that uses load statements and creates a 1:M mapping from // module to target. -func customBp2BuildMutatorFromStarlark(ctx android.TopDownMutatorContext) { - if m, ok := ctx.Module().(*customModule); ok { - if !m.ConvertWithBp2build(ctx) { - return - } +func customBp2buildOneToMany(ctx android.TopDownMutatorContext, m *customModule) { - baseName := m.Name() - attrs := &customBazelModuleAttributes{} + baseName := m.Name() + attrs := &customBazelModuleAttributes{} - myLibraryProps := bazel.BazelTargetModuleProperties{ - Rule_class: "my_library", - Bzl_load_location: "//build/bazel/rules:rules.bzl", - } - ctx.CreateBazelTargetModule(myLibraryProps, android.CommonAttributes{Name: baseName}, attrs) + myLibraryProps := bazel.BazelTargetModuleProperties{ + Rule_class: "my_library", + Bzl_load_location: "//build/bazel/rules:rules.bzl", + } + ctx.CreateBazelTargetModule(myLibraryProps, android.CommonAttributes{Name: baseName}, attrs) - protoLibraryProps := bazel.BazelTargetModuleProperties{ - Rule_class: "proto_library", - Bzl_load_location: "//build/bazel/rules:proto.bzl", - } - ctx.CreateBazelTargetModule(protoLibraryProps, android.CommonAttributes{Name: baseName + "_proto_library_deps"}, attrs) + protoLibraryProps := bazel.BazelTargetModuleProperties{ + Rule_class: "proto_library", + Bzl_load_location: "//build/bazel/rules:proto.bzl", + } + ctx.CreateBazelTargetModule(protoLibraryProps, android.CommonAttributes{Name: baseName + "_proto_library_deps"}, attrs) - myProtoLibraryProps := bazel.BazelTargetModuleProperties{ - Rule_class: "my_proto_library", - Bzl_load_location: "//build/bazel/rules:proto.bzl", - } - ctx.CreateBazelTargetModule(myProtoLibraryProps, android.CommonAttributes{Name: baseName + "_my_proto_library_deps"}, attrs) + myProtoLibraryProps := bazel.BazelTargetModuleProperties{ + Rule_class: "my_proto_library", + Bzl_load_location: "//build/bazel/rules:proto.bzl", } + ctx.CreateBazelTargetModule(myProtoLibraryProps, android.CommonAttributes{Name: baseName + "_my_proto_library_deps"}, attrs) } // Helper method for tests to easily access the targets in a dir. @@ -353,7 +348,6 @@ func generateBazelTargetsForDir(codegenCtx *CodegenContext, dir string) (BazelTa func registerCustomModuleForBp2buildConversion(ctx *android.TestContext) { ctx.RegisterModuleType("custom", customModuleFactory) - ctx.RegisterBp2BuildMutator("custom", customBp2BuildMutator) ctx.RegisterForBazelConversion() } diff --git a/bpfix/Android.bp b/bpfix/Android.bp index 345dbd078..a72d9b4e1 100644 --- a/bpfix/Android.bp +++ b/bpfix/Android.bp @@ -52,5 +52,6 @@ bootstrap_go_package { ], deps: [ "blueprint-parser", + "blueprint-pathtools", ], } diff --git a/bpfix/bpfix/bpfix.go b/bpfix/bpfix/bpfix.go index e1140b85f..c0925fe3b 100644 --- a/bpfix/bpfix/bpfix.go +++ b/bpfix/bpfix/bpfix.go @@ -22,6 +22,7 @@ import ( "flag" "fmt" "io" + "io/ioutil" "os" "path/filepath" "reflect" @@ -29,6 +30,7 @@ import ( "strings" "github.com/google/blueprint/parser" + "github.com/google/blueprint/pathtools" ) // Reformat takes a blueprint file as a string and returns a formatted version @@ -166,7 +168,7 @@ var fixStepsOnce = []FixStep{ }, { Name: "rewriteLicenseProperties", - Fix: runPatchListMod(rewriteLicenseProperties), + Fix: runPatchListMod(rewriteLicenseProperty(nil, "")), }, } @@ -1452,9 +1454,16 @@ func formatFlagProperties(mod *parser.Module, buf []byte, patchlist *parser.Patc return nil } +func rewriteLicenseProperty(fs pathtools.FileSystem, relativePath string) patchListModFunction { + return func(mod *parser.Module, buf []byte, patchList *parser.PatchList) error { + return rewriteLicenseProperties(mod, patchList, fs, relativePath) + } +} + // rewrite the "android_license_kinds" and "android_license_files" properties to a package module // (and a license module when needed). -func rewriteLicenseProperties(mod *parser.Module, buf []byte, patchList *parser.PatchList) error { +func rewriteLicenseProperties(mod *parser.Module, patchList *parser.PatchList, fs pathtools.FileSystem, + relativePath string) error { // if a package module has been added, no more action is needed. for _, patch := range *patchList { if strings.Contains(patch.Replacement, "package {") { @@ -1462,15 +1471,33 @@ func rewriteLicenseProperties(mod *parser.Module, buf []byte, patchList *parser. } } + // initial the fs + if fs == nil { + fs = pathtools.NewOsFs(os.Getenv("ANDROID_BUILD_TOP")) + } + + // initial the relativePath + if len(relativePath) == 0 { + relativePath = getModuleRelativePath() + } + // validate the relativePath + ok := hasFile(relativePath+"/Android.mk", fs) + // some modules in the existing test cases in the androidmk_test.go do not have a valid path + if !ok && len(relativePath) > 0 { + return fmt.Errorf("Cannot find an Android.mk file at path %s", relativePath) + } + licenseKindsPropertyName := "android_license_kinds" licenseFilesPropertyName := "android_license_files" - androidBpFileErr := "// Error: No Android.bp file is found at\n" + + androidBpFileErr := "// Error: No Android.bp file is found at path\n" + "// %s\n" + - "// Please add one there with the needed license module first.\n" + "// Please add one there with the needed license module first.\n" + + "// Then reset the default_applicable_licenses property below with the license module name.\n" licenseModuleErr := "// Error: Cannot get the name of the license module in the\n" + "// %s file.\n" + - "// If no such license module exists, please add one there first.\n" + "// If no such license module exists, please add one there first.\n" + + "// Then reset the default_applicable_licenses property below with the license module name.\n" defaultApplicableLicense := "Android-Apache-2.0" var licenseModuleName, licensePatch string @@ -1482,15 +1509,16 @@ func rewriteLicenseProperties(mod *parser.Module, buf []byte, patchList *parser. // if have LOCAL_NOTICE_FILE outside the current directory, need to find and refer to the license // module in the LOCAL_NOTICE_FILE location directly and no new license module needs to be created if hasFileInParentDir { - bpPath, ok := getPathFromProperty(mod, licenseFilesPropertyName) + bpPath, ok := getPathFromProperty(mod, licenseFilesPropertyName, fs, relativePath) if !ok { - bpDir, err := getDirFromProperty(mod, licenseFilesPropertyName) + bpDir, err := getDirFromProperty(mod, licenseFilesPropertyName, fs, relativePath) if err != nil { return err } licensePatch += fmt.Sprintf(androidBpFileErr, bpDir) + defaultApplicableLicense = "" } else { - licenseModuleName, _ = getModuleName(bpPath, "license") + licenseModuleName, _ = getModuleName(bpPath, "license", fs) if len(licenseModuleName) == 0 { licensePatch += fmt.Sprintf(licenseModuleErr, bpPath) } @@ -1498,7 +1526,6 @@ func rewriteLicenseProperties(mod *parser.Module, buf []byte, patchList *parser. } } else { // if have LOCAL_NOTICE_FILE in the current directory, need to create a new license module - relativePath := getModuleRelativePath() if len(relativePath) == 0 { return fmt.Errorf("Cannot obtain the relative path of the Android.mk file") } @@ -1617,17 +1644,14 @@ func getModuleAbsolutePath() string { return absPath } -// check whether a file exists in a directory -func hasFile(dir string, fileName string) error { - _, err := os.Stat(dir + fileName) - if err != nil { - return err - } - return nil +// check whether a file exists in a filesystem +func hasFile(path string, fs pathtools.FileSystem) bool { + ok, _, _ := fs.Exists(path) + return ok } // get the directory where an `Android.bp` file and the property files are expected to locate -func getDirFromProperty(mod *parser.Module, property string) (string, error) { +func getDirFromProperty(mod *parser.Module, property string, fs pathtools.FileSystem, relativePath string) (string, error) { listValue, ok := getLiteralListPropertyValue(mod, property) if !ok { // if do not find @@ -1637,7 +1661,11 @@ func getDirFromProperty(mod *parser.Module, property string) (string, error) { // if empty return "", fmt.Errorf("Cannot find the value of the %s.%s property", mod.Type, property) } - path := getModuleAbsolutePath() + _, isDir, _ := fs.Exists(relativePath) + if !isDir { + return "", fmt.Errorf("Cannot find the path %s", relativePath) + } + path := relativePath for { if !strings.HasPrefix(listValue[0], "../") { break @@ -1645,25 +1673,29 @@ func getDirFromProperty(mod *parser.Module, property string) (string, error) { path = filepath.Dir(path) listValue[0] = strings.TrimPrefix(listValue[0], "../") } + _, isDir, _ = fs.Exists(path) + if !isDir { + return "", fmt.Errorf("Cannot find the path %s", path) + } return path, nil } // get the path of the `Android.bp` file at the expected location where the property files locate -func getPathFromProperty(mod *parser.Module, property string) (string, bool) { - dir, err := getDirFromProperty(mod, property) +func getPathFromProperty(mod *parser.Module, property string, fs pathtools.FileSystem, relativePath string) (string, bool) { + dir, err := getDirFromProperty(mod, property, fs, relativePath) if err != nil { return "", false } - err = hasFile(dir, "/Android.bp") - if err != nil { + ok := hasFile(dir+"/Android.bp", fs) + if !ok { return "", false } return dir + "/Android.bp", true } // parse an Android.bp file to get the name of the first module with type of moduleType -func getModuleName(path string, moduleType string) (string, error) { - tree, err := parserPath(path) +func getModuleName(path string, moduleType string, fs pathtools.FileSystem) (string, error) { + tree, err := parserPath(path, fs) if err != nil { return "", err } @@ -1685,8 +1717,13 @@ func getModuleName(path string, moduleType string) (string, error) { } // parse an Android.bp file with the specific path -func parserPath(path string) (tree *parser.File, err error) { - fileContent, _ := os.ReadFile(path) +func parserPath(path string, fs pathtools.FileSystem) (tree *parser.File, err error) { + f, err := fs.Open(path) + if err != nil { + return tree, err + } + defer f.Close() + fileContent, _ := ioutil.ReadAll(f) tree, err = parse(path, bytes.NewBufferString(string(fileContent))) if err != nil { return tree, err diff --git a/bpfix/bpfix/bpfix_test.go b/bpfix/bpfix/bpfix_test.go index e6b6af5f8..221df45ce 100644 --- a/bpfix/bpfix/bpfix_test.go +++ b/bpfix/bpfix/bpfix_test.go @@ -25,6 +25,7 @@ import ( "reflect" "github.com/google/blueprint/parser" + "github.com/google/blueprint/pathtools" ) // TODO(jeffrygaston) remove this when position is removed from ParseNode (in b/38325146) and we can directly do reflect.DeepEqual @@ -1678,10 +1679,20 @@ func TestFormatFlagProperty(t *testing.T) { } } -func TestRewriteLicenseProperties(t *testing.T) { +func TestRewriteLicenseProperty(t *testing.T) { + mockFs := pathtools.MockFs(map[string][]byte{ + "a/b/c/d/Android.mk": []byte("this is not important."), + "a/b/LicenseFile1": []byte("LicenseFile1"), + "a/b/LicenseFile2": []byte("LicenseFile2"), + "a/b/Android.bp": []byte("license {\n\tname: \"reuse_a_b_license\",\n}\n"), + }) + relativePath := "a/b/c/d" + relativePathErr := "a/b/c" tests := []struct { name string in string + fs pathtools.FileSystem + path string out string }{ { @@ -1744,13 +1755,194 @@ func TestRewriteLicenseProperties(t *testing.T) { } `, }, - // TODO(b/205615944): When valid "android_license_files" exists, the test requires an Android.mk - // file (and an Android.bp file is required as well if the license files locates outside the current - // directory). So plan to use a mock file system to mock the Android.mk and Android.bp files. + { + name: "license rewriting with license files in the current directory", + in: ` + android_test { + name: "foo", + android_license_kinds: ["license_kind"], + android_license_conditions: ["license_notice"], + android_license_files: ["LicenseFile1", "LicenseFile2",], + } + `, + fs: mockFs, + path: relativePath, + out: ` + package { + // See: http://go/android-license-faq + default_applicable_licenses: [ + "a_b_c_d_license", + ], + } + + license { + name: "a_b_c_d_license", + visibility: [":__subpackages__"], + license_kinds: [ + "license_kind", + ], + license_text: [ + "LicenseFile1", + "LicenseFile2", + ], + } + + android_test { + name: "foo", + android_license_kinds: ["license_kind"], + android_license_conditions: ["license_notice"], + android_license_files: [ + "LicenseFile1", + "LicenseFile2", + ], + } + `, + }, + { + name: "license rewriting with license files outside the current directory", + in: ` + android_test { + name: "foo", + android_license_kinds: ["license_kind"], + android_license_conditions: ["license_notice"], + android_license_files: ["../../LicenseFile1", "../../LicenseFile2",], + } + `, + fs: mockFs, + path: relativePath, + out: ` + package { + // See: http://go/android-license-faq + default_applicable_licenses: [ + "reuse_a_b_license", + ], + } + + android_test { + name: "foo", + android_license_kinds: ["license_kind"], + android_license_conditions: ["license_notice"], + android_license_files: [ + "../../LicenseFile1", + "../../LicenseFile2", + ], + } + `, + }, + { + name: "license rewriting with no Android.bp file in the expected location", + in: ` + android_test { + name: "foo", + android_license_kinds: ["license_kind"], + android_license_conditions: ["license_notice"], + android_license_files: ["../../LicenseFile1", "../../LicenseFile2",], + } + `, + fs: pathtools.MockFs(map[string][]byte{ + "a/b/c/d/Android.mk": []byte("this is not important."), + "a/b/LicenseFile1": []byte("LicenseFile1"), + "a/b/LicenseFile2": []byte("LicenseFile2"), + "a/Android.bp": []byte("license {\n\tname: \"reuse_a_b_license\",\n}\n"), + }), + path: relativePath, + out: ` + // Error: No Android.bp file is found at path + // a/b + // Please add one there with the needed license module first. + // Then reset the default_applicable_licenses property below with the license module name. + package { + // See: http://go/android-license-faq + default_applicable_licenses: [ + "", + ], + } + + android_test { + name: "foo", + android_license_kinds: ["license_kind"], + android_license_conditions: ["license_notice"], + android_license_files: [ + "../../LicenseFile1", + "../../LicenseFile2", + ], + } + `, + }, + { + name: "license rewriting with an Android.bp file without a license module", + in: ` + android_test { + name: "foo", + android_license_kinds: ["license_kind"], + android_license_conditions: ["license_notice"], + android_license_files: ["../../LicenseFile1", "../../LicenseFile2",], + } + `, + fs: pathtools.MockFs(map[string][]byte{ + "a/b/c/d/Android.mk": []byte("this is not important."), + "a/b/LicenseFile1": []byte("LicenseFile1"), + "a/b/LicenseFile2": []byte("LicenseFile2"), + "a/b/Android.bp": []byte("non_license {\n\tname: \"reuse_a_b_license\",\n}\n"), + }), + path: relativePath, + out: ` + // Error: Cannot get the name of the license module in the + // a/b/Android.bp file. + // If no such license module exists, please add one there first. + // Then reset the default_applicable_licenses property below with the license module name. + package { + // See: http://go/android-license-faq + default_applicable_licenses: [ + "", + ], + } + + android_test { + name: "foo", + android_license_kinds: ["license_kind"], + android_license_conditions: ["license_notice"], + android_license_files: [ + "../../LicenseFile1", + "../../LicenseFile2", + ], + } + `, + }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { - runPassOnce(t, test.in, test.out, runPatchListMod(rewriteLicenseProperties)) + runPassOnce(t, test.in, test.out, runPatchListMod(rewriteLicenseProperty(test.fs, test.path))) + }) + } + + testErrs := []struct { + name string + in string + fs pathtools.FileSystem + path string + expectedErr string + }{ + { + name: "license rewriting with a wrong path", + in: ` + android_test { + name: "foo", + android_license_kinds: ["license_kind"], + android_license_conditions: ["license_notice"], + android_license_files: ["../../LicenseFile1", "../../LicenseFile2",], + } + `, + fs: mockFs, + path: relativePathErr, + expectedErr: ` + Cannot find an Android.mk file at path a/b/c + `, + }, + } + for _, test := range testErrs { + t.Run(test.name, func(t *testing.T) { + checkError(t, test.in, test.expectedErr, runPatchListMod(rewriteLicenseProperty(test.fs, test.path))) }) } } diff --git a/build_test.bash b/build_test.bash index b039285ca..b6d00e23f 100755 --- a/build_test.bash +++ b/build_test.bash @@ -50,7 +50,9 @@ esac echo echo "Free disk space:" -df -h +# Ignore df errors because it errors out on gvfsd file systems +# but still displays most of the useful info we need +df -h || true echo echo "Running Bazel smoke test..." diff --git a/cc/androidmk.go b/cc/androidmk.go index 45bb1ca2a..636bab81e 100644 --- a/cc/androidmk.go +++ b/cc/androidmk.go @@ -263,9 +263,10 @@ func (library *libraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries library.androidMkWriteExportedFlags(entries) library.androidMkEntriesWriteAdditionalDependenciesForSourceAbiDiff(entries) - _, _, ext := android.SplitFileExt(entries.OutputFile.Path().Base()) - - entries.SetString("LOCAL_BUILT_MODULE_STEM", "$(LOCAL_MODULE)"+ext) + if entries.OutputFile.Valid() { + _, _, ext := android.SplitFileExt(entries.OutputFile.Path().Base()) + entries.SetString("LOCAL_BUILT_MODULE_STEM", "$(LOCAL_MODULE)"+ext) + } if library.coverageOutputFile.Valid() { entries.SetString("LOCAL_PREBUILT_COVERAGE_ARCHIVE", library.coverageOutputFile.String()) diff --git a/cc/binary.go b/cc/binary.go index a5afb0725..50175d92f 100644 --- a/cc/binary.go +++ b/cc/binary.go @@ -18,6 +18,7 @@ import ( "path/filepath" "github.com/google/blueprint" + "github.com/google/blueprint/proptools" "android/soong/android" "android/soong/bazel" @@ -68,13 +69,14 @@ func RegisterBinaryBuildComponents(ctx android.RegistrationContext) { // cc_binary produces a binary that is runnable on a device. func BinaryFactory() android.Module { - module, _ := NewBinary(android.HostAndDeviceSupported) + module, _ := newBinary(android.HostAndDeviceSupported, true) return module.Init() } // cc_binary_host produces a binary that is runnable on a host. func BinaryHostFactory() android.Module { - module, _ := NewBinary(android.HostSupported) + module, _ := newBinary(android.HostSupported, true) + module.bazelable = true return module.Init() } @@ -192,6 +194,10 @@ func (binary *binaryDecorator) linkerDeps(ctx DepsContext, deps Deps) Deps { // Individual module implementations which comprise a C++ binary should call this function, // set some fields on the result, and then call the Init function. func NewBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecorator) { + return newBinary(hod, true) +} + +func newBinary(hod android.HostOrDeviceSupported, bazelable bool) (*Module, *binaryDecorator) { module := newModule(hod, android.MultilibFirst) binary := &binaryDecorator{ baseLinker: NewBaseLinker(module.sanitize), @@ -200,6 +206,7 @@ func NewBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecorator) { module.compiler = NewBaseCompiler() module.linker = binary module.installer = binary + module.bazelable = bazelable // Allow module to be added as member of an sdk/module_exports. module.sdkMemberTypes = []android.SdkMemberType{ @@ -344,6 +351,12 @@ func (binary *binaryDecorator) link(ctx ModuleContext, flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--no-dynamic-linker") } + if ctx.Darwin() && deps.DarwinSecondArchOutput.Valid() { + fatOutputFile := outputFile + outputFile = android.PathForModuleOut(ctx, "pre-fat", fileName) + transformDarwinUniversalBinary(ctx, fatOutputFile, outputFile, deps.DarwinSecondArchOutput.Path()) + } + builderFlags := flagsToBuilderFlags(flags) stripFlags := flagsToStripFlags(flags) if binary.stripper.NeedsStrip(ctx) { @@ -388,7 +401,7 @@ func (binary *binaryDecorator) link(ctx ModuleContext, } } - var validations android.WritablePaths + var validations android.Paths // Handle host bionic linker symbols. if ctx.Os() == android.LinuxBionic && !binary.static() { @@ -411,6 +424,7 @@ func (binary *binaryDecorator) link(ctx ModuleContext, linkerDeps = append(linkerDeps, deps.EarlySharedLibsDeps...) linkerDeps = append(linkerDeps, deps.SharedLibsDeps...) linkerDeps = append(linkerDeps, deps.LateSharedLibsDeps...) + linkerDeps = append(linkerDeps, ndkSharedLibDeps(ctx)...) } validations = append(validations, objs.tidyFiles...) @@ -543,33 +557,7 @@ func (binary *binaryDecorator) verifyHostBionicLinker(ctx ModuleContext, in, lin }) } -func init() { - android.RegisterBp2BuildMutator("cc_binary", BinaryBp2build) - android.RegisterBp2BuildMutator("cc_binary_host", BinaryHostBp2build) -} - -func BinaryBp2build(ctx android.TopDownMutatorContext) { - binaryBp2build(ctx, "cc_binary") -} - -func BinaryHostBp2build(ctx android.TopDownMutatorContext) { - binaryBp2build(ctx, "cc_binary_host") -} - -func binaryBp2build(ctx android.TopDownMutatorContext, typ string) { - m, ok := ctx.Module().(*Module) - if !ok { - // Not a cc module - return - } - if !m.ConvertWithBp2build(ctx) { - return - } - - if ctx.ModuleType() != typ { - return - } - +func binaryBp2build(ctx android.TopDownMutatorContext, m *Module, typ string) { var compatibleWith bazel.StringListAttribute if typ == "cc_binary_host" { //incompatible with android OS @@ -578,9 +566,16 @@ func binaryBp2build(ctx android.TopDownMutatorContext, typ string) { } baseAttrs := bp2BuildParseBaseProps(ctx, m) + binaryLinkerAttrs := bp2buildBinaryLinkerProps(ctx, m) + + if proptools.BoolDefault(binaryLinkerAttrs.Linkshared, true) { + baseAttrs.implementationDynamicDeps.Add(baseAttrs.protoDependency) + } else { + baseAttrs.implementationDeps.Add(baseAttrs.protoDependency) + } attrs := &binaryAttributes{ - binaryLinkerAttrs: bp2buildBinaryLinkerProps(ctx, m), + binaryLinkerAttrs: binaryLinkerAttrs, Srcs: baseAttrs.srcs, Srcs_c: baseAttrs.cSrcs, diff --git a/cc/bp2build.go b/cc/bp2build.go index d9494362f..6c1646cbb 100644 --- a/cc/bp2build.go +++ b/cc/bp2build.go @@ -27,9 +27,10 @@ import ( ) const ( - cSrcPartition = "c" - asSrcPartition = "as" - cppSrcPartition = "cpp" + cSrcPartition = "c" + asSrcPartition = "as" + cppSrcPartition = "cpp" + protoSrcPartition = "proto" ) // staticOrSharedAttributes are the Bazel-ified versions of StaticOrSharedProperties -- @@ -41,52 +42,53 @@ type staticOrSharedAttributes struct { Hdrs bazel.LabelListAttribute Copts bazel.StringListAttribute - Deps bazel.LabelListAttribute - Implementation_deps bazel.LabelListAttribute - Dynamic_deps bazel.LabelListAttribute - Implementation_dynamic_deps bazel.LabelListAttribute - Whole_archive_deps bazel.LabelListAttribute + Deps bazel.LabelListAttribute + Implementation_deps bazel.LabelListAttribute + Dynamic_deps bazel.LabelListAttribute + Implementation_dynamic_deps bazel.LabelListAttribute + Whole_archive_deps bazel.LabelListAttribute + Implementation_whole_archive_deps bazel.LabelListAttribute System_dynamic_deps bazel.LabelListAttribute } func groupSrcsByExtension(ctx android.BazelConversionPathContext, srcs bazel.LabelListAttribute) bazel.PartitionToLabelListAttribute { - // Check that a module is a filegroup type named <label>. - isFilegroupNamed := func(m android.Module, fullLabel string) bool { - if ctx.OtherModuleType(m) != "filegroup" { - return false - } - labelParts := strings.Split(fullLabel, ":") - if len(labelParts) > 2 { - // There should not be more than one colon in a label. - ctx.ModuleErrorf("%s is not a valid Bazel label for a filegroup", fullLabel) - } - return m.Name() == labelParts[len(labelParts)-1] + // Check that a module is a filegroup type + isFilegroup := func(m blueprint.Module) bool { + return ctx.OtherModuleType(m) == "filegroup" } // Convert filegroup dependencies into extension-specific filegroups filtered in the filegroup.bzl // macro. addSuffixForFilegroup := func(suffix string) bazel.LabelMapper { - return func(ctx bazel.OtherModuleContext, label string) (string, bool) { - m, exists := ctx.ModuleFromName(label) - if !exists { - return label, false - } - aModule, _ := m.(android.Module) - if !isFilegroupNamed(aModule, label) { - return label, false + return func(ctx bazel.OtherModuleContext, label bazel.Label) (string, bool) { + m, exists := ctx.ModuleFromName(label.OriginalModuleName) + labelStr := label.Label + if !exists || !isFilegroup(m) { + return labelStr, false } - return label + suffix, true + return labelStr + suffix, true } } + isProtoFilegroup := func(ctx bazel.OtherModuleContext, label bazel.Label) (string, bool) { + m, exists := ctx.ModuleFromName(label.OriginalModuleName) + labelStr := label.Label + if !exists || !isFilegroup(m) { + return labelStr, false + } + likelyProtos := strings.HasSuffix(labelStr, "proto") || strings.HasSuffix(labelStr, "protos") + return labelStr, likelyProtos + } + // TODO(b/190006308): Handle language detection of sources in a Bazel rule. partitioned := bazel.PartitionLabelListAttribute(ctx, &srcs, bazel.LabelPartitions{ cSrcPartition: bazel.LabelPartition{Extensions: []string{".c"}, LabelMapper: addSuffixForFilegroup("_c_srcs")}, asSrcPartition: bazel.LabelPartition{Extensions: []string{".s", ".S"}, LabelMapper: addSuffixForFilegroup("_as_srcs")}, // C++ is the "catch-all" group, and comprises generated sources because we don't // know the language of these sources until the genrule is executed. - cppSrcPartition: bazel.LabelPartition{Extensions: []string{".cpp", ".cc", ".cxx", ".mm"}, LabelMapper: addSuffixForFilegroup("_cpp_srcs"), Keep_remainder: true}, + cppSrcPartition: bazel.LabelPartition{Extensions: []string{".cpp", ".cc", ".cxx", ".mm"}, LabelMapper: addSuffixForFilegroup("_cpp_srcs"), Keep_remainder: true}, + protoSrcPartition: bazel.LabelPartition{Extensions: []string{".proto"}, LabelMapper: isProtoFilegroup}, }) return partitioned @@ -195,6 +197,11 @@ func bp2buildParseStaticOrSharedProps(ctx android.BazelConversionPathContext, mo attrs.Srcs_c = partitionedSrcs[cSrcPartition] attrs.Srcs_as = partitionedSrcs[asSrcPartition] + if !partitionedSrcs[protoSrcPartition].IsEmpty() { + // TODO(b/208815215): determine whether this is used and add support if necessary + ctx.ModuleErrorf("Migrating static/shared only proto srcs is not currently supported") + } + return attrs } @@ -230,6 +237,8 @@ func Bp2BuildParsePrebuiltLibraryProps(ctx android.BazelConversionPathContext, m type baseAttributes struct { compilerAttributes linkerAttributes + + protoDependency *bazel.LabelAttribute } // Convenience struct to hold all attributes parsed from compiler properties. @@ -252,10 +261,15 @@ type compilerAttributes struct { // Not affected by arch variants stl *string + cStd *string cppStd *string localIncludes bazel.StringListAttribute absoluteIncludes bazel.StringListAttribute + + includes BazelIncludes + + protoSrcs bazel.LabelListAttribute } func parseCommandLineFlags(soongFlags []string) []string { @@ -278,8 +292,7 @@ func (ca *compilerAttributes) bp2buildForAxisAndConfig(ctx android.BazelConversi localIncludeDirs := props.Local_include_dirs if axis == bazel.NoConfigAxis { - ca.cppStd = bp2buildResolveCppStdValue(props.Cpp_std, props.Gnu_extensions) - + ca.cStd, ca.cppStd = bp2buildResolveCppStdValue(props.C_std, props.Cpp_std, props.Gnu_extensions) if includeBuildDirectory(props.Include_build_directory) { localIncludeDirs = append(localIncludeDirs, ".") } @@ -337,6 +350,8 @@ func (ca *compilerAttributes) finalize(ctx android.BazelConversionPathContext, i ca.srcs.ResolveExcludes() partitionedSrcs := groupSrcsByExtension(ctx, ca.srcs) + ca.protoSrcs = partitionedSrcs[protoSrcPartition] + for p, lla := range partitionedSrcs { // if there are no sources, there is no need for headers if lla.IsEmpty() { @@ -371,28 +386,63 @@ func parseSrcs(ctx android.BazelConversionPathContext, props *BaseCompilerProper return bazel.AppendBazelLabelLists(allSrcsLabelList, generatedSrcsLabelList), anySrcs } -func bp2buildResolveCppStdValue(cpp_std *string, gnu_extensions *bool) *string { - var cppStd *string - // If cpp_std is not specified, don't generate it in the - // BUILD file. For readability purposes, cpp_std and gnu_extensions are - // combined into a single -std=<version> copt, except in the - // default case where cpp_std is nil and gnu_extensions is true or unspecified, - // then the toolchain's default "gnu++17" will be used. +func bp2buildResolveCppStdValue(c_std *string, cpp_std *string, gnu_extensions *bool) (*string, *string) { + var cStdVal, cppStdVal string + // If c{,pp}std properties are not specified, don't generate them in the BUILD file. + // Defaults are handled by the toolchain definition. + // However, if gnu_extensions is false, then the default gnu-to-c version must be specified. if cpp_std != nil { - // TODO(b/202491296): Handle C_std. - // These transformations are shared with compiler.go. - cppStdVal := parseCppStd(cpp_std) - _, cppStdVal = maybeReplaceGnuToC(gnu_extensions, "", cppStdVal) - cppStd = &cppStdVal + cppStdVal = parseCppStd(cpp_std) } else if gnu_extensions != nil && !*gnu_extensions { - cppStdVal := "c++17" - cppStd = &cppStdVal + cppStdVal = "c++17" + } + if c_std != nil { + cStdVal = parseCStd(c_std) + } else if gnu_extensions != nil && !*gnu_extensions { + cStdVal = "c99" + } + + cStdVal, cppStdVal = maybeReplaceGnuToC(gnu_extensions, cStdVal, cppStdVal) + var c_std_prop, cpp_std_prop *string + if cStdVal != "" { + c_std_prop = &cStdVal + } + if cppStdVal != "" { + cpp_std_prop = &cppStdVal } - return cppStd + + return c_std_prop, cpp_std_prop +} + +// packageFromLabel extracts package from a fully-qualified or relative Label and whether the label +// is fully-qualified. +// e.g. fully-qualified "//a/b:foo" -> "a/b", true, relative: ":bar" -> ".", false +func packageFromLabel(label string) (string, bool) { + split := strings.Split(label, ":") + if len(split) != 2 { + return "", false + } + if split[0] == "" { + return ".", false + } + // remove leading "//" + return split[0][2:], true +} + +// includesFromLabelList extracts relative/absolute includes from a bazel.LabelList> +func includesFromLabelList(labelList bazel.LabelList) (relative, absolute []string) { + for _, hdr := range labelList.Includes { + if pkg, hasPkg := packageFromLabel(hdr.Label); hasPkg { + absolute = append(absolute, pkg) + } else if pkg != "" { + relative = append(relative, pkg) + } + } + return relative, absolute } // bp2BuildParseCompilerProps returns copts, srcs and hdrs and other attributes. -func bp2BuildParseBaseProps(ctx android.BazelConversionPathContext, module *Module) baseAttributes { +func bp2BuildParseBaseProps(ctx android.Bp2buildMutatorContext, module *Module) baseAttributes { archVariantCompilerProps := module.GetArchVariantProperties(ctx, &BaseCompilerProperties{}) archVariantLinkerProps := module.GetArchVariantProperties(ctx, &BaseLinkerProperties{}) @@ -434,6 +484,18 @@ func bp2BuildParseBaseProps(ctx android.BazelConversionPathContext, module *Modu headers := maybePartitionExportedAndImplementationsDeps(ctx, !module.Binary(), allHdrs, exportHdrs, android.BazelLabelForModuleDeps) implementationHdrs.SetSelectValue(axis, config, headers.implementation) compilerAttrs.hdrs.SetSelectValue(axis, config, headers.export) + + exportIncludes, exportAbsoluteIncludes := includesFromLabelList(headers.export) + compilerAttrs.includes.Includes.SetSelectValue(axis, config, exportIncludes) + compilerAttrs.includes.AbsoluteIncludes.SetSelectValue(axis, config, exportAbsoluteIncludes) + + includes, absoluteIncludes := includesFromLabelList(headers.implementation) + currAbsoluteIncludes := compilerAttrs.absoluteIncludes.SelectValue(axis, config) + currAbsoluteIncludes = android.FirstUniqueStrings(append(currAbsoluteIncludes, absoluteIncludes...)) + compilerAttrs.absoluteIncludes.SetSelectValue(axis, config, currAbsoluteIncludes) + currIncludes := compilerAttrs.localIncludes.SelectValue(axis, config) + currIncludes = android.FirstUniqueStrings(append(currIncludes, includes...)) + compilerAttrs.localIncludes.SetSelectValue(axis, config, currIncludes) } } @@ -448,23 +510,34 @@ func bp2BuildParseBaseProps(ctx android.BazelConversionPathContext, module *Modu (&compilerAttrs).finalize(ctx, implementationHdrs) (&linkerAttrs).finalize() + protoDep := bp2buildProto(ctx, module, compilerAttrs.protoSrcs) + + // bp2buildProto will only set wholeStaticLib or implementationWholeStaticLib, but we don't know + // which. This will add the newly generated proto library to the appropriate attribute and nothing + // to the other + (&linkerAttrs).wholeArchiveDeps.Add(protoDep.wholeStaticLib) + (&linkerAttrs).implementationWholeArchiveDeps.Add(protoDep.implementationWholeStaticLib) + return baseAttributes{ compilerAttrs, linkerAttrs, + protoDep.protoDep, } } // Convenience struct to hold all attributes parsed from linker properties. type linkerAttributes struct { - deps bazel.LabelListAttribute - implementationDeps bazel.LabelListAttribute - dynamicDeps bazel.LabelListAttribute - implementationDynamicDeps bazel.LabelListAttribute - wholeArchiveDeps bazel.LabelListAttribute - systemDynamicDeps bazel.LabelListAttribute + deps bazel.LabelListAttribute + implementationDeps bazel.LabelListAttribute + dynamicDeps bazel.LabelListAttribute + implementationDynamicDeps bazel.LabelListAttribute + wholeArchiveDeps bazel.LabelListAttribute + implementationWholeArchiveDeps bazel.LabelListAttribute + systemDynamicDeps bazel.LabelListAttribute linkCrt bazel.BoolAttribute useLibcrt bazel.BoolAttribute + useVersionLib bazel.BoolAttribute linkopts bazel.StringListAttribute additionalLinkerInputs bazel.LabelListAttribute stripKeepSymbols bazel.BoolAttribute @@ -534,6 +607,10 @@ func (la *linkerAttributes) bp2buildForAxisAndConfig(ctx android.BazelConversion la.linkopts.SetSelectValue(axis, config, linkerFlags) la.useLibcrt.SetSelectValue(axis, config, props.libCrt()) + if axis == bazel.NoConfigAxis { + la.useVersionLib.SetSelectValue(axis, config, props.Use_version_lib) + } + // it's very unlikely for nocrt to be arch variant, so bp2build doesn't support it. if props.crt() != nil { if axis == bazel.NoConfigAxis { @@ -656,13 +733,14 @@ func bp2BuildMakePathsRelativeToModule(ctx android.BazelConversionPathContext, p // BazelIncludes contains information about -I and -isystem paths from a module converted to Bazel // attributes. type BazelIncludes struct { - Includes bazel.StringListAttribute - SystemIncludes bazel.StringListAttribute + AbsoluteIncludes bazel.StringListAttribute + Includes bazel.StringListAttribute + SystemIncludes bazel.StringListAttribute } -func bp2BuildParseExportedIncludes(ctx android.BazelConversionPathContext, module *Module) BazelIncludes { +func bp2BuildParseExportedIncludes(ctx android.BazelConversionPathContext, module *Module, existingIncludes BazelIncludes) BazelIncludes { libraryDecorator := module.linker.(*libraryDecorator) - return bp2BuildParseExportedIncludesHelper(ctx, module, libraryDecorator) + return bp2BuildParseExportedIncludesHelper(ctx, module, libraryDecorator, &existingIncludes) } // Bp2buildParseExportedIncludesForPrebuiltLibrary returns a BazelIncludes with Bazel-ified values @@ -670,25 +748,31 @@ func bp2BuildParseExportedIncludes(ctx android.BazelConversionPathContext, modul func Bp2BuildParseExportedIncludesForPrebuiltLibrary(ctx android.BazelConversionPathContext, module *Module) BazelIncludes { prebuiltLibraryLinker := module.linker.(*prebuiltLibraryLinker) libraryDecorator := prebuiltLibraryLinker.libraryDecorator - return bp2BuildParseExportedIncludesHelper(ctx, module, libraryDecorator) + return bp2BuildParseExportedIncludesHelper(ctx, module, libraryDecorator, nil) } // bp2BuildParseExportedIncludes creates a string list attribute contains the // exported included directories of a module. -func bp2BuildParseExportedIncludesHelper(ctx android.BazelConversionPathContext, module *Module, libraryDecorator *libraryDecorator) BazelIncludes { - exported := BazelIncludes{} +func bp2BuildParseExportedIncludesHelper(ctx android.BazelConversionPathContext, module *Module, libraryDecorator *libraryDecorator, includes *BazelIncludes) BazelIncludes { + var exported BazelIncludes + if includes != nil { + exported = *includes + } else { + exported = BazelIncludes{} + } for axis, configToProps := range module.GetArchVariantProperties(ctx, &FlagExporterProperties{}) { for config, props := range configToProps { if flagExporterProperties, ok := props.(*FlagExporterProperties); ok { if len(flagExporterProperties.Export_include_dirs) > 0 { - exported.Includes.SetSelectValue(axis, config, flagExporterProperties.Export_include_dirs) + exported.Includes.SetSelectValue(axis, config, android.FirstUniqueStrings(append(exported.Includes.SelectValue(axis, config), flagExporterProperties.Export_include_dirs...))) } if len(flagExporterProperties.Export_system_include_dirs) > 0 { - exported.SystemIncludes.SetSelectValue(axis, config, flagExporterProperties.Export_system_include_dirs) + exported.SystemIncludes.SetSelectValue(axis, config, android.FirstUniqueStrings(append(exported.SystemIncludes.SelectValue(axis, config), flagExporterProperties.Export_system_include_dirs...))) } } } } + exported.AbsoluteIncludes.DeduplicateAxesFromBase() exported.Includes.DeduplicateAxesFromBase() exported.SystemIncludes.DeduplicateAxesFromBase() diff --git a/cc/builder.go b/cc/builder.go index 72c2fa555..8af225535 100644 --- a/cc/builder.go +++ b/cc/builder.go @@ -165,6 +165,12 @@ var ( } }() + darwinLipo = pctx.AndroidStaticRule("darwinLipo", + blueprint.RuleParams{ + Command: "${config.MacLipoPath} -create -output $out $in", + CommandDeps: []string{"${config.MacLipoPath}"}, + }) + _ = pctx.SourcePathVariable("archiveRepackPath", "build/soong/scripts/archive_repack.sh") // Rule to repack an archive (.a) file with a subset of object files. @@ -413,7 +419,7 @@ type StripFlags struct { // Objects is a collection of file paths corresponding to outputs for C++ related build statements. type Objects struct { objFiles android.Paths - tidyFiles android.WritablePaths + tidyFiles android.Paths coverageFiles android.Paths sAbiDumpFiles android.Paths kytheFiles android.Paths @@ -422,7 +428,7 @@ type Objects struct { func (a Objects) Copy() Objects { return Objects{ objFiles: append(android.Paths{}, a.objFiles...), - tidyFiles: append(android.WritablePaths{}, a.tidyFiles...), + tidyFiles: append(android.Paths{}, a.tidyFiles...), coverageFiles: append(android.Paths{}, a.coverageFiles...), sAbiDumpFiles: append(android.Paths{}, a.sAbiDumpFiles...), kytheFiles: append(android.Paths{}, a.kytheFiles...), @@ -451,11 +457,11 @@ func transformSourceToObj(ctx android.ModuleContext, subdir string, srcFiles, no // Source files are one-to-one with tidy, coverage, or kythe files, if enabled. objFiles := make(android.Paths, len(srcFiles)) - var tidyFiles android.WritablePaths + var tidyFiles android.Paths noTidySrcsMap := make(map[android.Path]bool) var tidyVars string if flags.tidy { - tidyFiles = make(android.WritablePaths, 0, len(srcFiles)) + tidyFiles = make(android.Paths, 0, len(srcFiles)) for _, path := range noTidySrcs { noTidySrcsMap[path] = true } @@ -665,7 +671,6 @@ func transformSourceToObj(ctx android.ModuleContext, subdir string, srcFiles, no rule = clangTidyRE } - ctx.TidyFile(tidyFile) ctx.Build(pctx, android.BuildParams{ Rule: rule, Description: "clang-tidy " + srcFile.Rel(), @@ -719,7 +724,7 @@ func transformSourceToObj(ctx android.ModuleContext, subdir string, srcFiles, no // Generate a rule for compiling multiple .o files to a static library (.a) func transformObjToStaticLib(ctx android.ModuleContext, objFiles android.Paths, wholeStaticLibs android.Paths, - flags builderFlags, outputFile android.ModuleOutPath, deps android.Paths, validations android.WritablePaths) { + flags builderFlags, outputFile android.ModuleOutPath, deps android.Paths, validations android.Paths) { arCmd := "${config.ClangBin}/llvm-ar" arFlags := "" @@ -734,7 +739,7 @@ func transformObjToStaticLib(ctx android.ModuleContext, Output: outputFile, Inputs: objFiles, Implicits: deps, - Validations: validations.Paths(), + Validations: validations, Args: map[string]string{ "arFlags": "crsPD" + arFlags, "arCmd": arCmd, @@ -764,7 +769,7 @@ func transformObjToStaticLib(ctx android.ModuleContext, func transformObjToDynamicBinary(ctx android.ModuleContext, objFiles, sharedLibs, staticLibs, lateStaticLibs, wholeStaticLibs, deps, crtBegin, crtEnd android.Paths, groupLate bool, flags builderFlags, outputFile android.WritablePath, - implicitOutputs android.WritablePaths, validations android.WritablePaths) { + implicitOutputs android.WritablePaths, validations android.Paths) { ldCmd := "${config.ClangBin}/clang++" @@ -831,7 +836,7 @@ func transformObjToDynamicBinary(ctx android.ModuleContext, Inputs: objFiles, Implicits: deps, OrderOnly: sharedLibs, - Validations: validations.Paths(), + Validations: validations, Args: args, }) } @@ -1060,6 +1065,15 @@ func transformDarwinStrip(ctx android.ModuleContext, inputFile android.Path, }) } +func transformDarwinUniversalBinary(ctx android.ModuleContext, outputFile android.WritablePath, inputFiles ...android.Path) { + ctx.Build(pctx, android.BuildParams{ + Rule: darwinLipo, + Description: "lipo " + outputFile.Base(), + Output: outputFile, + Inputs: inputFiles, + }) +} + // Registers build statement to zip one or more coverage files. func transformCoverageFilesToZip(ctx android.ModuleContext, inputs Objects, baseName string) android.OptionalPath { @@ -167,6 +167,10 @@ type PathDeps struct { // Path to the dynamic linker binary DynamicLinker android.OptionalPath + + // For Darwin builds, the path to the second architecture's output that should + // be combined with this architectures's output into a FAT MachO file. + DarwinSecondArchOutput android.OptionalPath } // LocalOrGlobalFlags contains flags that need to have values set globally by the build system or locally by the module @@ -682,6 +686,15 @@ func (d libraryDependencyTag) static() bool { return d.Kind == staticLibraryDependency } +func (d libraryDependencyTag) LicenseAnnotations() []android.LicenseAnnotation { + if d.shared() { + return []android.LicenseAnnotation{android.LicenseAnnotationSharedDependency} + } + return nil +} + +var _ android.LicenseAnnotationsDependencyTag = libraryDependencyTag{} + // InstallDepNeeded returns true for shared libraries so that shared library dependencies of // binaries or other shared libraries are installed as dependencies. func (d libraryDependencyTag) InstallDepNeeded() bool { @@ -773,8 +786,9 @@ type Module struct { Properties BaseProperties // initialize before calling Init - hod android.HostOrDeviceSupported - multilib android.Multilib + hod android.HostOrDeviceSupported + multilib android.Multilib + bazelable bool // Allowable SdkMemberTypes of this module type. sdkMemberTypes []android.SdkMemberType @@ -815,6 +829,10 @@ type Module struct { makeLinkType string // Kythe (source file indexer) paths for this compilation module kytheFiles android.Paths + // Object .o file output paths for this compilation module + objFiles android.Paths + // Tidy .tidy file output paths for this compilation module + tidyFiles android.Paths // For apex variants, this is set as apex.min_sdk_version apexSdkVersion android.ApiLevel @@ -1133,7 +1151,9 @@ func (c *Module) Init() android.Module { } android.InitAndroidArchModule(c, c.hod, c.multilib) - android.InitBazelModule(c) + if c.bazelable { + android.InitBazelModule(c) + } android.InitApexModule(c) android.InitSdkAwareModule(c) android.InitDefaultableModule(c) @@ -1713,7 +1733,15 @@ func (c *Module) setSubnameProperty(actx android.ModuleContext) { // Returns true if Bazel was successfully used for the analysis of this module. func (c *Module) maybeGenerateBazelActions(actx android.ModuleContext) bool { - bazelModuleLabel := c.GetBazelLabel(actx, c) + var bazelModuleLabel string + if actx.ModuleType() == "cc_library" && c.static() { + // cc_library is a special case in bp2build; two targets are generated -- one for each + // of the shared and static variants. The shared variant keeps the module name, but the + // static variant uses a different suffixed name. + bazelModuleLabel = bazelLabelForStaticModule(actx, c) + } else { + bazelModuleLabel = c.GetBazelLabel(actx, c) + } bazelActionsUsed := false // Mixed builds mode is disabled for modules outside of device OS. // TODO(b/200841190): Support non-device OS in mixed builds. @@ -1827,6 +1855,8 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { return } c.kytheFiles = objs.kytheFiles + c.objFiles = objs.objFiles + c.tidyFiles = objs.tidyFiles } if c.linker != nil { @@ -2570,6 +2600,11 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { depName := ctx.OtherModuleName(dep) depTag := ctx.OtherModuleDependencyTag(dep) + if depTag == android.DarwinUniversalVariantTag { + depPaths.DarwinSecondArchOutput = dep.(*Module).OutputFile() + return + } + ccDep, ok := dep.(LinkableInterface) if !ok { @@ -3153,6 +3188,24 @@ func (c *Module) testBinary() bool { return false } +func (c *Module) benchmarkBinary() bool { + if b, ok := c.linker.(interface { + benchmarkBinary() bool + }); ok { + return b.benchmarkBinary() + } + return false +} + +func (c *Module) fuzzBinary() bool { + if f, ok := c.linker.(interface { + fuzzBinary() bool + }); ok { + return f.fuzzBinary() + } + return false +} + // Header returns true if the module is a header-only variant. (See cc/library.go header()). func (c *Module) Header() bool { if h, ok := c.linker.(interface { @@ -3398,6 +3451,45 @@ func (c *Module) AlwaysRequiresPlatformApexVariant() bool { var _ snapshot.RelativeInstallPath = (*Module)(nil) +// ConvertWithBp2build converts Module to Bazel for bp2build. +func (c *Module) ConvertWithBp2build(ctx android.TopDownMutatorContext) { + prebuilt := c.IsPrebuilt() + if c.Binary() { + if !prebuilt { + binaryBp2build(ctx, c, ctx.ModuleType()) + } + } else if c.Object() { + if !prebuilt { + objectBp2Build(ctx, c) + } + } else if c.CcLibrary() { + static := c.BuildStaticVariant() + shared := c.BuildSharedVariant() + + if static && shared { + if !prebuilt { + libraryBp2Build(ctx, c) + } + } else if !static && !shared { + if !prebuilt { + libraryHeadersBp2Build(ctx, c) + } + } else if static { + if prebuilt { + prebuiltLibraryStaticBp2Build(ctx, c) + } else { + sharedOrStaticLibraryBp2Build(ctx, c, true) + } + } else if shared { + if prebuilt { + prebuiltLibrarySharedBp2Build(ctx, c) + } else { + sharedOrStaticLibraryBp2Build(ctx, c, false) + } + } + } +} + // // Defaults // diff --git a/cc/compiler.go b/cc/compiler.go index ffe8b2e36..8adc3ab16 100644 --- a/cc/compiler.go +++ b/cc/compiler.go @@ -304,11 +304,24 @@ func parseCppStd(cppStdPtr *string) string { cppStd := String(cppStdPtr) switch cppStd { case "": - cppStd = config.CppStdVersion + return config.CppStdVersion case "experimental": - cppStd = config.ExperimentalCppStdVersion + return config.ExperimentalCppStdVersion + default: + return cppStd + } +} + +func parseCStd(cStdPtr *string) string { + cStd := String(cStdPtr) + switch cStd { + case "": + return config.CStdVersion + case "experimental": + return config.ExperimentalCStdVersion + default: + return cStd } - return cppStd } // Create a Flags struct that collects the compile flags from global values, @@ -479,13 +492,7 @@ func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps flags.Global.CommonFlags = append(flags.Global.CommonFlags, tc.ToolchainCflags()) - cStd := config.CStdVersion - if String(compiler.Properties.C_std) == "experimental" { - cStd = config.ExperimentalCStdVersion - } else if String(compiler.Properties.C_std) != "" { - cStd = String(compiler.Properties.C_std) - } - + cStd := parseCStd(compiler.Properties.C_std) cppStd := parseCppStd(compiler.Properties.Cpp_std) cStd, cppStd = maybeReplaceGnuToC(compiler.Properties.Gnu_extensions, cStd, cppStd) @@ -630,9 +637,9 @@ var gnuToCReplacer = strings.NewReplacer("gnu", "c") func ndkPathDeps(ctx ModuleContext) android.Paths { if ctx.Module().(*Module).IsSdkVariant() { - // The NDK sysroot timestamp file depends on all the NDK sysroot files - // (headers and libraries). - return android.Paths{getNdkBaseTimestampFile(ctx)} + // The NDK sysroot timestamp file depends on all the NDK sysroot header files + // for compiling src to obj files. + return android.Paths{getNdkHeadersTimestampFile(ctx)} } return nil } diff --git a/cc/config/darwin_host.go b/cc/config/darwin_host.go index 318acb4e7..206bec110 100644 --- a/cc/config/darwin_host.go +++ b/cc/config/darwin_host.go @@ -54,6 +54,7 @@ var ( darwinSupportedSdkVersions = []string{ "11", + "12", } darwinAvailableLibraries = append( @@ -87,6 +88,10 @@ func init() { return getMacTools(ctx).arPath }) + pctx.VariableFunc("MacLipoPath", func(ctx android.PackageVarContext) string { + return getMacTools(ctx).lipoPath + }) + pctx.VariableFunc("MacStripPath", func(ctx android.PackageVarContext) string { return getMacTools(ctx).stripPath }) @@ -118,6 +123,7 @@ type macPlatformTools struct { sdkRoot string arPath string + lipoPath string stripPath string toolPath string } @@ -157,6 +163,7 @@ func getMacTools(ctx android.PathContext) *macPlatformTools { macTools.sdkRoot = xcrun("--show-sdk-path") macTools.arPath = xcrun("--find", "ar") + macTools.lipoPath = xcrun("--find", "lipo") macTools.stripPath = xcrun("--find", "strip") macTools.toolPath = filepath.Dir(xcrun("--find", "ld")) }) diff --git a/cc/config/global.go b/cc/config/global.go index 0b229be76..a340e465e 100644 --- a/cc/config/global.go +++ b/cc/config/global.go @@ -46,7 +46,6 @@ var ( "-O2", "-g", - "-fdebug-info-for-profiling", "-fno-strict-aliasing", @@ -125,6 +124,9 @@ var ( "-Werror=sequence-point", "-Werror=format-security", "-nostdlibinc", + + // Emit additional debug info for AutoFDO + "-fdebug-info-for-profiling", } deviceGlobalCppflags = []string{ diff --git a/cc/fuzz.go b/cc/fuzz.go index e987fe43b..23d81d600 100644 --- a/cc/fuzz.go +++ b/cc/fuzz.go @@ -52,6 +52,10 @@ type fuzzBinary struct { installedSharedDeps []string } +func (fuzz *fuzzBinary) fuzzBinary() bool { + return true +} + func (fuzz *fuzzBinary) linkerProps() []interface{} { props := fuzz.binaryDecorator.linkerProps() props = append(props, &fuzz.fuzzPackagedModule.FuzzProperties) @@ -234,7 +238,7 @@ func (fuzz *fuzzBinary) install(ctx ModuleContext, file android.Path) { } func NewFuzz(hod android.HostOrDeviceSupported) *Module { - module, binary := NewBinary(hod) + module, binary := newBinary(hod, false) binary.baseInstaller = NewFuzzInstaller() module.sanitize.SetSanitizer(Fuzzer, true) diff --git a/cc/libbuildversion/Android.bp b/cc/libbuildversion/Android.bp index 4debb1c45..b105a3029 100644 --- a/cc/libbuildversion/Android.bp +++ b/cc/libbuildversion/Android.bp @@ -14,8 +14,10 @@ cc_library_static { enabled: true, }, }, + min_sdk_version: "26", apex_available: [ "//apex_available:platform", "//apex_available:anyapex", ], + vendor_available: true, } diff --git a/cc/libbuildversion/libbuildversion.cpp b/cc/libbuildversion/libbuildversion.cpp index 5242025eb..1e01c1145 100644 --- a/cc/libbuildversion/libbuildversion.cpp +++ b/cc/libbuildversion/libbuildversion.cpp @@ -36,7 +36,11 @@ std::string GetBuildNumber() { return soong_build_number; } +#ifdef __ANDROID_VENDOR__ + const prop_info* pi = __system_property_find("ro.vendor.build.version.incremental"); +#else const prop_info* pi = __system_property_find("ro.build.version.incremental"); +#endif if (pi == nullptr) return ""; std::string property_value; diff --git a/cc/library.go b/cc/library.go index dbf927d61..216c12409 100644 --- a/cc/library.go +++ b/cc/library.go @@ -207,10 +207,6 @@ type FlagExporterProperties struct { func init() { RegisterLibraryBuildComponents(android.InitRegistrationContext) - - android.RegisterBp2BuildMutator("cc_library_static", CcLibraryStaticBp2Build) - android.RegisterBp2BuildMutator("cc_library_shared", CcLibrarySharedBp2Build) - android.RegisterBp2BuildMutator("cc_library", CcLibraryBp2Build) } func RegisterLibraryBuildComponents(ctx android.RegistrationContext) { @@ -236,12 +232,13 @@ type bazelCcLibraryAttributes struct { Hdrs bazel.LabelListAttribute - Deps bazel.LabelListAttribute - Implementation_deps bazel.LabelListAttribute - Dynamic_deps bazel.LabelListAttribute - Implementation_dynamic_deps bazel.LabelListAttribute - Whole_archive_deps bazel.LabelListAttribute - System_dynamic_deps bazel.LabelListAttribute + Deps bazel.LabelListAttribute + Implementation_deps bazel.LabelListAttribute + Dynamic_deps bazel.LabelListAttribute + Implementation_dynamic_deps bazel.LabelListAttribute + Whole_archive_deps bazel.LabelListAttribute + Implementation_whole_archive_deps bazel.LabelListAttribute + System_dynamic_deps bazel.LabelListAttribute Export_includes bazel.StringListAttribute Export_system_includes bazel.StringListAttribute @@ -253,6 +250,7 @@ type bazelCcLibraryAttributes struct { Stl *string Cpp_std *string + C_std *string // This is shared only. Link_crt bazel.BoolAttribute @@ -275,21 +273,12 @@ type stripAttributes struct { None bazel.BoolAttribute } -func CcLibraryBp2Build(ctx android.TopDownMutatorContext) { - m, ok := ctx.Module().(*Module) - if !ok || !m.ConvertWithBp2build(ctx) { - return - } - - if ctx.ModuleType() != "cc_library" { - return - } - +func libraryBp2Build(ctx android.TopDownMutatorContext, m *Module) { // For some cc_library modules, their static variants are ready to be // converted, but not their shared variants. For these modules, delegate to // the cc_library_static bp2build converter temporarily instead. if android.GenerateCcLibraryStaticOnly(ctx.Module().Name()) { - ccSharedOrStaticBp2BuildMutatorInternal(ctx, m, "cc_library_static") + sharedOrStaticLibraryBp2Build(ctx, m, true) return } @@ -298,43 +287,89 @@ func CcLibraryBp2Build(ctx android.TopDownMutatorContext) { baseAttributes := bp2BuildParseBaseProps(ctx, m) compilerAttrs := baseAttributes.compilerAttributes linkerAttrs := baseAttributes.linkerAttributes - exportedIncludes := bp2BuildParseExportedIncludes(ctx, m) + exportedIncludes := bp2BuildParseExportedIncludes(ctx, m, compilerAttrs.includes) srcs := compilerAttrs.srcs + sharedAttrs.Dynamic_deps.Add(baseAttributes.protoDependency) + staticAttrs.Deps.Add(baseAttributes.protoDependency) + asFlags := compilerAttrs.asFlags if compilerAttrs.asSrcs.IsEmpty() && sharedAttrs.Srcs_as.IsEmpty() && staticAttrs.Srcs_as.IsEmpty() { // Skip asflags for BUILD file simplicity if there are no assembly sources. asFlags = bazel.MakeStringListAttribute(nil) } - attrs := &bazelCcLibraryAttributes{ - Srcs: srcs, - Srcs_c: compilerAttrs.cSrcs, - Srcs_as: compilerAttrs.asSrcs, - Hdrs: compilerAttrs.hdrs, + staticCommonAttrs := staticOrSharedAttributes{ + Srcs: *srcs.Clone().Append(staticAttrs.Srcs), + Srcs_c: *compilerAttrs.cSrcs.Clone().Append(staticAttrs.Srcs_c), + Srcs_as: *compilerAttrs.asSrcs.Clone().Append(staticAttrs.Srcs_as), + Copts: *compilerAttrs.copts.Clone().Append(staticAttrs.Copts), + Hdrs: *compilerAttrs.hdrs.Clone().Append(staticAttrs.Hdrs), + + Deps: *linkerAttrs.deps.Clone().Append(staticAttrs.Deps), + Implementation_deps: *linkerAttrs.implementationDeps.Clone().Append(staticAttrs.Implementation_deps), + Dynamic_deps: *linkerAttrs.dynamicDeps.Clone().Append(staticAttrs.Dynamic_deps), + Implementation_dynamic_deps: *linkerAttrs.implementationDynamicDeps.Clone().Append(staticAttrs.Implementation_dynamic_deps), + Implementation_whole_archive_deps: linkerAttrs.implementationWholeArchiveDeps, + Whole_archive_deps: *linkerAttrs.wholeArchiveDeps.Clone().Append(staticAttrs.Whole_archive_deps), + System_dynamic_deps: *linkerAttrs.systemDynamicDeps.Clone().Append(staticAttrs.System_dynamic_deps), + } + + sharedCommonAttrs := staticOrSharedAttributes{ + Srcs: *srcs.Clone().Append(sharedAttrs.Srcs), + Srcs_c: *compilerAttrs.cSrcs.Clone().Append(sharedAttrs.Srcs_c), + Srcs_as: *compilerAttrs.asSrcs.Clone().Append(sharedAttrs.Srcs_as), + Copts: *compilerAttrs.copts.Clone().Append(sharedAttrs.Copts), + Hdrs: *compilerAttrs.hdrs.Clone().Append(sharedAttrs.Hdrs), + + Deps: *linkerAttrs.deps.Clone().Append(sharedAttrs.Deps), + Implementation_deps: *linkerAttrs.implementationDeps.Clone().Append(sharedAttrs.Implementation_deps), + Dynamic_deps: *linkerAttrs.dynamicDeps.Clone().Append(sharedAttrs.Dynamic_deps), + Implementation_dynamic_deps: *linkerAttrs.implementationDynamicDeps.Clone().Append(sharedAttrs.Implementation_dynamic_deps), + Whole_archive_deps: *linkerAttrs.wholeArchiveDeps.Clone().Append(sharedAttrs.Whole_archive_deps), + System_dynamic_deps: *linkerAttrs.systemDynamicDeps.Clone().Append(sharedAttrs.System_dynamic_deps), + } + + staticTargetAttrs := &bazelCcLibraryStaticAttributes{ + staticOrSharedAttributes: staticCommonAttrs, - Copts: compilerAttrs.copts, Cppflags: compilerAttrs.cppFlags, Conlyflags: compilerAttrs.conlyFlags, Asflags: asFlags, - Implementation_deps: linkerAttrs.implementationDeps, - Deps: linkerAttrs.deps, - Implementation_dynamic_deps: linkerAttrs.implementationDynamicDeps, - Dynamic_deps: linkerAttrs.dynamicDeps, - Whole_archive_deps: linkerAttrs.wholeArchiveDeps, - System_dynamic_deps: linkerAttrs.systemDynamicDeps, - Export_includes: exportedIncludes.Includes, - Export_system_includes: exportedIncludes.SystemIncludes, - Local_includes: compilerAttrs.localIncludes, - Absolute_includes: compilerAttrs.absoluteIncludes, - Linkopts: linkerAttrs.linkopts, - Link_crt: linkerAttrs.linkCrt, - Use_libcrt: linkerAttrs.useLibcrt, - Rtti: compilerAttrs.rtti, - Stl: compilerAttrs.stl, - Cpp_std: compilerAttrs.cppStd, + Export_includes: exportedIncludes.Includes, + Export_absolute_includes: exportedIncludes.AbsoluteIncludes, + Export_system_includes: exportedIncludes.SystemIncludes, + Local_includes: compilerAttrs.localIncludes, + Absolute_includes: compilerAttrs.absoluteIncludes, + Use_libcrt: linkerAttrs.useLibcrt, + Rtti: compilerAttrs.rtti, + Stl: compilerAttrs.stl, + Cpp_std: compilerAttrs.cppStd, + C_std: compilerAttrs.cStd, + + Features: linkerAttrs.features, + } + + sharedTargetAttrs := &bazelCcLibrarySharedAttributes{ + staticOrSharedAttributes: sharedCommonAttrs, + Cppflags: compilerAttrs.cppFlags, + Conlyflags: compilerAttrs.conlyFlags, + Asflags: asFlags, + + Export_includes: exportedIncludes.Includes, + Export_absolute_includes: exportedIncludes.AbsoluteIncludes, + Export_system_includes: exportedIncludes.SystemIncludes, + Local_includes: compilerAttrs.localIncludes, + Absolute_includes: compilerAttrs.absoluteIncludes, + Linkopts: linkerAttrs.linkopts, + Link_crt: linkerAttrs.linkCrt, + Use_libcrt: linkerAttrs.useLibcrt, + Rtti: compilerAttrs.rtti, + Stl: compilerAttrs.stl, + Cpp_std: compilerAttrs.cppStd, + C_std: compilerAttrs.cStd, Additional_linker_inputs: linkerAttrs.additionalLinkerInputs, @@ -345,20 +380,20 @@ func CcLibraryBp2Build(ctx android.TopDownMutatorContext) { All: linkerAttrs.stripAll, None: linkerAttrs.stripNone, }, - - Shared: sharedAttrs, - - Static: staticAttrs, - Features: linkerAttrs.features, } - props := bazel.BazelTargetModuleProperties{ - Rule_class: "cc_library", - Bzl_load_location: "//build/bazel/rules:full_cc_library.bzl", + staticProps := bazel.BazelTargetModuleProperties{ + Rule_class: "cc_library_static", + Bzl_load_location: "//build/bazel/rules:cc_library_static.bzl", + } + sharedProps := bazel.BazelTargetModuleProperties{ + Rule_class: "cc_library_shared", + Bzl_load_location: "//build/bazel/rules:cc_library_shared.bzl", } - ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs) + ctx.CreateBazelTargetModule(staticProps, android.CommonAttributes{Name: m.Name() + "_bp2build_cc_library_static"}, staticTargetAttrs) + ctx.CreateBazelTargetModule(sharedProps, android.CommonAttributes{Name: m.Name()}, sharedTargetAttrs) } // cc_library creates both static and/or shared libraries for a device and/or @@ -373,6 +408,7 @@ func LibraryFactory() android.Module { staticLibrarySdkMemberType, staticAndSharedLibrarySdkMemberType, } + module.bazelable = true module.bazelHandler = &ccLibraryBazelHandler{module: module} return module.Init() } @@ -382,6 +418,7 @@ func LibraryStaticFactory() android.Module { module, library := NewLibrary(android.HostAndDeviceSupported) library.BuildOnlyStatic() module.sdkMemberTypes = []android.SdkMemberType{staticLibrarySdkMemberType} + module.bazelable = true module.bazelHandler = &ccLibraryBazelHandler{module: module} return module.Init() } @@ -391,6 +428,7 @@ func LibrarySharedFactory() android.Module { module, library := NewLibrary(android.HostAndDeviceSupported) library.BuildOnlyShared() module.sdkMemberTypes = []android.SdkMemberType{sharedLibrarySdkMemberType} + module.bazelable = true module.bazelHandler = &ccLibraryBazelHandler{module: module} return module.Init() } @@ -409,6 +447,8 @@ func LibraryHostSharedFactory() android.Module { module, library := NewLibrary(android.HostSupported) library.BuildOnlyShared() module.sdkMemberTypes = []android.SdkMemberType{sharedLibrarySdkMemberType} + module.bazelable = true + module.bazelHandler = &ccLibraryBazelHandler{module: module} return module.Init() } @@ -1320,11 +1360,21 @@ func (library *libraryDecorator) linkStatic(ctx ModuleContext, return outputFile } +func ndkSharedLibDeps(ctx ModuleContext) android.Paths { + if ctx.Module().(*Module).IsSdkVariant() { + // The NDK sysroot timestamp file depends on all the NDK + // sysroot header and shared library files. + return android.Paths{getNdkBaseTimestampFile(ctx)} + } + return nil +} + func (library *libraryDecorator) linkShared(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path { var linkerDeps android.Paths linkerDeps = append(linkerDeps, flags.LdFlagsDeps...) + linkerDeps = append(linkerDeps, ndkSharedLibDeps(ctx)...) unexportedSymbols := ctx.ExpandOptionalSource(library.Properties.Unexported_symbols_list, "unexported_symbols_list") forceNotWeakSymbols := ctx.ExpandOptionalSource(library.Properties.Force_symbols_not_weak_list, "force_symbols_not_weak_list") @@ -1373,6 +1423,12 @@ func (library *libraryDecorator) linkShared(ctx ModuleContext, builderFlags := flagsToBuilderFlags(flags) + if ctx.Darwin() && deps.DarwinSecondArchOutput.Valid() { + fatOutputFile := outputFile + outputFile = android.PathForModuleOut(ctx, "pre-fat", fileName) + transformDarwinUniversalBinary(ctx, fatOutputFile, outputFile, deps.DarwinSecondArchOutput.Path()) + } + // Optimize out relinking against shared libraries whose interface hasn't changed by // depending on a table of contents file instead of the library itself. tocFile := outputFile.ReplaceExtension(ctx, flags.Toolchain.ShlibSuffix()[1:]+".toc") @@ -2349,30 +2405,12 @@ func maybeInjectBoringSSLHash(ctx android.ModuleContext, outputFile android.Modu return outputFile } -func ccSharedOrStaticBp2BuildMutator(ctx android.TopDownMutatorContext, modType string) { - module, ok := ctx.Module().(*Module) - if !ok { - // Not a cc module - return - } - if !module.ConvertWithBp2build(ctx) { - return - } - - ccSharedOrStaticBp2BuildMutatorInternal(ctx, module, modType) -} - -func ccSharedOrStaticBp2BuildMutatorInternal(ctx android.TopDownMutatorContext, module *Module, modType string) { - if modType != "cc_library_static" && modType != "cc_library_shared" { - panic("ccSharedOrStaticBp2BuildMutatorInternal only supports cc_library_{static,shared}") - } - isStatic := modType == "cc_library_static" - +func sharedOrStaticLibraryBp2Build(ctx android.TopDownMutatorContext, module *Module, isStatic bool) { baseAttributes := bp2BuildParseBaseProps(ctx, module) compilerAttrs := baseAttributes.compilerAttributes linkerAttrs := baseAttributes.linkerAttributes - exportedIncludes := bp2BuildParseExportedIncludes(ctx, module) + exportedIncludes := bp2BuildParseExportedIncludes(ctx, module, compilerAttrs.includes) // Append shared/static{} stanza properties. These won't be specified on // cc_library_* itself, but may be specified in cc_defaults that this module @@ -2403,27 +2441,34 @@ func ccSharedOrStaticBp2BuildMutatorInternal(ctx android.TopDownMutatorContext, Copts: compilerAttrs.copts, Hdrs: compilerAttrs.hdrs, - Deps: linkerAttrs.deps, - Implementation_deps: linkerAttrs.implementationDeps, - Dynamic_deps: linkerAttrs.dynamicDeps, - Implementation_dynamic_deps: linkerAttrs.implementationDynamicDeps, - Whole_archive_deps: linkerAttrs.wholeArchiveDeps, - System_dynamic_deps: linkerAttrs.systemDynamicDeps, + Deps: linkerAttrs.deps, + Implementation_deps: linkerAttrs.implementationDeps, + Dynamic_deps: linkerAttrs.dynamicDeps, + Implementation_dynamic_deps: linkerAttrs.implementationDynamicDeps, + Whole_archive_deps: linkerAttrs.wholeArchiveDeps, + Implementation_whole_archive_deps: linkerAttrs.implementationWholeArchiveDeps, + System_dynamic_deps: linkerAttrs.systemDynamicDeps, } var attrs interface{} if isStatic { + commonAttrs.Deps.Add(baseAttributes.protoDependency) attrs = &bazelCcLibraryStaticAttributes{ staticOrSharedAttributes: commonAttrs, - Use_libcrt: linkerAttrs.useLibcrt, - Rtti: compilerAttrs.rtti, - Stl: compilerAttrs.stl, - Cpp_std: compilerAttrs.cppStd, - Export_includes: exportedIncludes.Includes, - Export_system_includes: exportedIncludes.SystemIncludes, - Local_includes: compilerAttrs.localIncludes, - Absolute_includes: compilerAttrs.absoluteIncludes, + Use_libcrt: linkerAttrs.useLibcrt, + Use_version_lib: linkerAttrs.useVersionLib, + + Rtti: compilerAttrs.rtti, + Stl: compilerAttrs.stl, + Cpp_std: compilerAttrs.cppStd, + C_std: compilerAttrs.cStd, + + Export_includes: exportedIncludes.Includes, + Export_absolute_includes: exportedIncludes.AbsoluteIncludes, + Export_system_includes: exportedIncludes.SystemIncludes, + Local_includes: compilerAttrs.localIncludes, + Absolute_includes: compilerAttrs.absoluteIncludes, Cppflags: compilerAttrs.cppFlags, Conlyflags: compilerAttrs.conlyFlags, @@ -2432,21 +2477,27 @@ func ccSharedOrStaticBp2BuildMutatorInternal(ctx android.TopDownMutatorContext, Features: linkerAttrs.features, } } else { + commonAttrs.Dynamic_deps.Add(baseAttributes.protoDependency) + attrs = &bazelCcLibrarySharedAttributes{ staticOrSharedAttributes: commonAttrs, Cppflags: compilerAttrs.cppFlags, Conlyflags: compilerAttrs.conlyFlags, Asflags: asFlags, - Linkopts: linkerAttrs.linkopts, - Link_crt: linkerAttrs.linkCrt, - Use_libcrt: linkerAttrs.useLibcrt, - Rtti: compilerAttrs.rtti, - Stl: compilerAttrs.stl, - Cpp_std: compilerAttrs.cppStd, + Linkopts: linkerAttrs.linkopts, + Link_crt: linkerAttrs.linkCrt, + Use_libcrt: linkerAttrs.useLibcrt, + Use_version_lib: linkerAttrs.useVersionLib, + + Rtti: compilerAttrs.rtti, + Stl: compilerAttrs.stl, + Cpp_std: compilerAttrs.cppStd, + C_std: compilerAttrs.cStd, Export_includes: exportedIncludes.Includes, + Export_absolute_includes: exportedIncludes.AbsoluteIncludes, Export_system_includes: exportedIncludes.SystemIncludes, Local_includes: compilerAttrs.localIncludes, Absolute_includes: compilerAttrs.absoluteIncludes, @@ -2464,6 +2515,12 @@ func ccSharedOrStaticBp2BuildMutatorInternal(ctx android.TopDownMutatorContext, } } + var modType string + if isStatic { + modType = "cc_library_static" + } else { + modType = "cc_library_shared" + } props := bazel.BazelTargetModuleProperties{ Rule_class: modType, Bzl_load_location: fmt.Sprintf("//build/bazel/rules:%s.bzl", modType), @@ -2476,16 +2533,20 @@ func ccSharedOrStaticBp2BuildMutatorInternal(ctx android.TopDownMutatorContext, type bazelCcLibraryStaticAttributes struct { staticOrSharedAttributes - Use_libcrt bazel.BoolAttribute - Rtti bazel.BoolAttribute - Stl *string - Cpp_std *string + Use_libcrt bazel.BoolAttribute + Use_version_lib bazel.BoolAttribute - Export_includes bazel.StringListAttribute - Export_system_includes bazel.StringListAttribute - Local_includes bazel.StringListAttribute - Absolute_includes bazel.StringListAttribute - Hdrs bazel.LabelListAttribute + Rtti bazel.BoolAttribute + Stl *string + Cpp_std *string + C_std *string + + Export_includes bazel.StringListAttribute + Export_absolute_includes bazel.StringListAttribute + Export_system_includes bazel.StringListAttribute + Local_includes bazel.StringListAttribute + Absolute_includes bazel.StringListAttribute + Hdrs bazel.LabelListAttribute Cppflags bazel.StringListAttribute Conlyflags bazel.StringListAttribute @@ -2494,34 +2555,27 @@ type bazelCcLibraryStaticAttributes struct { Features bazel.StringListAttribute } -func CcLibraryStaticBp2Build(ctx android.TopDownMutatorContext) { - isLibraryStatic := ctx.ModuleType() == "cc_library_static" - if b, ok := ctx.Module().(android.Bazelable); ok { - // This is created by a custom soong config module type, so its ctx.ModuleType() is not - // cc_library_static. Check its BaseModuleType. - isLibraryStatic = isLibraryStatic || b.BaseModuleType() == "cc_library_static" - } - if isLibraryStatic { - ccSharedOrStaticBp2BuildMutator(ctx, "cc_library_static") - } -} - // TODO(b/199902614): Can this be factored to share with the other Attributes? type bazelCcLibrarySharedAttributes struct { staticOrSharedAttributes - Linkopts bazel.StringListAttribute - Link_crt bazel.BoolAttribute // Only for linking shared library (and cc_binary) - Use_libcrt bazel.BoolAttribute - Rtti bazel.BoolAttribute - Stl *string - Cpp_std *string + Linkopts bazel.StringListAttribute + Link_crt bazel.BoolAttribute // Only for linking shared library (and cc_binary) - Export_includes bazel.StringListAttribute - Export_system_includes bazel.StringListAttribute - Local_includes bazel.StringListAttribute - Absolute_includes bazel.StringListAttribute - Hdrs bazel.LabelListAttribute + Use_libcrt bazel.BoolAttribute + Use_version_lib bazel.BoolAttribute + + Rtti bazel.BoolAttribute + Stl *string + Cpp_std *string + C_std *string + + Export_includes bazel.StringListAttribute + Export_absolute_includes bazel.StringListAttribute + Export_system_includes bazel.StringListAttribute + Local_includes bazel.StringListAttribute + Absolute_includes bazel.StringListAttribute + Hdrs bazel.LabelListAttribute Strip stripAttributes Additional_linker_inputs bazel.LabelListAttribute @@ -2532,15 +2586,3 @@ type bazelCcLibrarySharedAttributes struct { Features bazel.StringListAttribute } - -func CcLibrarySharedBp2Build(ctx android.TopDownMutatorContext) { - isLibraryShared := ctx.ModuleType() == "cc_library_shared" - if b, ok := ctx.Module().(android.Bazelable); ok { - // This is created by a custom soong config module type, so its ctx.ModuleType() is not - // cc_library_shared. Check its BaseModuleType. - isLibraryShared = isLibraryShared || b.BaseModuleType() == "cc_library_shared" - } - if isLibraryShared { - ccSharedOrStaticBp2BuildMutator(ctx, "cc_library_shared") - } -} diff --git a/cc/library_headers.go b/cc/library_headers.go index ede6ab3c0..70e4715ad 100644 --- a/cc/library_headers.go +++ b/cc/library_headers.go @@ -25,7 +25,6 @@ func init() { // Register sdk member types. android.RegisterSdkMemberType(headersLibrarySdkMemberType) - android.RegisterBp2BuildMutator("cc_library_headers", CcLibraryHeadersBp2Build) } var headersLibrarySdkMemberType = &librarySdkMemberType{ @@ -96,52 +95,41 @@ func LibraryHeaderFactory() android.Module { module, library := NewLibrary(android.HostAndDeviceSupported) library.HeaderOnly() module.sdkMemberTypes = []android.SdkMemberType{headersLibrarySdkMemberType} + module.bazelable = true module.bazelHandler = &libraryHeaderBazelHander{module: module, library: library} return module.Init() } // cc_prebuilt_library_headers is a prebuilt version of cc_library_headers func prebuiltLibraryHeaderFactory() android.Module { - module, library := NewPrebuiltLibrary(android.HostAndDeviceSupported) + module, library := NewPrebuiltLibrary(android.HostAndDeviceSupported, "") library.HeaderOnly() return module.Init() } type bazelCcLibraryHeadersAttributes struct { - Hdrs bazel.LabelListAttribute - Export_includes bazel.StringListAttribute - Export_system_includes bazel.StringListAttribute - Deps bazel.LabelListAttribute - Implementation_deps bazel.LabelListAttribute - System_dynamic_deps bazel.LabelListAttribute + Hdrs bazel.LabelListAttribute + Export_includes bazel.StringListAttribute + Export_absolute_includes bazel.StringListAttribute + Export_system_includes bazel.StringListAttribute + Deps bazel.LabelListAttribute + Implementation_deps bazel.LabelListAttribute + System_dynamic_deps bazel.LabelListAttribute } -func CcLibraryHeadersBp2Build(ctx android.TopDownMutatorContext) { - module, ok := ctx.Module().(*Module) - if !ok { - // Not a cc module - return - } - - if !module.ConvertWithBp2build(ctx) { - return - } - - if ctx.ModuleType() != "cc_library_headers" { - return - } - - exportedIncludes := bp2BuildParseExportedIncludes(ctx, module) +func libraryHeadersBp2Build(ctx android.TopDownMutatorContext, module *Module) { baseAttributes := bp2BuildParseBaseProps(ctx, module) + exportedIncludes := bp2BuildParseExportedIncludes(ctx, module, baseAttributes.includes) linkerAttrs := baseAttributes.linkerAttributes attrs := &bazelCcLibraryHeadersAttributes{ - Export_includes: exportedIncludes.Includes, - Export_system_includes: exportedIncludes.SystemIncludes, - Implementation_deps: linkerAttrs.implementationDeps, - Deps: linkerAttrs.deps, - System_dynamic_deps: linkerAttrs.systemDynamicDeps, - Hdrs: baseAttributes.hdrs, + Export_includes: exportedIncludes.Includes, + Export_absolute_includes: exportedIncludes.AbsoluteIncludes, + Export_system_includes: exportedIncludes.SystemIncludes, + Implementation_deps: linkerAttrs.implementationDeps, + Deps: linkerAttrs.deps, + System_dynamic_deps: linkerAttrs.systemDynamicDeps, + Hdrs: baseAttributes.hdrs, } props := bazel.BazelTargetModuleProperties{ diff --git a/cc/library_headers_test.go b/cc/library_headers_test.go index 564ef61fb..3e448ba26 100644 --- a/cc/library_headers_test.go +++ b/cc/library_headers_test.go @@ -15,48 +15,85 @@ package cc import ( - "strings" + "fmt" "testing" + + "android/soong/android" + + "github.com/google/blueprint" ) func TestLibraryHeaders(t *testing.T) { - ctx := testCc(t, ` - cc_library_headers { - name: "headers", - export_include_dirs: ["my_include"], - } - cc_library_static { - name: "lib", - srcs: ["foo.c"], - header_libs: ["headers"], - } - `) + bp := ` + %s { + name: "headers", + export_include_dirs: ["my_include"], + } + cc_library_static { + name: "lib", + srcs: ["foo.c"], + header_libs: ["headers"], + } + ` + + for _, headerModule := range []string{"cc_library_headers", "cc_prebuilt_library_headers"} { + t.Run(headerModule, func(t *testing.T) { + ctx := testCc(t, fmt.Sprintf(bp, headerModule)) - // test if header search paths are correctly added - cc := ctx.ModuleForTests("lib", "android_arm64_armv8-a_static").Rule("cc") - cflags := cc.Args["cFlags"] - if !strings.Contains(cflags, " -Imy_include ") { - t.Errorf("cflags for libsystem must contain -Imy_include, but was %#v.", cflags) + // test if header search paths are correctly added + cc := ctx.ModuleForTests("lib", "android_arm64_armv8-a_static").Rule("cc") + android.AssertStringDoesContain(t, "cFlags for lib module", cc.Args["cFlags"], " -Imy_include ") + + // Test that there's a valid AndroidMk entry. + headers := ctx.ModuleForTests("headers", "android_arm64_armv8-a").Module() + e := android.AndroidMkEntriesForTest(t, ctx, headers)[0] + + // This duplicates the tests done in AndroidMkEntries.write. It would be + // better to test its output, but there are no test functions that capture that. + android.AssertBoolEquals(t, "AndroidMkEntries.Disabled", false, e.Disabled) + android.AssertBoolEquals(t, "AndroidMkEntries.OutputFile.Valid()", true, e.OutputFile.Valid()) + + android.AssertStringListContains(t, "LOCAL_EXPORT_CFLAGS for headers module", e.EntryMap["LOCAL_EXPORT_CFLAGS"], "-Imy_include") + }) } } -func TestPrebuiltLibraryHeaders(t *testing.T) { - ctx := testCc(t, ` - cc_prebuilt_library_headers { - name: "headers", - export_include_dirs: ["my_include"], - } - cc_library_static { - name: "lib", - srcs: ["foo.c"], - header_libs: ["headers"], - } - `) +func TestPrebuiltLibraryHeadersPreferred(t *testing.T) { + bp := ` + cc_library_headers { + name: "headers", + export_include_dirs: ["my_include"], + } + cc_prebuilt_library_headers { + name: "headers", + prefer: %t, + export_include_dirs: ["my_include"], + } + cc_library_static { + name: "lib", + srcs: ["foo.c"], + header_libs: ["headers"], + } + ` - // test if header search paths are correctly added - cc := ctx.ModuleForTests("lib", "android_arm64_armv8-a_static").Rule("cc") - cflags := cc.Args["cFlags"] - if !strings.Contains(cflags, " -Imy_include ") { - t.Errorf("cflags for libsystem must contain -Imy_include, but was %#v.", cflags) + for _, prebuiltPreferred := range []bool{false, true} { + t.Run(fmt.Sprintf("prebuilt prefer %t", prebuiltPreferred), func(t *testing.T) { + ctx := testCc(t, fmt.Sprintf(bp, prebuiltPreferred)) + lib := ctx.ModuleForTests("lib", "android_arm64_armv8-a_static") + sourceDep := ctx.ModuleForTests("headers", "android_arm64_armv8-a") + prebuiltDep := ctx.ModuleForTests("prebuilt_headers", "android_arm64_armv8-a") + hasSourceDep := false + hasPrebuiltDep := false + ctx.VisitDirectDeps(lib.Module(), func(dep blueprint.Module) { + if dep == sourceDep.Module() { + hasSourceDep = true + } + if dep == prebuiltDep.Module() { + hasPrebuiltDep = true + } + }) + android.AssertBoolEquals(t, "depends on source headers", !prebuiltPreferred, hasSourceDep) + android.AssertBoolEquals(t, "depends on prebuilt headers", prebuiltPreferred, hasPrebuiltDep) + }) } } diff --git a/cc/library_test.go b/cc/library_test.go index 7ddfaa7fd..d220e19f8 100644 --- a/cc/library_test.go +++ b/cc/library_test.go @@ -257,9 +257,16 @@ cc_library { CcObjectFiles: []string{"foo.o"}, Includes: []string{"include"}, SystemIncludes: []string{"system_include"}, - RootStaticArchives: []string{"foo.a"}, + Headers: []string{"foo.h"}, RootDynamicLibraries: []string{"foo.so"}, }, + "//foo/bar:bar_bp2build_cc_library_static": cquery.CcInfo{ + CcObjectFiles: []string{"foo.o"}, + Includes: []string{"include"}, + SystemIncludes: []string{"system_include"}, + Headers: []string{"foo.h"}, + RootStaticArchives: []string{"foo.a"}, + }, }, } ctx := testCcWithConfig(t, config) @@ -273,18 +280,25 @@ cc_library { expectedOutputFiles := []string{"outputbase/execroot/__main__/foo.a"} android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings()) + flagExporter := ctx.ModuleProvider(staticFoo, FlagExporterInfoProvider).(FlagExporterInfo) + android.AssertPathsRelativeToTopEquals(t, "exported include dirs", []string{"outputbase/execroot/__main__/include"}, flagExporter.IncludeDirs) + android.AssertPathsRelativeToTopEquals(t, "exported system include dirs", []string{"outputbase/execroot/__main__/system_include"}, flagExporter.SystemIncludeDirs) + android.AssertPathsRelativeToTopEquals(t, "exported headers", []string{"outputbase/execroot/__main__/foo.h"}, flagExporter.GeneratedHeaders) + android.AssertPathsRelativeToTopEquals(t, "deps", []string{"outputbase/execroot/__main__/foo.h"}, flagExporter.Deps) + sharedFoo := ctx.ModuleForTests("foo", "android_arm_armv7-a-neon_shared").Module() outputFiles, err = sharedFoo.(android.OutputFileProducer).OutputFiles("") if err != nil { - t.Errorf("Unexpected error getting cc_object outputfiles %s", err) + t.Errorf("Unexpected error getting cc_library outputfiles %s", err) } expectedOutputFiles = []string{"outputbase/execroot/__main__/foo.so"} android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings()) - entries := android.AndroidMkEntriesForTest(t, ctx, sharedFoo)[0] - expectedFlags := []string{"-Ioutputbase/execroot/__main__/include", "-isystem outputbase/execroot/__main__/system_include"} - gotFlags := entries.EntryMap["LOCAL_EXPORT_CFLAGS"] - android.AssertDeepEquals(t, "androidmk exported cflags", expectedFlags, gotFlags) + flagExporter = ctx.ModuleProvider(sharedFoo, FlagExporterInfoProvider).(FlagExporterInfo) + android.AssertPathsRelativeToTopEquals(t, "exported include dirs", []string{"outputbase/execroot/__main__/include"}, flagExporter.IncludeDirs) + android.AssertPathsRelativeToTopEquals(t, "exported system include dirs", []string{"outputbase/execroot/__main__/system_include"}, flagExporter.SystemIncludeDirs) + android.AssertPathsRelativeToTopEquals(t, "exported headers", []string{"outputbase/execroot/__main__/foo.h"}, flagExporter.GeneratedHeaders) + android.AssertPathsRelativeToTopEquals(t, "deps", []string{"outputbase/execroot/__main__/foo.h"}, flagExporter.Deps) } func TestLibraryVersionScript(t *testing.T) { diff --git a/cc/linkable.go b/cc/linkable.go index 560c9debe..02d7047bf 100644 --- a/cc/linkable.go +++ b/cc/linkable.go @@ -384,9 +384,13 @@ func flagExporterInfoFromCcInfo(ctx android.ModuleContext, ccInfo cquery.CcInfo) includes := android.PathsForBazelOut(ctx, ccInfo.Includes) systemIncludes := android.PathsForBazelOut(ctx, ccInfo.SystemIncludes) + headers := android.PathsForBazelOut(ctx, ccInfo.Headers) return FlagExporterInfo{ IncludeDirs: android.FirstUniquePaths(includes), SystemIncludeDirs: android.FirstUniquePaths(systemIncludes), + GeneratedHeaders: headers, + // necessary to ensure generated headers are considered implicit deps of dependent actions + Deps: headers, } } diff --git a/cc/ndk_sysroot.go b/cc/ndk_sysroot.go index fd458d96b..6c200f5dd 100644 --- a/cc/ndk_sysroot.go +++ b/cc/ndk_sysroot.go @@ -82,6 +82,12 @@ func getNdkBaseTimestampFile(ctx android.PathContext) android.WritablePath { return android.PathForOutput(ctx, "ndk_base.timestamp") } +// The headers timestamp file depends only on the NDK headers. +// This is used mainly for .tidy files that do not need any stub libraries. +func getNdkHeadersTimestampFile(ctx android.PathContext) android.WritablePath { + return android.PathForOutput(ctx, "ndk_headers.timestamp") +} + // The full timestamp file depends on the base timestamp *and* the static // libraries. func getNdkFullTimestampFile(ctx android.PathContext) android.WritablePath { @@ -96,6 +102,7 @@ type ndkSingleton struct{} func (n *ndkSingleton) GenerateBuildActions(ctx android.SingletonContext) { var staticLibInstallPaths android.Paths + var headerPaths android.Paths var installPaths android.Paths var licensePaths android.Paths ctx.VisitAllModules(func(module android.Module) { @@ -104,16 +111,19 @@ func (n *ndkSingleton) GenerateBuildActions(ctx android.SingletonContext) { } if m, ok := module.(*headerModule); ok { + headerPaths = append(headerPaths, m.installPaths...) installPaths = append(installPaths, m.installPaths...) licensePaths = append(licensePaths, m.licensePath) } if m, ok := module.(*versionedHeaderModule); ok { + headerPaths = append(headerPaths, m.installPaths...) installPaths = append(installPaths, m.installPaths...) licensePaths = append(licensePaths, m.licensePath) } if m, ok := module.(*preprocessedHeadersModule); ok { + headerPaths = append(headerPaths, m.installPaths...) installPaths = append(installPaths, m.installPaths...) licensePaths = append(licensePaths, m.licensePath) } @@ -153,6 +163,12 @@ func (n *ndkSingleton) GenerateBuildActions(ctx android.SingletonContext) { Validation: getNdkAbiDiffTimestampFile(ctx), }) + ctx.Build(pctx, android.BuildParams{ + Rule: android.Touch, + Output: getNdkHeadersTimestampFile(ctx), + Implicits: headerPaths, + }) + fullDepPaths := append(staticLibInstallPaths, getNdkBaseTimestampFile(ctx)) // There's a phony "ndk" rule defined in core/main.mk that depends on this. diff --git a/cc/object.go b/cc/object.go index 0327a451a..bd43e3670 100644 --- a/cc/object.go +++ b/cc/object.go @@ -29,7 +29,6 @@ func init() { android.RegisterModuleType("cc_object", ObjectFactory) android.RegisterSdkMemberType(ccObjectSdkMemberType) - android.RegisterBp2BuildMutator("cc_object", ObjectBp2Build) } var ccObjectSdkMemberType = &librarySdkMemberType{ @@ -117,6 +116,7 @@ func ObjectFactory() android.Module { module.sdkMemberTypes = []android.SdkMemberType{ccObjectSdkMemberType} + module.bazelable = true return module.Init() } @@ -135,19 +135,9 @@ type bazelObjectAttributes struct { Linker_script bazel.LabelAttribute } -// ObjectBp2Build is the bp2build converter from cc_object modules to the +// objectBp2Build is the bp2build converter from cc_object modules to the // Bazel equivalent target, plus any necessary include deps for the cc_object. -func ObjectBp2Build(ctx android.TopDownMutatorContext) { - m, ok := ctx.Module().(*Module) - if !ok || !m.ConvertWithBp2build(ctx) { - return - } - - // a Module can be something other than a cc_object. - if ctx.ModuleType() != "cc_object" { - return - } - +func objectBp2Build(ctx android.TopDownMutatorContext, m *Module) { if m.compiler == nil { // a cc_object must have access to the compiler decorator for its props. ctx.ModuleErrorf("compiler must not be nil for a cc_object module") @@ -96,10 +96,6 @@ func (props *PgoProperties) addInstrumentationProfileGatherFlags(ctx ModuleConte flags.Local.LdFlags = append(flags.Local.LdFlags, profileInstrumentFlag) return flags } -func (props *PgoProperties) addSamplingProfileGatherFlags(ctx ModuleContext, flags Flags) Flags { - flags.Local.CFlags = append(flags.Local.CFlags, props.Pgo.Cflags...) - return flags -} func (props *PgoProperties) getPgoProfileFile(ctx BaseModuleContext) android.OptionalPath { profileFile := *props.Pgo.Profile_file @@ -313,10 +309,6 @@ func (pgo *pgo) flags(ctx ModuleContext, flags Flags) Flags { if (props.ShouldProfileModule && props.isInstrumentation()) || props.PgoInstrLink { // Instrumentation PGO use and gather flags cannot coexist. return props.addInstrumentationProfileGatherFlags(ctx, flags) - } else if props.ShouldProfileModule && props.isSampling() { - flags = props.addSamplingProfileGatherFlags(ctx, flags) - } else if ctx.DeviceConfig().SamplingPGO() { - flags = props.addSamplingProfileGatherFlags(ctx, flags) } if !ctx.Config().IsEnvTrue("ANDROID_PGO_NO_PROFILE_USE") { diff --git a/cc/prebuilt.go b/cc/prebuilt.go index 16945ac69..feae81266 100644 --- a/cc/prebuilt.go +++ b/cc/prebuilt.go @@ -32,8 +32,6 @@ func RegisterPrebuiltBuildComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("cc_prebuilt_test_library_shared", PrebuiltSharedTestLibraryFactory) ctx.RegisterModuleType("cc_prebuilt_object", prebuiltObjectFactory) ctx.RegisterModuleType("cc_prebuilt_binary", prebuiltBinaryFactory) - - android.RegisterBp2BuildMutator("cc_prebuilt_library_shared", PrebuiltLibrarySharedBp2Build) } type prebuiltLinkerInterface interface { @@ -197,7 +195,13 @@ func (p *prebuiltLibraryLinker) link(ctx ModuleContext, if p.header() { ctx.SetProvider(HeaderLibraryInfoProvider, HeaderLibraryInfo{}) - return nil + // Need to return an output path so that the AndroidMk logic doesn't skip + // the prebuilt header. For compatibility, in case Android.mk files use a + // header lib in LOCAL_STATIC_LIBRARIES, create an empty ar file as + // placeholder, just like non-prebuilt header modules do in linkStatic(). + ph := android.PathForModuleOut(ctx, ctx.ModuleName()+staticLibraryExtension) + transformObjToStaticLib(ctx, nil, nil, builderFlags{}, ph, nil, nil) + return ph } return nil @@ -235,7 +239,7 @@ func (p *prebuiltLibraryLinker) implementationModuleName(name string) string { return android.RemoveOptionalPrebuiltPrefix(name) } -func NewPrebuiltLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator) { +func NewPrebuiltLibrary(hod android.HostOrDeviceSupported, srcsProperty string) (*Module, *libraryDecorator) { module, library := NewLibrary(hod) module.compiler = nil @@ -247,11 +251,15 @@ func NewPrebuiltLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDec module.AddProperties(&prebuilt.properties) - srcsSupplier := func(ctx android.BaseModuleContext, _ android.Module) []string { - return prebuilt.prebuiltSrcs(ctx) - } + if srcsProperty == "" { + android.InitPrebuiltModuleWithoutSrcs(module) + } else { + srcsSupplier := func(ctx android.BaseModuleContext, _ android.Module) []string { + return prebuilt.prebuiltSrcs(ctx) + } - android.InitPrebuiltModuleWithSrcSupplier(module, srcsSupplier, "srcs") + android.InitPrebuiltModuleWithSrcSupplier(module, srcsSupplier, srcsProperty) + } // Prebuilt libraries can be used in SDKs. android.InitSdkAwareModule(module) @@ -261,7 +269,7 @@ func NewPrebuiltLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDec // cc_prebuilt_library installs a precompiled shared library that are // listed in the srcs property in the device's directory. func PrebuiltLibraryFactory() android.Module { - module, _ := NewPrebuiltLibrary(android.HostAndDeviceSupported) + module, _ := NewPrebuiltLibrary(android.HostAndDeviceSupported, "srcs") // Prebuilt shared libraries can be included in APEXes android.InitApexModule(module) @@ -280,15 +288,16 @@ func PrebuiltSharedLibraryFactory() android.Module { // to be used as a data dependency of a test-related module (such as cc_test, or // cc_test_library). func PrebuiltSharedTestLibraryFactory() android.Module { - module, library := NewPrebuiltLibrary(android.HostAndDeviceSupported) + module, library := NewPrebuiltLibrary(android.HostAndDeviceSupported, "srcs") library.BuildOnlyShared() library.baseInstaller = NewTestInstaller() return module.Init() } func NewPrebuiltSharedLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator) { - module, library := NewPrebuiltLibrary(hod) + module, library := NewPrebuiltLibrary(hod, "srcs") library.BuildOnlyShared() + module.bazelable = true // Prebuilt shared libraries can be included in APEXes android.InitApexModule(module) @@ -304,33 +313,43 @@ func PrebuiltStaticLibraryFactory() android.Module { } func NewPrebuiltStaticLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator) { - module, library := NewPrebuiltLibrary(hod) + module, library := NewPrebuiltLibrary(hod, "srcs") library.BuildOnlyStatic() + module.bazelable = true module.bazelHandler = &prebuiltStaticLibraryBazelHandler{module: module, library: library} return module, library } -type bazelPrebuiltLibrarySharedAttributes struct { - Shared_library bazel.LabelAttribute +type bazelPrebuiltLibraryStaticAttributes struct { + Static_library bazel.LabelAttribute + Export_includes bazel.StringListAttribute + Export_system_includes bazel.StringListAttribute } -func PrebuiltLibrarySharedBp2Build(ctx android.TopDownMutatorContext) { - module, ok := ctx.Module().(*Module) - if !ok { - // Not a cc module - return - } - if !module.ConvertWithBp2build(ctx) { - return +func prebuiltLibraryStaticBp2Build(ctx android.TopDownMutatorContext, module *Module) { + prebuiltAttrs := Bp2BuildParsePrebuiltLibraryProps(ctx, module) + exportedIncludes := Bp2BuildParseExportedIncludesForPrebuiltLibrary(ctx, module) + + attrs := &bazelPrebuiltLibraryStaticAttributes{ + Static_library: prebuiltAttrs.Src, + Export_includes: exportedIncludes.Includes, + Export_system_includes: exportedIncludes.SystemIncludes, } - if ctx.ModuleType() != "cc_prebuilt_library_shared" { - return + + props := bazel.BazelTargetModuleProperties{ + Rule_class: "prebuilt_library_static", + Bzl_load_location: "//build/bazel/rules:prebuilt_library_static.bzl", } - prebuiltLibrarySharedBp2BuildInternal(ctx, module) + name := android.RemoveOptionalPrebuiltPrefix(module.Name()) + ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: name}, attrs) +} + +type bazelPrebuiltLibrarySharedAttributes struct { + Shared_library bazel.LabelAttribute } -func prebuiltLibrarySharedBp2BuildInternal(ctx android.TopDownMutatorContext, module *Module) { +func prebuiltLibrarySharedBp2Build(ctx android.TopDownMutatorContext, module *Module) { prebuiltAttrs := Bp2BuildParsePrebuiltLibraryProps(ctx, module) attrs := &bazelPrebuiltLibrarySharedAttributes{ @@ -533,7 +552,7 @@ func prebuiltBinaryFactory() android.Module { } func NewPrebuiltBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecorator) { - module, binary := NewBinary(hod) + module, binary := newBinary(hod, false) module.compiler = nil prebuilt := &prebuiltBinaryLinker{ diff --git a/cc/proto.go b/cc/proto.go index 44661447c..f3410bc2b 100644 --- a/cc/proto.go +++ b/cc/proto.go @@ -16,8 +16,14 @@ package cc import ( "github.com/google/blueprint/pathtools" + "github.com/google/blueprint/proptools" "android/soong/android" + "android/soong/bazel" +) + +const ( + protoTypeDefault = "lite" ) // genProto creates a rule to convert a .proto file to generated .pb.cc and .pb.h files and returns @@ -63,7 +69,7 @@ func protoDeps(ctx DepsContext, deps Deps, p *android.ProtoProperties, static bo var lib string if String(p.Proto.Plugin) == "" { - switch String(p.Proto.Type) { + switch proptools.StringDefault(p.Proto.Type, protoTypeDefault) { case "full": if ctx.useSdk() { lib = "libprotobuf-cpp-full-ndk" @@ -71,7 +77,7 @@ func protoDeps(ctx DepsContext, deps Deps, p *android.ProtoProperties, static bo } else { lib = "libprotobuf-cpp-full" } - case "lite", "": + case "lite": if ctx.useSdk() { lib = "libprotobuf-cpp-lite-ndk" static = true @@ -157,3 +163,69 @@ func protoFlags(ctx ModuleContext, flags Flags, p *android.ProtoProperties) Flag return flags } + +type protoAttributes struct { + Deps bazel.LabelListAttribute +} + +type bp2buildProtoDeps struct { + wholeStaticLib *bazel.LabelAttribute + implementationWholeStaticLib *bazel.LabelAttribute + protoDep *bazel.LabelAttribute +} + +func bp2buildProto(ctx android.Bp2buildMutatorContext, m *Module, protoSrcs bazel.LabelListAttribute) bp2buildProtoDeps { + var ret bp2buildProtoDeps + + protoInfo, ok := android.Bp2buildProtoProperties(ctx, m, protoSrcs) + if !ok { + return ret + } + + var depName string + typ := proptools.StringDefault(protoInfo.Type, protoTypeDefault) + var rule_class string + suffix := "_cc_proto" + switch typ { + case "lite": + suffix += "_lite" + rule_class = "cc_lite_proto_library" + depName = "libprotobuf-cpp-lite" + case "full": + rule_class = "cc_proto_library" + depName = "libprotobuf-cpp-full" + default: + ctx.PropertyErrorf("proto.type", "cannot handle conversion at this time: %q", typ) + } + + dep := android.BazelLabelForModuleDepSingle(ctx, depName) + ret.protoDep = &bazel.LabelAttribute{Value: &dep} + + protoLabel := bazel.Label{Label: ":" + protoInfo.Name} + var protoAttrs protoAttributes + protoAttrs.Deps.SetValue(bazel.LabelList{Includes: []bazel.Label{protoLabel}}) + + name := m.Name() + suffix + + ctx.CreateBazelTargetModule( + bazel.BazelTargetModuleProperties{ + Rule_class: rule_class, + Bzl_load_location: "//build/bazel/rules:cc_proto.bzl", + }, + android.CommonAttributes{Name: name}, + &protoAttrs) + + var privateHdrs bool + if lib, ok := m.linker.(*libraryDecorator); ok { + privateHdrs = !proptools.Bool(lib.Properties.Proto.Export_proto_headers) + } + + labelAttr := &bazel.LabelAttribute{Value: &bazel.Label{Label: ":" + name}} + if privateHdrs { + ret.implementationWholeStaticLib = labelAttr + } else { + ret.wholeStaticLib = labelAttr + } + + return ret +} diff --git a/cc/sanitize.go b/cc/sanitize.go index 93d4b4c54..d7b1adee5 100644 --- a/cc/sanitize.go +++ b/cc/sanitize.go @@ -35,7 +35,6 @@ var ( asanCflags = []string{ "-fno-omit-frame-pointer", - "-fno-experimental-new-pass-manager", } asanLdflags = []string{"-Wl,-u,__asan_preinit"} @@ -666,9 +665,6 @@ func (sanitize *sanitize) flags(ctx ModuleContext, flags Flags) Flags { flags.Local.LdFlags = append(flags.Local.LdFlags, "-fno-sanitize-coverage=stack-depth") flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize-coverage=stack-depth") - // TODO(b/133876586): Experimental PM breaks sanitizer coverage. - flags.Local.CFlags = append(flags.Local.CFlags, "-fno-experimental-new-pass-manager") - // Disable fortify for fuzzing builds. Generally, we'll be building with // UBSan or ASan here and the fortify checks pollute the stack traces. flags.Local.CFlags = append(flags.Local.CFlags, "-U_FORTIFY_SOURCE") diff --git a/cc/test.go b/cc/test.go index f37fdae38..d8b7833ba 100644 --- a/cc/test.go +++ b/cc/test.go @@ -105,11 +105,6 @@ type TestBinaryProperties struct { // Add RunCommandTargetPreparer to stop framework before the test and start it after the test. Disable_framework *bool - // Add ShippingApiLevelModuleController to auto generated test config. If the device properties - // for the shipping api level is less than the test_min_api_level, skip this module. - // Deprecated (b/187258404). Use test_options.min_shipping_api_level instead. - Test_min_api_level *int64 - // Flag to indicate whether or not to create test config automatically. If AndroidTest.xml // doesn't exist next to the Android.bp, this attribute doesn't need to be set to true // explicitly. @@ -432,14 +427,6 @@ func (test *testBinary) install(ctx ModuleContext, file android.Path) { var options []tradefed.Option options = append(options, tradefed.Option{Name: "min-api-level", Value: strconv.FormatInt(int64(*test.Properties.Test_options.Min_shipping_api_level), 10)}) configs = append(configs, tradefed.Object{"module_controller", "com.android.tradefed.testtype.suite.module.ShippingApiLevelModuleController", options}) - } else if test.Properties.Test_min_api_level != nil { - // TODO: (b/187258404) Remove test.Properties.Test_min_api_level - if test.Properties.Test_options.Vsr_min_shipping_api_level != nil { - ctx.PropertyErrorf("test_min_api_level", "must not be set at the same time as 'vsr_min_shipping_api_level'.") - } - var options []tradefed.Option - options = append(options, tradefed.Option{Name: "min-api-level", Value: strconv.FormatInt(int64(*test.Properties.Test_min_api_level), 10)}) - configs = append(configs, tradefed.Object{"module_controller", "com.android.tradefed.testtype.suite.module.ShippingApiLevelModuleController", options}) } if test.Properties.Test_options.Vsr_min_shipping_api_level != nil { var options []tradefed.Option @@ -474,7 +461,7 @@ func (test *testBinary) install(ctx ModuleContext, file android.Path) { } func NewTest(hod android.HostOrDeviceSupported) *Module { - module, binary := NewBinary(hod) + module, binary := newBinary(hod, false) module.multilib = android.MultilibBoth binary.baseInstaller = NewTestInstaller() @@ -564,6 +551,10 @@ type benchmarkDecorator struct { testConfig android.Path } +func (benchmark *benchmarkDecorator) benchmarkBinary() bool { + return true +} + func (benchmark *benchmarkDecorator) linkerInit(ctx BaseModuleContext) { runpath := "../../lib" if ctx.toolchain().Is64Bit() { @@ -601,7 +592,7 @@ func (benchmark *benchmarkDecorator) install(ctx ModuleContext, file android.Pat } func NewBenchmark(hod android.HostOrDeviceSupported) *Module { - module, binary := NewBinary(hod) + module, binary := newBinary(hod, false) module.multilib = android.MultilibBoth binary.baseInstaller = NewBaseInstaller("benchmarktest", "benchmarktest64", InstallInData) diff --git a/cc/tidy.go b/cc/tidy.go index 53ff1564b..78a791faf 100644 --- a/cc/tidy.go +++ b/cc/tidy.go @@ -15,6 +15,7 @@ package cc import ( + "path/filepath" "regexp" "strings" @@ -183,3 +184,154 @@ func (tidy *tidyFeature) flags(ctx ModuleContext, flags Flags) Flags { } return flags } + +func init() { + android.RegisterSingletonType("tidy_phony_targets", TidyPhonySingleton) +} + +// This TidyPhonySingleton generates both tidy-* and obj-* phony targets for C/C++ files. +func TidyPhonySingleton() android.Singleton { + return &tidyPhonySingleton{} +} + +type tidyPhonySingleton struct{} + +// Given a final module, add its tidy/obj phony targets to tidy/objModulesInDirGroup. +func collectTidyObjModuleTargets(ctx android.SingletonContext, module android.Module, + tidyModulesInDirGroup, objModulesInDirGroup map[string]map[string]android.Paths) { + allObjFileGroups := make(map[string]android.Paths) // variant group name => obj file Paths + allTidyFileGroups := make(map[string]android.Paths) // variant group name => tidy file Paths + subsetObjFileGroups := make(map[string]android.Paths) // subset group name => obj file Paths + subsetTidyFileGroups := make(map[string]android.Paths) // subset group name => tidy file Paths + + // (1) Collect all obj/tidy files into OS-specific groups. + ctx.VisitAllModuleVariants(module, func(variant android.Module) { + if ctx.Config().KatiEnabled() && android.ShouldSkipAndroidMkProcessing(variant) { + return + } + if m, ok := variant.(*Module); ok { + osName := variant.Target().Os.Name + addToOSGroup(osName, m.objFiles, allObjFileGroups, subsetObjFileGroups) + addToOSGroup(osName, m.tidyFiles, allTidyFileGroups, subsetTidyFileGroups) + } + }) + + // (2) Add an all-OS group, with "" or "subset" name, to include all os-specific phony targets. + addAllOSGroup(ctx, module, allObjFileGroups, "", "obj") + addAllOSGroup(ctx, module, allTidyFileGroups, "", "tidy") + addAllOSGroup(ctx, module, subsetObjFileGroups, "subset", "obj") + addAllOSGroup(ctx, module, subsetTidyFileGroups, "subset", "tidy") + + tidyTargetGroups := make(map[string]android.Path) + objTargetGroups := make(map[string]android.Path) + genObjTidyPhonyTargets(ctx, module, "obj", allObjFileGroups, objTargetGroups) + genObjTidyPhonyTargets(ctx, module, "obj", subsetObjFileGroups, objTargetGroups) + genObjTidyPhonyTargets(ctx, module, "tidy", allTidyFileGroups, tidyTargetGroups) + genObjTidyPhonyTargets(ctx, module, "tidy", subsetTidyFileGroups, tidyTargetGroups) + + moduleDir := ctx.ModuleDir(module) + appendToModulesInDirGroup(tidyTargetGroups, moduleDir, tidyModulesInDirGroup) + appendToModulesInDirGroup(objTargetGroups, moduleDir, objModulesInDirGroup) +} + +func (m *tidyPhonySingleton) GenerateBuildActions(ctx android.SingletonContext) { + // For tidy-* directory phony targets, there are different variant groups. + // tidyModulesInDirGroup[G][D] is for group G, directory D, with Paths + // of all phony targets to be included into direct dependents of tidy-D_G. + tidyModulesInDirGroup := make(map[string]map[string]android.Paths) + // Also for obj-* directory phony targets. + objModulesInDirGroup := make(map[string]map[string]android.Paths) + + // Collect tidy/obj targets from the 'final' modules. + ctx.VisitAllModules(func(module android.Module) { + if module == ctx.FinalModule(module) { + collectTidyObjModuleTargets(ctx, module, tidyModulesInDirGroup, objModulesInDirGroup) + } + }) + + suffix := "" + if ctx.Config().KatiEnabled() { + suffix = "-soong" + } + generateObjTidyPhonyTargets(ctx, suffix, "obj", objModulesInDirGroup) + generateObjTidyPhonyTargets(ctx, suffix, "tidy", tidyModulesInDirGroup) +} + +// The name for an obj/tidy module variant group phony target is Name_group-obj/tidy, +func objTidyModuleGroupName(module android.Module, group string, suffix string) string { + if group == "" { + return module.Name() + "-" + suffix + } + return module.Name() + "_" + group + "-" + suffix +} + +// Generate obj-* or tidy-* phony targets. +func generateObjTidyPhonyTargets(ctx android.SingletonContext, suffix string, prefix string, objTidyModulesInDirGroup map[string]map[string]android.Paths) { + // For each variant group, create a <prefix>-<directory>_group target that + // depends on all subdirectories and modules in the directory. + for group, modulesInDir := range objTidyModulesInDirGroup { + groupSuffix := "" + if group != "" { + groupSuffix = "_" + group + } + mmTarget := func(dir string) string { + return prefix + "-" + strings.Replace(filepath.Clean(dir), "/", "-", -1) + groupSuffix + } + dirs, topDirs := android.AddAncestors(ctx, modulesInDir, mmTarget) + // Create a <prefix>-soong_group target that depends on all <prefix>-dir_group of top level dirs. + var topDirPaths android.Paths + for _, dir := range topDirs { + topDirPaths = append(topDirPaths, android.PathForPhony(ctx, mmTarget(dir))) + } + ctx.Phony(prefix+suffix+groupSuffix, topDirPaths...) + // Create a <prefix>-dir_group target that depends on all targets in modulesInDir[dir] + for _, dir := range dirs { + if dir != "." && dir != "" { + ctx.Phony(mmTarget(dir), modulesInDir[dir]...) + } + } + } +} + +// Append (obj|tidy)TargetGroups[group] into (obj|tidy)ModulesInDirGroups[group][moduleDir]. +func appendToModulesInDirGroup(targetGroups map[string]android.Path, moduleDir string, modulesInDirGroup map[string]map[string]android.Paths) { + for group, phonyPath := range targetGroups { + if _, found := modulesInDirGroup[group]; !found { + modulesInDirGroup[group] = make(map[string]android.Paths) + } + modulesInDirGroup[group][moduleDir] = append(modulesInDirGroup[group][moduleDir], phonyPath) + } +} + +// Add given files to the OS group and subset group. +func addToOSGroup(osName string, files android.Paths, allGroups, subsetGroups map[string]android.Paths) { + if len(files) > 0 { + subsetName := osName + "_subset" + allGroups[osName] = append(allGroups[osName], files...) + // Now include only the first variant in the subsetGroups. + // If clang and clang-tidy get faster, we might include more variants. + if _, found := subsetGroups[subsetName]; !found { + subsetGroups[subsetName] = files + } + } +} + +// Add an all-OS group, with groupName, to include all os-specific phony targets. +func addAllOSGroup(ctx android.SingletonContext, module android.Module, phonyTargetGroups map[string]android.Paths, groupName string, objTidyName string) { + if len(phonyTargetGroups) > 0 { + var targets android.Paths + for group, _ := range phonyTargetGroups { + targets = append(targets, android.PathForPhony(ctx, objTidyModuleGroupName(module, group, objTidyName))) + } + phonyTargetGroups[groupName] = targets + } +} + +// Create one phony targets for each group and add them to the targetGroups. +func genObjTidyPhonyTargets(ctx android.SingletonContext, module android.Module, objTidyName string, fileGroups map[string]android.Paths, targetGroups map[string]android.Path) { + for group, files := range fileGroups { + groupName := objTidyModuleGroupName(module, group, objTidyName) + ctx.Phony(groupName, files...) + targetGroups[group] = android.PathForPhony(ctx, groupName) + } +} diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go index dfc4eae7a..f07eafabe 100644 --- a/cmd/soong_build/main.go +++ b/cmd/soong_build/main.go @@ -386,7 +386,7 @@ func touch(path string) { // - won't be overwritten by corresponding bp2build generated files // // And return their paths so they can be left out of the Bazel workspace dir (i.e. ignored) -func getPathsToIgnoredBuildFiles(topDir string, generatedRoot string, srcDirBazelFiles []string) []string { +func getPathsToIgnoredBuildFiles(topDir string, generatedRoot string, srcDirBazelFiles []string, verbose bool) []string { paths := make([]string, 0) for _, srcDirBazelFileRelativePath := range srcDirBazelFiles { @@ -416,7 +416,9 @@ func getPathsToIgnoredBuildFiles(topDir string, generatedRoot string, srcDirBaze // BUILD file clash resolution happens later in the symlink forest creation continue } - fmt.Fprintf(os.Stderr, "Ignoring existing BUILD file: %s\n", srcDirBazelFileRelativePath) + if verbose { + fmt.Fprintf(os.Stderr, "Ignoring existing BUILD file: %s\n", srcDirBazelFileRelativePath) + } paths = append(paths, srcDirBazelFileRelativePath) } @@ -523,7 +525,7 @@ func runBp2Build(configuration android.Config, extraNinjaDeps []string) { os.Exit(1) } - pathsToIgnoredBuildFiles := getPathsToIgnoredBuildFiles(topDir, generatedRoot, existingBazelRelatedFiles) + pathsToIgnoredBuildFiles := getPathsToIgnoredBuildFiles(topDir, generatedRoot, existingBazelRelatedFiles, configuration.IsEnvTrue("BP2BUILD_VERBOSE")) excludes = append(excludes, pathsToIgnoredBuildFiles...) excludes = append(excludes, getTemporaryExcludes()...) @@ -535,6 +537,7 @@ func runBp2Build(configuration android.Config, extraNinjaDeps []string) { // for queryview, since that's a total repo-wide conversion and there's a // 1:1 mapping for each module. metrics.Print() + writeBp2BuildMetrics(&metrics, configuration) ninjaDeps = append(ninjaDeps, codegenContext.AdditionalNinjaDeps()...) ninjaDeps = append(ninjaDeps, symlinkForestDeps...) @@ -544,3 +547,13 @@ func runBp2Build(configuration android.Config, extraNinjaDeps []string) { // Create an empty bp2build marker file. touch(shared.JoinPath(topDir, bp2buildMarker)) } + +// Write Bp2Build metrics into $LOG_DIR +func writeBp2BuildMetrics(metrics *bp2build.CodegenMetrics, configuration android.Config) { + metricsDir := configuration.Getenv("LOG_DIR") + if len(metricsDir) < 1 { + fmt.Fprintf(os.Stderr, "\nMissing required env var for generating bp2build metrics: LOG_DIR\n") + os.Exit(1) + } + metrics.Write(metricsDir) +} diff --git a/compliance/build_license_metadata/Android.bp b/compliance/build_license_metadata/Android.bp index 500034615..48265261b 100644 --- a/compliance/build_license_metadata/Android.bp +++ b/compliance/build_license_metadata/Android.bp @@ -25,5 +25,6 @@ blueprint_go_binary { "license_metadata_proto", "golang-protobuf-proto", "golang-protobuf-encoding-prototext", + "soong-response", ], } diff --git a/compliance/build_license_metadata/build_license_metadata.go b/compliance/build_license_metadata/build_license_metadata.go index 8b1fe589e..53d2407cb 100644 --- a/compliance/build_license_metadata/build_license_metadata.go +++ b/compliance/build_license_metadata/build_license_metadata.go @@ -26,28 +26,12 @@ import ( "google.golang.org/protobuf/proto" "android/soong/compliance/license_metadata_proto" + "android/soong/response" ) -var ( - packageName = flag.String("p", "", "license package name") - moduleType = newMultiString("mt", "module type") - moduleClass = newMultiString("mc", "module class") - kinds = newMultiString("k", "license kinds") - conditions = newMultiString("c", "license conditions") - notices = newMultiString("n", "license notice file") - deps = newMultiString("d", "license metadata file dependency") - sources = newMultiString("s", "source (input) dependency") - built = newMultiString("t", "built targets") - installed = newMultiString("i", "installed targets") - roots = newMultiString("r", "root directory of project") - installedMap = newMultiString("m", "map dependent targets to their installed names") - isContainer = flag.Bool("is_container", false, "preserved dependent target name when given") - outFile = flag.String("o", "", "output file") -) - -func newMultiString(name, usage string) *multiString { +func newMultiString(flags *flag.FlagSet, name, usage string) *multiString { var f multiString - flag.Var(&f, name, usage) + flags.Var(&f, name, usage) return &f } @@ -57,7 +41,45 @@ func (ms *multiString) String() string { return strings.Join(*ms, ", ") } func (ms *multiString) Set(s string) error { *ms = append(*ms, s); return nil } func main() { - flag.Parse() + var expandedArgs []string + for _, arg := range os.Args[1:] { + if strings.HasPrefix(arg, "@") { + f, err := os.Open(strings.TrimPrefix(arg, "@")) + if err != nil { + fmt.Fprintln(os.Stderr, err.Error()) + os.Exit(1) + } + + respArgs, err := response.ReadRspFile(f) + f.Close() + if err != nil { + fmt.Fprintln(os.Stderr, err.Error()) + os.Exit(1) + } + expandedArgs = append(expandedArgs, respArgs...) + } else { + expandedArgs = append(expandedArgs, arg) + } + } + + flags := flag.NewFlagSet("flags", flag.ExitOnError) + + packageName := flags.String("p", "", "license package name") + moduleType := newMultiString(flags, "mt", "module type") + kinds := newMultiString(flags, "k", "license kinds") + moduleClass := newMultiString(flags, "mc", "module class") + conditions := newMultiString(flags, "c", "license conditions") + notices := newMultiString(flags, "n", "license notice file") + deps := newMultiString(flags, "d", "license metadata file dependency") + sources := newMultiString(flags, "s", "source (input) dependency") + built := newMultiString(flags, "t", "built targets") + installed := newMultiString(flags, "i", "installed targets") + roots := newMultiString(flags, "r", "root directory of project") + installedMap := newMultiString(flags, "m", "map dependent targets to their installed names") + isContainer := flags.Bool("is_container", false, "preserved dependent target name when given") + outFile := flags.String("o", "", "output file") + + flags.Parse(expandedArgs) metadata := license_metadata_proto.LicenseMetadata{} metadata.PackageName = proto.String(*packageName) diff --git a/dexpreopt/config.go b/dexpreopt/config.go index de3666a33..6d6b41d4b 100644 --- a/dexpreopt/config.go +++ b/dexpreopt/config.go @@ -49,10 +49,12 @@ type GlobalConfig struct { ArtApexJars android.ConfiguredJarList // modules for jars that are in the ART APEX - SystemServerJars android.ConfiguredJarList // jars that form the system server - SystemServerApps []string // apps that are loaded into system server - ApexSystemServerJars android.ConfiguredJarList // jars within apex that are loaded into system server - SpeedApps []string // apps that should be speed optimized + SystemServerJars android.ConfiguredJarList // system_server classpath jars on the platform + SystemServerApps []string // apps that are loaded into system server + ApexSystemServerJars android.ConfiguredJarList // system_server classpath jars delivered via apex + StandaloneSystemServerJars android.ConfiguredJarList // jars on the platform that system_server loads dynamically using separate classloaders + ApexStandaloneSystemServerJars android.ConfiguredJarList // jars delivered via apex that system_server loads dynamically using separate classloaders + SpeedApps []string // apps that should be speed optimized BrokenSuboptimalOrderOfSystemServerJars bool // if true, sub-optimal order does not cause a build error @@ -619,6 +621,8 @@ func GlobalConfigForTests(ctx android.PathContext) *GlobalConfig { SystemServerJars: android.EmptyConfiguredJarList(), SystemServerApps: nil, ApexSystemServerJars: android.EmptyConfiguredJarList(), + StandaloneSystemServerJars: android.EmptyConfiguredJarList(), + ApexStandaloneSystemServerJars: android.EmptyConfiguredJarList(), SpeedApps: nil, PreoptFlags: nil, DefaultCompilerFilter: "", diff --git a/dexpreopt/testing.go b/dexpreopt/testing.go index 8f5c31521..5131cd3f4 100644 --- a/dexpreopt/testing.go +++ b/dexpreopt/testing.go @@ -85,12 +85,12 @@ var PrepareForTestWithFakeDex2oatd = android.GroupFixturePreparers( // Prepares a test fixture by enabling dexpreopt, registering the fake_tool_binary module type and // using that to define the `dex2oatd` module. var PrepareForTestByEnablingDexpreopt = android.GroupFixturePreparers( - FixtureModifyGlobalConfig(func(*GlobalConfig) {}), + FixtureModifyGlobalConfig(func(android.PathContext, *GlobalConfig) {}), ) // FixtureModifyGlobalConfig enables dexpreopt (unless modified by the mutator) and modifies the // configuration. -func FixtureModifyGlobalConfig(configModifier func(dexpreoptConfig *GlobalConfig)) android.FixturePreparer { +func FixtureModifyGlobalConfig(configModifier func(ctx android.PathContext, dexpreoptConfig *GlobalConfig)) android.FixturePreparer { return android.FixtureModifyConfig(func(config android.Config) { // Initialize the dexpreopt GlobalConfig to an empty structure. This has no effect if it has // already been set. @@ -100,48 +100,70 @@ func FixtureModifyGlobalConfig(configModifier func(dexpreoptConfig *GlobalConfig // Retrieve the existing configuration and modify it. dexpreoptConfig = GetGlobalConfig(pathCtx) - configModifier(dexpreoptConfig) + configModifier(pathCtx, dexpreoptConfig) }) } // FixtureSetArtBootJars enables dexpreopt and sets the ArtApexJars property. func FixtureSetArtBootJars(bootJars ...string) android.FixturePreparer { - return FixtureModifyGlobalConfig(func(dexpreoptConfig *GlobalConfig) { + return FixtureModifyGlobalConfig(func(_ android.PathContext, dexpreoptConfig *GlobalConfig) { dexpreoptConfig.ArtApexJars = android.CreateTestConfiguredJarList(bootJars) }) } // FixtureSetBootJars enables dexpreopt and sets the BootJars property. func FixtureSetBootJars(bootJars ...string) android.FixturePreparer { - return FixtureModifyGlobalConfig(func(dexpreoptConfig *GlobalConfig) { + return FixtureModifyGlobalConfig(func(_ android.PathContext, dexpreoptConfig *GlobalConfig) { dexpreoptConfig.BootJars = android.CreateTestConfiguredJarList(bootJars) }) } // FixtureSetApexBootJars sets the ApexBootJars property in the global config. func FixtureSetApexBootJars(bootJars ...string) android.FixturePreparer { - return FixtureModifyGlobalConfig(func(dexpreoptConfig *GlobalConfig) { + return FixtureModifyGlobalConfig(func(_ android.PathContext, dexpreoptConfig *GlobalConfig) { dexpreoptConfig.ApexBootJars = android.CreateTestConfiguredJarList(bootJars) }) } +// FixtureSetStandaloneSystemServerJars sets the StandaloneSystemServerJars property. +func FixtureSetStandaloneSystemServerJars(jars ...string) android.FixturePreparer { + return FixtureModifyGlobalConfig(func(_ android.PathContext, dexpreoptConfig *GlobalConfig) { + dexpreoptConfig.StandaloneSystemServerJars = android.CreateTestConfiguredJarList(jars) + }) +} + // FixtureSetSystemServerJars sets the SystemServerJars property. func FixtureSetSystemServerJars(jars ...string) android.FixturePreparer { - return FixtureModifyGlobalConfig(func(dexpreoptConfig *GlobalConfig) { + return FixtureModifyGlobalConfig(func(_ android.PathContext, dexpreoptConfig *GlobalConfig) { dexpreoptConfig.SystemServerJars = android.CreateTestConfiguredJarList(jars) }) } // FixtureSetApexSystemServerJars sets the ApexSystemServerJars property in the global config. func FixtureSetApexSystemServerJars(jars ...string) android.FixturePreparer { - return FixtureModifyGlobalConfig(func(dexpreoptConfig *GlobalConfig) { + return FixtureModifyGlobalConfig(func(_ android.PathContext, dexpreoptConfig *GlobalConfig) { dexpreoptConfig.ApexSystemServerJars = android.CreateTestConfiguredJarList(jars) }) } +// FixtureSetApexStandaloneSystemServerJars sets the ApexStandaloneSystemServerJars property in the +// global config. +func FixtureSetApexStandaloneSystemServerJars(jars ...string) android.FixturePreparer { + return FixtureModifyGlobalConfig(func(_ android.PathContext, dexpreoptConfig *GlobalConfig) { + dexpreoptConfig.ApexStandaloneSystemServerJars = android.CreateTestConfiguredJarList(jars) + }) +} + // FixtureSetPreoptWithUpdatableBcp sets the PreoptWithUpdatableBcp property in the global config. func FixtureSetPreoptWithUpdatableBcp(value bool) android.FixturePreparer { - return FixtureModifyGlobalConfig(func(dexpreoptConfig *GlobalConfig) { + return FixtureModifyGlobalConfig(func(_ android.PathContext, dexpreoptConfig *GlobalConfig) { dexpreoptConfig.PreoptWithUpdatableBcp = value }) } + +// FixtureSetBootImageProfiles sets the BootImageProfiles property in the global config. +func FixtureSetBootImageProfiles(profiles ...string) android.FixturePreparer { + return FixtureModifyGlobalConfig(func(ctx android.PathContext, dexpreoptConfig *GlobalConfig) { + dexpreoptConfig.BootImageProfiles = android.PathsForSource(ctx, profiles) + }) +} diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go index 2865ffad2..80ab41be6 100644 --- a/etc/prebuilt_etc.go +++ b/etc/prebuilt_etc.go @@ -63,7 +63,6 @@ func RegisterPrebuiltEtcBuildComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("prebuilt_defaults", defaultsFactory) - android.RegisterBp2BuildMutator("prebuilt_etc", PrebuiltEtcBp2Build) } var PrepareForTestWithPrebuiltEtc = android.FixtureRegisterWithContext(RegisterPrebuiltEtcBuildComponents) @@ -663,20 +662,14 @@ type bazelPrebuiltEtcAttributes struct { Installable bazel.BoolAttribute } -func PrebuiltEtcBp2Build(ctx android.TopDownMutatorContext) { - module, ok := ctx.Module().(*PrebuiltEtc) - if !ok { - // Not an prebuilt_etc - return - } - if !module.ConvertWithBp2build(ctx) { - return - } +// ConvertWithBp2build performs bp2build conversion of PrebuiltEtc +func (p *PrebuiltEtc) ConvertWithBp2build(ctx android.TopDownMutatorContext) { + // All prebuilt_* modules are PrebuiltEtc, but at this time, we only convert prebuilt_etc modules. if ctx.ModuleType() != "prebuilt_etc" { return } - prebuiltEtcBp2BuildInternal(ctx, module) + prebuiltEtcBp2BuildInternal(ctx, p) } func prebuiltEtcBp2BuildInternal(ctx android.TopDownMutatorContext, module *PrebuiltEtc) { diff --git a/genrule/genrule.go b/genrule/genrule.go index c9bf958a3..6a91e012d 100644 --- a/genrule/genrule.go +++ b/genrule/genrule.go @@ -67,13 +67,6 @@ func RegisterGenruleBuildComponents(ctx android.RegistrationContext) { ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) { ctx.BottomUp("genrule_tool_deps", toolDepsMutator).Parallel() }) - - android.RegisterBp2BuildMutator("genrule", GenruleBp2Build) - android.RegisterBp2BuildMutator("cc_genrule", CcGenruleBp2Build) -} - -func RegisterGenruleBp2BuildDeps(ctx android.RegisterMutatorsContext) { - ctx.BottomUp("genrule_tool_deps", toolDepsMutator) } var ( @@ -110,6 +103,7 @@ type HostToolProvider interface { type hostToolDependencyTag struct { blueprint.BaseDependencyTag + android.LicenseAnnotationToolchainDependencyTag label string } type generatorProperties struct { @@ -832,38 +826,8 @@ type bazelGenruleAttributes struct { Cmd string } -// CcGenruleBp2Build is for cc_genrule. -func CcGenruleBp2Build(ctx android.TopDownMutatorContext) { - m, ok := ctx.Module().(*Module) - if !ok || !m.ConvertWithBp2build(ctx) { - return - } - - if ctx.ModuleType() != "cc_genrule" { - // Not a cc_genrule. - return - } - - genruleBp2Build(ctx) -} - -// GenruleBp2Build is used for genrule. -func GenruleBp2Build(ctx android.TopDownMutatorContext) { - m, ok := ctx.Module().(*Module) - if !ok || !m.ConvertWithBp2build(ctx) { - return - } - - if ctx.ModuleType() != "genrule" { - // Not a regular genrule. - return - } - - genruleBp2Build(ctx) -} - -func genruleBp2Build(ctx android.TopDownMutatorContext) { - m, _ := ctx.Module().(*Module) +// ConvertWithBp2build converts a Soong module -> Bazel target. +func (m *Module) ConvertWithBp2build(ctx android.TopDownMutatorContext) { // Bazel only has the "tools" attribute. tools_prop := android.BazelLabelForModuleDeps(ctx, m.properties.Tools) tool_files_prop := android.BazelLabelForModuleSrc(ctx, m.properties.Tool_files) diff --git a/java/android_manifest.go b/java/android_manifest.go index 38065f153..f29d8ad1a 100644 --- a/java/android_manifest.go +++ b/java/android_manifest.go @@ -16,6 +16,7 @@ package java import ( "fmt" + "strconv" "strings" "github.com/google/blueprint" @@ -42,6 +43,21 @@ var manifestMergerRule = pctx.AndroidStaticRule("manifestMerger", }, "args", "libs") +// targetSdkVersion for manifest_fixer +// When TARGET_BUILD_APPS is not empty, this method returns 10000 for modules targeting an unreleased SDK +// This enables release builds (that run with TARGET_BUILD_APPS=[val...]) to target APIs that have not yet been finalized as part of an SDK +func targetSdkVersionForManifestFixer(ctx android.ModuleContext, sdkContext android.SdkContext) string { + targetSdkVersionSpec := sdkContext.TargetSdkVersion(ctx) + if ctx.Config().UnbundledBuildApps() && targetSdkVersionSpec.ApiLevel.IsPreview() { + return strconv.Itoa(android.FutureApiLevel.FinalOrFutureInt()) + } + targetSdkVersion, err := targetSdkVersionSpec.EffectiveVersionString(ctx) + if err != nil { + ctx.ModuleErrorf("invalid targetSdkVersion: %s", err) + } + return targetSdkVersion +} + // Uses manifest_fixer.py to inject minSdkVersion, etc. into an AndroidManifest.xml func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext android.SdkContext, classLoaderContexts dexpreopt.ClassLoaderContextMap, isLibrary, useEmbeddedNativeLibs, usesNonSdkApis, @@ -89,10 +105,8 @@ func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext args = append(args, "--logging-parent", loggingParent) } var deps android.Paths - targetSdkVersion, err := sdkContext.TargetSdkVersion(ctx).EffectiveVersionString(ctx) - if err != nil { - ctx.ModuleErrorf("invalid targetSdkVersion: %s", err) - } + targetSdkVersion := targetSdkVersionForManifestFixer(ctx, sdkContext) + if UseApiFingerprint(ctx) && ctx.ModuleName() != "framework-res" { targetSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", ApiFingerprintPath(ctx).String()) deps = append(deps, ApiFingerprintPath(ctx)) diff --git a/java/android_resources.go b/java/android_resources.go index 6864ebb90..8c5908f69 100644 --- a/java/android_resources.go +++ b/java/android_resources.go @@ -43,7 +43,7 @@ var androidResourceIgnoreFilenames = []string{ // androidResourceGlob returns the list of files in the given directory, using the standard // exclusion patterns for Android resources. -func androidResourceGlob(ctx android.ModuleContext, dir android.Path) android.Paths { +func androidResourceGlob(ctx android.EarlyModuleContext, dir android.Path) android.Paths { return ctx.GlobFiles(filepath.Join(dir.String(), "**/*"), androidResourceIgnoreFilenames) } diff --git a/java/app.go b/java/app.go index c08ec0697..b753c0cb8 100755 --- a/java/app.go +++ b/java/app.go @@ -43,8 +43,6 @@ func RegisterAppBuildComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("android_app_certificate", AndroidAppCertificateFactory) ctx.RegisterModuleType("override_android_app", OverrideAndroidAppModuleFactory) ctx.RegisterModuleType("override_android_test", OverrideAndroidTestModuleFactory) - - android.RegisterBp2BuildMutator("android_app_certificate", AndroidAppCertificateBp2Build) } // AndroidManifest.xml merging @@ -139,6 +137,7 @@ type overridableAppProperties struct { } type AndroidApp struct { + android.BazelModuleBase Library aapt android.OverridableModuleBase @@ -291,7 +290,7 @@ func (a *AndroidApp) checkAppSdkVersions(ctx android.ModuleContext) { if minSdkVersion, err := a.MinSdkVersion(ctx).EffectiveVersion(ctx); err == nil { a.checkJniLibsSdkVersion(ctx, minSdkVersion) - android.CheckMinSdkVersion(a, ctx, minSdkVersion) + android.CheckMinSdkVersion(ctx, minSdkVersion, a.WalkPayloadDeps) } else { ctx.PropertyErrorf("min_sdk_version", "%s", err.Error()) } @@ -943,6 +942,7 @@ func AndroidAppFactory() android.Module { android.InitDefaultableModule(module) android.InitOverridableModule(module, &module.appProperties.Overrides) android.InitApexModule(module) + android.InitBazelModule(module) return module } @@ -1405,23 +1405,11 @@ type bazelAndroidAppCertificateAttributes struct { Certificate string } -func AndroidAppCertificateBp2Build(ctx android.TopDownMutatorContext) { - module, ok := ctx.Module().(*AndroidAppCertificate) - if !ok { - // Not an Android app certificate - return - } - if !module.ConvertWithBp2build(ctx) { - return - } - if ctx.ModuleType() != "android_app_certificate" { - return - } - - androidAppCertificateBp2BuildInternal(ctx, module) +func (m *AndroidAppCertificate) ConvertWithBp2build(ctx android.TopDownMutatorContext) { + androidAppCertificateBp2Build(ctx, m) } -func androidAppCertificateBp2BuildInternal(ctx android.TopDownMutatorContext, module *AndroidAppCertificate) { +func androidAppCertificateBp2Build(ctx android.TopDownMutatorContext, module *AndroidAppCertificate) { var certificate string if module.properties.Certificate != nil { certificate = *module.properties.Certificate @@ -1438,3 +1426,39 @@ func androidAppCertificateBp2BuildInternal(ctx android.TopDownMutatorContext, mo ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name()}, attrs) } + +type bazelAndroidAppAttributes struct { + Srcs bazel.LabelListAttribute + Manifest bazel.Label + Custom_package *string + Resource_files bazel.LabelListAttribute +} + +// ConvertWithBp2build is used to convert android_app to Bazel. +func (a *AndroidApp) ConvertWithBp2build(ctx android.TopDownMutatorContext) { + //TODO(b/209577426): Support multiple arch variants + srcs := bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrcExcludes(ctx, a.properties.Srcs, a.properties.Exclude_srcs)) + + manifest := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml") + + resourceFiles := bazel.LabelList{ + Includes: []bazel.Label{}, + } + for _, dir := range android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Resource_dirs, "res") { + files := android.RootToModuleRelativePaths(ctx, androidResourceGlob(ctx, dir)) + resourceFiles.Includes = append(resourceFiles.Includes, files...) + } + + attrs := &bazelAndroidAppAttributes{ + Srcs: srcs, + Manifest: android.BazelLabelForModuleSrcSingle(ctx, manifest), + // TODO(b/209576404): handle package name override by product variable PRODUCT_MANIFEST_PACKAGE_NAME_OVERRIDES + Custom_package: a.overridableAppProperties.Package_name, + Resource_files: bazel.MakeLabelListAttribute(resourceFiles), + } + props := bazel.BazelTargetModuleProperties{Rule_class: "android_binary", + Bzl_load_location: "@rules_android//rules:rules.bzl"} + + ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: a.Name()}, attrs) + +} diff --git a/java/app_test.go b/java/app_test.go index 0aae9280d..4da7c3dba 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -2873,3 +2873,76 @@ func TestExportedProguardFlagFiles(t *testing.T) { t.Errorf("App does not use library proguard config") } } + +func TestTargetSdkVersionManifestFixer(t *testing.T) { + platform_sdk_codename := "Tiramisu" + testCases := []struct { + name string + targetSdkVersionInBp string + targetSdkVersionExpected string + unbundledBuild bool + }{ + { + name: "Non-Unbundled build: Android.bp has targetSdkVersion", + targetSdkVersionInBp: "30", + targetSdkVersionExpected: "30", + unbundledBuild: false, + }, + { + name: "Unbundled build: Android.bp has targetSdkVersion", + targetSdkVersionInBp: "30", + targetSdkVersionExpected: "30", + unbundledBuild: true, + }, + { + name: "Non-Unbundled build: Android.bp has targetSdkVersion equal to platform_sdk_codename", + targetSdkVersionInBp: platform_sdk_codename, + targetSdkVersionExpected: platform_sdk_codename, + unbundledBuild: false, + }, + { + name: "Unbundled build: Android.bp has targetSdkVersion equal to platform_sdk_codename", + targetSdkVersionInBp: platform_sdk_codename, + targetSdkVersionExpected: "10000", + unbundledBuild: true, + }, + + { + name: "Non-Unbundled build: Android.bp has no targetSdkVersion", + targetSdkVersionExpected: platform_sdk_codename, + unbundledBuild: false, + }, + { + name: "Unbundled build: Android.bp has no targetSdkVersion", + targetSdkVersionExpected: "10000", + unbundledBuild: true, + }, + } + for _, testCase := range testCases { + bp := fmt.Sprintf(` + android_app { + name: "foo", + sdk_version: "current", + target_sdk_version: "%v", + } + `, testCase.targetSdkVersionInBp) + fixture := android.GroupFixturePreparers( + prepareForJavaTest, + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + // explicitly set platform_sdk_codename to make the test deterministic + variables.Platform_sdk_codename = &platform_sdk_codename + variables.Platform_version_active_codenames = []string{platform_sdk_codename} + // create a non-empty list if unbundledBuild==true + if testCase.unbundledBuild { + variables.Unbundled_build_apps = []string{"apex_a", "apex_b"} + } + }), + ) + + result := fixture.RunTestWithBp(t, bp) + foo := result.ModuleForTests("foo", "android_common") + + manifestFixerArgs := foo.Output("manifest_fixer/AndroidManifest.xml").Args + android.AssertStringEquals(t, testCase.name, testCase.targetSdkVersionExpected, manifestFixerArgs["targetSdkVersion"]) + } +} diff --git a/java/base.go b/java/base.go index d9b126059..c45ef641e 100644 --- a/java/base.go +++ b/java/base.go @@ -197,6 +197,10 @@ type DeviceProperties struct { // Defaults to sdk_version if not set. See sdk_version for possible values. Min_sdk_version *string + // if not blank, set the maximum version of the sdk that the compiled artifacts will run against. + // Defaults to empty string "". See sdk_version for possible values. + Max_sdk_version *string + // if not blank, set the targetSdkVersion in the AndroidManifest.xml. // Defaults to sdk_version if not set. See sdk_version for possible values. Target_sdk_version *string @@ -368,6 +372,7 @@ type Module struct { android.DefaultableModuleBase android.ApexModuleBase android.SdkBase + android.BazelModuleBase // Functionality common to Module and Import. embeddableInModuleAndImport @@ -460,6 +465,7 @@ type Module struct { sdkVersion android.SdkSpec minSdkVersion android.SdkSpec + maxSdkVersion android.SdkSpec } func (j *Module) CheckStableSdkVersion(ctx android.BaseModuleContext) error { @@ -617,6 +623,13 @@ func (j *Module) MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { return j.SdkVersion(ctx) } +func (j *Module) MaxSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { + maxSdkVersion := proptools.StringDefault(j.deviceProperties.Max_sdk_version, "") + // SdkSpecFrom returns SdkSpecPrivate for this, which may be confusing. + // TODO(b/208456999): ideally MaxSdkVersion should be an ApiLevel and not SdkSpec. + return android.SdkSpecFrom(ctx, maxSdkVersion) +} + func (j *Module) MinSdkVersionString() string { return j.minSdkVersion.Raw } @@ -1631,8 +1644,7 @@ func (j *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Modu } // Implements android.ApexModule -func (j *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, - sdkVersion android.ApiLevel) error { +func (j *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion android.ApiLevel) error { sdkSpec := j.MinSdkVersion(ctx) if !sdkSpec.Specified() { return fmt.Errorf("min_sdk_version is not specified") @@ -1941,3 +1953,17 @@ type ModuleWithStem interface { } var _ ModuleWithStem = (*Module)(nil) + +func (j *Module) ConvertWithBp2build(ctx android.TopDownMutatorContext) { + switch ctx.ModuleType() { + case "java_library", "java_library_host": + if lib, ok := ctx.Module().(*Library); ok { + javaLibraryBp2Build(ctx, lib) + } + case "java_binary_host": + if binary, ok := ctx.Module().(*Binary); ok { + javaBinaryHostBp2Build(ctx, binary) + } + } + +} diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go index bfa683824..bfe895c17 100644 --- a/java/bootclasspath_fragment.go +++ b/java/bootclasspath_fragment.go @@ -390,6 +390,13 @@ type BootclasspathFragmentApexContentInfo struct { // Map from the base module name (without prebuilt_ prefix) of a fragment's contents module to the // hidden API encoded dex jar path. contentModuleDexJarPaths bootDexJarByModule + + // Path to the image profile file on host (or empty, if profile is not generated). + profilePathOnHost android.Path + + // Install path of the boot image profile if it needs to be installed in the APEX, or empty if not + // needed. + profileInstallPathInApex string } func (i BootclasspathFragmentApexContentInfo) Modules() android.ConfiguredJarList { @@ -418,6 +425,14 @@ func (i BootclasspathFragmentApexContentInfo) DexBootJarPathForContentModule(mod } } +func (i BootclasspathFragmentApexContentInfo) ProfilePathOnHost() android.Path { + return i.profilePathOnHost +} + +func (i BootclasspathFragmentApexContentInfo) ProfileInstallPathInApex() string { + return i.profileInstallPathInApex +} + func (b *BootclasspathFragmentModule) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool { tag := ctx.OtherModuleDependencyTag(dep) if IsBootclasspathFragmentContentDepTag(tag) { @@ -579,6 +594,11 @@ func (b *BootclasspathFragmentModule) provideApexContentInfo(ctx android.ModuleC if imageConfig != nil { info.modules = imageConfig.modules + global := dexpreopt.GetGlobalConfig(ctx) + if !global.DisableGenerateProfile { + info.profilePathOnHost = imageConfig.profilePathOnHost + info.profileInstallPathInApex = imageConfig.profileInstallPathInApex + } } info.bootImageFilesByArch = bootImageFilesByArch diff --git a/java/classpath_fragment.go b/java/classpath_fragment.go index f63d81d6e..e77971b13 100644 --- a/java/classpath_fragment.go +++ b/java/classpath_fragment.go @@ -25,7 +25,7 @@ import ( "android/soong/android" ) -// Build rules and utilities to generate individual packages/modules/SdkExtensions/proto/classpaths.proto +// Build rules and utilities to generate individual packages/modules/common/proto/classpaths.proto // config files based on build configuration to embed into /system and /apex on a device. // // See `derive_classpath` service that reads the configs at runtime and defines *CLASSPATH variables @@ -34,14 +34,15 @@ import ( type classpathType int const ( - // Matches definition in packages/modules/SdkExtensions/proto/classpaths.proto + // Matches definition in packages/modules/common/proto/classpaths.proto BOOTCLASSPATH classpathType = iota DEX2OATBOOTCLASSPATH SYSTEMSERVERCLASSPATH + STANDALONE_SYSTEMSERVER_JARS ) func (c classpathType) String() string { - return [...]string{"BOOTCLASSPATH", "DEX2OATBOOTCLASSPATH", "SYSTEMSERVERCLASSPATH"}[c] + return [...]string{"BOOTCLASSPATH", "DEX2OATBOOTCLASSPATH", "SYSTEMSERVERCLASSPATH", "STANDALONE_SYSTEMSERVER_JARS"}[c] } type classpathFragmentProperties struct { @@ -84,11 +85,10 @@ func initClasspathFragment(c classpathFragment, classpathType classpathType) { // Matches definition of Jar in packages/modules/SdkExtensions/proto/classpaths.proto type classpathJar struct { - path string - classpath classpathType - // TODO(satayev): propagate min/max sdk versions for the jars - minSdkVersion int32 - maxSdkVersion int32 + path string + classpath classpathType + minSdkVersion string + maxSdkVersion string } // gatherPossibleApexModuleNamesAndStems returns a set of module and stem names from the @@ -120,10 +120,32 @@ func configuredJarListToClasspathJars(ctx android.ModuleContext, configuredJars jars := make([]classpathJar, 0, len(paths)*len(classpaths)) for i := 0; i < len(paths); i++ { for _, classpathType := range classpaths { - jars = append(jars, classpathJar{ + jar := classpathJar{ classpath: classpathType, path: paths[i], + } + ctx.VisitDirectDepsIf(func(m android.Module) bool { + return m.Name() == configuredJars.Jar(i) + }, func(m android.Module) { + if s, ok := m.(*SdkLibrary); ok { + // TODO(208456999): instead of mapping "current" to latest, min_sdk_version should never be set to "current" + if s.minSdkVersion.Specified() { + if s.minSdkVersion.ApiLevel.IsCurrent() { + jar.minSdkVersion = ctx.Config().LatestPreviewApiLevel().String() + } else { + jar.minSdkVersion = s.minSdkVersion.ApiLevel.String() + } + } + if s.maxSdkVersion.Specified() { + if s.maxSdkVersion.ApiLevel.IsCurrent() { + jar.maxSdkVersion = ctx.Config().LatestPreviewApiLevel().String() + } else { + jar.maxSdkVersion = s.maxSdkVersion.ApiLevel.String() + } + } + } }) + jars = append(jars, jar) } } return jars @@ -136,15 +158,15 @@ func (c *ClasspathFragmentBase) generateClasspathProtoBuildActions(ctx android.M c.outputFilepath = android.PathForModuleOut(ctx, outputFilename).OutputPath c.installDirPath = android.PathForModuleInstall(ctx, "etc", "classpaths") - generatedJson := android.PathForModuleOut(ctx, outputFilename+".json") - writeClasspathsJson(ctx, generatedJson, jars) + generatedTextproto := android.PathForModuleOut(ctx, outputFilename+".textproto") + writeClasspathsTextproto(ctx, generatedTextproto, jars) rule := android.NewRuleBuilder(pctx, ctx) rule.Command(). BuiltTool("conv_classpaths_proto"). Flag("encode"). - Flag("--format=json"). - FlagWithInput("--input=", generatedJson). + Flag("--format=textproto"). + FlagWithInput("--input=", generatedTextproto). FlagWithOutput("--output=", c.outputFilepath) rule.Build("classpath_fragment", "Compiling "+c.outputFilepath.String()) @@ -159,24 +181,18 @@ func (c *ClasspathFragmentBase) generateClasspathProtoBuildActions(ctx android.M ctx.SetProvider(ClasspathFragmentProtoContentInfoProvider, classpathProtoInfo) } -func writeClasspathsJson(ctx android.ModuleContext, output android.WritablePath, jars []classpathJar) { +func writeClasspathsTextproto(ctx android.ModuleContext, output android.WritablePath, jars []classpathJar) { var content strings.Builder - fmt.Fprintf(&content, "{\n") - fmt.Fprintf(&content, "\"jars\": [\n") - for idx, jar := range jars { - fmt.Fprintf(&content, "{\n") - fmt.Fprintf(&content, "\"path\": \"%s\",\n", jar.path) - fmt.Fprintf(&content, "\"classpath\": \"%s\"\n", jar.classpath) - - if idx < len(jars)-1 { - fmt.Fprintf(&content, "},\n") - } else { - fmt.Fprintf(&content, "}\n") - } + for _, jar := range jars { + fmt.Fprintf(&content, "jars {\n") + fmt.Fprintf(&content, "path: \"%s\"\n", jar.path) + fmt.Fprintf(&content, "classpath: %s\n", jar.classpath) + fmt.Fprintf(&content, "min_sdk_version: \"%s\"\n", jar.minSdkVersion) + fmt.Fprintf(&content, "max_sdk_version: \"%s\"\n", jar.maxSdkVersion) + fmt.Fprintf(&content, "}\n") } - fmt.Fprintf(&content, "]\n") - fmt.Fprintf(&content, "}\n") + android.WriteFileRule(ctx, output, content.String()) } diff --git a/java/dexpreopt.go b/java/dexpreopt.go index 7c081b6e5..f3a53eed9 100644 --- a/java/dexpreopt.go +++ b/java/dexpreopt.go @@ -122,29 +122,33 @@ func moduleName(ctx android.BaseModuleContext) string { } func (d *dexpreopter) dexpreoptDisabled(ctx android.BaseModuleContext) bool { - global := dexpreopt.GetGlobalConfig(ctx) + if !ctx.Device() { + return true + } - if global.DisablePreopt { + if d.isTest { return true } - if inList(moduleName(ctx), global.DisablePreoptModules) { + if !BoolDefault(d.dexpreoptProperties.Dex_preopt.Enabled, true) { return true } - if d.isTest { + if !ctx.Module().(DexpreopterInterface).IsInstallable() { return true } - if !BoolDefault(d.dexpreoptProperties.Dex_preopt.Enabled, true) { + if !android.IsModulePreferred(ctx.Module()) { return true } - if !ctx.Module().(DexpreopterInterface).IsInstallable() { + global := dexpreopt.GetGlobalConfig(ctx) + + if global.DisablePreopt { return true } - if ctx.Host() { + if inList(moduleName(ctx), global.DisablePreoptModules) { return true } @@ -161,10 +165,6 @@ func (d *dexpreopter) dexpreoptDisabled(ctx android.BaseModuleContext) bool { } } - if !android.IsModulePreferred(ctx.Module()) { - return true - } - // TODO: contains no java code return false diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go index 284a19a1f..75083e8c2 100644 --- a/java/dexpreopt_bootjars.go +++ b/java/dexpreopt_bootjars.go @@ -256,6 +256,10 @@ type bootImageConfig struct { // Subdirectory where the image files on device are installed. installDirOnDevice string + // Install path of the boot image profile if it needs to be installed in the APEX, or empty if not + // needed. + profileInstallPathInApex string + // A list of (location, jar) pairs for the Java modules in this image. modules android.ConfiguredJarList @@ -272,6 +276,9 @@ type bootImageConfig struct { // Rules which should be used in make to install the outputs. profileInstalls android.RuleBuilderInstalls + // Path to the image profile file on host (or empty, if profile is not generated). + profilePathOnHost android.Path + // Target-dependent fields. variants []*bootImageVariant } @@ -625,7 +632,6 @@ func buildBootImageVariant(ctx android.ModuleContext, image *bootImageVariant, p Flag("--runtime-arg").FlagWithArg("-Xmx", global.Dex2oatImageXmx) if profile != nil { - cmd.FlagWithArg("--compiler-filter=", "speed-profile") cmd.FlagWithInput("--profile-file=", profile) } @@ -770,11 +776,14 @@ func bootImageProfileRule(ctx android.ModuleContext, image *bootImageConfig) and FlagForEachArg("--dex-location=", image.getAnyAndroidVariant().dexLocationsDeps). FlagWithOutput("--reference-profile-file=", profile) - rule.Install(profile, "/system/etc/boot-image.prof") + if image == defaultBootImageConfig(ctx) { + rule.Install(profile, "/system/etc/boot-image.prof") + image.profileInstalls = append(image.profileInstalls, rule.Installs()...) + } rule.Build("bootJarsProfile", "profile boot jars") - image.profileInstalls = append(image.profileInstalls, rule.Installs()...) + image.profilePathOnHost = profile return profile } diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go index 415a1d4e7..26c110544 100644 --- a/java/dexpreopt_config.go +++ b/java/dexpreopt_config.go @@ -56,22 +56,20 @@ func genBootImageConfigs(ctx android.PathContext) map[string]*bootImageConfig { artModules := global.ArtApexJars frameworkModules := global.BootJars.RemoveList(artModules) - artDirOnHost := "apex/art_boot_images/javalib" - artDirOnDevice := "apex/com.android.art/javalib" - frameworkSubdir := "system/framework" - // ART config for the primary boot image in the ART apex. // It includes the Core Libraries. artCfg := bootImageConfig{ - name: artBootImageName, - stem: "boot", - installDirOnHost: artDirOnHost, - installDirOnDevice: artDirOnDevice, - modules: artModules, + name: artBootImageName, + stem: "boot", + installDirOnHost: "apex/art_boot_images/javalib", + installDirOnDevice: "apex/com.android.art/javalib", + profileInstallPathInApex: "etc/boot-image.prof", + modules: artModules, } // Framework config for the boot image extension. // It includes framework libraries and depends on the ART config. + frameworkSubdir := "system/framework" frameworkCfg := bootImageConfig{ extends: &artCfg, name: frameworkBootImageName, diff --git a/java/java.go b/java/java.go index 2f9e03a80..f77c694ba 100644 --- a/java/java.go +++ b/java/java.go @@ -21,7 +21,9 @@ package java import ( "fmt" "path/filepath" + "strings" + "android/soong/bazel" "github.com/google/blueprint" "github.com/google/blueprint/proptools" @@ -270,6 +272,9 @@ func (j *Module) InstallBypassMake() bool { return true } type dependencyTag struct { blueprint.BaseDependencyTag name string + + // True if the dependency is relinked at runtime. + runtimeLinked bool } // installDependencyTag is a dependency tag that is annotated to cause the installed files of the @@ -280,6 +285,15 @@ type installDependencyTag struct { name string } +func (d dependencyTag) LicenseAnnotations() []android.LicenseAnnotation { + if d.runtimeLinked { + return []android.LicenseAnnotation{android.LicenseAnnotationSharedDependency} + } + return nil +} + +var _ android.LicenseAnnotationsDependencyTag = dependencyTag{} + type usesLibraryDependencyTag struct { dependencyTag @@ -296,10 +310,13 @@ type usesLibraryDependencyTag struct { func makeUsesLibraryDependencyTag(sdkVersion int, optional bool, implicit bool) usesLibraryDependencyTag { return usesLibraryDependencyTag{ - dependencyTag: dependencyTag{name: fmt.Sprintf("uses-library-%d", sdkVersion)}, - sdkVersion: sdkVersion, - optional: optional, - implicit: implicit, + dependencyTag: dependencyTag{ + name: fmt.Sprintf("uses-library-%d", sdkVersion), + runtimeLinked: true, + }, + sdkVersion: sdkVersion, + optional: optional, + implicit: implicit, } } @@ -310,22 +327,22 @@ func IsJniDepTag(depTag blueprint.DependencyTag) bool { var ( dataNativeBinsTag = dependencyTag{name: "dataNativeBins"} staticLibTag = dependencyTag{name: "staticlib"} - libTag = dependencyTag{name: "javalib"} - java9LibTag = dependencyTag{name: "java9lib"} + libTag = dependencyTag{name: "javalib", runtimeLinked: true} + java9LibTag = dependencyTag{name: "java9lib", runtimeLinked: true} pluginTag = dependencyTag{name: "plugin"} errorpronePluginTag = dependencyTag{name: "errorprone-plugin"} exportedPluginTag = dependencyTag{name: "exported-plugin"} - bootClasspathTag = dependencyTag{name: "bootclasspath"} - systemModulesTag = dependencyTag{name: "system modules"} + bootClasspathTag = dependencyTag{name: "bootclasspath", runtimeLinked: true} + systemModulesTag = dependencyTag{name: "system modules", runtimeLinked: true} frameworkResTag = dependencyTag{name: "framework-res"} - kotlinStdlibTag = dependencyTag{name: "kotlin-stdlib"} - kotlinAnnotationsTag = dependencyTag{name: "kotlin-annotations"} + kotlinStdlibTag = dependencyTag{name: "kotlin-stdlib", runtimeLinked: true} + kotlinAnnotationsTag = dependencyTag{name: "kotlin-annotations", runtimeLinked: true} kotlinPluginTag = dependencyTag{name: "kotlin-plugin"} proguardRaiseTag = dependencyTag{name: "proguard-raise"} certificateTag = dependencyTag{name: "certificate"} instrumentationForTag = dependencyTag{name: "instrumentation_for"} extraLintCheckTag = dependencyTag{name: "extra-lint-check"} - jniLibTag = dependencyTag{name: "jnilib"} + jniLibTag = dependencyTag{name: "jnilib", runtimeLinked: true} syspropPublicStubDepTag = dependencyTag{name: "sysprop public stub"} jniInstallTag = installDependencyTag{name: "jni install"} binaryInstallTag = installDependencyTag{name: "binary install"} @@ -434,6 +451,12 @@ func getJavaVersion(ctx android.ModuleContext, javaVersion string, sdkContext an return normalizeJavaVersion(ctx, javaVersion) } else if ctx.Device() { return defaultJavaLanguageVersion(ctx, sdkContext.SdkVersion(ctx)) + } else if ctx.Config().IsEnvTrue("EXPERIMENTAL_TARGET_JAVA_VERSION_11") { + // Temporary experimental flag to be able to try and build with + // java version 11 options. The flag, if used, just sets Java + // 11 as the default version, leaving any components that + // target an older version intact. + return JAVA_VERSION_11 } else { return JAVA_VERSION_9 } @@ -447,6 +470,7 @@ const ( JAVA_VERSION_7 = 7 JAVA_VERSION_8 = 8 JAVA_VERSION_9 = 9 + JAVA_VERSION_11 = 11 ) func (v javaVersion) String() string { @@ -459,6 +483,8 @@ func (v javaVersion) String() string { return "1.8" case JAVA_VERSION_9: return "1.9" + case JAVA_VERSION_11: + return "11" default: return "unsupported" } @@ -479,8 +505,10 @@ func normalizeJavaVersion(ctx android.BaseModuleContext, javaVersion string) jav return JAVA_VERSION_8 case "1.9", "9": return JAVA_VERSION_9 - case "10", "11": - ctx.PropertyErrorf("java_version", "Java language levels above 9 are not supported") + case "11": + return JAVA_VERSION_11 + case "10": + ctx.PropertyErrorf("java_version", "Java language levels 10 is not supported") return JAVA_VERSION_UNSUPPORTED default: ctx.PropertyErrorf("java_version", "Unrecognized Java language level") @@ -545,6 +573,7 @@ func setUncompressDex(ctx android.ModuleContext, dexpreopter *dexpreopter, dexer func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { j.sdkVersion = j.SdkVersion(ctx) j.minSdkVersion = j.MinSdkVersion(ctx) + j.maxSdkVersion = j.MaxSdkVersion(ctx) apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo) if !apexInfo.IsForPlatform() { @@ -729,6 +758,7 @@ func LibraryFactory() android.Module { android.InitApexModule(module) android.InitSdkAwareModule(module) + android.InitBazelModule(module) InitJavaModule(module, android.HostAndDeviceSupported) return module } @@ -751,6 +781,7 @@ func LibraryHostFactory() android.Module { android.InitApexModule(module) android.InitSdkAwareModule(module) + android.InitBazelModule(module) InitJavaModule(module, android.HostSupported) return module } @@ -1201,6 +1232,8 @@ func BinaryFactory() android.Module { android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommonFirst) android.InitDefaultableModule(module) + android.InitBazelModule(module) + return module } @@ -1218,6 +1251,7 @@ func BinaryHostFactory() android.Module { android.InitAndroidArchModule(module, android.HostSupported, android.MultilibCommonFirst) android.InitDefaultableModule(module) + android.InitBazelModule(module) return module } @@ -1934,3 +1968,103 @@ func addCLCFromDep(ctx android.ModuleContext, depModule android.Module, clcMap.AddContextMap(dep.ClassLoaderContexts(), depName) } } + +type javaLibraryAttributes struct { + Srcs bazel.LabelListAttribute + Deps bazel.LabelListAttribute + Javacopts bazel.StringListAttribute +} + +func javaLibraryBp2Build(ctx android.TopDownMutatorContext, m *Library) { + srcs := bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs)) + attrs := &javaLibraryAttributes{ + Srcs: srcs, + } + + if m.properties.Javacflags != nil { + attrs.Javacopts = bazel.MakeStringListAttribute(m.properties.Javacflags) + } + + if m.properties.Libs != nil { + attrs.Deps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, m.properties.Libs)) + } + + props := bazel.BazelTargetModuleProperties{ + Rule_class: "java_library", + Bzl_load_location: "//build/bazel/rules/java:library.bzl", + } + + ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs) +} + +type javaBinaryHostAttributes struct { + Srcs bazel.LabelListAttribute + Deps bazel.LabelListAttribute + Main_class string + Jvm_flags bazel.StringListAttribute +} + +// JavaBinaryHostBp2Build is for java_binary_host bp2build. +func javaBinaryHostBp2Build(ctx android.TopDownMutatorContext, m *Binary) { + mainClass := "" + if m.binaryProperties.Main_class != nil { + mainClass = *m.binaryProperties.Main_class + } + if m.properties.Manifest != nil { + mainClassInManifest, err := android.GetMainClassInManifest(ctx.Config(), android.PathForModuleSrc(ctx, *m.properties.Manifest).String()) + if err != nil { + return + } + mainClass = mainClassInManifest + } + srcs := bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs)) + attrs := &javaBinaryHostAttributes{ + Srcs: srcs, + Main_class: mainClass, + } + + // Attribute deps + deps := []string{} + if m.properties.Static_libs != nil { + deps = append(deps, m.properties.Static_libs...) + } + if m.binaryProperties.Jni_libs != nil { + deps = append(deps, m.binaryProperties.Jni_libs...) + } + if len(deps) > 0 { + attrs.Deps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, deps)) + } + + // Attribute jvm_flags + if m.binaryProperties.Jni_libs != nil { + jniLibPackages := map[string]bool{} + for _, jniLibLabel := range android.BazelLabelForModuleDeps(ctx, m.binaryProperties.Jni_libs).Includes { + jniLibPackage := jniLibLabel.Label + indexOfColon := strings.Index(jniLibLabel.Label, ":") + if indexOfColon > 0 { + // JNI lib from other package + jniLibPackage = jniLibLabel.Label[2:indexOfColon] + } else if indexOfColon == 0 { + // JNI lib in the same package of java_binary + packageOfCurrentModule := m.GetBazelLabel(ctx, m) + jniLibPackage = packageOfCurrentModule[2:strings.Index(packageOfCurrentModule, ":")] + } + if _, inMap := jniLibPackages[jniLibPackage]; !inMap { + jniLibPackages[jniLibPackage] = true + } + } + jniLibPaths := []string{} + for jniLibPackage, _ := range jniLibPackages { + // See cs/f:.*/third_party/bazel/.*java_stub_template.txt for the use of RUNPATH + jniLibPaths = append(jniLibPaths, "$${RUNPATH}"+jniLibPackage) + } + attrs.Jvm_flags = bazel.MakeStringListAttribute([]string{"-Djava.library.path=" + strings.Join(jniLibPaths, ":")}) + } + + props := bazel.BazelTargetModuleProperties{ + Rule_class: "java_binary", + } + + // Create the BazelTargetModule. + ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs) +} diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go index 9fec08a69..1e2723845 100644 --- a/java/platform_bootclasspath.go +++ b/java/platform_bootclasspath.go @@ -68,7 +68,6 @@ type platformBootclasspathProperties struct { func platformBootclasspathFactory() android.SingletonModule { m := &platformBootclasspathModule{} m.AddProperties(&m.properties) - // TODO(satayev): split apex jars into separate configs. initClasspathFragment(m, BOOTCLASSPATH) android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon) return m diff --git a/java/sdk.go b/java/sdk.go index e6bf220b4..de7070eef 100644 --- a/java/sdk.go +++ b/java/sdk.go @@ -55,6 +55,12 @@ func defaultJavaLanguageVersion(ctx android.EarlyModuleContext, s android.SdkSpe return JAVA_VERSION_7 } else if sdk.FinalOrFutureInt() <= 29 { return JAVA_VERSION_8 + } else if ctx.Config().IsEnvTrue("EXPERIMENTAL_TARGET_JAVA_VERSION_11") { + // Temporary experimental flag to be able to try and build with + // java version 11 options. The flag, if used, just sets Java + // 11 as the default version, leaving any components that + // target an older version intact. + return JAVA_VERSION_11 } else { return JAVA_VERSION_9 } diff --git a/java/sdk_library.go b/java/sdk_library.go index d7f14d659..de0d796cc 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -21,6 +21,7 @@ import ( "reflect" "regexp" "sort" + "strconv" "strings" "sync" @@ -32,25 +33,7 @@ import ( ) const ( - sdkXmlFileSuffix = ".xml" - permissionsTemplate = `<?xml version=\"1.0\" encoding=\"utf-8\"?>\n` + - `<!-- Copyright (C) 2018 The Android Open Source Project\n` + - `\n` + - ` Licensed under the Apache License, Version 2.0 (the \"License\");\n` + - ` you may not use this file except in compliance with the License.\n` + - ` You may obtain a copy of the License at\n` + - `\n` + - ` http://www.apache.org/licenses/LICENSE-2.0\n` + - `\n` + - ` Unless required by applicable law or agreed to in writing, software\n` + - ` distributed under the License is distributed on an \"AS IS\" BASIS,\n` + - ` WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n` + - ` See the License for the specific language governing permissions and\n` + - ` limitations under the License.\n` + - `-->\n` + - `<permissions>\n` + - ` <library name=\"%s\" file=\"%s\"/>\n` + - `</permissions>\n` + sdkXmlFileSuffix = ".xml" ) // A tag to associated a dependency with a specific api scope. @@ -637,6 +620,33 @@ type commonToSdkLibraryAndImportProperties struct { // Files containing information about supported java doc tags. Doctag_files []string `android:"path"` + + // Signals that this shared library is part of the bootclasspath starting + // on the version indicated in this attribute. + // + // This will make platforms at this level and above to ignore + // <uses-library> tags with this library name because the library is already + // available + On_bootclasspath_since *string + + // Signals that this shared library was part of the bootclasspath before + // (but not including) the version indicated in this attribute. + // + // The system will automatically add a <uses-library> tag with this library to + // apps that target any SDK less than the version indicated in this attribute. + On_bootclasspath_before *string + + // Indicates that PackageManager should ignore this shared library if the + // platform is below the version indicated in this attribute. + // + // This means that the device won't recognise this library as installed. + Min_device_sdk *string + + // Indicates that PackageManager should ignore this shared library if the + // platform is above the version indicated in this attribute. + // + // This means that the device won't recognise this library as installed. + Max_device_sdk *string } // commonSdkLibraryAndImportModule defines the interface that must be provided by a module that @@ -1119,6 +1129,22 @@ func (module *SdkLibrary) getGeneratedApiScopes(ctx android.EarlyModuleContext) return generatedScopes } +var _ android.ModuleWithMinSdkVersionCheck = (*SdkLibrary)(nil) + +func (module *SdkLibrary) CheckMinSdkVersion(ctx android.ModuleContext) { + android.CheckMinSdkVersion(ctx, module.MinSdkVersion(ctx).ApiLevel, func(c android.ModuleContext, do android.PayloadDepsCallback) { + ctx.WalkDeps(func(child android.Module, parent android.Module) bool { + isExternal := !module.depIsInSameApex(ctx, child) + if am, ok := child.(android.ApexModule); ok { + if !do(ctx, parent, am, isExternal) { + return false + } + } + return !isExternal + }) + }) +} + type sdkLibraryComponentTag struct { blueprint.BaseDependencyTag name string @@ -1196,14 +1222,23 @@ func (module *SdkLibrary) DepsMutator(ctx android.BottomUpMutatorContext) { func (module *SdkLibrary) OutputFiles(tag string) (android.Paths, error) { paths, err := module.commonOutputFiles(tag) - if paths == nil && err == nil { - return module.Library.OutputFiles(tag) - } else { + if paths != nil || err != nil { return paths, err } + if module.requiresRuntimeImplementationLibrary() { + return module.Library.OutputFiles(tag) + } + if tag == "" { + return nil, nil + } + return nil, fmt.Errorf("unsupported module reference tag %q", tag) } func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { + if proptools.String(module.deviceProperties.Min_sdk_version) != "" { + module.CheckMinSdkVersion(ctx) + } + module.generateCommonBuildActions(ctx) // Only build an implementation library if required. @@ -1580,14 +1615,29 @@ func (module *SdkLibrary) UniqueApexVariations() bool { // Creates the xml file that publicizes the runtime library func (module *SdkLibrary) createXmlFile(mctx android.DefaultableHookContext) { + moduleMinApiLevel := module.Library.MinSdkVersion(mctx).ApiLevel + var moduleMinApiLevelStr = moduleMinApiLevel.String() + if moduleMinApiLevel == android.NoneApiLevel { + moduleMinApiLevelStr = "current" + } props := struct { - Name *string - Lib_name *string - Apex_available []string + Name *string + Lib_name *string + Apex_available []string + On_bootclasspath_since *string + On_bootclasspath_before *string + Min_device_sdk *string + Max_device_sdk *string + Sdk_library_min_api_level *string }{ - Name: proptools.StringPtr(module.xmlPermissionsModuleName()), - Lib_name: proptools.StringPtr(module.BaseModuleName()), - Apex_available: module.ApexProperties.Apex_available, + Name: proptools.StringPtr(module.xmlPermissionsModuleName()), + Lib_name: proptools.StringPtr(module.BaseModuleName()), + Apex_available: module.ApexProperties.Apex_available, + On_bootclasspath_since: module.commonSdkLibraryProperties.On_bootclasspath_since, + On_bootclasspath_before: module.commonSdkLibraryProperties.On_bootclasspath_before, + Min_device_sdk: module.commonSdkLibraryProperties.Min_device_sdk, + Max_device_sdk: module.commonSdkLibraryProperties.Max_device_sdk, + Sdk_library_min_api_level: &moduleMinApiLevelStr, } mctx.CreateModule(sdkLibraryXmlFactory, &props) @@ -2383,6 +2433,38 @@ type sdkLibraryXml struct { type sdkLibraryXmlProperties struct { // canonical name of the lib Lib_name *string + + // Signals that this shared library is part of the bootclasspath starting + // on the version indicated in this attribute. + // + // This will make platforms at this level and above to ignore + // <uses-library> tags with this library name because the library is already + // available + On_bootclasspath_since *string + + // Signals that this shared library was part of the bootclasspath before + // (but not including) the version indicated in this attribute. + // + // The system will automatically add a <uses-library> tag with this library to + // apps that target any SDK less than the version indicated in this attribute. + On_bootclasspath_before *string + + // Indicates that PackageManager should ignore this shared library if the + // platform is below the version indicated in this attribute. + // + // This means that the device won't recognise this library as installed. + Min_device_sdk *string + + // Indicates that PackageManager should ignore this shared library if the + // platform is above the version indicated in this attribute. + // + // This means that the device won't recognise this library as installed. + Max_device_sdk *string + + // The SdkLibrary's min api level as a string + // + // This value comes from the ApiLevel of the MinSdkVersion property. + Sdk_library_min_api_level *string } // java_sdk_library_xml builds the permission xml file for a java_sdk_library. @@ -2459,11 +2541,81 @@ func (module *sdkLibraryXml) implPath(ctx android.ModuleContext) string { return "/" + partition + "/framework/" + implName + ".jar" } +func formattedOptionalSdkLevelAttribute(ctx android.ModuleContext, attrName string, value *string) string { + if value == nil { + return "" + } + apiLevel, err := android.ApiLevelFromUser(ctx, *value) + if err != nil { + // attributes in bp files have underscores but in the xml have dashes. + ctx.PropertyErrorf(strings.ReplaceAll(attrName, "-", "_"), err.Error()) + return "" + } + intStr := strconv.Itoa(apiLevel.FinalOrPreviewInt()) + return formattedOptionalAttribute(attrName, &intStr) +} + +// formats an attribute for the xml permissions file if the value is not null +// returns empty string otherwise +func formattedOptionalAttribute(attrName string, value *string) string { + if value == nil { + return "" + } + return fmt.Sprintf(` %s=\"%s\"\n`, attrName, *value) +} + +func (module *sdkLibraryXml) permissionsContents(ctx android.ModuleContext) string { + libName := proptools.String(module.properties.Lib_name) + libNameAttr := formattedOptionalAttribute("name", &libName) + filePath := module.implPath(ctx) + filePathAttr := formattedOptionalAttribute("file", &filePath) + implicitFromAttr := formattedOptionalSdkLevelAttribute(ctx, "on-bootclasspath-since", module.properties.On_bootclasspath_since) + implicitUntilAttr := formattedOptionalSdkLevelAttribute(ctx, "on-bootclasspath-before", module.properties.On_bootclasspath_before) + minSdkAttr := formattedOptionalSdkLevelAttribute(ctx, "min-device-sdk", module.properties.Min_device_sdk) + maxSdkAttr := formattedOptionalSdkLevelAttribute(ctx, "max-device-sdk", module.properties.Max_device_sdk) + // <library> is understood in all android versions whereas <updatable-library> is only understood from API T (and ignored before that). + // similarly, min_device_sdk is only understood from T. So if a library is using that, we need to use the updatable-library to make sure this library is not loaded before T + var libraryTag string + if module.properties.Min_device_sdk != nil { + libraryTag = ` <updatable-library\n` + } else { + libraryTag = ` <library\n` + } + + return strings.Join([]string{ + `<?xml version=\"1.0\" encoding=\"utf-8\"?>\n`, + `<!-- Copyright (C) 2018 The Android Open Source Project\n`, + `\n`, + ` Licensed under the Apache License, Version 2.0 (the \"License\");\n`, + ` you may not use this file except in compliance with the License.\n`, + ` You may obtain a copy of the License at\n`, + `\n`, + ` http://www.apache.org/licenses/LICENSE-2.0\n`, + `\n`, + ` Unless required by applicable law or agreed to in writing, software\n`, + ` distributed under the License is distributed on an \"AS IS\" BASIS,\n`, + ` WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n`, + ` See the License for the specific language governing permissions and\n`, + ` limitations under the License.\n`, + `-->\n`, + `<permissions>\n`, + libraryTag, + libNameAttr, + filePathAttr, + implicitFromAttr, + implicitUntilAttr, + minSdkAttr, + maxSdkAttr, + ` />\n`, + `</permissions>\n`}, "") +} + func (module *sdkLibraryXml) GenerateAndroidBuildActions(ctx android.ModuleContext) { module.hideApexVariantFromMake = !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform() libName := proptools.String(module.properties.Lib_name) - xmlContent := fmt.Sprintf(permissionsTemplate, libName, module.implPath(ctx)) + module.selfValidate(ctx) + xmlContent := module.permissionsContents(ctx) module.outputFilePath = android.PathForModuleOut(ctx, libName+".xml").OutputPath rule := android.NewRuleBuilder(pctx, ctx) @@ -2478,12 +2630,12 @@ func (module *sdkLibraryXml) GenerateAndroidBuildActions(ctx android.ModuleConte func (module *sdkLibraryXml) AndroidMkEntries() []android.AndroidMkEntries { if module.hideApexVariantFromMake { - return []android.AndroidMkEntries{android.AndroidMkEntries{ + return []android.AndroidMkEntries{{ Disabled: true, }} } - return []android.AndroidMkEntries{android.AndroidMkEntries{ + return []android.AndroidMkEntries{{ Class: "ETC", OutputFile: android.OptionalPathForPath(module.outputFilePath), ExtraEntries: []android.AndroidMkExtraEntriesFunc{ @@ -2496,6 +2648,81 @@ func (module *sdkLibraryXml) AndroidMkEntries() []android.AndroidMkEntries { }} } +func (module *sdkLibraryXml) selfValidate(ctx android.ModuleContext) { + module.validateAtLeastTAttributes(ctx) + module.validateMinAndMaxDeviceSdk(ctx) + module.validateMinMaxDeviceSdkAndModuleMinSdk(ctx) + module.validateOnBootclasspathBeforeRequirements(ctx) +} + +func (module *sdkLibraryXml) validateAtLeastTAttributes(ctx android.ModuleContext) { + t := android.ApiLevelOrPanic(ctx, "Tiramisu") + module.attrAtLeastT(ctx, t, module.properties.Min_device_sdk, "min_device_sdk") + module.attrAtLeastT(ctx, t, module.properties.Max_device_sdk, "max_device_sdk") + module.attrAtLeastT(ctx, t, module.properties.On_bootclasspath_before, "on_bootclasspath_before") + module.attrAtLeastT(ctx, t, module.properties.On_bootclasspath_since, "on_bootclasspath_since") +} + +func (module *sdkLibraryXml) attrAtLeastT(ctx android.ModuleContext, t android.ApiLevel, attr *string, attrName string) { + if attr != nil { + if level, err := android.ApiLevelFromUser(ctx, *attr); err == nil { + // we will inform the user of invalid inputs when we try to write the + // permissions xml file so we don't need to do it here + if t.GreaterThan(level) { + ctx.PropertyErrorf(attrName, "Attribute value needs to be at least T") + } + } + } +} + +func (module *sdkLibraryXml) validateMinAndMaxDeviceSdk(ctx android.ModuleContext) { + if module.properties.Min_device_sdk != nil && module.properties.Max_device_sdk != nil { + min, minErr := android.ApiLevelFromUser(ctx, *module.properties.Min_device_sdk) + max, maxErr := android.ApiLevelFromUser(ctx, *module.properties.Max_device_sdk) + if minErr == nil && maxErr == nil { + // we will inform the user of invalid inputs when we try to write the + // permissions xml file so we don't need to do it here + if min.GreaterThan(max) { + ctx.ModuleErrorf("min_device_sdk can't be greater than max_device_sdk") + } + } + } +} + +func (module *sdkLibraryXml) validateMinMaxDeviceSdkAndModuleMinSdk(ctx android.ModuleContext) { + moduleMinApi := android.ApiLevelOrPanic(ctx, *module.properties.Sdk_library_min_api_level) + if module.properties.Min_device_sdk != nil { + api, err := android.ApiLevelFromUser(ctx, *module.properties.Min_device_sdk) + if err == nil { + if moduleMinApi.GreaterThan(api) { + ctx.PropertyErrorf("min_device_sdk", "Can't be less than module's min sdk (%s)", moduleMinApi) + } + } + } + if module.properties.Max_device_sdk != nil { + api, err := android.ApiLevelFromUser(ctx, *module.properties.Max_device_sdk) + if err == nil { + if moduleMinApi.GreaterThan(api) { + ctx.PropertyErrorf("max_device_sdk", "Can't be less than module's min sdk (%s)", moduleMinApi) + } + } + } +} + +func (module *sdkLibraryXml) validateOnBootclasspathBeforeRequirements(ctx android.ModuleContext) { + moduleMinApi := android.ApiLevelOrPanic(ctx, *module.properties.Sdk_library_min_api_level) + if module.properties.On_bootclasspath_before != nil { + t := android.ApiLevelOrPanic(ctx, "Tiramisu") + // if we use the attribute, then we need to do this validation + if moduleMinApi.LessThan(t) { + // if minAPi is < T, then we need to have min_device_sdk (which only accepts T+) + if module.properties.Min_device_sdk == nil { + ctx.PropertyErrorf("on_bootclasspath_before", "Using this property requires that the module's min_sdk_version or the shared library's min_device_sdk is at least T") + } + } + } +} + type sdkLibrarySdkMemberType struct { android.SdkMemberTypeBase } @@ -2547,6 +2774,33 @@ type sdkLibrarySdkMemberProperties struct { Doctag_paths android.Paths Permitted_packages []string + + // Signals that this shared library is part of the bootclasspath starting + // on the version indicated in this attribute. + // + // This will make platforms at this level and above to ignore + // <uses-library> tags with this library name because the library is already + // available + On_bootclasspath_since *string + + // Signals that this shared library was part of the bootclasspath before + // (but not including) the version indicated in this attribute. + // + // The system will automatically add a <uses-library> tag with this library to + // apps that target any SDK less than the version indicated in this attribute. + On_bootclasspath_before *string + + // Indicates that PackageManager should ignore this shared library if the + // platform is below the version indicated in this attribute. + // + // This means that the device won't recognise this library as installed. + Min_device_sdk *string + + // Indicates that PackageManager should ignore this shared library if the + // platform is above the version indicated in this attribute. + // + // This means that the device won't recognise this library as installed. + Max_device_sdk *string } type scopeProperties struct { @@ -2593,6 +2847,10 @@ func (s *sdkLibrarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMembe s.Compile_dex = sdk.dexProperties.Compile_dex s.Doctag_paths = sdk.doctagPaths s.Permitted_packages = sdk.PermittedPackagesForUpdatableBootJars() + s.On_bootclasspath_since = sdk.commonSdkLibraryProperties.On_bootclasspath_since + s.On_bootclasspath_before = sdk.commonSdkLibraryProperties.On_bootclasspath_before + s.Min_device_sdk = sdk.commonSdkLibraryProperties.Min_device_sdk + s.Max_device_sdk = sdk.commonSdkLibraryProperties.Max_device_sdk } func (s *sdkLibrarySdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) { diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go index be23536ea..f3a19e956 100644 --- a/java/sdk_library_test.go +++ b/java/sdk_library_test.go @@ -15,12 +15,13 @@ package java import ( - "android/soong/android" "fmt" "path/filepath" "regexp" "testing" + "android/soong/android" + "github.com/google/blueprint/proptools" ) @@ -107,7 +108,7 @@ func TestJavaSdkLibrary(t *testing.T) { libs: ["foo"], sdk_version: "module_30", } - `) + `) // check the existence of the internal modules foo := result.ModuleForTests("foo", "android_common") @@ -162,6 +163,185 @@ func TestJavaSdkLibrary(t *testing.T) { } } +func TestJavaSdkLibrary_UpdatableLibrary(t *testing.T) { + result := android.GroupFixturePreparers( + prepareForJavaTest, + PrepareForTestWithJavaSdkLibraryFiles, + FixtureWithPrebuiltApis(map[string][]string{ + "28": {"foo"}, + "29": {"foo"}, + "30": {"foo", "fooUpdatable", "fooUpdatableErr"}, + }), + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.Platform_version_active_codenames = []string{"Tiramisu", "U", "V", "W"} + }), + ).RunTestWithBp(t, + ` + java_sdk_library { + name: "fooUpdatable", + srcs: ["a.java", "b.java"], + api_packages: ["foo"], + on_bootclasspath_since: "U", + on_bootclasspath_before: "V", + min_device_sdk: "W", + max_device_sdk: "current", + min_sdk_version: "S", + } + java_sdk_library { + name: "foo", + srcs: ["a.java", "b.java"], + api_packages: ["foo"], + } +`) + // test that updatability attributes are passed on correctly + fooUpdatable := result.ModuleForTests("fooUpdatable.xml", "android_common").Rule("java_sdk_xml") + android.AssertStringDoesContain(t, "fooUpdatable.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `on-bootclasspath-since=\"9001\"`) + android.AssertStringDoesContain(t, "fooUpdatable.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `on-bootclasspath-before=\"9002\"`) + android.AssertStringDoesContain(t, "fooUpdatable.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `min-device-sdk=\"9003\"`) + android.AssertStringDoesContain(t, "fooUpdatable.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `max-device-sdk=\"10000\"`) + + // double check that updatability attributes are not written if they don't exist in the bp file + // the permissions file for the foo library defined above + fooPermissions := result.ModuleForTests("foo.xml", "android_common").Rule("java_sdk_xml") + android.AssertStringDoesNotContain(t, "foo.xml java_sdk_xml command", fooPermissions.RuleParams.Command, `on-bootclasspath-since`) + android.AssertStringDoesNotContain(t, "foo.xml java_sdk_xml command", fooPermissions.RuleParams.Command, `on-bootclasspath-before`) + android.AssertStringDoesNotContain(t, "foo.xml java_sdk_xml command", fooPermissions.RuleParams.Command, `min-device-sdk`) + android.AssertStringDoesNotContain(t, "foo.xml java_sdk_xml command", fooPermissions.RuleParams.Command, `max-device-sdk`) +} + +func TestJavaSdkLibrary_UpdatableLibrary_Validation_ValidVersion(t *testing.T) { + android.GroupFixturePreparers( + prepareForJavaTest, + PrepareForTestWithJavaSdkLibraryFiles, + FixtureWithPrebuiltApis(map[string][]string{ + "30": {"fooUpdatable", "fooUpdatableErr"}, + }), + ).ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern( + []string{ + `on_bootclasspath_since: "aaa" could not be parsed as an integer and is not a recognized codename`, + `on_bootclasspath_before: "bbc" could not be parsed as an integer and is not a recognized codename`, + `min_device_sdk: "ccc" could not be parsed as an integer and is not a recognized codename`, + `max_device_sdk: "ddd" could not be parsed as an integer and is not a recognized codename`, + })).RunTestWithBp(t, + ` + java_sdk_library { + name: "fooUpdatableErr", + srcs: ["a.java", "b.java"], + api_packages: ["foo"], + on_bootclasspath_since: "aaa", + on_bootclasspath_before: "bbc", + min_device_sdk: "ccc", + max_device_sdk: "ddd", + } +`) +} + +func TestJavaSdkLibrary_UpdatableLibrary_Validation_AtLeastTAttributes(t *testing.T) { + android.GroupFixturePreparers( + prepareForJavaTest, + PrepareForTestWithJavaSdkLibraryFiles, + FixtureWithPrebuiltApis(map[string][]string{ + "28": {"foo"}, + }), + ).ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern( + []string{ + "on_bootclasspath_since: Attribute value needs to be at least T", + "on_bootclasspath_before: Attribute value needs to be at least T", + "min_device_sdk: Attribute value needs to be at least T", + "max_device_sdk: Attribute value needs to be at least T", + }, + )).RunTestWithBp(t, + ` + java_sdk_library { + name: "foo", + srcs: ["a.java", "b.java"], + api_packages: ["foo"], + on_bootclasspath_since: "S", + on_bootclasspath_before: "S", + min_device_sdk: "S", + max_device_sdk: "S", + min_sdk_version: "S", + } +`) +} + +func TestJavaSdkLibrary_UpdatableLibrary_Validation_MinAndMaxDeviceSdk(t *testing.T) { + android.GroupFixturePreparers( + prepareForJavaTest, + PrepareForTestWithJavaSdkLibraryFiles, + FixtureWithPrebuiltApis(map[string][]string{ + "28": {"foo"}, + }), + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.Platform_version_active_codenames = []string{"Tiramisu", "U", "V"} + }), + ).ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern( + []string{ + "min_device_sdk can't be greater than max_device_sdk", + }, + )).RunTestWithBp(t, + ` + java_sdk_library { + name: "foo", + srcs: ["a.java", "b.java"], + api_packages: ["foo"], + min_device_sdk: "V", + max_device_sdk: "U", + min_sdk_version: "S", + } +`) +} + +func TestJavaSdkLibrary_UpdatableLibrary_Validation_MinAndMaxDeviceSdkAndModuleMinSdk(t *testing.T) { + android.GroupFixturePreparers( + prepareForJavaTest, + PrepareForTestWithJavaSdkLibraryFiles, + FixtureWithPrebuiltApis(map[string][]string{ + "28": {"foo"}, + }), + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.Platform_version_active_codenames = []string{"Tiramisu", "U", "V"} + }), + ).ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern( + []string{ + regexp.QuoteMeta("min_device_sdk: Can't be less than module's min sdk (V)"), + regexp.QuoteMeta("max_device_sdk: Can't be less than module's min sdk (V)"), + }, + )).RunTestWithBp(t, + ` + java_sdk_library { + name: "foo", + srcs: ["a.java", "b.java"], + api_packages: ["foo"], + min_device_sdk: "U", + max_device_sdk: "U", + min_sdk_version: "V", + } +`) +} + +func TestJavaSdkLibrary_UpdatableLibrary_usesNewTag(t *testing.T) { + result := android.GroupFixturePreparers( + prepareForJavaTest, + PrepareForTestWithJavaSdkLibraryFiles, + FixtureWithPrebuiltApis(map[string][]string{ + "30": {"foo"}, + }), + ).RunTestWithBp(t, + ` + java_sdk_library { + name: "foo", + srcs: ["a.java", "b.java"], + min_device_sdk: "Tiramisu", + min_sdk_version: "S", + } +`) + // test that updatability attributes are passed on correctly + fooUpdatable := result.ModuleForTests("foo.xml", "android_common").Rule("java_sdk_xml") + android.AssertStringDoesContain(t, "foo.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `<updatable-library`) + android.AssertStringDoesNotContain(t, "foo.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `<library`) +} + func TestJavaSdkLibrary_StubOrImplOnlyLibs(t *testing.T) { result := android.GroupFixturePreparers( prepareForJavaTest, @@ -960,3 +1140,87 @@ func TestJavaSdkLibraryDist(t *testing.T) { }) } } + +func TestSdkLibrary_CheckMinSdkVersion(t *testing.T) { + preparer := android.GroupFixturePreparers( + PrepareForTestWithJavaBuildComponents, + PrepareForTestWithJavaDefaultModules, + PrepareForTestWithJavaSdkLibraryFiles, + ) + + preparer.RunTestWithBp(t, ` + java_sdk_library { + name: "sdklib", + srcs: ["a.java"], + static_libs: ["util"], + min_sdk_version: "30", + unsafe_ignore_missing_latest_api: true, + } + + java_library { + name: "util", + srcs: ["a.java"], + min_sdk_version: "30", + } + `) + + preparer. + RunTestWithBp(t, ` + java_sdk_library { + name: "sdklib", + srcs: ["a.java"], + libs: ["util"], + impl_only_libs: ["util"], + stub_only_libs: ["util"], + stub_only_static_libs: ["util"], + min_sdk_version: "30", + unsafe_ignore_missing_latest_api: true, + } + + java_library { + name: "util", + srcs: ["a.java"], + } + `) + + preparer.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "util".*should support min_sdk_version\(30\)`)). + RunTestWithBp(t, ` + java_sdk_library { + name: "sdklib", + srcs: ["a.java"], + static_libs: ["util"], + min_sdk_version: "30", + unsafe_ignore_missing_latest_api: true, + } + + java_library { + name: "util", + srcs: ["a.java"], + min_sdk_version: "31", + } + `) + + preparer.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "another_util".*should support min_sdk_version\(30\)`)). + RunTestWithBp(t, ` + java_sdk_library { + name: "sdklib", + srcs: ["a.java"], + static_libs: ["util"], + min_sdk_version: "30", + unsafe_ignore_missing_latest_api: true, + } + + java_library { + name: "util", + srcs: ["a.java"], + static_libs: ["another_util"], + min_sdk_version: "30", + } + + java_library { + name: "another_util", + srcs: ["a.java"], + min_sdk_version: "31", + } + `) +} diff --git a/java/systemserver_classpath_fragment.go b/java/systemserver_classpath_fragment.go index e263cc44c..2ec33a422 100644 --- a/java/systemserver_classpath_fragment.go +++ b/java/systemserver_classpath_fragment.go @@ -58,6 +58,10 @@ func (p *platformSystemServerClasspathModule) AndroidMkEntries() (entries []andr func (p *platformSystemServerClasspathModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { configuredJars := p.configuredJars(ctx) classpathJars := configuredJarListToClasspathJars(ctx, configuredJars, p.classpathType) + standaloneConfiguredJars := p.standaloneConfiguredJars(ctx) + standaloneClasspathJars := configuredJarListToClasspathJars(ctx, standaloneConfiguredJars, STANDALONE_SYSTEMSERVER_JARS) + configuredJars = configuredJars.AppendList(standaloneConfiguredJars) + classpathJars = append(classpathJars, standaloneClasspathJars...) p.classpathFragmentBase().generateClasspathProtoBuildActions(ctx, configuredJars, classpathJars) } @@ -66,6 +70,10 @@ func (p *platformSystemServerClasspathModule) configuredJars(ctx android.ModuleC return dexpreopt.GetGlobalConfig(ctx).SystemServerJars } +func (p *platformSystemServerClasspathModule) standaloneConfiguredJars(ctx android.ModuleContext) android.ConfiguredJarList { + return dexpreopt.GetGlobalConfig(ctx).StandaloneSystemServerJars +} + type SystemServerClasspathModule struct { android.ModuleBase android.ApexModuleBase @@ -84,10 +92,15 @@ func (s *SystemServerClasspathModule) ShouldSupportSdkVersion(ctx android.BaseMo } type systemServerClasspathFragmentProperties struct { - // The contents of this systemserverclasspath_fragment, could be either java_library, or java_sdk_library. + // List of system_server classpath jars, could be either java_library, or java_sdk_library. // // The order of this list matters as it is the order that is used in the SYSTEMSERVERCLASSPATH. Contents []string + + // List of jars that system_server loads dynamically using separate classloaders. + // + // The order does not matter. + Standalone_contents []string } func systemServerClasspathFactory() android.Module { @@ -101,12 +114,16 @@ func systemServerClasspathFactory() android.Module { } func (s *SystemServerClasspathModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { - if len(s.properties.Contents) == 0 { - ctx.PropertyErrorf("contents", "empty contents are not allowed") + if len(s.properties.Contents) == 0 && len(s.properties.Standalone_contents) == 0 { + ctx.PropertyErrorf("contents", "Either contents or standalone_contents needs to be non-empty") } configuredJars := s.configuredJars(ctx) classpathJars := configuredJarListToClasspathJars(ctx, configuredJars, s.classpathType) + standaloneConfiguredJars := s.standaloneConfiguredJars(ctx) + standaloneClasspathJars := configuredJarListToClasspathJars(ctx, standaloneConfiguredJars, STANDALONE_SYSTEMSERVER_JARS) + configuredJars = configuredJars.AppendList(standaloneConfiguredJars) + classpathJars = append(classpathJars, standaloneClasspathJars...) s.classpathFragmentBase().generateClasspathProtoBuildActions(ctx, configuredJars, classpathJars) // Collect the module directory for IDE info in java/jdeps.go. @@ -145,6 +162,17 @@ func (s *SystemServerClasspathModule) configuredJars(ctx android.ModuleContext) return jars } +func (s *SystemServerClasspathModule) standaloneConfiguredJars(ctx android.ModuleContext) android.ConfiguredJarList { + global := dexpreopt.GetGlobalConfig(ctx) + + possibleUpdatableModules := gatherPossibleApexModuleNamesAndStems(ctx, s.properties.Standalone_contents, systemServerClasspathFragmentContentDepTag) + jars, _ := global.ApexStandaloneSystemServerJars.Filter(possibleUpdatableModules) + + // TODO(jiakaiz): add a check to ensure that the contents are declared in make. + + return jars +} + type systemServerClasspathFragmentContentDependencyTag struct { blueprint.BaseDependencyTag } @@ -192,8 +220,11 @@ func IsSystemServerClasspathFragmentContentDepTag(tag blueprint.DependencyTag) b func (s *SystemServerClasspathModule) ComponentDepsMutator(ctx android.BottomUpMutatorContext) { module := ctx.Module() _, isSourceModule := module.(*SystemServerClasspathModule) + var deps []string + deps = append(deps, s.properties.Contents...) + deps = append(deps, s.properties.Standalone_contents...) - for _, name := range s.properties.Contents { + for _, name := range deps { // A systemserverclasspath_fragment must depend only on other source modules, while the // prebuilt_systemserverclasspath_fragment_fragment must only depend on other prebuilt modules. if !isSourceModule { @@ -206,6 +237,7 @@ func (s *SystemServerClasspathModule) ComponentDepsMutator(ctx android.BottomUpM // Collect information for opening IDE project files in java/jdeps.go. func (s *SystemServerClasspathModule) IDEInfo(dpInfo *android.IdeInfo) { dpInfo.Deps = append(dpInfo.Deps, s.properties.Contents...) + dpInfo.Deps = append(dpInfo.Deps, s.properties.Standalone_contents...) dpInfo.Paths = append(dpInfo.Paths, s.modulePaths...) } @@ -233,14 +265,22 @@ func (s *systemServerClasspathFragmentMemberType) CreateVariantPropertiesStruct( type systemServerClasspathFragmentSdkMemberProperties struct { android.SdkMemberPropertiesBase - // Contents of the systemserverclasspath fragment + // List of system_server classpath jars, could be either java_library, or java_sdk_library. + // + // The order of this list matters as it is the order that is used in the SYSTEMSERVERCLASSPATH. Contents []string + + // List of jars that system_server loads dynamically using separate classloaders. + // + // The order does not matter. + Standalone_contents []string } func (s *systemServerClasspathFragmentSdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) { module := variant.(*SystemServerClasspathModule) s.Contents = module.properties.Contents + s.Standalone_contents = module.properties.Standalone_contents } func (s *systemServerClasspathFragmentSdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) { @@ -250,6 +290,10 @@ func (s *systemServerClasspathFragmentSdkMemberProperties) AddToPropertySet(ctx if len(s.Contents) > 0 { propertySet.AddPropertyWithTag("contents", s.Contents, requiredMemberDependency) } + + if len(s.Standalone_contents) > 0 { + propertySet.AddPropertyWithTag("standalone_contents", s.Standalone_contents, requiredMemberDependency) + } } var _ android.SdkMemberType = (*systemServerClasspathFragmentMemberType)(nil) diff --git a/java/systemserver_classpath_fragment_test.go b/java/systemserver_classpath_fragment_test.go index 9ad50dd4a..ba328e7b1 100644 --- a/java/systemserver_classpath_fragment_test.go +++ b/java/systemserver_classpath_fragment_test.go @@ -99,7 +99,7 @@ func TestPlatformSystemServerClasspathModule_AndroidMkEntries(t *testing.T) { func TestSystemServerClasspathFragmentWithoutContents(t *testing.T) { prepareForTestWithSystemServerClasspath. ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern( - `\Qempty contents are not allowed\E`)). + `\QEither contents or standalone_contents needs to be non-empty\E`)). RunTestWithBp(t, ` systemserverclasspath_fragment { name: "systemserverclasspath-fragment", diff --git a/mk2rbc/Android.bp b/mk2rbc/Android.bp index b18bfc72c..4fa3eb678 100644 --- a/mk2rbc/Android.bp +++ b/mk2rbc/Android.bp @@ -38,7 +38,6 @@ bootstrap_go_package { "soong_variables.go", "types.go", "variable.go", - "version_defaults.go", ], deps: ["androidmk-parser"], } diff --git a/mk2rbc/cmd/mk2rbc.go b/mk2rbc/cmd/mk2rbc.go index bb5a68033..d9b4e86b7 100644 --- a/mk2rbc/cmd/mk2rbc.go +++ b/mk2rbc/cmd/mk2rbc.go @@ -80,7 +80,6 @@ var backupSuffix string var tracedVariables []string var errorLogger = errorSink{data: make(map[string]datum)} var makefileFinder = &LinuxMakefileFinder{} -var versionDefaultsMk = filepath.Join("build", "make", "core", "version_defaults.mk") func main() { flag.Usage = func() { @@ -168,18 +167,14 @@ func main() { if len(files) != 1 { quit(fmt.Errorf("a launcher can be generated only for a single product")) } - versionDefaults, err := generateVersionDefaults() - if err != nil { - quit(err) + if *inputVariables == "" { + quit(fmt.Errorf("the product launcher requires an input variables file")) } - versionDefaultsPath := outputFilePath(versionDefaultsMk) - err = writeGenerated(versionDefaultsPath, versionDefaults) - if err != nil { - fmt.Fprintf(os.Stderr, "%s: %s", files[0], err) - ok = false + if !convertOne(*inputVariables) { + quit(fmt.Errorf("the product launcher input variables file failed to convert")) } - err = writeGenerated(*launcher, mk2rbc.Launcher(outputFilePath(files[0]), versionDefaultsPath, + err := writeGenerated(*launcher, mk2rbc.Launcher(outputFilePath(files[0]), outputFilePath(*inputVariables), mk2rbc.MakePath2ModuleName(files[0]))) if err != nil { fmt.Fprintf(os.Stderr, "%s: %s", files[0], err) @@ -213,15 +208,6 @@ func main() { } } -func generateVersionDefaults() (string, error) { - versionSettings, err := mk2rbc.ParseVersionDefaults(filepath.Join(*rootDir, versionDefaultsMk)) - if err != nil { - return "", err - } - return mk2rbc.VersionDefaults(versionSettings), nil - -} - func quit(s interface{}) { fmt.Fprintln(os.Stderr, s) os.Exit(2) diff --git a/mk2rbc/expr.go b/mk2rbc/expr.go index ec0b279b9..81b31c736 100644 --- a/mk2rbc/expr.go +++ b/mk2rbc/expr.go @@ -85,6 +85,31 @@ func (s *intLiteralExpr) emitListVarCopy(gctx *generationContext) { s.emit(gctx) } +// Boolean literal +type boolLiteralExpr struct { + literal bool +} + +func (b *boolLiteralExpr) eval(_ map[string]starlarkExpr) (res starlarkExpr, same bool) { + return b, true +} + +func (b *boolLiteralExpr) emit(gctx *generationContext) { + if b.literal { + gctx.write("True") + } else { + gctx.write("False") + } +} + +func (_ *boolLiteralExpr) typ() starlarkType { + return starlarkTypeBool +} + +func (b *boolLiteralExpr) emitListVarCopy(gctx *generationContext) { + b.emit(gctx) +} + // interpolateExpr represents Starlark's interpolation operator <string> % list // we break <string> into a list of chunks, i.e., "first%second%third" % (X, Y) // will have chunks = ["first", "second", "third"] and args = [X, Y] @@ -617,6 +642,55 @@ func (cx *callExpr) emitListVarCopy(gctx *generationContext) { cx.emit(gctx) } +type ifExpr struct { + condition starlarkExpr + ifTrue starlarkExpr + ifFalse starlarkExpr +} + +func (i *ifExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) { + cond, condSame := i.condition.eval(valueMap) + t, tSame := i.ifTrue.eval(valueMap) + f, fSame := i.ifFalse.eval(valueMap) + same = condSame && tSame && fSame + if same { + return i, same + } else { + return &ifExpr{ + condition: cond, + ifTrue: t, + ifFalse: f, + }, same + } +} + +func (i *ifExpr) emit(gctx *generationContext) { + gctx.write("(") + i.ifTrue.emit(gctx) + gctx.write(" if ") + i.condition.emit(gctx) + gctx.write(" else ") + i.ifFalse.emit(gctx) + gctx.write(")") +} + +func (i *ifExpr) typ() starlarkType { + tType := i.ifTrue.typ() + fType := i.ifFalse.typ() + if tType != fType && tType != starlarkTypeUnknown && fType != starlarkTypeUnknown { + panic("Conflicting types in if expression") + } + if tType != starlarkTypeUnknown { + return tType + } else { + return fType + } +} + +func (i *ifExpr) emitListVarCopy(gctx *generationContext) { + i.emit(gctx) +} + type badExpr struct { errorLocation ErrorLocation message string diff --git a/mk2rbc/mk2rbc.go b/mk2rbc/mk2rbc.go index 4b9779c68..d5ff18105 100644 --- a/mk2rbc/mk2rbc.go +++ b/mk2rbc/mk2rbc.go @@ -112,6 +112,7 @@ var knownFunctions = map[string]struct { "filter-out": {baseName + ".filter_out", starlarkTypeList, hiddenArgNone}, "firstword": {"!firstword", starlarkTypeString, hiddenArgNone}, "get-vendor-board-platforms": {"!get-vendor-board-platforms", starlarkTypeList, hiddenArgNone}, // internal macro, used by is-board-platform, etc. + "if": {"!if", starlarkTypeUnknown, hiddenArgNone}, "info": {baseName + ".mkinfo", starlarkTypeVoid, hiddenArgNone}, "is-android-codename": {"!is-android-codename", starlarkTypeBool, hiddenArgNone}, // unused by product config "is-android-codename-in-list": {"!is-android-codename-in-list", starlarkTypeBool, hiddenArgNone}, // unused by product config @@ -1111,10 +1112,8 @@ func (ctx *parseContext) parseCompareSpecialCases(directive *mkparser.Directive, } switch call.name { - case "filter": + case "filter", "filter-out": return ctx.parseCompareFilterFuncResult(directive, call, value, isEq), true - case "filter-out": - return ctx.parseCompareFilterFuncResult(directive, call, value, !isEq), true case "wildcard": return ctx.parseCompareWildcardFuncResult(directive, call, value, !isEq), true case "findstring": @@ -1333,6 +1332,34 @@ func (ctx *parseContext) parseReference(node mkparser.Node, ref *mkparser.MakeSt // TODO (asmundak): if we find many, maybe handle them. return ctx.newBadExpr(node, "SOONG_CONFIG_ variables cannot be referenced, use soong_config_get instead: %s", refDump) } + // Handle substitution references: https://www.gnu.org/software/make/manual/html_node/Substitution-Refs.html + if strings.Contains(refDump, ":") { + parts := strings.SplitN(refDump, ":", 2) + substParts := strings.SplitN(parts[1], "=", 2) + if len(substParts) < 2 || strings.Count(substParts[0], "%") > 1 { + return ctx.newBadExpr(node, "Invalid substitution reference") + } + if !strings.Contains(substParts[0], "%") { + if strings.Contains(substParts[1], "%") { + return ctx.newBadExpr(node, "A substitution reference must have a %% in the \"before\" part of the substitution if it has one in the \"after\" part.") + } + substParts[0] = "%" + substParts[0] + substParts[1] = "%" + substParts[1] + } + v := ctx.addVariable(parts[0]) + if v == nil { + return ctx.newBadExpr(node, "unknown variable %s", refDump) + } + return &callExpr{ + name: "patsubst", + returnType: knownFunctions["patsubst"].returnType, + args: []starlarkExpr{ + &stringLiteralExpr{literal: substParts[0]}, + &stringLiteralExpr{literal: substParts[1]}, + &variableRefExpr{v, ctx.lastAssignment(v.name()) != nil}, + }, + } + } if v := ctx.addVariable(refDump); v != nil { return &variableRefExpr{v, ctx.lastAssignment(v.name()) != nil} } @@ -1370,6 +1397,8 @@ func (ctx *parseContext) parseReference(node mkparser.Node, ref *mkparser.MakeSt return ctx.newBadExpr(node, "cannot handle invoking %s", expr.name) } switch expr.name { + case "if": + return ctx.parseIfFunc(node, args) case "word": return ctx.parseWordFunc(node, args) case "firstword", "lastword": @@ -1425,6 +1454,35 @@ func (ctx *parseContext) parseSubstFunc(node mkparser.Node, fname string, args * } } +func (ctx *parseContext) parseIfFunc(node mkparser.Node, args *mkparser.MakeString) starlarkExpr { + words := args.Split(",") + if len(words) != 2 && len(words) != 3 { + return ctx.newBadExpr(node, "if function should have 2 or 3 arguments, found "+strconv.Itoa(len(words))) + } + condition := ctx.parseMakeString(node, words[0]) + ifTrue := ctx.parseMakeString(node, words[1]) + var ifFalse starlarkExpr + if len(words) == 3 { + ifFalse = ctx.parseMakeString(node, words[2]) + } else { + switch ifTrue.typ() { + case starlarkTypeList: + ifFalse = &listExpr{items: []starlarkExpr{}} + case starlarkTypeInt: + ifFalse = &intLiteralExpr{literal: 0} + case starlarkTypeBool: + ifFalse = &boolLiteralExpr{literal: false} + default: + ifFalse = &stringLiteralExpr{literal: ""} + } + } + return &ifExpr{ + condition, + ifTrue, + ifFalse, + } +} + func (ctx *parseContext) parseWordFunc(node mkparser.Node, args *mkparser.MakeString) starlarkExpr { words := args.Split(",") if len(words) != 2 { @@ -1695,12 +1753,12 @@ func Convert(req Request) (*StarlarkScript, error) { return starScript, nil } -func Launcher(mainModuleUri, versionDefaultsUri, mainModuleName string) string { +func Launcher(mainModuleUri, inputVariablesUri, mainModuleName string) string { var buf bytes.Buffer fmt.Fprintf(&buf, "load(%q, %q)\n", baseUri, baseName) - fmt.Fprintf(&buf, "load(%q, \"version_defaults\")\n", versionDefaultsUri) + fmt.Fprintf(&buf, "load(%q, input_variables_init = \"init\")\n", inputVariablesUri) fmt.Fprintf(&buf, "load(%q, \"init\")\n", mainModuleUri) - fmt.Fprintf(&buf, "%s(%s(%q, init, version_defaults))\n", cfnPrintVars, cfnMain, mainModuleName) + fmt.Fprintf(&buf, "%s(%s(%q, init, input_variables_init))\n", cfnPrintVars, cfnMain, mainModuleName) return buf.String() } diff --git a/mk2rbc/mk2rbc_test.go b/mk2rbc/mk2rbc_test.go index dfdf274ef..78444c9c6 100644 --- a/mk2rbc/mk2rbc_test.go +++ b/mk2rbc/mk2rbc_test.go @@ -390,6 +390,8 @@ endif ifeq (,$(filter barbet coral%,$(TARGET_PRODUCT))) else ifneq (,$(filter barbet%,$(TARGET_PRODUCT))) endif +ifeq (,$(filter-out sunfish_kasan, $(TARGET_PRODUCT))) +endif `, expected: `load("//build/make/core:product_config.rbc", "rblf") @@ -409,6 +411,8 @@ def init(g, handle): pass elif rblf.filter("barbet%", g["TARGET_PRODUCT"]): pass + if not rblf.filter_out("sunfish_kasan", g["TARGET_PRODUCT"]): + pass `, }, { @@ -1087,6 +1091,46 @@ def init(g, handle): pass `, }, + { + desc: "if expression", + mkname: "product.mk", + in: ` +TEST_VAR := foo +TEST_VAR_LIST := foo +TEST_VAR_LIST += bar +TEST_VAR_2 := $(if $(TEST_VAR),bar) +TEST_VAR_3 := $(if $(TEST_VAR),bar,baz) +TEST_VAR_3 := $(if $(TEST_VAR),$(TEST_VAR_LIST)) +`, + expected: `load("//build/make/core:product_config.rbc", "rblf") + +def init(g, handle): + cfg = rblf.cfg(handle) + g["TEST_VAR"] = "foo" + g["TEST_VAR_LIST"] = ["foo"] + g["TEST_VAR_LIST"] += ["bar"] + g["TEST_VAR_2"] = ("bar" if g["TEST_VAR"] else "") + g["TEST_VAR_3"] = ("bar" if g["TEST_VAR"] else "baz") + g["TEST_VAR_3"] = (g["TEST_VAR_LIST"] if g["TEST_VAR"] else []) +`, + }, + { + desc: "substitution references", + mkname: "product.mk", + in: ` +SOURCES := foo.c bar.c +OBJECTS := $(SOURCES:.c=.o) +OBJECTS2 := $(SOURCES:%.c=%.o) +`, + expected: `load("//build/make/core:product_config.rbc", "rblf") + +def init(g, handle): + cfg = rblf.cfg(handle) + g["SOURCES"] = "foo.c bar.c" + g["OBJECTS"] = rblf.mkpatsubst("%.c", "%.o", g["SOURCES"]) + g["OBJECTS2"] = rblf.mkpatsubst("%.c", "%.o", g["SOURCES"]) +`, + }, } var known_variables = []struct { diff --git a/mk2rbc/version_defaults.go b/mk2rbc/version_defaults.go deleted file mode 100644 index 64645d761..000000000 --- a/mk2rbc/version_defaults.go +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2021 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package mk2rbc - -import ( - "bytes" - "fmt" - "io/ioutil" - "os" - "sort" - "strconv" - "strings" - - mkparser "android/soong/androidmk/parser" -) - -const codenamePrefix = "PLATFORM_VERSION_CODENAME." - -// ParseVersionDefaults extracts version settings from the given file -// and returns the map. -func ParseVersionDefaults(path string) (map[string]string, error) { - contents, err := ioutil.ReadFile(path) - if err != nil { - return nil, err - } - parser := mkparser.NewParser(path, bytes.NewBuffer(contents)) - nodes, errs := parser.Parse() - if len(errs) > 0 { - for _, e := range errs { - fmt.Fprintln(os.Stderr, "ERROR:", e) - } - return nil, fmt.Errorf("cannot parse %s", path) - } - - result := map[string]string{ - "DEFAULT_PLATFORM_VERSION": "", - "MAX_PLATFORM_VERSION": "", - "MIN_PLATFORM_VERSION": "A", - "PLATFORM_BASE_SDK_EXTENSION_VERSION": "", - "PLATFORM_SDK_EXTENSION_VERSION": "", - "PLATFORM_SDK_VERSION": "", - "PLATFORM_SECURITY_PATCH": "", - "PLATFORM_VERSION_LAST_STABLE": "", - } - for _, node := range nodes { - asgn, ok := node.(*mkparser.Assignment) - if !(ok && asgn.Name.Const()) { - continue - } - s := asgn.Name.Strings[0] - _, ok = result[s] - if !ok { - ok = strings.HasPrefix(s, codenamePrefix) - } - if !ok { - continue - } - v := asgn.Value - if !v.Const() { - return nil, fmt.Errorf("the value of %s should be constant", s) - } - result[s] = strings.TrimSpace(v.Strings[0]) - } - return result, nil -} - -func genericValue(s string) interface{} { - if ival, err := strconv.ParseInt(s, 0, 0); err == nil { - return ival - } - return s -} - -// VersionDefaults generates the contents of the version_defaults.rbc file -func VersionDefaults(values map[string]string) string { - var sink bytes.Buffer - var lines []string - var codenames []string - for name, value := range values { - if strings.HasPrefix(name, codenamePrefix) { - codenames = append(codenames, - fmt.Sprintf("%q: %q", strings.TrimPrefix(name, codenamePrefix), value)) - } else { - // Print numbers as such - lines = append(lines, fmt.Sprintf(" %s = %#v,\n", - strings.ToLower(name), genericValue(value))) - } - } - - sort.Strings(lines) - sort.Strings(codenames) - - sink.WriteString("version_defaults = struct(\n") - for _, l := range lines { - sink.WriteString(l) - } - sink.WriteString(" codenames = { ") - sink.WriteString(strings.Join(codenames, ", ")) - sink.WriteString(" }\n)\n") - return sink.String() -} diff --git a/mk2rbc/version_defaults_test.go b/mk2rbc/version_defaults_test.go deleted file mode 100644 index c78fa3238..000000000 --- a/mk2rbc/version_defaults_test.go +++ /dev/null @@ -1,60 +0,0 @@ -package mk2rbc - -import ( - "path/filepath" - "reflect" - "strings" - "testing" -) - -func TestParseVersionDefaults(t *testing.T) { - testDir := getTestDirectory() - abspath := func(relPath string) string { return filepath.Join(testDir, relPath) } - actualProducts, err := ParseVersionDefaults(abspath("version_defaults.mk.test")) - if err != nil { - t.Fatal(err) - } - expectedProducts := map[string]string{ - "DEFAULT_PLATFORM_VERSION": "TP1A", - "MAX_PLATFORM_VERSION": "TP1A", - "MIN_PLATFORM_VERSION": "TP1A", - "PLATFORM_BASE_SDK_EXTENSION_VERSION": "0", - "PLATFORM_SDK_EXTENSION_VERSION": "1", - "PLATFORM_SDK_VERSION": "31", - "PLATFORM_SECURITY_PATCH": "2021-10-05", - "PLATFORM_VERSION_LAST_STABLE": "12", - "PLATFORM_VERSION_CODENAME.SP2A": "Sv2", - "PLATFORM_VERSION_CODENAME.TP1A": "Tiramisu", - } - if !reflect.DeepEqual(actualProducts, expectedProducts) { - t.Errorf("\nExpected: %v\n Actual: %v", expectedProducts, actualProducts) - } -} - -func TestVersionDefaults(t *testing.T) { - testDir := getTestDirectory() - abspath := func(relPath string) string { return filepath.Join(testDir, relPath) } - actualProducts, err := ParseVersionDefaults(abspath("version_defaults.mk.test")) - if err != nil { - t.Fatal(err) - } - expectedString := `version_defaults = struct( - default_platform_version = "TP1A", - max_platform_version = "TP1A", - min_platform_version = "TP1A", - platform_base_sdk_extension_version = 0, - platform_sdk_extension_version = 1, - platform_sdk_version = 31, - platform_security_patch = "2021-10-05", - platform_version_last_stable = 12, - codenames = { "SP2A": "Sv2", "TP1A": "Tiramisu" } -) -` - actualString := VersionDefaults(actualProducts) - if !reflect.DeepEqual(actualString, expectedString) { - t.Errorf("\nExpected: %v\nActual:\n%v", - strings.ReplaceAll(expectedString, "\n", "\n"), - strings.ReplaceAll(actualString, "\n", "\n")) - } - -} diff --git a/python/androidmk.go b/python/androidmk.go index 13b41723e..ccc85ec6a 100644 --- a/python/androidmk.go +++ b/python/androidmk.go @@ -75,12 +75,6 @@ func (p *testDecorator) AndroidMk(base *Module, entries *android.AndroidMkEntrie } func (installer *pythonInstaller) AndroidMk(base *Module, entries *android.AndroidMkEntries) { - // Soong installation is only supported for host modules. Have Make - // installation trigger Soong installation. - if base.Target().Os.Class == android.Host { - entries.OutputFile = android.OptionalPathForPath(installer.path) - } - entries.Required = append(entries.Required, "libc++") entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { diff --git a/python/binary.go b/python/binary.go index bf6167c3c..99c625916 100644 --- a/python/binary.go +++ b/python/binary.go @@ -27,7 +27,6 @@ import ( func init() { registerPythonBinaryComponents(android.InitRegistrationContext) - android.RegisterBp2BuildMutator("python_binary_host", PythonBinaryBp2Build) } func registerPythonBinaryComponents(ctx android.RegistrationContext) { @@ -35,29 +34,19 @@ func registerPythonBinaryComponents(ctx android.RegistrationContext) { } type bazelPythonBinaryAttributes struct { - Main string + Main *string Srcs bazel.LabelListAttribute Deps bazel.LabelListAttribute - Python_version string + Python_version *string } -func PythonBinaryBp2Build(ctx android.TopDownMutatorContext) { - m, ok := ctx.Module().(*Module) - if !ok || !m.ConvertWithBp2build(ctx) { - return - } - - // a Module can be something other than a python_binary_host - if ctx.ModuleType() != "python_binary_host" { - return - } - - var main string +func pythonBinaryBp2Build(ctx android.TopDownMutatorContext, m *Module) { + var main *string for _, propIntf := range m.GetProperties() { if props, ok := propIntf.(*BinaryProperties); ok { // main is optional. if props.Main != nil { - main = *props.Main + main = props.Main break } } @@ -69,13 +58,13 @@ func PythonBinaryBp2Build(ctx android.TopDownMutatorContext) { // under Bionic. py3Enabled := proptools.BoolDefault(m.properties.Version.Py3.Enabled, false) py2Enabled := proptools.BoolDefault(m.properties.Version.Py2.Enabled, false) - var python_version string + var python_version *string if py3Enabled && py2Enabled { panic(fmt.Errorf( "error for '%s' module: bp2build's python_binary_host converter does not support "+ "converting a module that is enabled for both Python 2 and 3 at the same time.", m.Name())) } else if py2Enabled { - python_version = "PY2" + python_version = &pyVersion2 } else { // do nothing, since python_version defaults to PY3. } diff --git a/python/library.go b/python/library.go index d136a4efb..d026c1323 100644 --- a/python/library.go +++ b/python/library.go @@ -17,17 +17,14 @@ package python // This file contains the module types for building Python library. import ( - "fmt" - "android/soong/android" "android/soong/bazel" + "github.com/google/blueprint/proptools" ) func init() { registerPythonLibraryComponents(android.InitRegistrationContext) - android.RegisterBp2BuildMutator("python_library_host", PythonLibraryHostBp2Build) - android.RegisterBp2BuildMutator("python_library", PythonLibraryBp2Build) } func registerPythonLibraryComponents(ctx android.RegistrationContext) { @@ -46,43 +43,23 @@ func PythonLibraryHostFactory() android.Module { type bazelPythonLibraryAttributes struct { Srcs bazel.LabelListAttribute Deps bazel.LabelListAttribute - Srcs_version string -} - -func PythonLibraryHostBp2Build(ctx android.TopDownMutatorContext) { - pythonLibBp2Build(ctx, "python_library_host") -} - -func PythonLibraryBp2Build(ctx android.TopDownMutatorContext) { - pythonLibBp2Build(ctx, "python_library") + Srcs_version *string } -func pythonLibBp2Build(ctx android.TopDownMutatorContext, modType string) { - m, ok := ctx.Module().(*Module) - if !ok || !m.ConvertWithBp2build(ctx) { - return - } - - // a Module can be something other than a `modType` - if ctx.ModuleType() != modType { - return - } - +func pythonLibBp2Build(ctx android.TopDownMutatorContext, m *Module) { // TODO(b/182306917): this doesn't fully handle all nested props versioned // by the python version, which would have been handled by the version split // mutator. This is sufficient for very simple python_library modules under // Bionic. py3Enabled := proptools.BoolDefault(m.properties.Version.Py3.Enabled, true) py2Enabled := proptools.BoolDefault(m.properties.Version.Py2.Enabled, false) - var python_version string + var python_version *string if py2Enabled && !py3Enabled { - python_version = "PY2" + python_version = &pyVersion2 } else if !py2Enabled && py3Enabled { - python_version = "PY3" + python_version = &pyVersion3 } else if !py2Enabled && !py3Enabled { - panic(fmt.Errorf( - "error for '%s' module: bp2build's %s converter doesn't understand having "+ - "neither py2 nor py3 enabled", m.Name(), modType)) + ctx.ModuleErrorf("bp2build converter doesn't understand having neither py2 nor py3 enabled") } else { // do nothing, since python_version defaults to PY2ANDPY3 } @@ -95,8 +72,8 @@ func pythonLibBp2Build(ctx android.TopDownMutatorContext, modType string) { } props := bazel.BazelTargetModuleProperties{ - // Use the native py_library rule. - Rule_class: "py_library", + Rule_class: "py_library", + Bzl_load_location: "//build/bazel/rules/python:library.bzl", } ctx.CreateBazelTargetModule(props, android.CommonAttributes{ diff --git a/python/python.go b/python/python.go index 401d91fe3..734ac57f1 100644 --- a/python/python.go +++ b/python/python.go @@ -23,6 +23,7 @@ import ( "strings" "android/soong/bazel" + "github.com/google/blueprint" "github.com/google/blueprint/proptools" @@ -667,18 +668,25 @@ func (p *Module) createSrcsZip(ctx android.ModuleContext, pkgPath string) androi } // isPythonLibModule returns whether the given module is a Python library Module or not -// This is distinguished by the fact that Python libraries are not installable, while other Python -// modules are. func isPythonLibModule(module blueprint.Module) bool { if m, ok := module.(*Module); ok { - // Python library has no bootstrapper or installer - if m.bootstrapper == nil && m.installer == nil { - return true - } + return m.isLibrary() } return false } +// This is distinguished by the fact that Python libraries are not installable, while other Python +// modules are. +func (p *Module) isLibrary() bool { + // Python library has no bootstrapper or installer + return p.bootstrapper == nil && p.installer == nil +} + +func (p *Module) isBinary() bool { + _, ok := p.bootstrapper.(*binaryDecorator) + return ok +} + // collectPathsFromTransitiveDeps checks for source/data files for duplicate paths // for module and its transitive dependencies and collects list of data/source file // zips for transitive dependencies. @@ -752,6 +760,14 @@ func (p *Module) InstallInData() bool { return true } +func (p *Module) ConvertWithBp2build(ctx android.TopDownMutatorContext) { + if p.isLibrary() { + pythonLibBp2Build(ctx, p) + } else if p.isBinary() { + pythonBinaryBp2Build(ctx, p) + } +} + var Bool = proptools.Bool var BoolDefault = proptools.BoolDefault var String = proptools.String diff --git a/rust/bindgen.go b/rust/bindgen.go index 32d02e4f6..5e1b4b74a 100644 --- a/rust/bindgen.go +++ b/rust/bindgen.go @@ -30,7 +30,7 @@ var ( defaultBindgenFlags = []string{""} // bindgen should specify its own Clang revision so updating Clang isn't potentially blocked on bindgen failures. - bindgenClangVersion = "clang-r433403" + bindgenClangVersion = "clang-r437112" _ = pctx.VariableFunc("bindgenClangVersion", func(ctx android.PackageVarContext) string { if override := ctx.Config().Getenv("LLVM_BINDGEN_PREBUILTS_VERSION"); override != "" { diff --git a/rust/builder.go b/rust/builder.go index 60b5926e8..a7efc282a 100644 --- a/rust/builder.go +++ b/rust/builder.go @@ -216,6 +216,13 @@ func transformSrctoCrate(ctx ModuleContext, main android.Path, deps PathDeps, fl // Suppress an implicit sysroot rustcFlags = append(rustcFlags, "--sysroot=/dev/null") + // Enable incremental compilation if requested by user + if ctx.Config().IsEnvTrue("SOONG_RUSTC_INCREMENTAL") { + incrementalPath := android.PathForOutput(ctx, "rustc").String() + + rustcFlags = append(rustcFlags, "-C incremental="+incrementalPath) + } + // Collect linker flags linkFlags = append(linkFlags, flags.GlobalLinkFlags...) linkFlags = append(linkFlags, flags.LinkFlags...) diff --git a/rust/config/global.go b/rust/config/global.go index d3826acf5..bfb2d1ff5 100644 --- a/rust/config/global.go +++ b/rust/config/global.go @@ -24,9 +24,9 @@ import ( var pctx = android.NewPackageContext("android/soong/rust/config") var ( - RustDefaultVersion = "1.56.1p1" + RustDefaultVersion = "1.57.0" RustDefaultBase = "prebuilts/rust/" - DefaultEdition = "2018" + DefaultEdition = "2021" Stdlibs = []string{ "libstd", } @@ -41,12 +41,13 @@ var ( } GlobalRustFlags = []string{ - "--remap-path-prefix $$(pwd)=", + "-Z remap-cwd-prefix=.", "-C codegen-units=1", "-C debuginfo=2", "-C opt-level=3", "-C relocation-model=pic", "-C overflow-checks=on", + "-C force-unwind-tables=yes", // Use v0 mangling to distinguish from C++ symbols "-Z symbol-mangling-version=v0", } @@ -54,6 +55,8 @@ var ( deviceGlobalRustFlags = []string{ "-C panic=abort", "-Z link-native-libraries=no", + // Generate additional debug info for AutoFDO + "-Z debug-info-for-profiling", } deviceGlobalLinkFlags = []string{ diff --git a/rust/project_json.go b/rust/project_json.go index ae48312b5..fe259d6c2 100644 --- a/rust/project_json.go +++ b/rust/project_json.go @@ -211,6 +211,8 @@ func isModuleSupported(ctx android.SingletonContext, module android.Module) (*Mo comp = c.binaryDecorator.baseCompiler case *procMacroDecorator: comp = c.baseCompiler + case *toolchainLibraryDecorator: + comp = c.baseCompiler default: return nil, nil, false } diff --git a/rust/rust.go b/rust/rust.go index b575c7a82..300c0f57a 100644 --- a/rust/rust.go +++ b/rust/rust.go @@ -969,6 +969,7 @@ type dependencyTag struct { name string library bool procMacro bool + dynamic bool } // InstallDepNeeded returns true for rlibs, dylibs, and proc macros so that they or their transitive @@ -979,10 +980,19 @@ func (d dependencyTag) InstallDepNeeded() bool { var _ android.InstallNeededDependencyTag = dependencyTag{} +func (d dependencyTag) LicenseAnnotations() []android.LicenseAnnotation { + if d.library && d.dynamic { + return []android.LicenseAnnotation{android.LicenseAnnotationSharedDependency} + } + return nil +} + +var _ android.LicenseAnnotationsDependencyTag = dependencyTag{} + var ( customBindgenDepTag = dependencyTag{name: "customBindgenTag"} rlibDepTag = dependencyTag{name: "rlibTag", library: true} - dylibDepTag = dependencyTag{name: "dylib", library: true} + dylibDepTag = dependencyTag{name: "dylib", library: true, dynamic: true} procMacroDepTag = dependencyTag{name: "procMacro", procMacro: true} testPerSrcDepTag = dependencyTag{name: "rust_unit_tests"} sourceDepTag = dependencyTag{name: "source"} diff --git a/scripts/Android.bp b/scripts/Android.bp index 730d7567e..4c847a121 100644 --- a/scripts/Android.bp +++ b/scripts/Android.bp @@ -47,15 +47,6 @@ python_library_host { srcs: [ "manifest.py", ], - version: { - py2: { - // TODO(b/203436762) Remove when system/apex/apexer/apexer.py is converted - enabled: true, - }, - py3: { - enabled: true, - }, - }, visibility: ["//system/apex/apexer:__pkg__"], } diff --git a/scripts/check_boot_jars/package_allowed_list.txt b/scripts/check_boot_jars/package_allowed_list.txt index ed63651ef..a02c19560 100644 --- a/scripts/check_boot_jars/package_allowed_list.txt +++ b/scripts/check_boot_jars/package_allowed_list.txt @@ -72,6 +72,7 @@ javax\.xml\.xpath jdk\.internal jdk\.internal\.math jdk\.internal\.misc +jdk\.internal\.ref jdk\.internal\.reflect jdk\.internal\.util jdk\.internal\.vm\.annotation diff --git a/scripts/gen_java_usedby_apex.sh b/scripts/gen_java_usedby_apex.sh index 251d7aa5f..e3985414b 100755 --- a/scripts/gen_java_usedby_apex.sh +++ b/scripts/gen_java_usedby_apex.sh @@ -30,9 +30,11 @@ genUsedByList() { shift rm -f "$out" touch "$out" + echo "<externals>" >> "$out" for x in "$@"; do - "$dexdeps" "$x" >> "$out" || true + "$dexdeps" "$x" >> "$out" || echo "</external>" >> "$out" done + echo "</externals>" >> "$out" } if [[ "$1" == "help" ]] diff --git a/scripts/rbc-run b/scripts/rbc-run index 235da7517..7243421ff 100755 --- a/scripts/rbc-run +++ b/scripts/rbc-run @@ -2,7 +2,7 @@ # Convert and run one configuration # Args: a product/board makefile optionally followed by additional arguments # that will be passed to rbcrun. -[[ $# -gt 0 && -f "$1" ]] || { echo "Usage: ${0##*/} product.mk [Additional rbcrun arguments]" >&2; exit 1; } +[[ $# -gt 1 && -f "$1" && -f "$2" ]] || { echo "Usage: ${0##*/} product.mk input_variables.mk [Additional rbcrun arguments]" >&2; exit 1; } set -eu declare -r output_root="${OUT_DIR:-out}" @@ -10,7 +10,8 @@ declare -r runner="${output_root}/soong/rbcrun" declare -r converter="${output_root}/soong/mk2rbc" declare -r launcher="${output_root}/rbc/launcher.rbc" declare -r makefile="$1" -shift -"${converter}" -mode=write -r --outdir "${output_root}/rbc" --launcher="${launcher}" "${makefile}" +declare -r input_variables="$2" +shift 2 +"${converter}" -mode=write -r --outdir "${output_root}/rbc" --input_variables "${input_variables}" --launcher="${launcher}" "${makefile}" "${runner}" RBC_OUT="make,global" RBC_DEBUG="${RBC_DEBUG:-}" $@ "${launcher}" diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go index ff2af439f..2dacdb55c 100644 --- a/sdk/bootclasspath_fragment_sdk_test.go +++ b/sdk/bootclasspath_fragment_sdk_test.go @@ -40,6 +40,7 @@ func fixtureAddPlatformBootclasspathForBootclasspathFragment(apex, fragment stri } `, apex, fragment)), android.FixtureAddFile("frameworks/base/config/boot-profile.txt", nil), + android.FixtureAddFile("frameworks/base/config/boot-image-profile.txt", nil), android.FixtureAddFile("build/soong/scripts/check_boot_jars/package_allowed_list.txt", nil), ) } diff --git a/sh/sh_binary.go b/sh/sh_binary.go index c32cde01e..2d98e8be0 100644 --- a/sh/sh_binary.go +++ b/sh/sh_binary.go @@ -42,8 +42,6 @@ func init() { pctx.Import("android/soong/android") registerShBuildComponents(android.InitRegistrationContext) - - android.RegisterBp2BuildMutator("sh_binary", ShBinaryBp2Build) } func registerShBuildComponents(ctx android.RegistrationContext) { @@ -516,7 +514,9 @@ func ShTestHostFactory() android.Module { } type bazelShBinaryAttributes struct { - Srcs bazel.LabelListAttribute + Srcs bazel.LabelListAttribute + Filename string + Sub_dir string // Bazel also supports the attributes below, but (so far) these are not required for Bionic // deps // data @@ -538,21 +538,29 @@ type bazelShBinaryAttributes struct { // visibility } -func ShBinaryBp2Build(ctx android.TopDownMutatorContext) { - m, ok := ctx.Module().(*ShBinary) - if !ok || !m.ConvertWithBp2build(ctx) { - return - } - +func (m *ShBinary) ConvertWithBp2build(ctx android.TopDownMutatorContext) { srcs := bazel.MakeLabelListAttribute( android.BazelLabelForModuleSrc(ctx, []string{*m.properties.Src})) + var filename string + if m.properties.Filename != nil { + filename = *m.properties.Filename + } + + var subDir string + if m.properties.Sub_dir != nil { + subDir = *m.properties.Sub_dir + } + attrs := &bazelShBinaryAttributes{ - Srcs: srcs, + Srcs: srcs, + Filename: filename, + Sub_dir: subDir, } props := bazel.BazelTargetModuleProperties{ - Rule_class: "sh_binary", + Rule_class: "sh_binary", + Bzl_load_location: "//build/bazel/rules:sh_binary.bzl", } ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs) diff --git a/shared/Android.bp b/shared/Android.bp index deb17f8f6..3c84f5532 100644 --- a/shared/Android.bp +++ b/shared/Android.bp @@ -9,11 +9,13 @@ bootstrap_go_package { "env.go", "paths.go", "debug.go", + "proto.go", ], testSrcs: [ "paths_test.go", ], deps: [ "soong-bazel", + "golang-protobuf-proto", ], } diff --git a/shared/proto.go b/shared/proto.go new file mode 100644 index 000000000..232656ba4 --- /dev/null +++ b/shared/proto.go @@ -0,0 +1,41 @@ +// Copyright 2021 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package shared + +import ( + "io/ioutil" + "os" + + "google.golang.org/protobuf/proto" +) + +// Save takes a protobuf message, marshals to an array of bytes +// and is then saved to a file. +func Save(pb proto.Message, filepath string) (err error) { + data, err := proto.Marshal(pb) + if err != nil { + return err + } + tempFilepath := filepath + ".tmp" + if err := ioutil.WriteFile(tempFilepath, []byte(data), 0644 /* rw-r--r-- */); err != nil { + return err + } + + if err := os.Rename(tempFilepath, filepath); err != nil { + return err + } + + return nil +} diff --git a/tests/androidmk_test.sh b/tests/androidmk_test.sh new file mode 100755 index 000000000..331dc7770 --- /dev/null +++ b/tests/androidmk_test.sh @@ -0,0 +1,135 @@ +#!/bin/bash -eu + +set -o pipefail + +# How to run: bash path-to-script/androidmk_test.sh +# Tests of converting license functionality of the androidmk tool +REAL_TOP="$(readlink -f "$(dirname "$0")"/../../..)" +$REAL_TOP/build/soong/soong_ui.bash --make-mode androidmk + +source "$(dirname "$0")/lib.sh" + +# Expect to create a new license module +function test_rewrite_license_property_inside_current_directory { + setup + + # Create an Android.mk file + mkdir -p a/b + cat > a/b/Android.mk <<'EOF' +include $(CLEAR_VARS) +LOCAL_MODULE := foo +LOCAL_LICENSE_KINDS := license_kind1 license_kind2 +LOCAL_LICENSE_CONDITIONS := license_condition +LOCAL_NOTICE_FILE := $(LOCAL_PATH)/license_notice1 $(LOCAL_PATH)/license_notice2 +include $(BUILD_PACKAGE) +EOF + + # Create an expected Android.bp file for the module "foo" + cat > a/b/Android.bp <<'EOF' +package { + // See: http://go/android-license-faq + default_applicable_licenses: [ + "a_b_license", + ], +} + +license { + name: "a_b_license", + visibility: [":__subpackages__"], + license_kinds: [ + "license_kind1", + "license_kind2", + ], + license_text: [ + "license_notice1", + "license_notice2", + ], +} + +android_app { + name: "foo", +} +EOF + + run_androidmk_test "a/b/Android.mk" "a/b/Android.bp" +} + +# Expect to reference to an existing license module +function test_rewrite_license_property_outside_current_directory { + setup + + # Create an Android.mk file + mkdir -p a/b/c/d + cat > a/b/c/d/Android.mk <<'EOF' +include $(CLEAR_VARS) +LOCAL_MODULE := foo +LOCAL_LICENSE_KINDS := license_kind1 license_kind2 +LOCAL_LICENSE_CONDITIONS := license_condition +LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../license_notice1 $(LOCAL_PATH)/../../license_notice2 +include $(BUILD_PACKAGE) +EOF + + # Create an expected (input) Android.bp file at a/b/ + cat > a/b/Android.bp <<'EOF' +package { + // See: http://go/android-license-faq + default_applicable_licenses: [ + "a_b_license", + ], +} + +license { + name: "a_b_license", + visibility: [":__subpackages__"], + license_kinds: [ + "license_kind1", + "license_kind2", + ], + license_text: [ + "license_notice1", + "license_notice2", + ], +} + +android_app { + name: "bar", +} +EOF + + # Create an expected (output) Android.bp file for the module "foo" + cat > a/b/c/d/Android.bp <<'EOF' +package { + // See: http://go/android-license-faq + default_applicable_licenses: [ + "a_b_license", + ], +} + +android_app { + name: "foo", +} +EOF + + run_androidmk_test "a/b/c/d/Android.mk" "a/b/c/d/Android.bp" +} + +run_androidmk_test () { + export ANDROID_BUILD_TOP="$MOCK_TOP" + + local out=$($REAL_TOP/*/host/*/bin/androidmk "$1") + local expected=$(<"$2") + + if [[ "$out" != "$expected" ]]; then + ANDROID_BUILD_TOP="$REAL_TOP" + cleanup_mock_top + fail "The output is not the same as the expected" + fi + + ANDROID_BUILD_TOP="$REAL_TOP" + cleanup_mock_top + echo "Succeeded" +} + +test_rewrite_license_property_inside_current_directory + +test_rewrite_license_property_outside_current_directory diff --git a/tests/run_integration_tests.sh b/tests/run_integration_tests.sh index a376e0698..76a918be4 100755 --- a/tests/run_integration_tests.sh +++ b/tests/run_integration_tests.sh @@ -3,8 +3,9 @@ set -o pipefail TOP="$(readlink -f "$(dirname "$0")"/../../..)" +"$TOP/build/soong/tests/androidmk_test.sh" "$TOP/build/soong/tests/bootstrap_test.sh" "$TOP/build/soong/tests/mixed_mode_test.sh" "$TOP/build/soong/tests/bp2build_bazel_test.sh" "$TOP/build/soong/tests/soong_test.sh" -"$TOP/build/bazel/ci/rbc_product_config.sh" aosp_arm64-userdebug +"$TOP/build/bazel/ci/rbc_regression_test.sh" aosp_arm64-userdebug diff --git a/ui/build/config.go b/ui/build/config.go index c30663349..4c26d3ea5 100644 --- a/ui/build/config.go +++ b/ui/build/config.go @@ -1255,16 +1255,22 @@ func (c *configImpl) MetricsUploaderApp() string { return c.metricsUploader } -// LogsDir returns the logs directory where build log and metrics -// files are located. By default, the logs directory is the out +// LogsDir returns the absolute path to the logs directory where build log and +// metrics files are located. By default, the logs directory is the out // directory. If the argument dist is specified, the logs directory // is <dist_dir>/logs. func (c *configImpl) LogsDir() string { + dir := c.OutDir() if c.Dist() { // Always write logs to the real dist dir, even if Bazel is using a rigged dist dir for other files - return filepath.Join(c.RealDistDir(), "logs") + dir = filepath.Join(c.RealDistDir(), "logs") } - return c.OutDir() + absDir, err := filepath.Abs(dir) + if err != nil { + fmt.Fprintf(os.Stderr, "\nError making log dir '%s' absolute: %s\n", dir, err.Error()) + os.Exit(1) + } + return absDir } // BazelMetricsDir returns the <logs dir>/bazel_metrics directory diff --git a/ui/build/soong.go b/ui/build/soong.go index 4ced722d6..5360342eb 100644 --- a/ui/build/soong.go +++ b/ui/build/soong.go @@ -153,7 +153,12 @@ func fileExists(path string) (bool, error) { return true, nil } -func primaryBuilderInvocation(config Config, name string, output string, specificArgs []string) bootstrap.PrimaryBuilderInvocation { +func primaryBuilderInvocation( + config Config, + name string, + output string, + specificArgs []string, + description string) bootstrap.PrimaryBuilderInvocation { commonArgs := make([]string, 0, 0) if !config.skipSoongTests { @@ -178,9 +183,10 @@ func primaryBuilderInvocation(config Config, name string, output string, specifi allArgs = append(allArgs, "Android.bp") return bootstrap.PrimaryBuilderInvocation{ - Inputs: []string{"Android.bp"}, - Outputs: []string{output}, - Args: allArgs, + Inputs: []string{"Android.bp"}, + Outputs: []string{output}, + Args: allArgs, + Description: description, } } @@ -232,7 +238,9 @@ func bootstrapBlueprint(ctx Context, config Config) { config, soongBuildTag, config.SoongNinjaFile(), - mainSoongBuildExtraArgs) + mainSoongBuildExtraArgs, + fmt.Sprintf("analyzing Android.bp files and generating ninja file at %s", config.SoongNinjaFile()), + ) if config.bazelBuildMode() == mixedBuild { // Mixed builds call Bazel from soong_build and they therefore need the @@ -248,7 +256,9 @@ func bootstrapBlueprint(ctx Context, config Config) { config.Bp2BuildMarkerFile(), []string{ "--bp2build_marker", config.Bp2BuildMarkerFile(), - }) + }, + fmt.Sprintf("converting Android.bp files to BUILD files at %s/bp2build", config.SoongOutDir()), + ) jsonModuleGraphInvocation := primaryBuilderInvocation( config, @@ -256,15 +266,20 @@ func bootstrapBlueprint(ctx Context, config Config) { config.ModuleGraphFile(), []string{ "--module_graph_file", config.ModuleGraphFile(), - }) + }, + fmt.Sprintf("generating the Soong module graph at %s", config.ModuleGraphFile()), + ) + queryviewDir := filepath.Join(config.SoongOutDir(), "queryview") queryviewInvocation := primaryBuilderInvocation( config, queryviewTag, config.QueryviewMarkerFile(), []string{ - "--bazel_queryview_dir", filepath.Join(config.SoongOutDir(), "queryview"), - }) + "--bazel_queryview_dir", queryviewDir, + }, + fmt.Sprintf("generating the Soong module graph as a Bazel workspace at %s", queryviewDir), + ) soongDocsInvocation := primaryBuilderInvocation( config, @@ -272,7 +287,9 @@ func bootstrapBlueprint(ctx Context, config Config) { config.SoongDocsHtml(), []string{ "--soong_docs", config.SoongDocsHtml(), - }) + }, + fmt.Sprintf("generating Soong docs at %s", config.SoongDocsHtml()), + ) globFiles := []string{ config.NamedGlobFile(soongBuildTag), @@ -356,6 +373,7 @@ func runSoong(ctx Context, config Config) { soongBuildEnv.Set("BAZEL_OUTPUT_BASE", filepath.Join(config.BazelOutDir(), "output")) soongBuildEnv.Set("BAZEL_WORKSPACE", absPath(ctx, ".")) soongBuildEnv.Set("BAZEL_METRICS_DIR", config.BazelMetricsDir()) + soongBuildEnv.Set("LOG_DIR", config.LogsDir()) // For Soong bootstrapping tests if os.Getenv("ALLOW_MISSING_DEPENDENCIES") == "true" { diff --git a/ui/metrics/Android.bp b/ui/metrics/Android.bp index 96f6389e8..3ba3907a6 100644 --- a/ui/metrics/Android.bp +++ b/ui/metrics/Android.bp @@ -25,6 +25,7 @@ bootstrap_go_package { "soong-ui-metrics_proto", "soong-ui-bp2build_metrics_proto", "soong-ui-tracer", + "soong-shared", ], srcs: [ "metrics.go", diff --git a/ui/metrics/metrics.go b/ui/metrics/metrics.go index f1bb862bd..80f8c1ad0 100644 --- a/ui/metrics/metrics.go +++ b/ui/metrics/metrics.go @@ -32,12 +32,12 @@ package metrics // of what an event is and how the metrics system is a stack based system. import ( - "io/ioutil" "os" "runtime" "strings" "time" + "android/soong/shared" "google.golang.org/protobuf/proto" soong_metrics_proto "android/soong/ui/metrics/metrics_proto" @@ -196,7 +196,7 @@ func (m *Metrics) Dump(out string) error { } m.metrics.HostOs = proto.String(runtime.GOOS) - return save(&m.metrics, out) + return shared.Save(&m.metrics, out) } // SetSoongBuildMetrics sets the metrics collected from the soong_build @@ -228,25 +228,5 @@ func (c *CriticalUserJourneysMetrics) Add(name string, metrics *Metrics) { // Dump saves the collected CUJs metrics to the raw protobuf file. func (c *CriticalUserJourneysMetrics) Dump(filename string) (err error) { - return save(&c.cujs, filename) -} - -// save takes a protobuf message, marshals to an array of bytes -// and is then saved to a file. -func save(pb proto.Message, filename string) (err error) { - data, err := proto.Marshal(pb) - if err != nil { - return err - } - - tempFilename := filename + ".tmp" - if err := ioutil.WriteFile(tempFilename, []byte(data), 0644 /* rw-r--r-- */); err != nil { - return err - } - - if err := os.Rename(tempFilename, filename); err != nil { - return err - } - - return nil + return shared.Save(&c.cujs, filename) } diff --git a/ui/terminal/simple_status.go b/ui/terminal/simple_status.go index 936b275a1..31578136c 100644 --- a/ui/terminal/simple_status.go +++ b/ui/terminal/simple_status.go @@ -22,32 +22,41 @@ import ( ) type simpleStatusOutput struct { - writer io.Writer - formatter formatter - keepANSI bool + writer io.Writer + formatter formatter + keepANSI bool + outputLevel status.MsgLevel } // NewSimpleStatusOutput returns a StatusOutput that represents the // current build status similarly to Ninja's built-in terminal // output. -func NewSimpleStatusOutput(w io.Writer, formatter formatter, keepANSI bool) status.StatusOutput { +func NewSimpleStatusOutput(w io.Writer, formatter formatter, keepANSI bool, quietBuild bool) status.StatusOutput { + level := status.StatusLvl + if quietBuild { + level = status.PrintLvl + } return &simpleStatusOutput{ - writer: w, - formatter: formatter, - keepANSI: keepANSI, + writer: w, + formatter: formatter, + keepANSI: keepANSI, + outputLevel: level, } } func (s *simpleStatusOutput) Message(level status.MsgLevel, message string) { - if level >= status.StatusLvl { + if level >= s.outputLevel { fmt.Fprintln(s.writer, s.formatter.message(level, message)) } } -func (s *simpleStatusOutput) StartAction(action *status.Action, counts status.Counts) { +func (s *simpleStatusOutput) StartAction(_ *status.Action, _ status.Counts) { } func (s *simpleStatusOutput) FinishAction(result status.ActionResult, counts status.Counts) { + if s.outputLevel > status.StatusLvl { + return + } str := result.Description if str == "" { str = result.Command diff --git a/ui/terminal/status.go b/ui/terminal/status.go index 2ad174fee..ff0af4737 100644 --- a/ui/terminal/status.go +++ b/ui/terminal/status.go @@ -29,9 +29,9 @@ import ( func NewStatusOutput(w io.Writer, statusFormat string, forceSimpleOutput, quietBuild, forceKeepANSI bool) status.StatusOutput { formatter := newFormatter(statusFormat, quietBuild) - if !forceSimpleOutput && isSmartTerminal(w) { - return NewSmartStatusOutput(w, formatter) + if forceSimpleOutput || quietBuild || !isSmartTerminal(w) { + return NewSimpleStatusOutput(w, formatter, forceKeepANSI, quietBuild) } else { - return NewSimpleStatusOutput(w, formatter, forceKeepANSI) + return NewSmartStatusOutput(w, formatter) } } |